• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kpassivepopup.cpp

Go to the documentation of this file.
00001 /*
00002  *   copyright            : (C) 2001-2006 by Richard Moore
00003  *   copyright            : (C) 2004-2005 by Sascha Cunz
00004  *   License              : This file is released under the terms of the LGPL, version 2.
00005  *   email                : rich@kde.org
00006  *   email                : sascha.cunz@tiscali.de
00007  *
00008  *   This library is free software; you can redistribute it and/or
00009  *   modify it under the terms of the GNU Library General Public
00010  *   License as published by the Free Software Foundation; either
00011  *   version 2 of the License, or (at your option) any later version.
00012  *
00013  *   This library is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *   Library General Public License for more details.
00017  *
00018  *   You should have received a copy of the GNU Library General Public License
00019  *   along with this library; see the file COPYING.LIB.  If not, write to
00020  *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021  */
00022 
00023 #include "kpassivepopup.h"
00024 #include "kpassivepopup.moc"
00025 
00026 // Qt
00027 #include <QApplication>
00028 #include <QBitmap>
00029 #include <QLabel>
00030 #include <QLayout>
00031 #include <QMouseEvent>
00032 #include <QPainter>
00033 #include <QPainterPath>
00034 #include <QPolygonF>
00035 #include <QTimer>
00036 #include <QToolTip>
00037 #include <QSystemTrayIcon>
00038 
00039 #include <kvbox.h>
00040 #include <kdebug.h>
00041 #include <kdialog.h>
00042 #include <kglobalsettings.h>
00043 
00044 #include <kconfig.h>
00045 
00046 #ifdef Q_WS_X11
00047 #include <qx11info_x11.h>
00048 #include <netwm.h>
00049 #endif
00050 
00051 #include <config.h>
00052 
00053 static const int DEFAULT_POPUP_TYPE = KPassivePopup::Boxed;
00054 static const int DEFAULT_POPUP_TIME = 6*1000;
00055 static const Qt::WindowFlags POPUP_FLAGS = Qt::Tool | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint;
00056 
00057 class KPassivePopup::Private
00058 {
00059 public:
00060     Private()
00061     : popupStyle( DEFAULT_POPUP_TYPE ),
00062       msgView(0),
00063       topLayout(0),
00064       hideDelay( DEFAULT_POPUP_TIME ),
00065       hideTimer(0),
00066       autoDelete( false )
00067     {
00068 
00069     }
00070 
00071     int popupStyle;
00072     QPolygon surround;
00073     QPoint                    anchor;
00074     QPoint                    fixedPosition;
00075 
00076     WId window;
00077     QWidget *msgView;
00078     QBoxLayout *topLayout;
00079     int hideDelay;
00080     QTimer *hideTimer;
00081 
00082     QLabel *ttlIcon;
00083     QLabel *ttl;
00084     QLabel *msg;
00085 
00086     bool autoDelete;
00087 };
00088 
00089 KPassivePopup::KPassivePopup( QWidget *parent, Qt::WFlags f )
00090     : QFrame( 0, f ? f : POPUP_FLAGS ),
00091       d(new Private())
00092 {
00093     init( parent ? parent->effectiveWinId() : 0L );
00094 }
00095 
00096 KPassivePopup::KPassivePopup( WId win )
00097     : QFrame( 0 ),
00098       d(new Private())
00099 {
00100     init( win );
00101 }
00102 
00103 #if 0 // These break macos and win32 where the definition of WId makes them ambiguous
00104 KPassivePopup::KPassivePopup( int popupStyle, QWidget *parent, Qt::WFlags f )
00105     : QFrame( 0, f ? f : POPUP_FLAGS ),
00106       d(new Private())
00107 {
00108     init( parent ? parent->winId() : 0L );
00109     setPopupStyle( popupStyle );
00110 }
00111 
00112 KPassivePopup::KPassivePopup( int popupStyle, WId win, Qt::WFlags f )
00113     : QFrame( 0, f ? f : POPUP_FLAGS ),
00114       d(new Private())
00115 {
00116     init( win );
00117     setPopupStyle( popupStyle );
00118 }
00119 #endif
00120 
00121 void KPassivePopup::init( WId window )
00122 {
00123     d->window = window;
00124     d->hideTimer = new QTimer( this );
00125 
00126     setWindowFlags( POPUP_FLAGS );
00127     setFrameStyle( QFrame::Box| QFrame::Plain );
00128     setLineWidth( 2 );
00129 
00130     if( d->popupStyle == Boxed )
00131     {
00132         setFrameStyle( QFrame::Box| QFrame::Plain );
00133         setLineWidth( 2 );
00134     }
00135     else if( d->popupStyle == Balloon )
00136     {
00137         setPalette(QToolTip::palette());
00138         //XXX dead ? setAutoMask(true);
00139     }
00140     connect( d->hideTimer, SIGNAL( timeout() ), SLOT( hide() ) );
00141     connect( this, SIGNAL( clicked() ), SLOT( hide() ) );
00142 }
00143 
00144 KPassivePopup::~KPassivePopup()
00145 {
00146     delete d;
00147 }
00148 
00149 void KPassivePopup::setPopupStyle( int popupstyle )
00150 {
00151     if ( d->popupStyle == popupstyle )
00152     return;
00153 
00154     d->popupStyle = popupstyle;
00155     if( d->popupStyle == Boxed )
00156     {
00157         setFrameStyle( QFrame::Box| QFrame::Plain );
00158         setLineWidth( 2 );
00159     }
00160     else if( d->popupStyle == Balloon )
00161     {
00162         setPalette(QToolTip::palette());
00163         //XXX dead ? setAutoMask(true);
00164     }
00165 }
00166 
00167 void KPassivePopup::setView( QWidget *child )
00168 {
00169     delete d->msgView;
00170     d->msgView = child;
00171 
00172     delete d->topLayout;
00173     d->topLayout = new QVBoxLayout( this );
00174     if ( d->popupStyle == Balloon ) {
00175         d->topLayout->setMargin( 2 * KDialog::marginHint() );
00176     }
00177     d->topLayout->addWidget( d->msgView );
00178     d->topLayout->activate();
00179 }
00180 
00181 void KPassivePopup::setView( const QString &caption, const QString &text,
00182                              const QPixmap &icon )
00183 {
00184     // kDebug() << "KPassivePopup::setView " << caption << ", " << text;
00185     setView( standardView( caption, text, icon, this ) );
00186 }
00187 
00188 
00189 KVBox * KPassivePopup::standardView( const QString& caption,
00190                                      const QString& text,
00191                                      const QPixmap& icon,
00192                                      QWidget *parent )
00193 {
00194     KVBox *vb = new KVBox( parent ? parent : this );
00195     vb->setSpacing( -1 );
00196 
00197     KHBox *hb=0;
00198     if ( !icon.isNull() ) {
00199     hb = new KHBox( vb );
00200     hb->setMargin( 0 );
00201     hb->setSpacing( -1 );
00202     d->ttlIcon = new QLabel( hb );
00203     d->ttlIcon->setPixmap( icon );
00204         d->ttlIcon->setAlignment( Qt::AlignLeft );
00205     }
00206 
00207     if ( !caption.isEmpty() ) {
00208     d->ttl = new QLabel( caption, hb ? hb : vb );
00209     QFont fnt = d->ttl->font();
00210     fnt.setBold( true );
00211     d->ttl->setFont( fnt );
00212     d->ttl->setAlignment( Qt::AlignHCenter );
00213 
00214         if ( hb )
00215             hb->setStretchFactor( d->ttl, 10 ); // enforce centering
00216     }
00217 
00218     if ( !text.isEmpty() ) {
00219         d->msg = new QLabel( text, vb );
00220         d->msg->setAlignment( Qt::AlignLeft );
00221         d->msg->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
00222         d->msg->setOpenExternalLinks(true);
00223     }
00224 
00225     return vb;
00226 }
00227 
00228 void KPassivePopup::setView( const QString &caption, const QString &text )
00229 {
00230     setView( caption, text, QPixmap() );
00231 }
00232 
00233 QWidget *KPassivePopup::view() const
00234 {
00235     return d->msgView;
00236 }
00237 
00238 int KPassivePopup::timeout() const
00239 {
00240     return d->hideDelay;
00241 }
00242 
00243 void KPassivePopup::setTimeout( int delay )
00244 {
00245     d->hideDelay = delay;
00246     if( d->hideTimer->isActive() )
00247     {
00248         if( delay ) {
00249             d->hideTimer->start( delay );
00250         } else {
00251             d->hideTimer->stop();
00252         }
00253     }
00254 }
00255 
00256 bool KPassivePopup::autoDelete() const
00257 {
00258     return d->autoDelete;
00259 }
00260 
00261 void KPassivePopup::setAutoDelete( bool autoDelete )
00262 {
00263     d->autoDelete = autoDelete;
00264 }
00265 
00266 void KPassivePopup::mouseReleaseEvent( QMouseEvent *e )
00267 {
00268     emit clicked();
00269     emit clicked( e->pos() );
00270 }
00271 
00272 //
00273 // Main Implementation
00274 //
00275 
00276 void KPassivePopup::setVisible( bool visible )
00277 {
00278     if (! visible ) {
00279         QFrame::setVisible( visible );
00280         return;
00281     }
00282 
00283     if ( size() != sizeHint() )
00284         resize( sizeHint() );
00285 
00286     if ( d->fixedPosition.isNull() )
00287         positionSelf();
00288     else {
00289         if( d->popupStyle == Balloon )
00290             setAnchor( d->fixedPosition );
00291         else
00292             move( d->fixedPosition );
00293     }
00294     QFrame::setVisible( /*visible=*/ true );
00295 
00296     int delay = d->hideDelay;
00297     if ( delay < 0 ) {
00298         delay = DEFAULT_POPUP_TIME;
00299     }
00300 
00301     if ( delay > 0 ) {
00302         d->hideTimer->start( delay );
00303     }
00304 }
00305 
00306 void KPassivePopup::show()
00307 {
00308     QFrame::show();
00309 }
00310 
00311 void KPassivePopup::show(const QPoint &p)
00312 {
00313     d->fixedPosition = p;
00314     show();
00315 }
00316 
00317 void KPassivePopup::hideEvent( QHideEvent * )
00318 {
00319     d->hideTimer->stop();
00320     if ( d->autoDelete )
00321         deleteLater();
00322 }
00323 
00324 QRect KPassivePopup::defaultArea() const
00325 {
00326 #ifdef Q_WS_X11
00327     NETRootInfo info( QX11Info::display(),
00328                       NET::NumberOfDesktops |
00329                       NET::CurrentDesktop |
00330                       NET::WorkArea,
00331                       -1, false );
00332     info.activate();
00333     NETRect workArea = info.workArea( info.currentDesktop() );
00334     QRect r;
00335     r.setRect( workArea.pos.x, workArea.pos.y, 0, 0 ); // top left
00336 #else
00337     // FIX IT
00338     QRect r;
00339     r.setRect( 100, 100, 200, 200 ); // top left
00340 #endif
00341     return r;
00342 }
00343 
00344 void KPassivePopup::positionSelf()
00345 {
00346     QRect target;
00347 
00348 #ifdef Q_WS_X11
00349     if ( !d->window ) {
00350         target = defaultArea();
00351     }
00352 
00353     else {
00354         NETWinInfo ni( QX11Info::display(), d->window, QX11Info::appRootWindow(),
00355                        NET::WMIconGeometry );
00356 
00357         // Figure out where to put the popup. Note that we must handle
00358         // windows that skip the taskbar cleanly
00359         if ( ni.state() & NET::SkipTaskbar ) {
00360             target = defaultArea();
00361         }
00362         else {
00363             NETRect r = ni.iconGeometry();
00364             target.setRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00365                 if ( target.isNull() ) { // bogus value, use the exact position
00366                     NETRect dummy;
00367                     ni.kdeGeometry( dummy, r );
00368                     target.setRect( r.pos.x, r.pos.y,
00369                                     r.size.width, r.size.height);
00370                 }
00371         }
00372     }
00373 #else
00374         target = defaultArea();
00375 #endif
00376     moveNear( target );
00377 }
00378 
00379 void KPassivePopup::moveNear( const QRect &target )
00380 {
00381     QPoint pos = calculateNearbyPoint(target);
00382     if( d->popupStyle == Balloon )
00383         setAnchor( pos );
00384     else
00385         move( pos.x(), pos.y() );
00386 }
00387 
00388 QPoint KPassivePopup::calculateNearbyPoint( const QRect &target) {
00389     QPoint pos = target.topLeft();
00390     int x = pos.x();
00391     int y = pos.y();
00392     int w = minimumSizeHint().width();
00393     int h = minimumSizeHint().height();
00394 
00395     QRect r = KGlobalSettings::desktopGeometry(QPoint(x+w/2,y+h/2));
00396 
00397     if( d->popupStyle == Balloon )
00398     {
00399         // find a point to anchor to
00400         if( x + w > r.width() ){
00401             x = x + target.width();
00402         }
00403 
00404         if( y + h > r.height() ){
00405             y = y + target.height();
00406         }
00407     } else
00408     {
00409         if ( x < r.center().x() )
00410             x = x + target.width();
00411         else
00412             x = x - w;
00413 
00414         // It's apparently trying to go off screen, so display it ALL at the bottom.
00415         if ( (y + h) > r.bottom() )
00416             y = r.bottom() - h;
00417 
00418         if ( (x + w) > r.right() )
00419             x = r.right() - w;
00420     }
00421     if ( y < r.top() )
00422         y = r.top();
00423 
00424     if ( x < r.left() )
00425         x = r.left();
00426 
00427     return QPoint( x, y );
00428 }
00429 
00430 QPoint KPassivePopup::anchor() const
00431 {
00432     return d->anchor;
00433 }
00434 
00435 void KPassivePopup::setAnchor(const QPoint &anchor)
00436 {
00437     d->anchor = anchor;
00438     updateMask();
00439 }
00440 
00441 void KPassivePopup::paintEvent( QPaintEvent* pe )
00442 {
00443     if( d->popupStyle == Balloon )
00444     {
00445         QPainter p;
00446         p.begin( this );
00447         p.drawPolygon( d->surround );
00448     } else
00449         QFrame::paintEvent( pe );
00450 }
00451 
00452 void KPassivePopup::updateMask()
00453 {
00454     // get screen-geometry for screen our anchor is on
00455     // (geometry can differ from screen to screen!
00456     QRect deskRect = KGlobalSettings::desktopGeometry(d->anchor);
00457 
00458     int xh = 70, xl = 40;
00459     if( width() < 80 )
00460         xh = xl = 40;
00461     else if( width() < 110 )
00462         xh = width() - 40;
00463 
00464     bool bottom = (d->anchor.y() + height()) > ((deskRect.y() + deskRect.height()-48));
00465     bool right = (d->anchor.x() + width()) > ((deskRect.x() + deskRect.width()-48));
00466 
00467     QPoint corners[4] = {
00468         QPoint( width() - 50, 10 ),
00469         QPoint( 10, 10 ),
00470         QPoint( 10, height() - 50 ),
00471         QPoint( width() - 50, height() - 50 )
00472     };
00473 
00474     QBitmap mask( width(), height() );
00475     mask.clear();
00476     QPainter p( &mask );
00477     QBrush brush( Qt::color1, Qt::SolidPattern );
00478     p.setBrush( brush );
00479 
00480     int i = 0, z = 0;
00481     for (; i < 4; ++i) {
00482         QPainterPath path;
00483         path.moveTo(corners[i].x(),corners[i].y());
00484         path.arcTo(corners[i].x(),corners[i].y(),40,40, i * 90 , 90);
00485         QPolygon corner = path.toFillPolygon().toPolygon();
00486 
00487         d->surround.resize( z + corner.count() - 1 );
00488         for (int s = 1; s < corner.count() - 1; s++, z++) {
00489             d->surround.setPoint( z, corner[s] );
00490         }
00491 
00492         if (bottom && i == 2) {
00493             if (right) {
00494                 d->surround.resize( z + 3 );
00495                 d->surround.setPoint( z++, QPoint( width() - xh, height() - 10 ) );
00496                 d->surround.setPoint( z++, QPoint( width() - 20, height() ) );
00497                 d->surround.setPoint( z++, QPoint( width() - xl, height() - 10 ) );
00498             } else {
00499                 d->surround.resize( z + 3 );
00500                 d->surround.setPoint( z++, QPoint( xl, height() - 10 ) );
00501                 d->surround.setPoint( z++, QPoint( 20, height() ) );
00502                 d->surround.setPoint( z++, QPoint( xh, height() - 10 ) );
00503             }
00504         } else if (!bottom && i == 0) {
00505             if (right) {
00506                 d->surround.resize( z + 3 );
00507                 d->surround.setPoint( z++, QPoint( width() - xl, 10 ) );
00508                 d->surround.setPoint( z++, QPoint( width() - 20, 0 ) );
00509                 d->surround.setPoint( z++, QPoint( width() - xh, 10 ) );
00510             } else {
00511                 d->surround.resize( z + 3 );
00512                 d->surround.setPoint( z++, QPoint( xh, 10 ) );
00513                 d->surround.setPoint( z++, QPoint( 20, 0 ) );
00514                 d->surround.setPoint( z++, QPoint( xl, 10 ) );
00515             }
00516         }
00517     }
00518 
00519     d->surround.resize( z + 1 );
00520     d->surround.setPoint( z, d->surround[0] );
00521     p.drawPolygon( d->surround );
00522     setMask(mask);
00523 
00524     move( right ? d->anchor.x() - width() + 20 : ( d->anchor.x() < 11 ? 11 : d->anchor.x() - 20 ),
00525           bottom ? d->anchor.y() - height() : ( d->anchor.y() < 11 ? 11 : d->anchor.y() ) );
00526 
00527     update();
00528 }
00529 
00530 //
00531 // Convenience Methods
00532 //
00533 
00534 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00535                        const QPixmap &icon,
00536                        QWidget *parent, int timeout )
00537 {
00538     return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, timeout );
00539 }
00540 
00541 KPassivePopup *KPassivePopup::message( const QString &text, QWidget *parent )
00542 {
00543     return message( DEFAULT_POPUP_TYPE, QString(), text, QPixmap(), parent );
00544 }
00545 
00546 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00547                        QWidget *parent )
00548 {
00549     return message( DEFAULT_POPUP_TYPE, caption, text, QPixmap(), parent );
00550 }
00551 
00552 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00553                        const QPixmap &icon, WId parent, int timeout )
00554 {
00555     return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, timeout );
00556 }
00557 
00558 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00559                        const QPixmap &icon,
00560                        QSystemTrayIcon *parent, int timeout )
00561 {
00562     return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, timeout );
00563 }
00564 
00565 KPassivePopup *KPassivePopup::message( const QString &text, QSystemTrayIcon *parent )
00566 {
00567     return message( DEFAULT_POPUP_TYPE, QString(), text, QPixmap(), parent );
00568 }
00569 
00570 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00571                        QSystemTrayIcon *parent )
00572 {
00573     return message( DEFAULT_POPUP_TYPE, caption, text, QPixmap(), parent );
00574 }
00575 
00576 
00577 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00578                        const QPixmap &icon,
00579                        QWidget *parent, int timeout )
00580 {
00581     KPassivePopup *pop = new KPassivePopup( parent );
00582     pop->setPopupStyle( popupStyle );
00583     pop->setAutoDelete( true );
00584     pop->setView( caption, text, icon );
00585     pop->d->hideDelay = timeout;
00586     pop->show();
00587 
00588     return pop;
00589 }
00590 
00591 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &text, QWidget *parent )
00592 {
00593     return message( popupStyle, QString(), text, QPixmap(), parent );
00594 }
00595 
00596 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00597                        QWidget *parent )
00598 {
00599     return message( popupStyle, caption, text, QPixmap(), parent );
00600 }
00601 
00602 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00603                        const QPixmap &icon, WId parent, int timeout )
00604 {
00605     KPassivePopup *pop = new KPassivePopup( parent );
00606     pop->setPopupStyle( popupStyle );
00607     pop->setAutoDelete( true );
00608     pop->setView( caption, text, icon );
00609     pop->d->hideDelay = timeout;
00610     pop->show();
00611 
00612     return pop;
00613 }
00614 
00615 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00616                        const QPixmap &icon,
00617                        QSystemTrayIcon *parent, int timeout )
00618 {
00619     KPassivePopup *pop = new KPassivePopup( );
00620     pop->setPopupStyle( popupStyle );
00621     pop->setAutoDelete( true );
00622     pop->setView( caption, text, icon );
00623     pop->d->hideDelay = timeout;
00624     QPoint pos = pop->calculateNearbyPoint(parent->geometry());
00625     pop->show(pos);
00626     pop->moveNear(parent->geometry());
00627 
00628     return pop;
00629 }
00630 
00631 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &text, QSystemTrayIcon *parent )
00632 {
00633     return message( popupStyle, QString(), text, QPixmap(), parent );
00634 }
00635 
00636 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00637                        QSystemTrayIcon *parent )
00638 {
00639     return message( popupStyle, caption, text, QPixmap(), parent );
00640 }
00641 
00642 
00643 // Local Variables:
00644 // c-basic-offset: 4
00645 // End:

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal