2 * copyright : (C) 2001-2006 by Richard Moore
3 * copyright : (C) 2004-2005 by Sascha Cunz
4 * License : This file is released under the terms of the LGPL, version 2.
6 * email : sascha.cunz@tiscali.de
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 #include "kpassivepopup.h"
24 #include "kpassivepopup.moc"
27 #include <QApplication>
31 #include <QMouseEvent>
33 #include <QPainterPath>
37 #include <QSystemTrayIcon>
42 #include <kglobalsettings.h>
47 #include <qx11info_x11.h>
53 static const int DEFAULT_POPUP_TYPE
= KPassivePopup::Boxed
;
54 static const int DEFAULT_POPUP_TIME
= 6*1000;
55 static const Qt::WindowFlags POPUP_FLAGS
= Qt::Tool
| Qt::X11BypassWindowManagerHint
| Qt::WindowStaysOnTopHint
| Qt::FramelessWindowHint
;
57 class KPassivePopup::Private
61 : popupStyle( DEFAULT_POPUP_TYPE
),
64 hideDelay( DEFAULT_POPUP_TIME
),
78 QBoxLayout
*topLayout
;
89 KPassivePopup::KPassivePopup( QWidget
*parent
, Qt::WFlags f
)
90 : QFrame( 0, f
? f
: POPUP_FLAGS
),
93 init( parent
? parent
->effectiveWinId() : 0L );
96 KPassivePopup::KPassivePopup( WId win
)
103 #if 0 // These break macos and win32 where the definition of WId makes them ambiguous
104 KPassivePopup::KPassivePopup( int popupStyle
, QWidget
*parent
, Qt::WFlags f
)
105 : QFrame( 0, f
? f
: POPUP_FLAGS
),
108 init( parent
? parent
->winId() : 0L );
109 setPopupStyle( popupStyle
);
112 KPassivePopup::KPassivePopup( int popupStyle
, WId win
, Qt::WFlags f
)
113 : QFrame( 0, f
? f
: POPUP_FLAGS
),
117 setPopupStyle( popupStyle
);
121 void KPassivePopup::init( WId window
)
124 d
->hideTimer
= new QTimer( this );
126 setWindowFlags( POPUP_FLAGS
);
127 setFrameStyle( QFrame::Box
| QFrame::Plain
);
130 if( d
->popupStyle
== Boxed
)
132 setFrameStyle( QFrame::Box
| QFrame::Plain
);
135 else if( d
->popupStyle
== Balloon
)
137 setPalette(QToolTip::palette());
138 //XXX dead ? setAutoMask(true);
140 connect( d
->hideTimer
, SIGNAL( timeout() ), SLOT( hide() ) );
141 connect( this, SIGNAL( clicked() ), SLOT( hide() ) );
144 KPassivePopup::~KPassivePopup()
149 void KPassivePopup::setPopupStyle( int popupstyle
)
151 if ( d
->popupStyle
== popupstyle
)
154 d
->popupStyle
= popupstyle
;
155 if( d
->popupStyle
== Boxed
)
157 setFrameStyle( QFrame::Box
| QFrame::Plain
);
160 else if( d
->popupStyle
== Balloon
)
162 setPalette(QToolTip::palette());
163 //XXX dead ? setAutoMask(true);
167 void KPassivePopup::setView( QWidget
*child
)
173 d
->topLayout
= new QVBoxLayout( this );
174 d
->topLayout
->setMargin( d
->popupStyle
== Balloon
? 22 : KDialog::marginHint() );
175 d
->topLayout
->setSpacing( KDialog::spacingHint() );
176 d
->topLayout
->addWidget( d
->msgView
);
177 d
->topLayout
->activate();
180 void KPassivePopup::setView( const QString
&caption
, const QString
&text
,
181 const QPixmap
&icon
)
183 // kDebug() << "KPassivePopup::setView " << caption << ", " << text;
184 setView( standardView( caption
, text
, icon
, this ) );
188 KVBox
* KPassivePopup::standardView( const QString
& caption
,
193 KVBox
*vb
= new KVBox( parent
? parent
: this );
194 vb
->setSpacing( KDialog::spacingHint() );
197 if ( !icon
.isNull() ) {
198 hb
= new KHBox( vb
);
200 hb
->setSpacing( KDialog::spacingHint() );
201 d
->ttlIcon
= new QLabel( hb
);
202 d
->ttlIcon
->setPixmap( icon
);
203 d
->ttlIcon
->setAlignment( Qt::AlignLeft
);
206 if ( !caption
.isEmpty() ) {
207 d
->ttl
= new QLabel( caption
, hb
? hb
: vb
);
208 QFont fnt
= d
->ttl
->font();
210 d
->ttl
->setFont( fnt
);
211 d
->ttl
->setAlignment( Qt::AlignHCenter
);
214 hb
->setStretchFactor( d
->ttl
, 10 ); // enforce centering
217 if ( !text
.isEmpty() ) {
218 d
->msg
= new QLabel( text
, vb
);
219 d
->msg
->setAlignment( Qt::AlignLeft
);
220 d
->msg
->setTextInteractionFlags(Qt::LinksAccessibleByMouse
);
221 d
->msg
->setOpenExternalLinks(true);
227 void KPassivePopup::setView( const QString
&caption
, const QString
&text
)
229 setView( caption
, text
, QPixmap() );
232 QWidget
*KPassivePopup::view() const
237 int KPassivePopup::timeout() const
242 void KPassivePopup::setTimeout( int delay
)
244 d
->hideDelay
= delay
;
245 if( d
->hideTimer
->isActive() )
248 d
->hideTimer
->start( delay
);
250 d
->hideTimer
->stop();
255 bool KPassivePopup::autoDelete() const
257 return d
->autoDelete
;
260 void KPassivePopup::setAutoDelete( bool autoDelete
)
262 d
->autoDelete
= autoDelete
;
265 void KPassivePopup::mouseReleaseEvent( QMouseEvent
*e
)
268 emit
clicked( e
->pos() );
272 // Main Implementation
275 void KPassivePopup::setVisible( bool visible
)
278 QFrame::setVisible( visible
);
282 if ( size() != sizeHint() )
283 resize( sizeHint() );
285 if ( d
->fixedPosition
.isNull() )
288 if( d
->popupStyle
== Balloon
)
289 setAnchor( d
->fixedPosition
);
291 move( d
->fixedPosition
);
293 QFrame::setVisible( /*visible=*/ true );
295 int delay
= d
->hideDelay
;
297 delay
= DEFAULT_POPUP_TIME
;
301 d
->hideTimer
->start( delay
);
305 void KPassivePopup::show()
310 void KPassivePopup::show(const QPoint
&p
)
312 d
->fixedPosition
= p
;
316 void KPassivePopup::hideEvent( QHideEvent
* )
318 d
->hideTimer
->stop();
323 QRect
KPassivePopup::defaultArea() const
326 NETRootInfo
info( QX11Info::display(),
327 NET::NumberOfDesktops
|
328 NET::CurrentDesktop
|
332 NETRect workArea
= info
.workArea( info
.currentDesktop() );
334 r
.setRect( workArea
.pos
.x
, workArea
.pos
.y
, 0, 0 ); // top left
338 r
.setRect( 100, 100, 200, 200 ); // top left
343 void KPassivePopup::positionSelf()
349 target
= defaultArea();
353 NETWinInfo
ni( QX11Info::display(), d
->window
, QX11Info::appRootWindow(),
354 NET::WMIconGeometry
);
356 // Figure out where to put the popup. Note that we must handle
357 // windows that skip the taskbar cleanly
358 if ( ni
.state() & NET::SkipTaskbar
) {
359 target
= defaultArea();
362 NETRect r
= ni
.iconGeometry();
363 target
.setRect( r
.pos
.x
, r
.pos
.y
, r
.size
.width
, r
.size
.height
);
364 if ( target
.isNull() ) { // bogus value, use the exact position
366 ni
.kdeGeometry( dummy
, r
);
367 target
.setRect( r
.pos
.x
, r
.pos
.y
,
368 r
.size
.width
, r
.size
.height
);
373 target
= defaultArea();
378 void KPassivePopup::moveNear( const QRect
&target
)
380 QPoint pos
= calculateNearbyPoint(target
);
381 if( d
->popupStyle
== Balloon
)
384 move( pos
.x(), pos
.y() );
387 QPoint
KPassivePopup::calculateNearbyPoint( const QRect
&target
) {
388 QPoint pos
= target
.topLeft();
391 int w
= minimumSizeHint().width();
392 int h
= minimumSizeHint().height();
394 QRect r
= KGlobalSettings::desktopGeometry(QPoint(x
+w
/2,y
+h
/2));
396 if( d
->popupStyle
== Balloon
)
398 // find a point to anchor to
399 if( x
+ w
> r
.width() ){
400 x
= x
+ target
.width();
403 if( y
+ h
> r
.height() ){
404 y
= y
+ target
.height();
408 if ( x
< r
.center().x() )
409 x
= x
+ target
.width();
413 // It's apparently trying to go off screen, so display it ALL at the bottom.
414 if ( (y
+ h
) > r
.bottom() )
417 if ( (x
+ w
) > r
.right() )
426 return QPoint( x
, y
);
429 QPoint
KPassivePopup::anchor() const
434 void KPassivePopup::setAnchor(const QPoint
&anchor
)
440 void KPassivePopup::paintEvent( QPaintEvent
* pe
)
442 if( d
->popupStyle
== Balloon
)
446 p
.drawPolygon( d
->surround
);
448 QFrame::paintEvent( pe
);
451 void KPassivePopup::updateMask()
453 // get screen-geometry for screen our anchor is on
454 // (geometry can differ from screen to screen!
455 QRect deskRect
= KGlobalSettings::desktopGeometry(d
->anchor
);
457 int xh
= 70, xl
= 40;
460 else if( width() < 110 )
463 bool bottom
= (d
->anchor
.y() + height()) > ((deskRect
.y() + deskRect
.height()-48));
464 bool right
= (d
->anchor
.x() + width()) > ((deskRect
.x() + deskRect
.width()-48));
466 QPoint corners
[4] = {
467 QPoint( width() - 50, 10 ),
469 QPoint( 10, height() - 50 ),
470 QPoint( width() - 50, height() - 50 )
473 QBitmap
mask( width(), height() );
476 QBrush
brush( Qt::color1
, Qt::SolidPattern
);
482 path
.moveTo(corners
[i
].x(),corners
[i
].y());
483 path
.arcTo(corners
[i
].x(),corners
[i
].y(),40,40, i
* 90 , 90);
484 QPolygon corner
= path
.toFillPolygon().toPolygon();
486 d
->surround
.resize( z
+ corner
.count() - 1 );
487 for (int s
= 1; s
< corner
.count() - 1; s
++, z
++) {
488 d
->surround
.setPoint( z
, corner
[s
] );
491 if (bottom
&& i
== 2) {
493 d
->surround
.resize( z
+ 3 );
494 d
->surround
.setPoint( z
++, QPoint( width() - xh
, height() - 10 ) );
495 d
->surround
.setPoint( z
++, QPoint( width() - 20, height() ) );
496 d
->surround
.setPoint( z
++, QPoint( width() - xl
, height() - 10 ) );
498 d
->surround
.resize( z
+ 3 );
499 d
->surround
.setPoint( z
++, QPoint( xl
, height() - 10 ) );
500 d
->surround
.setPoint( z
++, QPoint( 20, height() ) );
501 d
->surround
.setPoint( z
++, QPoint( xh
, height() - 10 ) );
503 } else if (!bottom
&& i
== 0) {
505 d
->surround
.resize( z
+ 3 );
506 d
->surround
.setPoint( z
++, QPoint( width() - xl
, 10 ) );
507 d
->surround
.setPoint( z
++, QPoint( width() - 20, 0 ) );
508 d
->surround
.setPoint( z
++, QPoint( width() - xh
, 10 ) );
510 d
->surround
.resize( z
+ 3 );
511 d
->surround
.setPoint( z
++, QPoint( xh
, 10 ) );
512 d
->surround
.setPoint( z
++, QPoint( 20, 0 ) );
513 d
->surround
.setPoint( z
++, QPoint( xl
, 10 ) );
518 d
->surround
.resize( z
+ 1 );
519 d
->surround
.setPoint( z
, d
->surround
[0] );
520 p
.drawPolygon( d
->surround
);
523 move( right
? d
->anchor
.x() - width() + 20 : ( d
->anchor
.x() < 11 ? 11 : d
->anchor
.x() - 20 ),
524 bottom
? d
->anchor
.y() - height() : ( d
->anchor
.y() < 11 ? 11 : d
->anchor
.y() ) );
530 // Convenience Methods
533 KPassivePopup
*KPassivePopup::message( const QString
&caption
, const QString
&text
,
535 QWidget
*parent
, int timeout
)
537 return message( DEFAULT_POPUP_TYPE
, caption
, text
, icon
, parent
, timeout
);
540 KPassivePopup
*KPassivePopup::message( const QString
&text
, QWidget
*parent
)
542 return message( DEFAULT_POPUP_TYPE
, QString(), text
, QPixmap(), parent
);
545 KPassivePopup
*KPassivePopup::message( const QString
&caption
, const QString
&text
,
548 return message( DEFAULT_POPUP_TYPE
, caption
, text
, QPixmap(), parent
);
551 KPassivePopup
*KPassivePopup::message( const QString
&caption
, const QString
&text
,
552 const QPixmap
&icon
, WId parent
, int timeout
)
554 return message( DEFAULT_POPUP_TYPE
, caption
, text
, icon
, parent
, timeout
);
557 KPassivePopup
*KPassivePopup::message( const QString
&caption
, const QString
&text
,
559 QSystemTrayIcon
*parent
, int timeout
)
561 return message( DEFAULT_POPUP_TYPE
, caption
, text
, icon
, parent
, timeout
);
564 KPassivePopup
*KPassivePopup::message( const QString
&text
, QSystemTrayIcon
*parent
)
566 return message( DEFAULT_POPUP_TYPE
, QString(), text
, QPixmap(), parent
);
569 KPassivePopup
*KPassivePopup::message( const QString
&caption
, const QString
&text
,
570 QSystemTrayIcon
*parent
)
572 return message( DEFAULT_POPUP_TYPE
, caption
, text
, QPixmap(), parent
);
576 KPassivePopup
*KPassivePopup::message( int popupStyle
, const QString
&caption
, const QString
&text
,
578 QWidget
*parent
, int timeout
)
580 KPassivePopup
*pop
= new KPassivePopup( parent
);
581 pop
->setPopupStyle( popupStyle
);
582 pop
->setAutoDelete( true );
583 pop
->setView( caption
, text
, icon
);
584 pop
->d
->hideDelay
= timeout
;
590 KPassivePopup
*KPassivePopup::message( int popupStyle
, const QString
&text
, QWidget
*parent
)
592 return message( popupStyle
, QString(), text
, QPixmap(), parent
);
595 KPassivePopup
*KPassivePopup::message( int popupStyle
, const QString
&caption
, const QString
&text
,
598 return message( popupStyle
, caption
, text
, QPixmap(), parent
);
601 KPassivePopup
*KPassivePopup::message( int popupStyle
, const QString
&caption
, const QString
&text
,
602 const QPixmap
&icon
, WId parent
, int timeout
)
604 KPassivePopup
*pop
= new KPassivePopup( parent
);
605 pop
->setPopupStyle( popupStyle
);
606 pop
->setAutoDelete( true );
607 pop
->setView( caption
, text
, icon
);
608 pop
->d
->hideDelay
= timeout
;
614 KPassivePopup
*KPassivePopup::message( int popupStyle
, const QString
&caption
, const QString
&text
,
616 QSystemTrayIcon
*parent
, int timeout
)
618 KPassivePopup
*pop
= new KPassivePopup( );
619 pop
->setPopupStyle( popupStyle
);
620 pop
->setAutoDelete( true );
621 pop
->setView( caption
, text
, icon
);
622 pop
->d
->hideDelay
= timeout
;
623 QPoint pos
= pop
->calculateNearbyPoint(parent
->geometry());
625 pop
->moveNear(parent
->geometry());
630 KPassivePopup
*KPassivePopup::message( int popupStyle
, const QString
&text
, QSystemTrayIcon
*parent
)
632 return message( popupStyle
, QString(), text
, QPixmap(), parent
);
635 KPassivePopup
*KPassivePopup::message( int popupStyle
, const QString
&caption
, const QString
&text
,
636 QSystemTrayIcon
*parent
)
638 return message( popupStyle
, caption
, text
, QPixmap(), parent
);