00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "ksystemtrayicon.h"
00024 #include "kaboutdata.h"
00025 #include "kaction.h"
00026 #include "kcomponentdata.h"
00027 #include "klocale.h"
00028 #include "kmenu.h"
00029 #include "kmessagebox.h"
00030 #include "kshortcut.h"
00031 #include "kactioncollection.h"
00032 #include "kstandardaction.h"
00033 #include <kwindowsystem.h>
00034
00035 #ifdef Q_WS_X11
00036 #include <QX11Info>
00037 #endif
00038 #ifdef Q_WS_WIN
00039 #include <windows.h>
00040 #endif
00041
00042 #include <kiconloader.h>
00043 #include <kapplication.h>
00044 #include <kconfiggroup.h>
00045
00046 #include <QMouseEvent>
00047 #include <QToolButton>
00048 #include <QMovie>
00049 #include <QPointer>
00050
00051 #ifdef Q_WS_WIN
00052 class KSystemTrayIconPrivate : public QObject
00053 #else
00054 class KSystemTrayIconPrivate
00055 #endif
00056 {
00057 public:
00058 KSystemTrayIconPrivate(KSystemTrayIcon* trayIcon, QWidget* parent)
00059 : q(trayIcon)
00060 {
00061 actionCollection = new KActionCollection( trayIcon );
00062 hasQuit = false;
00063 onAllDesktops = false;
00064 window = parent;
00065 movie = 0;
00066 #ifdef Q_WS_WIN
00067 if ( window ) {
00068 window->installEventFilter( this );
00069 }
00070 #endif
00071 }
00072
00073 ~KSystemTrayIconPrivate()
00074 {
00075 #ifdef Q_WS_WIN
00076 if ( window ) {
00077 window->removeEventFilter( this );
00078 }
00079 #endif
00080 delete actionCollection;
00081 delete menu;
00082 }
00083
00084
00085 void _k_slotNewFrame()
00086 {
00087 q->setIcon(QIcon(movie->currentPixmap()));
00088 }
00089
00090 #ifdef Q_WS_WIN
00091 bool eventFilter(QObject *obj, QEvent *ev)
00092 {
00093 if(ev->type() == QEvent::ActivationChange) {
00094 dwTickCount = GetTickCount();
00095 }
00096 return QObject::eventFilter(obj, ev);
00097 }
00098 DWORD dwTickCount;
00099 #endif
00100
00101 KSystemTrayIcon* q;
00102 KActionCollection* actionCollection;
00103 KMenu* menu;
00104 QWidget* window;
00105 QAction* titleAction;
00106 bool onAllDesktops : 1;
00107 bool hasQuit : 1;
00108 QPointer<QMovie> movie;
00109 };
00110
00111 KSystemTrayIcon::KSystemTrayIcon( QWidget* parent )
00112 : QSystemTrayIcon( parent ),
00113 d( new KSystemTrayIconPrivate( this, parent ) )
00114 {
00115 init( parent );
00116 }
00117
00118 KSystemTrayIcon::KSystemTrayIcon( const QString& icon, QWidget* parent )
00119 : QSystemTrayIcon( loadIcon( icon ), parent ),
00120 d( new KSystemTrayIconPrivate( this, parent ) )
00121 {
00122 init( parent );
00123 }
00124
00125 KSystemTrayIcon::KSystemTrayIcon( const QIcon& icon, QWidget* parent )
00126 : QSystemTrayIcon( icon, parent ),
00127 d( new KSystemTrayIconPrivate( this, parent ) )
00128 {
00129 init( parent );
00130 }
00131
00132 KSystemTrayIcon::KSystemTrayIcon(QMovie* movie, QWidget *parent)
00133 : QSystemTrayIcon(parent),
00134 d( new KSystemTrayIconPrivate( this, parent ) )
00135 {
00136 init(parent);
00137 setMovie(movie);
00138 }
00139
00140 void KSystemTrayIcon::init( QWidget* parent )
00141 {
00142
00143
00144 KGlobal::ref();
00145 d->menu = new KMenu( parent );
00146 d->titleAction = d->menu->addTitle( qApp->windowIcon(), KGlobal::caption() );
00147 d->menu->setTitle( KGlobal::mainComponent().aboutData()->programName() );
00148 connect( d->menu, SIGNAL( aboutToShow() ), this, SLOT( contextMenuAboutToShow() ) );
00149 setContextMenu( d->menu );
00150
00151 KStandardAction::quit( this, SLOT( maybeQuit() ), d->actionCollection );
00152
00153 if ( parent )
00154 {
00155 QAction *action = d->actionCollection->addAction("minimizeRestore");
00156 action->setText(i18n("Minimize"));
00157 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( minimizeRestoreAction() ) );
00158
00159 #ifdef Q_WS_X11
00160 KWindowInfo info = KWindowSystem::windowInfo( parent->winId(), NET::WMDesktop );
00161 d->onAllDesktops = info.onAllDesktops();
00162 #else
00163 d->onAllDesktops = false;
00164 #endif
00165 }
00166 else
00167 {
00168 d->onAllDesktops = false;
00169 }
00170
00171 connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ),
00172 SLOT( activateOrHide( QSystemTrayIcon::ActivationReason ) ) );
00173 }
00174
00175 QWidget *KSystemTrayIcon::parentWidget() const
00176 {
00177 return d->window;
00178 }
00179
00180 KSystemTrayIcon::~KSystemTrayIcon()
00181 {
00182 delete d;
00183 KGlobal::deref();
00184 }
00185
00186 void KSystemTrayIcon::contextMenuAboutToShow( )
00187 {
00188 if ( !d->hasQuit )
00189 {
00190
00191
00192 d->menu->addSeparator();
00193 QAction* action = d->actionCollection->action( "minimizeRestore" );
00194
00195 if ( action )
00196 {
00197 d->menu->addAction( action );
00198 }
00199
00200 action = d->actionCollection->action( KStandardAction::name( KStandardAction::Quit ) );
00201
00202 if ( action )
00203 {
00204 d->menu->addAction( action );
00205 }
00206
00207 d->hasQuit = true;
00208 }
00209
00210 if ( d->window )
00211 {
00212 QAction* action = d->actionCollection->action("minimizeRestore");
00213 if ( d->window->isVisible() )
00214 {
00215 action->setText( i18n("&Minimize") );
00216 }
00217 else
00218 {
00219 action->setText( i18n("&Restore") );
00220 }
00221 }
00222 }
00223
00224
00225
00226
00227 void KSystemTrayIcon::minimizeRestoreAction()
00228 {
00229 if ( d->window )
00230 {
00231 bool restore = !( d->window->isVisible() );
00232 minimizeRestore( restore );
00233 }
00234 }
00235
00236 void KSystemTrayIcon::maybeQuit()
00237 {
00238 QString caption = KGlobal::caption();
00239 QString query = i18n("<qt>Are you sure you want to quit <b>%1</b>?</qt>",
00240 caption);
00241 if (KMessageBox::warningContinueCancel(d->window, query,
00242 i18n("Confirm Quit From System Tray"),
00243 KStandardGuiItem::quit(),
00244 KStandardGuiItem::cancel(),
00245 QString("systemtrayquit%1")
00246 .arg(caption)) !=
00247 KMessageBox::Continue)
00248 {
00249 return;
00250 }
00251
00252 emit quitSelected();
00253 qApp->quit();
00254 }
00255
00256
00257
00258 void KSystemTrayIcon::activateOrHide( QSystemTrayIcon::ActivationReason reasonCalled )
00259 {
00260 if ( reasonCalled != QSystemTrayIcon::Trigger )
00261 {
00262 return;
00263 }
00264
00265 QWidget *pw = d->window;
00266 if ( !pw )
00267 {
00268 return;
00269 }
00270 #ifdef Q_WS_WIN
00271
00272
00273
00274 if( GetTickCount() - d->dwTickCount < 300 ) {
00275
00276 minimizeRestore( false );
00277 } else {
00278 minimizeRestore( true );
00279 }
00280 #elif defined(Q_WS_X11)
00281 KWindowInfo info1 = KWindowSystem::windowInfo( pw->winId(), NET::XAWMState | NET::WMState );
00282
00283 bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
00284
00285
00286
00287
00288 if( !mapped )
00289 minimizeRestore( true );
00290 else
00291 {
00292 QListIterator< WId > it (KWindowSystem::stackingOrder());
00293 it.toBack();
00294 while( it.hasPrevious() )
00295 {
00296 WId id = it.previous();
00297 if( id == pw->winId() )
00298 break;
00299 KWindowInfo info2 = KWindowSystem::windowInfo( id,
00300 NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType );
00301 if( info2.mappingState() != NET::Visible )
00302 continue;
00303 if( !info2.geometry().intersects( pw->geometry()))
00304 continue;
00305 if( !info1.hasState( NET::KeepAbove ) && info2.hasState( NET::KeepAbove ))
00306 continue;
00307 NET::WindowType type = info2.windowType( NET::NormalMask | NET::DesktopMask
00308 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00309 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
00310 if( type == NET::Dock || type == NET::TopMenu )
00311 continue;
00312 pw->raise();
00313 KWindowSystem::activateWindow( pw->winId());
00314 return;
00315 }
00316 minimizeRestore( false );
00317 }
00318 #endif
00319 }
00320
00321 void KSystemTrayIcon::minimizeRestore( bool restore )
00322 {
00323 QWidget* pw = d->window;
00324 if (!pw)
00325 return;
00326 #ifdef Q_WS_X11
00327 KWindowInfo info = KWindowSystem::windowInfo(pw->winId(), NET::WMGeometry | NET::WMDesktop);
00328 if (restore) {
00329 if (d->onAllDesktops) {
00330 KWindowSystem::setOnAllDesktops(pw->winId(), true);
00331 } else {
00332 KWindowSystem::setCurrentDesktop(info.desktop());
00333 }
00334 pw->move(info.geometry().topLeft());
00335 pw->show();
00336 pw->raise();
00337 KWindowSystem::activateWindow(pw->winId());
00338 } else {
00339 d->onAllDesktops = info.onAllDesktops();
00340 pw->hide();
00341 }
00342 #else
00343 if ( restore )
00344 {
00345 pw->show();
00346 pw->raise();
00347 KWindowSystem::forceActiveWindow( pw->winId() );
00348 } else {
00349 pw->hide();
00350 }
00351 #endif
00352 }
00353
00354 KActionCollection* KSystemTrayIcon::actionCollection()
00355 {
00356 return d->actionCollection;
00357 }
00358
00359 QIcon KSystemTrayIcon::loadIcon(const QString &icon, const KComponentData &componentData)
00360 {
00361 KConfigGroup cg(componentData.config(), "System Tray");
00362 const int iconWidth = cg.readEntry("systrayIconWidth", 22);
00363 return KIconLoader::global()->loadIcon( icon, KIconLoader::Panel, iconWidth );
00364 }
00365
00366 void KSystemTrayIcon::toggleActive()
00367 {
00368 activateOrHide( QSystemTrayIcon::Trigger );
00369 }
00370
00371 bool KSystemTrayIcon::parentWidgetTrayClose() const
00372 {
00373 if( kapp != NULL && kapp->sessionSaving())
00374 return false;
00375 return true;
00376 }
00377
00378 void KSystemTrayIcon::setContextMenuTitle(QAction *action)
00379 {
00380
00381 QToolButton *button = static_cast<QToolButton*>((static_cast<QWidgetAction*>(d->titleAction))->defaultWidget());
00382 button->setDefaultAction(action);
00383 }
00384
00385 QAction *KSystemTrayIcon::contextMenuTitle() const
00386 {
00387 QToolButton *button = static_cast<QToolButton*>((static_cast<QWidgetAction*>(d->titleAction))->defaultWidget());
00388 return button->defaultAction();
00389 }
00390
00391 void KSystemTrayIcon::setMovie(QMovie* m)
00392 {
00393 delete d->movie;
00394 m->setParent(this);
00395 d->movie = m;
00396 connect(d->movie, SIGNAL(frameChanged(int)), this, SLOT(_k_slotNewFrame()));
00397 d->movie->setCacheMode(QMovie::CacheAll);
00398 }
00399
00400 const QMovie* KSystemTrayIcon::movie() const
00401 {
00402 return d->movie;
00403 }
00404
00405 #include "ksystemtrayicon.moc"