• Skip to content
  • Skip to link menu
KDE 4.1 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 
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     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "ksystemtrayicon.h"
00022 #include "kaboutdata.h"
00023 #include "kaction.h"
00024 #include "kcomponentdata.h"
00025 #include "klocale.h"
00026 #include "kmenu.h"
00027 #include "kmessagebox.h"
00028 #include "kshortcut.h"
00029 #include "kactioncollection.h"
00030 #include "kstandardaction.h"
00031 #include <kwindowsystem.h>
00032 
00033 #ifdef Q_WS_X11
00034 #include <QX11Info>
00035 #endif
00036 #ifdef Q_WS_WIN
00037 #include <windows.h>
00038 #endif
00039 
00040 #include <kiconloader.h>
00041 #include <kapplication.h>
00042 #include <kconfiggroup.h>
00043 
00044 #include <QMouseEvent>
00045 #include <QToolButton>
00046 
00047 #ifdef Q_WS_WIN
00048 class KSystemTrayIconPrivate : public QObject
00049 #else
00050 class KSystemTrayIconPrivate
00051 #endif
00052 {
00053 public:
00054     KSystemTrayIconPrivate(KSystemTrayIcon* trayIcon, QWidget* parent)
00055     {
00056         actionCollection = new KActionCollection( trayIcon );
00057         hasQuit = false;
00058         onAllDesktops = false;
00059         window = parent;
00060 #ifdef Q_WS_WIN
00061         // FIXME the below makes korgac ( the reminder daemon in kdepim) crash
00062         // on startup
00063         // window->installEventFilter( this );
00064 #endif
00065     }
00066 
00067     ~KSystemTrayIconPrivate()
00068     {
00069 #ifdef Q_WS_WIN
00070      // FIXME makes korgac crash, see above
00071      //   window->removeEventFilter( this );
00072 #endif
00073         delete actionCollection;
00074         delete menu;
00075     }
00076 
00077 #ifdef Q_WS_WIN
00078     bool eventFilter(QObject *obj, QEvent *ev)
00079     {
00080       if(ev->type() == QEvent::ActivationChange) {
00081         dwTickCount = GetTickCount();
00082       }
00083       return QObject::eventFilter(obj, ev);
00084     }
00085     DWORD dwTickCount;
00086 #endif
00087 
00088     KActionCollection* actionCollection;
00089     KMenu* menu;
00090     QWidget* window;
00091     QAction* titleAction;
00092     bool onAllDesktops : 1; // valid only when the parent widget was hidden
00093     bool hasQuit : 1;
00094 };
00095 
00096 KSystemTrayIcon::KSystemTrayIcon( QWidget* parent )
00097     : QSystemTrayIcon( parent ),
00098       d( new KSystemTrayIconPrivate( this, parent ) )
00099 {
00100     init( parent );
00101 }
00102 
00103 KSystemTrayIcon::KSystemTrayIcon( const QString& icon, QWidget* parent )
00104     : QSystemTrayIcon( loadIcon( icon ), parent ),
00105       d( new KSystemTrayIconPrivate( this, parent ) )
00106 {
00107     init( parent );
00108 }
00109 
00110 KSystemTrayIcon::KSystemTrayIcon( const QIcon& icon, QWidget* parent )
00111     : QSystemTrayIcon( icon, parent ),
00112       d( new KSystemTrayIconPrivate( this, parent ) )
00113 {
00114     init( parent );
00115 }
00116 
00117 void KSystemTrayIcon::init( QWidget* parent )
00118 {
00119     // Ensure that closing the last KMainWindow doesn't exit the application
00120     // if a system tray icon is still present.
00121     KGlobal::ref();
00122     d->menu = new KMenu( parent );
00123     d->titleAction = d->menu->addTitle( qApp->windowIcon(), KGlobal::caption() );
00124     d->menu->setTitle( KGlobal::mainComponent().aboutData()->programName() );
00125     connect( d->menu, SIGNAL( aboutToShow() ), this, SLOT( contextMenuAboutToShow() ) );
00126     setContextMenu( d->menu );
00127 
00128     KStandardAction::quit( this, SLOT( maybeQuit() ), d->actionCollection );
00129 
00130     if ( parent )
00131     {
00132         QAction *action = d->actionCollection->addAction("minimizeRestore");
00133         action->setText(i18n("Minimize"));
00134         connect( action, SIGNAL( triggered( bool ) ), this, SLOT( minimizeRestoreAction() ) );
00135 
00136 #ifdef Q_WS_X11
00137         KWindowInfo info = KWindowSystem::windowInfo( parent->winId(), NET::WMDesktop );
00138         d->onAllDesktops = info.onAllDesktops();
00139 #else
00140         d->onAllDesktops = false;
00141 #endif
00142     }
00143     else
00144     {
00145         d->onAllDesktops = false;
00146     }
00147 
00148     connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ),
00149              SLOT( activateOrHide( QSystemTrayIcon::ActivationReason ) ) );
00150 }
00151 
00152 QWidget *KSystemTrayIcon::parentWidget() const
00153 {
00154     return d->window;
00155 }
00156 
00157 KSystemTrayIcon::~KSystemTrayIcon()
00158 {
00159     delete d;
00160     KGlobal::deref();
00161 }
00162 
00163 void KSystemTrayIcon::contextMenuAboutToShow( )
00164 {
00165     if ( !d->hasQuit )
00166     {
00167         // we need to add the actions to the menu afterwards so that these items
00168         // appear at the _END_ of the menu
00169         d->menu->addSeparator();
00170         QAction* action = d->actionCollection->action( "minimizeRestore" );
00171 
00172         if ( action )
00173         {
00174             d->menu->addAction( action );
00175         }
00176 
00177         action = d->actionCollection->action( KStandardAction::name( KStandardAction::Quit ) );
00178 
00179         if ( action )
00180         {
00181             d->menu->addAction( action );
00182         }
00183 
00184         d->hasQuit = true;
00185     }
00186 
00187     if ( d->window )
00188     {
00189         QAction* action = d->actionCollection->action("minimizeRestore");
00190         if ( d->window->isVisible() )
00191         {
00192             action->setText( i18n("&Minimize") );
00193         }
00194         else
00195         {
00196             action->setText( i18n("&Restore") );
00197         }
00198     }
00199 }
00200 
00201 // called from the popup menu - always do what the menu entry says,
00202 // i.e. if the window is shown, no matter if active or not, the menu
00203 // entry is "minimize", otherwise it's "restore"
00204 void KSystemTrayIcon::minimizeRestoreAction()
00205 {
00206     if ( d->window )
00207     {
00208         bool restore = !( d->window->isVisible() );
00209         minimizeRestore( restore );
00210     }
00211 }
00212 
00213 void KSystemTrayIcon::maybeQuit()
00214 {
00215     QString caption = KGlobal::caption();
00216     QString query = i18n("<qt>Are you sure you want to quit <b>%1</b>?</qt>",
00217                          caption);
00218     if (KMessageBox::warningContinueCancel(d->window, query,
00219                                      i18n("Confirm Quit From System Tray"),
00220                                      KStandardGuiItem::quit(),
00221                                      KStandardGuiItem::cancel(),
00222                                      QString("systemtrayquit%1")
00223                                             .arg(caption)) !=
00224         KMessageBox::Continue)
00225     {
00226         return;
00227     }
00228 
00229     emit quitSelected();
00230     qApp->quit();
00231 }
00232 
00233 // if the window is not the active one, show it if needed, and activate it
00234 // (just like taskbar); otherwise hide it
00235 void KSystemTrayIcon::activateOrHide( QSystemTrayIcon::ActivationReason reasonCalled )
00236 {
00237     if ( reasonCalled != QSystemTrayIcon::Trigger )
00238     {
00239         return;
00240     }
00241 
00242     QWidget *pw = d->window;
00243     if ( !pw )
00244     {
00245         return;
00246     }
00247 #ifdef Q_WS_WIN
00248     // the problem is that we lose focus when the systray icon is activated
00249     // and we don't know the former active window
00250     // therefore we watch for activation event and use our stopwatch :)
00251     if( GetTickCount() - d->dwTickCount < 300 ) {
00252         // we were active in the last 300ms -> hide it
00253         minimizeRestore( false );
00254     } else {
00255         minimizeRestore( true );
00256     }
00257 #elif defined(Q_WS_X11)
00258     KWindowInfo info1 = KWindowSystem::windowInfo( pw->winId(), NET::XAWMState | NET::WMState );
00259     // mapped = visible (but possibly obscured)
00260     bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
00261 //    - not mapped -> show, raise, focus
00262 //    - mapped
00263 //        - obscured -> raise, focus
00264 //        - not obscured -> hide
00265     if( !mapped )
00266         minimizeRestore( true );
00267     else
00268     {
00269         QListIterator< WId > it (KWindowSystem::stackingOrder());
00270         it.toBack();
00271         while( it.hasPrevious() )
00272         {
00273             WId id = it.previous();
00274             if( id == pw->winId() )
00275                 break;
00276             KWindowInfo info2 = KWindowSystem::windowInfo( id,
00277                 NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType );
00278             if( info2.mappingState() != NET::Visible )
00279                 continue; // not visible on current desktop -> ignore
00280             if( !info2.geometry().intersects( pw->geometry()))
00281                 continue; // not obscuring the window -> ignore
00282             if( !info1.hasState( NET::KeepAbove ) && info2.hasState( NET::KeepAbove ))
00283                 continue; // obscured by window kept above -> ignore
00284             NET::WindowType type = info2.windowType( NET::NormalMask | NET::DesktopMask
00285                 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00286                 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
00287             if( type == NET::Dock || type == NET::TopMenu )
00288                 continue; // obscured by dock or topmenu -> ignore
00289             pw->raise();
00290             KWindowSystem::activateWindow( pw->winId());
00291             return;
00292         }
00293         minimizeRestore( false ); // hide
00294     }
00295 #endif
00296 }
00297 
00298 void KSystemTrayIcon::minimizeRestore( bool restore )
00299 {
00300     QWidget* pw = d->window;
00301     if (!pw)
00302         return;
00303 #ifdef Q_WS_X11
00304     KWindowInfo info = KWindowSystem::windowInfo(pw->winId(), NET::WMGeometry | NET::WMDesktop);
00305     if (restore) {
00306         if (d->onAllDesktops) {
00307             KWindowSystem::setOnAllDesktops(pw->winId(), true);
00308         } else {
00309             KWindowSystem::setCurrentDesktop(info.desktop());
00310         }
00311         pw->move(info.geometry().topLeft()); // avoid placement policies
00312         pw->show();
00313         pw->raise();
00314         KWindowSystem::activateWindow(pw->winId());
00315     } else {
00316         d->onAllDesktops = info.onAllDesktops();
00317         pw->hide();
00318     }
00319 #else
00320     if ( restore )
00321     {
00322         pw->show();
00323         pw->raise();
00324         KWindowSystem::forceActiveWindow( pw->winId() );
00325     } else {
00326         pw->hide();
00327     }
00328 #endif
00329 }
00330 
00331 KActionCollection* KSystemTrayIcon::actionCollection()
00332 {
00333     return d->actionCollection;
00334 }
00335 
00336 QIcon KSystemTrayIcon::loadIcon(const QString &icon, const KComponentData &componentData)
00337 {
00338     KConfigGroup cg(componentData.config(), "System Tray");
00339     int iconWidth = cg.readEntry("systrayIconWidth", 22);
00340     return KIconLoader::global()->loadIcon( icon, KIconLoader::Panel, iconWidth );
00341 }
00342 
00343 void KSystemTrayIcon::toggleActive()
00344 {
00345     activateOrHide( QSystemTrayIcon::Trigger );
00346 }
00347 
00348 bool KSystemTrayIcon::parentWidgetTrayClose() const
00349 {
00350     if( kapp != NULL && kapp->sessionSaving())
00351         return false; // normal close
00352     return true;
00353 }
00354 
00355 void KSystemTrayIcon::setContextMenuTitle(QAction *action)
00356 {
00357     // can never be null, and is always the requsted type, so no need to do null checks after casts.
00358     QToolButton *button = static_cast<QToolButton*>((static_cast<QWidgetAction*>(d->titleAction))->defaultWidget());
00359     button->setDefaultAction(action);
00360 }
00361 
00362 QAction *KSystemTrayIcon::contextMenuTitle() const
00363 {
00364     QToolButton *button = static_cast<QToolButton*>((static_cast<QWidgetAction*>(d->titleAction))->defaultWidget());
00365     return button->defaultAction();
00366 }
00367 
00368 #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
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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