• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kpassivepopup.cpp

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