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