• Skip to content
  • Skip to link menu
KDE 4.2 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     d->topLayout->setMargin( d->popupStyle == Balloon ? 22 : KDialog::marginHint() );
00175     d->topLayout->setSpacing( KDialog::spacingHint() );
00176     d->topLayout->addWidget( d->msgView );
00177     d->topLayout->activate();
00178 }
00179 
00180 void KPassivePopup::setView( const QString &caption, const QString &text,
00181                              const QPixmap &icon )
00182 {
00183     // kDebug() << "KPassivePopup::setView " << caption << ", " << text;
00184     setView( standardView( caption, text, icon, this ) );
00185 }
00186 
00187 
00188 KVBox * KPassivePopup::standardView( const QString& caption,
00189                                      const QString& text,
00190                                      const QPixmap& icon,
00191                                      QWidget *parent )
00192 {
00193     KVBox *vb = new KVBox( parent ? parent : this );
00194     vb->setSpacing( KDialog::spacingHint() );
00195 
00196     KHBox *hb=0;
00197     if ( !icon.isNull() ) {
00198     hb = new KHBox( vb );
00199     hb->setMargin( 0 );
00200     hb->setSpacing( KDialog::spacingHint() );
00201     d->ttlIcon = new QLabel( hb );
00202     d->ttlIcon->setPixmap( icon );
00203         d->ttlIcon->setAlignment( Qt::AlignLeft );
00204     }
00205 
00206     if ( !caption.isEmpty() ) {
00207     d->ttl = new QLabel( caption, hb ? hb : vb );
00208     QFont fnt = d->ttl->font();
00209     fnt.setBold( true );
00210     d->ttl->setFont( fnt );
00211     d->ttl->setAlignment( Qt::AlignHCenter );
00212 
00213         if ( hb )
00214             hb->setStretchFactor( d->ttl, 10 ); // enforce centering
00215     }
00216 
00217     if ( !text.isEmpty() ) {
00218         d->msg = new QLabel( text, vb );
00219         d->msg->setAlignment( Qt::AlignLeft );
00220         d->msg->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
00221         d->msg->setOpenExternalLinks(true);
00222     }
00223 
00224     return vb;
00225 }
00226 
00227 void KPassivePopup::setView( const QString &caption, const QString &text )
00228 {
00229     setView( caption, text, QPixmap() );
00230 }
00231 
00232 QWidget *KPassivePopup::view() const
00233 {
00234     return d->msgView;
00235 }
00236 
00237 int KPassivePopup::timeout() const
00238 {
00239     return d->hideDelay;
00240 }
00241 
00242 void KPassivePopup::setTimeout( int delay )
00243 {
00244     d->hideDelay = delay;
00245     if( d->hideTimer->isActive() )
00246     {
00247         if( delay ) {
00248             d->hideTimer->start( delay );
00249         } else {
00250             d->hideTimer->stop();
00251         }
00252     }
00253 }
00254 
00255 bool KPassivePopup::autoDelete() const
00256 {
00257     return d->autoDelete;
00258 }
00259 
00260 void KPassivePopup::setAutoDelete( bool autoDelete )
00261 {
00262     d->autoDelete = autoDelete;
00263 }
00264 
00265 void KPassivePopup::mouseReleaseEvent( QMouseEvent *e )
00266 {
00267     emit clicked();
00268     emit clicked( e->pos() );
00269 }
00270 
00271 //
00272 // Main Implementation
00273 //
00274 
00275 void KPassivePopup::setVisible( bool visible )
00276 {
00277     if (! visible ) {
00278         QFrame::setVisible( visible );
00279         return;
00280     }
00281 
00282     if ( size() != sizeHint() )
00283         resize( sizeHint() );
00284 
00285     if ( d->fixedPosition.isNull() )
00286         positionSelf();
00287     else {
00288         if( d->popupStyle == Balloon )
00289             setAnchor( d->fixedPosition );
00290         else
00291             move( d->fixedPosition );
00292     }
00293     QFrame::setVisible( /*visible=*/ true );
00294 
00295     int delay = d->hideDelay;
00296     if ( delay < 0 ) {
00297         delay = DEFAULT_POPUP_TIME;
00298     }
00299 
00300     if ( delay > 0 ) {
00301         d->hideTimer->start( delay );
00302     }
00303 }
00304 
00305 void KPassivePopup::show()
00306 {
00307     QFrame::show();
00308 }
00309 
00310 void KPassivePopup::show(const QPoint &p)
00311 {
00312     d->fixedPosition = p;
00313     show();
00314 }
00315 
00316 void KPassivePopup::hideEvent( QHideEvent * )
00317 {
00318     d->hideTimer->stop();
00319     if ( d->autoDelete )
00320         deleteLater();
00321 }
00322 
00323 QRect KPassivePopup::defaultArea() const
00324 {
00325 #ifdef Q_WS_X11
00326     NETRootInfo info( QX11Info::display(),
00327                       NET::NumberOfDesktops |
00328                       NET::CurrentDesktop |
00329                       NET::WorkArea,
00330                       -1, false );
00331     info.activate();
00332     NETRect workArea = info.workArea( info.currentDesktop() );
00333     QRect r;
00334     r.setRect( workArea.pos.x, workArea.pos.y, 0, 0 ); // top left
00335 #else
00336     // FIX IT
00337     QRect r;
00338     r.setRect( 100, 100, 200, 200 ); // top left
00339 #endif
00340     return r;
00341 }
00342 
00343 void KPassivePopup::positionSelf()
00344 {
00345     QRect target;
00346 
00347 #ifdef Q_WS_X11
00348     if ( !d->window ) {
00349         target = defaultArea();
00350     }
00351 
00352     else {
00353         NETWinInfo ni( QX11Info::display(), d->window, QX11Info::appRootWindow(),
00354                        NET::WMIconGeometry );
00355 
00356         // Figure out where to put the popup. Note that we must handle
00357         // windows that skip the taskbar cleanly
00358         if ( ni.state() & NET::SkipTaskbar ) {
00359             target = defaultArea();
00360         }
00361         else {
00362             NETRect r = ni.iconGeometry();
00363             target.setRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00364                 if ( target.isNull() ) { // bogus value, use the exact position
00365                     NETRect dummy;
00366                     ni.kdeGeometry( dummy, r );
00367                     target.setRect( r.pos.x, r.pos.y,
00368                                     r.size.width, r.size.height);
00369                 }
00370         }
00371     }
00372 #else
00373         target = defaultArea();
00374 #endif
00375     moveNear( target );
00376 }
00377 
00378 void KPassivePopup::moveNear( const QRect &target )
00379 {
00380     QPoint pos = calculateNearbyPoint(target);
00381     if( d->popupStyle == Balloon )
00382         setAnchor( pos );
00383     else
00384         move( pos.x(), pos.y() );
00385 }
00386 
00387 QPoint KPassivePopup::calculateNearbyPoint( const QRect &target) {
00388     QPoint pos = target.topLeft();
00389     int x = pos.x();
00390     int y = pos.y();
00391     int w = minimumSizeHint().width();
00392     int h = minimumSizeHint().height();
00393 
00394     QRect r = KGlobalSettings::desktopGeometry(QPoint(x+w/2,y+h/2));
00395 
00396     if( d->popupStyle == Balloon )
00397     {
00398         // find a point to anchor to
00399         if( x + w > r.width() ){
00400             x = x + target.width();
00401         }
00402 
00403         if( y + h > r.height() ){
00404             y = y + target.height();
00405         }
00406     } else
00407     {
00408         if ( x < r.center().x() )
00409             x = x + target.width();
00410         else
00411             x = x - w;
00412 
00413         // It's apparently trying to go off screen, so display it ALL at the bottom.
00414         if ( (y + h) > r.bottom() )
00415             y = r.bottom() - h;
00416 
00417         if ( (x + w) > r.right() )
00418             x = r.right() - w;
00419     }
00420     if ( y < r.top() )
00421         y = r.top();
00422 
00423     if ( x < r.left() )
00424         x = r.left();
00425 
00426     return QPoint( x, y );
00427 }
00428 
00429 QPoint KPassivePopup::anchor() const
00430 {
00431     return d->anchor;
00432 }
00433 
00434 void KPassivePopup::setAnchor(const QPoint &anchor)
00435 {
00436     d->anchor = anchor;
00437     updateMask();
00438 }
00439 
00440 void KPassivePopup::paintEvent( QPaintEvent* pe )
00441 {
00442     if( d->popupStyle == Balloon )
00443     {
00444         QPainter p;
00445         p.begin( this );
00446         p.drawPolygon( d->surround );
00447     } else
00448         QFrame::paintEvent( pe );
00449 }
00450 
00451 void KPassivePopup::updateMask()
00452 {
00453     // get screen-geometry for screen our anchor is on
00454     // (geometry can differ from screen to screen!
00455     QRect deskRect = KGlobalSettings::desktopGeometry(d->anchor);
00456 
00457     int xh = 70, xl = 40;
00458     if( width() < 80 )
00459         xh = xl = 40;
00460     else if( width() < 110 )
00461         xh = width() - 40;
00462 
00463     bool bottom = (d->anchor.y() + height()) > ((deskRect.y() + deskRect.height()-48));
00464     bool right = (d->anchor.x() + width()) > ((deskRect.x() + deskRect.width()-48));
00465 
00466     QPoint corners[4] = {
00467         QPoint( width() - 50, 10 ),
00468         QPoint( 10, 10 ),
00469         QPoint( 10, height() - 50 ),
00470         QPoint( width() - 50, height() - 50 )
00471     };
00472 
00473     QBitmap mask( width(), height() );
00474     mask.clear();
00475     QPainter p( &mask );
00476     QBrush brush( Qt::color1, Qt::SolidPattern );
00477     p.setBrush( brush );
00478 
00479     int i = 0, z = 0;
00480     for (; i < 4; ++i) {
00481         QPainterPath path;
00482         path.moveTo(corners[i].x(),corners[i].y());
00483         path.arcTo(corners[i].x(),corners[i].y(),40,40, i * 90 , 90);
00484         QPolygon corner = path.toFillPolygon().toPolygon();
00485 
00486         d->surround.resize( z + corner.count() - 1 );
00487         for (int s = 1; s < corner.count() - 1; s++, z++) {
00488             d->surround.setPoint( z, corner[s] );
00489         }
00490 
00491         if (bottom && i == 2) {
00492             if (right) {
00493                 d->surround.resize( z + 3 );
00494                 d->surround.setPoint( z++, QPoint( width() - xh, height() - 10 ) );
00495                 d->surround.setPoint( z++, QPoint( width() - 20, height() ) );
00496                 d->surround.setPoint( z++, QPoint( width() - xl, height() - 10 ) );
00497             } else {
00498                 d->surround.resize( z + 3 );
00499                 d->surround.setPoint( z++, QPoint( xl, height() - 10 ) );
00500                 d->surround.setPoint( z++, QPoint( 20, height() ) );
00501                 d->surround.setPoint( z++, QPoint( xh, height() - 10 ) );
00502             }
00503         } else if (!bottom && i == 0) {
00504             if (right) {
00505                 d->surround.resize( z + 3 );
00506                 d->surround.setPoint( z++, QPoint( width() - xl, 10 ) );
00507                 d->surround.setPoint( z++, QPoint( width() - 20, 0 ) );
00508                 d->surround.setPoint( z++, QPoint( width() - xh, 10 ) );
00509             } else {
00510                 d->surround.resize( z + 3 );
00511                 d->surround.setPoint( z++, QPoint( xh, 10 ) );
00512                 d->surround.setPoint( z++, QPoint( 20, 0 ) );
00513                 d->surround.setPoint( z++, QPoint( xl, 10 ) );
00514             }
00515         }
00516     }
00517 
00518     d->surround.resize( z + 1 );
00519     d->surround.setPoint( z, d->surround[0] );
00520     p.drawPolygon( d->surround );
00521     setMask(mask);
00522 
00523     move( right ? d->anchor.x() - width() + 20 : ( d->anchor.x() < 11 ? 11 : d->anchor.x() - 20 ),
00524           bottom ? d->anchor.y() - height() : ( d->anchor.y() < 11 ? 11 : d->anchor.y() ) );
00525 
00526     update();
00527 }
00528 
00529 //
00530 // Convenience Methods
00531 //
00532 
00533 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00534                        const QPixmap &icon,
00535                        QWidget *parent, int timeout )
00536 {
00537     return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, timeout );
00538 }
00539 
00540 KPassivePopup *KPassivePopup::message( const QString &text, QWidget *parent )
00541 {
00542     return message( DEFAULT_POPUP_TYPE, QString(), text, QPixmap(), parent );
00543 }
00544 
00545 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00546                        QWidget *parent )
00547 {
00548     return message( DEFAULT_POPUP_TYPE, caption, text, QPixmap(), parent );
00549 }
00550 
00551 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00552                        const QPixmap &icon, WId parent, int timeout )
00553 {
00554     return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, timeout );
00555 }
00556 
00557 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00558                        const QPixmap &icon,
00559                        QSystemTrayIcon *parent, int timeout )
00560 {
00561     return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, timeout );
00562 }
00563 
00564 KPassivePopup *KPassivePopup::message( const QString &text, QSystemTrayIcon *parent )
00565 {
00566     return message( DEFAULT_POPUP_TYPE, QString(), text, QPixmap(), parent );
00567 }
00568 
00569 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00570                        QSystemTrayIcon *parent )
00571 {
00572     return message( DEFAULT_POPUP_TYPE, caption, text, QPixmap(), parent );
00573 }
00574 
00575 
00576 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00577                        const QPixmap &icon,
00578                        QWidget *parent, int timeout )
00579 {
00580     KPassivePopup *pop = new KPassivePopup( parent );
00581     pop->setPopupStyle( popupStyle );
00582     pop->setAutoDelete( true );
00583     pop->setView( caption, text, icon );
00584     pop->d->hideDelay = timeout;
00585     pop->show();
00586 
00587     return pop;
00588 }
00589 
00590 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &text, QWidget *parent )
00591 {
00592     return message( popupStyle, QString(), text, QPixmap(), parent );
00593 }
00594 
00595 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00596                        QWidget *parent )
00597 {
00598     return message( popupStyle, caption, text, QPixmap(), parent );
00599 }
00600 
00601 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00602                        const QPixmap &icon, WId parent, int timeout )
00603 {
00604     KPassivePopup *pop = new KPassivePopup( parent );
00605     pop->setPopupStyle( popupStyle );
00606     pop->setAutoDelete( true );
00607     pop->setView( caption, text, icon );
00608     pop->d->hideDelay = timeout;
00609     pop->show();
00610 
00611     return pop;
00612 }
00613 
00614 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00615                        const QPixmap &icon,
00616                        QSystemTrayIcon *parent, int timeout )
00617 {
00618     KPassivePopup *pop = new KPassivePopup( );
00619     pop->setPopupStyle( popupStyle );
00620     pop->setAutoDelete( true );
00621     pop->setView( caption, text, icon );
00622     pop->d->hideDelay = timeout;
00623     QPoint pos = pop->calculateNearbyPoint(parent->geometry());
00624     pop->show(pos);
00625     pop->moveNear(parent->geometry());
00626 
00627     return pop;
00628 }
00629 
00630 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &text, QSystemTrayIcon *parent )
00631 {
00632     return message( popupStyle, QString(), text, QPixmap(), parent );
00633 }
00634 
00635 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00636                        QSystemTrayIcon *parent )
00637 {
00638     return message( popupStyle, caption, text, QPixmap(), parent );
00639 }
00640 
00641 
00642 // Local Variables:
00643 // c-basic-offset: 4
00644 // 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
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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