00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <kconfig.h>
00010
00011 #include <qapplication.h>
00012 #include <qlabel.h>
00013 #include <qlayout.h>
00014 #include <qtimer.h>
00015 #include <qvbox.h>
00016 #include <qpainter.h>
00017 #include <qtooltip.h>
00018 #include <qbitmap.h>
00019 #include <qpointarray.h>
00020
00021 #include <kdebug.h>
00022 #include <kdialog.h>
00023 #include <kpixmap.h>
00024 #include <kpixmapeffect.h>
00025 #include <kglobalsettings.h>
00026
00027 #include "config.h"
00028 #ifdef Q_WS_X11
00029 #include <netwm.h>
00030 #endif
00031
00032 #include "kpassivepopup.h"
00033 #include "kpassivepopup.moc"
00034
00035 class KPassivePopup::Private
00036 {
00037 public:
00038 int popupStyle;
00039 QPointArray surround;
00040 QPoint anchor;
00041 QPoint fixedPosition;
00042 };
00043
00044 static const int DEFAULT_POPUP_TYPE = KPassivePopup::Boxed;
00045 static const int DEFAULT_POPUP_TIME = 6*1000;
00046 static const int POPUP_FLAGS = Qt::WStyle_Customize | Qt::WDestructiveClose | Qt::WX11BypassWM
00047 | Qt::WStyle_StaysOnTop | Qt::WStyle_Tool | Qt::WStyle_NoBorder;
00048
00049 KPassivePopup::KPassivePopup( QWidget *parent, const char *name, WFlags f )
00050 : QFrame( 0, name, f ? f : POPUP_FLAGS ),
00051 window( parent ? parent->winId() : 0L ), msgView( 0 ), topLayout( 0 ),
00052 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ),
00053 m_autoDelete( false )
00054 {
00055 init( DEFAULT_POPUP_TYPE );
00056 }
00057
00058 KPassivePopup::KPassivePopup( WId win, const char *name, WFlags f )
00059 : QFrame( 0, name, f ? f : POPUP_FLAGS ),
00060 window( win ), msgView( 0 ), topLayout( 0 ),
00061 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ),
00062 m_autoDelete( false )
00063 {
00064 init( DEFAULT_POPUP_TYPE );
00065 }
00066
00067 KPassivePopup::KPassivePopup( int popupStyle, QWidget *parent, const char *name, WFlags f )
00068 : QFrame( 0, name, f ? f : POPUP_FLAGS ),
00069 window( parent ? parent->winId() : 0L ), msgView( 0 ), topLayout( 0 ),
00070 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ),
00071 m_autoDelete( false )
00072 {
00073 init( popupStyle );
00074 }
00075
00076 KPassivePopup::KPassivePopup( int popupStyle, WId win, const char *name, WFlags f )
00077 : QFrame( 0, name, f ? f : POPUP_FLAGS ),
00078 window( win ), msgView( 0 ), topLayout( 0 ),
00079 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ),
00080 m_autoDelete( false )
00081 {
00082 init( popupStyle );
00083 }
00084
00085 void KPassivePopup::init( int popupStyle )
00086 {
00087 d = new Private;
00088 d->popupStyle = popupStyle;
00089 if( popupStyle == Boxed )
00090 {
00091 setFrameStyle( QFrame::Box| QFrame::Plain );
00092 setLineWidth( 2 );
00093 }
00094 else if( popupStyle == Balloon )
00095 {
00096 setPalette(QToolTip::palette());
00097 setAutoMask(TRUE);
00098 }
00099 connect( hideTimer, SIGNAL( timeout() ), SLOT( hide() ) );
00100 connect( this, SIGNAL( clicked() ), SLOT( hide() ) );
00101 }
00102
00103 KPassivePopup::~KPassivePopup()
00104 {
00105 delete d;
00106 }
00107
00108 void KPassivePopup::setView( QWidget *child )
00109 {
00110 delete msgView;
00111 msgView = child;
00112
00113 delete topLayout;
00114 topLayout = new QVBoxLayout( this, d->popupStyle == Balloon ? 22 : KDialog::marginHint(), KDialog::spacingHint() );
00115 topLayout->addWidget( msgView );
00116 topLayout->activate();
00117 }
00118
00119 void KPassivePopup::setView( const QString &caption, const QString &text,
00120 const QPixmap &icon )
00121 {
00122
00123 setView( standardView( caption, text, icon, this ) );
00124 }
00125
00126 QVBox * KPassivePopup::standardView( const QString& caption,
00127 const QString& text,
00128 const QPixmap& icon,
00129 QWidget *parent )
00130 {
00131 QVBox *vb = new QVBox( parent ? parent : this );
00132 vb->setSpacing( KDialog::spacingHint() );
00133
00134 QHBox *hb=0;
00135 if ( !icon.isNull() ) {
00136 hb = new QHBox( vb );
00137 hb->setMargin( 0 );
00138 hb->setSpacing( KDialog::spacingHint() );
00139 ttlIcon = new QLabel( hb, "title_icon" );
00140 ttlIcon->setPixmap( icon );
00141 ttlIcon->setAlignment( AlignLeft );
00142 }
00143
00144 if ( !caption.isEmpty() ) {
00145 ttl = new QLabel( caption, hb ? hb : vb, "title_label" );
00146 QFont fnt = ttl->font();
00147 fnt.setBold( true );
00148 ttl->setFont( fnt );
00149 ttl->setAlignment( Qt::AlignHCenter );
00150 if ( hb )
00151 hb->setStretchFactor( ttl, 10 );
00152 }
00153
00154 if ( !text.isEmpty() ) {
00155 msg = new QLabel( text, vb, "msg_label" );
00156 msg->setAlignment( AlignLeft );
00157 }
00158
00159 return vb;
00160 }
00161
00162 void KPassivePopup::setView( const QString &caption, const QString &text )
00163 {
00164 setView( caption, text, QPixmap() );
00165 }
00166
00167 void KPassivePopup::setTimeout( int delay )
00168 {
00169 hideDelay = delay;
00170 if( hideTimer->isActive() )
00171 {
00172 if( delay ) {
00173 hideTimer->changeInterval( delay );
00174 } else {
00175 hideTimer->stop();
00176 }
00177 }
00178 }
00179
00180 void KPassivePopup::setAutoDelete( bool autoDelete )
00181 {
00182 m_autoDelete = autoDelete;
00183 }
00184
00185 void KPassivePopup::mouseReleaseEvent( QMouseEvent *e )
00186 {
00187 emit clicked();
00188 emit clicked( e->pos() );
00189 }
00190
00191
00192
00193
00194
00195 void KPassivePopup::show()
00196 {
00197 if ( size() != sizeHint() )
00198 resize( sizeHint() );
00199
00200 if ( d->fixedPosition.isNull() )
00201 positionSelf();
00202 else {
00203 if( d->popupStyle == Balloon )
00204 setAnchor( d->fixedPosition );
00205 else
00206 move( d->fixedPosition );
00207 }
00208 QFrame::show();
00209
00210 int delay = hideDelay;
00211 if ( delay < 0 ) {
00212 delay = DEFAULT_POPUP_TIME;
00213 }
00214
00215 if ( delay > 0 ) {
00216 hideTimer->start( delay );
00217 }
00218 }
00219
00220 void KPassivePopup::show(const QPoint &p)
00221 {
00222 d->fixedPosition = p;
00223 show();
00224 }
00225
00226 void KPassivePopup::hideEvent( QHideEvent * )
00227 {
00228 hideTimer->stop();
00229 if ( m_autoDelete )
00230 deleteLater();
00231 }
00232
00233 QRect KPassivePopup::defaultArea() const
00234 {
00235 #ifdef Q_WS_X11
00236 NETRootInfo info( qt_xdisplay(),
00237 NET::NumberOfDesktops |
00238 NET::CurrentDesktop |
00239 NET::WorkArea,
00240 -1, false );
00241 info.activate();
00242 NETRect workArea = info.workArea( info.currentDesktop() );
00243 QRect r;
00244 r.setRect( workArea.pos.x, workArea.pos.y, 0, 0 );
00245 #else
00246
00247 QRect r;
00248 r.setRect( 100, 100, 200, 200 );
00249 #endif
00250 return r;
00251 }
00252
00253 void KPassivePopup::positionSelf()
00254 {
00255 QRect target;
00256
00257 #ifdef Q_WS_X11
00258 if ( !window ) {
00259 target = defaultArea();
00260 }
00261
00262 else {
00263 NETWinInfo ni( qt_xdisplay(), window, qt_xrootwin(),
00264 NET::WMIconGeometry | NET::WMKDESystemTrayWinFor );
00265
00266
00267
00268 if ( ni.kdeSystemTrayWinFor() ) {
00269 NETRect frame, win;
00270 ni.kdeGeometry( frame, win );
00271 target.setRect( win.pos.x, win.pos.y,
00272 win.size.width, win.size.height );
00273 }
00274 else if ( ni.state() & NET::SkipTaskbar ) {
00275 target = defaultArea();
00276 }
00277 else {
00278 NETRect r = ni.iconGeometry();
00279 target.setRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00280 if ( target.isNull() ) {
00281 NETRect dummy;
00282 ni.kdeGeometry( dummy, r );
00283 target.setRect( r.pos.x, r.pos.y,
00284 r.size.width, r.size.height);
00285 }
00286 }
00287 }
00288 #else
00289 target = defaultArea();
00290 #endif
00291 moveNear( target );
00292 }
00293
00294 void KPassivePopup::moveNear( QRect target )
00295 {
00296 QPoint pos = target.topLeft();
00297 int x = pos.x();
00298 int y = pos.y();
00299 int w = width();
00300 int h = height();
00301
00302 QRect r = KGlobalSettings::desktopGeometry(QPoint(x+w/2,y+h/2));
00303
00304 if( d->popupStyle == Balloon )
00305 {
00306
00307 if( x + w > r.width() ){
00308 x = x + target.width();
00309 }
00310
00311 if( y + h > r.height() ){
00312 y = y + target.height();
00313 }
00314 } else
00315 {
00316 if ( x < r.center().x() )
00317 x = x + target.width();
00318 else
00319 x = x - w;
00320
00321
00322 if ( (y + h) > r.bottom() )
00323 y = r.bottom() - h;
00324
00325 if ( (x + w) > r.right() )
00326 x = r.right() - w;
00327 }
00328 if ( y < r.top() )
00329 y = r.top();
00330
00331 if ( x < r.left() )
00332 x = r.left();
00333
00334 if( d->popupStyle == Balloon )
00335 setAnchor( QPoint( x, y ) );
00336 else
00337 move( x, y );
00338 }
00339
00340 void KPassivePopup::setAnchor(const QPoint &anchor)
00341 {
00342 d->anchor = anchor;
00343 updateMask();
00344 }
00345
00346 void KPassivePopup::paintEvent( QPaintEvent* pe )
00347 {
00348 if( d->popupStyle == Balloon )
00349 {
00350 QPainter p;
00351 p.begin( this );
00352 p.drawPolygon( d->surround );
00353 } else
00354 QFrame::paintEvent( pe );
00355 }
00356
00357 void KPassivePopup::updateMask()
00358 {
00359
00360
00361 QRect deskRect = KGlobalSettings::desktopGeometry(d->anchor);
00362
00363 int xh = 70, xl = 40;
00364 if( width() < 80 )
00365 xh = xl = 40;
00366 else if( width() < 110 )
00367 xh = width() - 40;
00368
00369 bool bottom = (d->anchor.y() + height()) > ((deskRect.y() + deskRect.height()-48));
00370 bool right = (d->anchor.x() + width()) > ((deskRect.x() + deskRect.width()-48));
00371
00372 QPoint corners[4] = {
00373 QPoint( width() - 50, 10 ),
00374 QPoint( 10, 10 ),
00375 QPoint( 10, height() - 50 ),
00376 QPoint( width() - 50, height() - 50 )
00377 };
00378
00379 QBitmap mask( width(), height(), true );
00380 QPainter p( &mask );
00381 QBrush brush( Qt::white, Qt::SolidPattern );
00382 p.setBrush( brush );
00383
00384 int i = 0, z = 0;
00385 for (; i < 4; ++i) {
00386 QPointArray corner;
00387 corner.makeArc(corners[i].x(), corners[i].y(), 40, 40, i * 16 * 90, 16 * 90);
00388
00389 d->surround.resize( z + corner.count() );
00390 for (unsigned int s = 0; s < corner.count() - 1; s++) {
00391 d->surround.setPoint( z++, corner[s] );
00392 }
00393
00394 if (bottom && i == 2) {
00395 if (right) {
00396 d->surround.resize( z + 3 );
00397 d->surround.setPoint( z++, QPoint( width() - xh, height() - 11 ) );
00398 d->surround.setPoint( z++, QPoint( width() - 20, height() ) );
00399 d->surround.setPoint( z++, QPoint( width() - xl, height() - 11 ) );
00400 } else {
00401 d->surround.resize( z + 3 );
00402 d->surround.setPoint( z++, QPoint( xl, height() - 11 ) );
00403 d->surround.setPoint( z++, QPoint( 20, height() ) );
00404 d->surround.setPoint( z++, QPoint( xh, height() - 11 ) );
00405 }
00406 } else if (!bottom && i == 0) {
00407 if (right) {
00408 d->surround.resize( z + 3 );
00409 d->surround.setPoint( z++, QPoint( width() - xl, 10 ) );
00410 d->surround.setPoint( z++, QPoint( width() - 20, 0 ) );
00411 d->surround.setPoint( z++, QPoint( width() - xh, 10 ) );
00412 } else {
00413 d->surround.resize( z + 3 );
00414 d->surround.setPoint( z++, QPoint( xh, 10 ) );
00415 d->surround.setPoint( z++, QPoint( 20, 0 ) );
00416 d->surround.setPoint( z++, QPoint( xl, 10 ) );
00417 }
00418 }
00419 }
00420
00421 d->surround.resize( z + 1 );
00422 d->surround.setPoint( z, d->surround[0] );
00423 p.drawPolygon( d->surround );
00424 setMask(mask);
00425
00426 move( right ? d->anchor.x() - width() + 20 : ( d->anchor.x() < 11 ? 11 : d->anchor.x() - 20 ),
00427 bottom ? d->anchor.y() - height() : ( d->anchor.y() < 11 ? 11 : d->anchor.y() ) );
00428
00429 update();
00430 }
00431
00432
00433
00434
00435
00436 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00437 const QPixmap &icon,
00438 QWidget *parent, const char *name, int timeout )
00439 {
00440 return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, name, timeout );
00441 }
00442
00443 KPassivePopup *KPassivePopup::message( const QString &text, QWidget *parent, const char *name )
00444 {
00445 return message( DEFAULT_POPUP_TYPE, QString::null, text, QPixmap(), parent, name );
00446 }
00447
00448 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00449 QWidget *parent, const char *name )
00450 {
00451 return message( DEFAULT_POPUP_TYPE, caption, text, QPixmap(), parent, name );
00452 }
00453
00454 KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text,
00455 const QPixmap &icon, WId parent, const char *name, int timeout )
00456 {
00457 return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, name, timeout );
00458 }
00459
00460 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00461 const QPixmap &icon,
00462 QWidget *parent, const char *name, int timeout )
00463 {
00464 KPassivePopup *pop = new KPassivePopup( popupStyle, parent, name );
00465 pop->setAutoDelete( true );
00466 pop->setView( caption, text, icon );
00467 pop->hideDelay = timeout;
00468 pop->show();
00469
00470 return pop;
00471 }
00472
00473 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &text, QWidget *parent, const char *name )
00474 {
00475 return message( popupStyle, QString::null, text, QPixmap(), parent, name );
00476 }
00477
00478 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00479 QWidget *parent, const char *name )
00480 {
00481 return message( popupStyle, caption, text, QPixmap(), parent, name );
00482 }
00483
00484 KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text,
00485 const QPixmap &icon, WId parent, const char *name, int timeout )
00486 {
00487 KPassivePopup *pop = new KPassivePopup( popupStyle, parent, name );
00488 pop->setAutoDelete( true );
00489 pop->setView( caption, text, icon );
00490 pop->hideDelay = timeout;
00491 pop->show();
00492
00493 return pop;
00494 }
00495
00496
00497
00498