• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

ksystemtrayicon.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002 
00003     Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
00004     Copyright (c) 2007      by Charles Connell <charles@connells.org>
00005     Copyright (C) 2008 Lukas Appelhans <l.appelhans@gmx.de>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020     Boston, MA 02110-1301, USA.
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         // FIXME the below makes korgac ( the reminder daemon in kdepim) crash
00068         // on startup
00069         window->installEventFilter( this );
00070 #endif
00071     }
00072 
00073     ~KSystemTrayIconPrivate()
00074     {
00075 #ifdef Q_WS_WIN
00076      // FIXME makes korgac crash, see above
00077      //   window->removeEventFilter( this );
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; // valid only when the parent widget was hidden
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     // Ensure that closing the last KMainWindow doesn't exit the application
00142     // if a system tray icon is still present.
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         // we need to add the actions to the menu afterwards so that these items
00190         // appear at the _END_ of the menu
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 // called from the popup menu - always do what the menu entry says,
00224 // i.e. if the window is shown, no matter if active or not, the menu
00225 // entry is "minimize", otherwise it's "restore"
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 // if the window is not the active one, show it if needed, and activate it
00256 // (just like taskbar); otherwise hide it
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     // the problem is that we lose focus when the systray icon is activated
00271     // and we don't know the former active window
00272     // therefore we watch for activation event and use our stopwatch :)
00273     if( GetTickCount() - d->dwTickCount < 300 ) {
00274         // we were active in the last 300ms -> hide it
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     // mapped = visible (but possibly obscured)
00282     bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
00283 //    - not mapped -> show, raise, focus
00284 //    - mapped
00285 //        - obscured -> raise, focus
00286 //        - not obscured -> hide
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; // not visible on current desktop -> ignore
00302             if( !info2.geometry().intersects( pw->geometry()))
00303                 continue; // not obscuring the window -> ignore
00304             if( !info1.hasState( NET::KeepAbove ) && info2.hasState( NET::KeepAbove ))
00305                 continue; // obscured by window kept above -> ignore
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; // obscured by dock or topmenu -> ignore
00311             pw->raise();
00312             KWindowSystem::activateWindow( pw->winId());
00313             return;
00314         }
00315         minimizeRestore( false ); // hide
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()); // avoid placement policies
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; // normal close
00374     return true;
00375 }
00376 
00377 void KSystemTrayIcon::setContextMenuTitle(QAction *action)
00378 {
00379     // can never be null, and is always the requsted type, so no need to do null checks after casts.
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"

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