ksystemtray.cpp

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 "config.h"
00022 #include "kaction.h"
00023 #include "kmessagebox.h"
00024 #include "kshortcut.h"
00025 #include "ksystemtray.h"
00026 #include "kpopupmenu.h"
00027 #include "kapplication.h"
00028 #include "klocale.h"
00029 #include "kaboutdata.h"
00030 
00031 #ifdef Q_WS_X11
00032 #include <kwin.h> 
00033 #include <kwinmodule.h> 
00034 #include <qxembed.h> 
00035 #endif
00036 
00037 #include <kiconloader.h>
00038 #include <kconfig.h>
00039 
00040 #include <qapplication.h>
00041 
00042 class KSystemTrayPrivate
00043 {
00044 public:
00045     KSystemTrayPrivate()
00046     {
00047         actionCollection = 0;
00048     }
00049 
00050     ~KSystemTrayPrivate()
00051     {
00052         delete actionCollection;
00053     }
00054 
00055     KActionCollection* actionCollection;
00056     bool on_all_desktops; // valid only when the parent widget was hidden
00057 };
00058 
00059 KSystemTray::KSystemTray( QWidget* parent, const char* name )
00060     : QLabel( parent, name, WType_TopLevel )
00061 {
00062 #ifdef Q_WS_X11
00063     QXEmbed::initialize();
00064 #endif
00065     
00066     d = new KSystemTrayPrivate;
00067     d->actionCollection = new KActionCollection(this);
00068 
00069 #ifdef Q_WS_X11
00070     KWin::setSystemTrayWindowFor( winId(), parent?parent->topLevelWidget()->winId(): qt_xrootwin() );
00071 #endif
00072     setBackgroundMode(X11ParentRelative);
00073     setBackgroundOrigin(WindowOrigin);
00074     hasQuit = 0;
00075     menu = new KPopupMenu( this );
00076     menu->insertTitle( kapp->miniIcon(), kapp->caption() );
00077     move( -1000, -1000 );
00078     KStdAction::quit(this, SLOT(maybeQuit()), d->actionCollection);
00079 
00080     if (parentWidget())
00081     {
00082         new KAction(i18n("Minimize"), KShortcut(),
00083                     this, SLOT( minimizeRestoreAction() ),
00084                     d->actionCollection, "minimizeRestore");
00085 #ifdef Q_WS_X11
00086     KWin::WindowInfo info = KWin::windowInfo( parentWidget()->winId());
00087     d->on_all_desktops = info.onAllDesktops();
00088 #else
00089     d->on_all_desktops = false;
00090 #endif
00091     }
00092     else
00093     {
00094         d->on_all_desktops = false;
00095     }
00096     setCaption( KGlobal::instance()->aboutData()->programName());
00097 }
00098 
00099 KSystemTray::~KSystemTray()
00100 {
00101     delete d;
00102 }
00103 
00104 
00105 void KSystemTray::showEvent( QShowEvent * )
00106 {
00107     if ( !hasQuit ) {
00108     menu->insertSeparator();
00109         KAction* action = d->actionCollection->action("minimizeRestore");
00110 
00111         if (action)
00112         {
00113             action->plug(menu);
00114         }
00115 
00116         action = d->actionCollection->action(KStdAction::name(KStdAction::Quit));
00117 
00118         if (action)
00119         {
00120             action->plug(menu);
00121         }
00122 
00123     hasQuit = 1;
00124     }
00125 }
00126 
00127 // KDE4 remove
00128 void KSystemTray::enterEvent( QEvent* e )
00129 {
00130     QLabel::enterEvent( e );
00131 }
00132 
00133 KPopupMenu* KSystemTray::contextMenu() const
00134 {
00135     return menu;
00136 }
00137 
00138 
00139 void KSystemTray::mousePressEvent( QMouseEvent *e )
00140 {
00141     if ( !rect().contains( e->pos() ) )
00142     return;
00143 
00144     switch ( e->button() ) {
00145     case LeftButton:
00146         toggleActive();
00147     break;
00148     case MidButton:
00149     // fall through
00150     case RightButton:
00151     if ( parentWidget() ) {
00152             KAction* action = d->actionCollection->action("minimizeRestore");
00153         if ( parentWidget()->isVisible() )
00154         action->setText( i18n("&Minimize") );
00155         else
00156         action->setText( i18n("&Restore") );
00157     }
00158     contextMenuAboutToShow( menu );
00159     menu->popup( e->globalPos() );
00160     break;
00161     default:
00162     // nothing
00163     break;
00164     }
00165 }
00166 
00167 void KSystemTray::mouseReleaseEvent( QMouseEvent * )
00168 {
00169 }
00170 
00171 
00172 void KSystemTray::contextMenuAboutToShow( KPopupMenu* )
00173 {
00174 }
00175 
00176 // called from the popup menu - always do what the menu entry says,
00177 // i.e. if the window is shown, no matter if active or not, the menu
00178 // entry is "minimize", otherwise it's "restore"
00179 void KSystemTray::minimizeRestoreAction()
00180 {
00181     if ( parentWidget() ) {
00182         bool restore = !( parentWidget()->isVisible() );
00183     minimizeRestore( restore );
00184     }
00185 }
00186 
00187 void KSystemTray::maybeQuit()
00188 {
00189     QString query = i18n("<qt>Are you sure you want to quit <b>%1</b>?</qt>")
00190                         .arg(kapp->caption());
00191     if (KMessageBox::warningContinueCancel(this, query,
00192                                      i18n("Confirm Quit From System Tray"),
00193                                      KStdGuiItem::quit(),
00194                                      QString("systemtrayquit%1")
00195                                             .arg(kapp->caption())) !=
00196         KMessageBox::Continue)
00197     {
00198         return;
00199     }
00200 
00201     emit quitSelected();
00202 
00203     // KDE4: stop closing the parent widget? it results in complex application code
00204     //       instead make applications connect to the quitSelected() signal
00205 
00206     if (parentWidget())
00207     {
00208         parentWidget()->close();
00209     }
00210     else
00211     {
00212         qApp->closeAllWindows();
00213     }
00214 }
00215 
00216 void KSystemTray::toggleActive()
00217 {
00218     activateOrHide();
00219 }
00220 
00221 void KSystemTray::setActive()
00222 {
00223     minimizeRestore( true );
00224 }
00225 
00226 void KSystemTray::setInactive()
00227 {
00228     minimizeRestore( false );
00229 }
00230 
00231 // called when left-clicking the tray icon
00232 // if the window is not the active one, show it if needed, and activate it
00233 // (just like taskbar); otherwise hide it
00234 void KSystemTray::activateOrHide()
00235 {
00236     QWidget *pw = parentWidget();
00237 
00238     if ( !pw )
00239     return;
00240 
00241 #ifdef Q_WS_X11
00242     KWin::WindowInfo info1 = KWin::windowInfo( pw->winId(), NET::XAWMState | NET::WMState );
00243     // mapped = visible (but possibly obscured)
00244     bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
00245 //    - not mapped -> show, raise, focus
00246 //    - mapped
00247 //        - obscured -> raise, focus
00248 //        - not obscured -> hide
00249     if( !mapped )
00250         minimizeRestore( true );
00251     else
00252     {
00253         KWinModule module;
00254         for( QValueList< WId >::ConstIterator it = module.stackingOrder().fromLast();
00255              it != module.stackingOrder().end() && (*it) != pw->winId();
00256              --it )
00257         {
00258             KWin::WindowInfo info2 = KWin::windowInfo( *it,
00259                 NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType );
00260             if( info2.mappingState() != NET::Visible )
00261                 continue; // not visible on current desktop -> ignore
00262             if( !info2.geometry().intersects( pw->geometry()))
00263                 continue; // not obscuring the window -> ignore
00264             if( !info1.hasState( NET::KeepAbove ) && info2.hasState( NET::KeepAbove ))
00265                 continue; // obscured by window kept above -> ignore
00266             NET::WindowType type = info2.windowType( NET::NormalMask | NET::DesktopMask
00267                 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00268                 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
00269             if( type == NET::Dock || type == NET::TopMenu )
00270                 continue; // obscured by dock or topmenu -> ignore
00271             pw->raise();
00272             KWin::activateWindow( pw->winId());
00273             return;
00274         }
00275         minimizeRestore( false ); // hide
00276     }
00277 #endif
00278 }
00279 
00280 void KSystemTray::minimizeRestore( bool restore )
00281 {
00282     QWidget* pw = parentWidget();
00283     if( !pw )
00284     return;
00285 #ifdef Q_WS_X11
00286     KWin::WindowInfo info = KWin::windowInfo( pw->winId(), NET::WMGeometry | NET::WMDesktop );
00287     if ( restore )
00288     {
00289     if( d->on_all_desktops )
00290         KWin::setOnAllDesktops( pw->winId(), true );
00291     else
00292         KWin::setCurrentDesktop( info.desktop() );
00293         pw->move( info.geometry().topLeft() ); // avoid placement policies
00294         pw->show();
00295         pw->raise();
00296     KWin::activateWindow( pw->winId() );
00297     } else {
00298     d->on_all_desktops = info.onAllDesktops();
00299     pw->hide();
00300     }
00301 #endif
00302 }
00303 
00304 KActionCollection* KSystemTray::actionCollection()
00305 {
00306     return d->actionCollection;
00307 }
00308     
00309 QPixmap KSystemTray::loadIcon( const QString &icon, KInstance *instance )
00310 {
00311     KConfig *appCfg = kapp->config();
00312     KConfigGroupSaver configSaver(appCfg, "System Tray");
00313     int iconWidth = appCfg->readNumEntry("systrayIconWidth", 22);
00314     return instance->iconLoader()->loadIcon( icon, KIcon::Panel, iconWidth );
00315 }
00316 
00317 void KSystemTray::setPixmap( const QPixmap& p )
00318 {
00319     QLabel::setPixmap( p );
00320 #ifdef Q_WS_X11
00321     KWin::setIcons( winId(), p, QPixmap());
00322 #endif
00323 }
00324 
00325 void KSystemTray::setCaption( const QString& s )
00326 {
00327     QLabel::setCaption( s );
00328 }
00329 
00330 void KSystemTray::virtual_hook( int, void* )
00331 { /*BASE::virtual_hook( id, data );*/ }
00332 
00333 #include "ksystemtray.moc"
00334 #include "kdockwindow.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys