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 setAlignment( alignment() | Qt::AlignVCenter | Qt::AlignHCenter ); 00098 } 00099 00100 KSystemTray::~KSystemTray() 00101 { 00102 delete d; 00103 } 00104 00105 00106 void KSystemTray::showEvent( QShowEvent * ) 00107 { 00108 if ( !hasQuit ) { 00109 menu->insertSeparator(); 00110 KAction* action = d->actionCollection->action("minimizeRestore"); 00111 00112 if (action) 00113 { 00114 action->plug(menu); 00115 } 00116 00117 action = d->actionCollection->action(KStdAction::name(KStdAction::Quit)); 00118 00119 if (action) 00120 { 00121 action->plug(menu); 00122 } 00123 00124 hasQuit = 1; 00125 } 00126 } 00127 00128 // KDE4 remove 00129 void KSystemTray::enterEvent( QEvent* e ) 00130 { 00131 QLabel::enterEvent( e ); 00132 } 00133 00134 KPopupMenu* KSystemTray::contextMenu() const 00135 { 00136 return menu; 00137 } 00138 00139 00140 void KSystemTray::mousePressEvent( QMouseEvent *e ) 00141 { 00142 if ( !rect().contains( e->pos() ) ) 00143 return; 00144 00145 switch ( e->button() ) { 00146 case LeftButton: 00147 toggleActive(); 00148 break; 00149 case MidButton: 00150 // fall through 00151 case RightButton: 00152 if ( parentWidget() ) { 00153 KAction* action = d->actionCollection->action("minimizeRestore"); 00154 if ( parentWidget()->isVisible() ) 00155 action->setText( i18n("&Minimize") ); 00156 else 00157 action->setText( i18n("&Restore") ); 00158 } 00159 contextMenuAboutToShow( menu ); 00160 menu->popup( e->globalPos() ); 00161 break; 00162 default: 00163 // nothing 00164 break; 00165 } 00166 } 00167 00168 void KSystemTray::mouseReleaseEvent( QMouseEvent * ) 00169 { 00170 } 00171 00172 00173 void KSystemTray::contextMenuAboutToShow( KPopupMenu* ) 00174 { 00175 } 00176 00177 // called from the popup menu - always do what the menu entry says, 00178 // i.e. if the window is shown, no matter if active or not, the menu 00179 // entry is "minimize", otherwise it's "restore" 00180 void KSystemTray::minimizeRestoreAction() 00181 { 00182 if ( parentWidget() ) { 00183 bool restore = !( parentWidget()->isVisible() ); 00184 minimizeRestore( restore ); 00185 } 00186 } 00187 00188 void KSystemTray::maybeQuit() 00189 { 00190 QString query = i18n("<qt>Are you sure you want to quit <b>%1</b>?</qt>") 00191 .arg(kapp->caption()); 00192 if (KMessageBox::warningContinueCancel(this, query, 00193 i18n("Confirm Quit From System Tray"), 00194 KStdGuiItem::quit(), 00195 QString("systemtrayquit%1") 00196 .arg(kapp->caption())) != 00197 KMessageBox::Continue) 00198 { 00199 return; 00200 } 00201 00202 emit quitSelected(); 00203 00204 // KDE4: stop closing the parent widget? it results in complex application code 00205 // instead make applications connect to the quitSelected() signal 00206 00207 if (parentWidget()) 00208 { 00209 parentWidget()->close(); 00210 } 00211 else 00212 { 00213 qApp->closeAllWindows(); 00214 } 00215 } 00216 00217 void KSystemTray::toggleActive() 00218 { 00219 activateOrHide(); 00220 } 00221 00222 void KSystemTray::setActive() 00223 { 00224 minimizeRestore( true ); 00225 } 00226 00227 void KSystemTray::setInactive() 00228 { 00229 minimizeRestore( false ); 00230 } 00231 00232 // called when left-clicking the tray icon 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 KSystemTray::activateOrHide() 00236 { 00237 QWidget *pw = parentWidget(); 00238 00239 if ( !pw ) 00240 return; 00241 00242 #ifdef Q_WS_X11 00243 KWin::WindowInfo info1 = KWin::windowInfo( pw->winId(), NET::XAWMState | NET::WMState ); 00244 // mapped = visible (but possibly obscured) 00245 bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized(); 00246 // - not mapped -> show, raise, focus 00247 // - mapped 00248 // - obscured -> raise, focus 00249 // - not obscured -> hide 00250 if( !mapped ) 00251 minimizeRestore( true ); 00252 else 00253 { 00254 KWinModule module; 00255 for( QValueList< WId >::ConstIterator it = module.stackingOrder().fromLast(); 00256 it != module.stackingOrder().end() && (*it) != pw->winId(); 00257 --it ) 00258 { 00259 KWin::WindowInfo info2 = KWin::windowInfo( *it, 00260 NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType ); 00261 if( info2.mappingState() != NET::Visible ) 00262 continue; // not visible on current desktop -> ignore 00263 if( !info2.geometry().intersects( pw->geometry())) 00264 continue; // not obscuring the window -> ignore 00265 if( !info1.hasState( NET::KeepAbove ) && info2.hasState( NET::KeepAbove )) 00266 continue; // obscured by window kept above -> ignore 00267 NET::WindowType type = info2.windowType( NET::NormalMask | NET::DesktopMask 00268 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask 00269 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask ); 00270 if( type == NET::Dock || type == NET::TopMenu ) 00271 continue; // obscured by dock or topmenu -> ignore 00272 pw->raise(); 00273 KWin::activateWindow( pw->winId()); 00274 return; 00275 } 00276 minimizeRestore( false ); // hide 00277 } 00278 #endif 00279 } 00280 00281 void KSystemTray::minimizeRestore( bool restore ) 00282 { 00283 QWidget* pw = parentWidget(); 00284 if( !pw ) 00285 return; 00286 #ifdef Q_WS_X11 00287 KWin::WindowInfo info = KWin::windowInfo( pw->winId(), NET::WMGeometry | NET::WMDesktop ); 00288 if ( restore ) 00289 { 00290 if( d->on_all_desktops ) 00291 KWin::setOnAllDesktops( pw->winId(), true ); 00292 else 00293 KWin::setCurrentDesktop( info.desktop() ); 00294 pw->move( info.geometry().topLeft() ); // avoid placement policies 00295 pw->show(); 00296 pw->raise(); 00297 KWin::activateWindow( pw->winId() ); 00298 } else { 00299 d->on_all_desktops = info.onAllDesktops(); 00300 pw->hide(); 00301 } 00302 #endif 00303 } 00304 00305 KActionCollection* KSystemTray::actionCollection() 00306 { 00307 return d->actionCollection; 00308 } 00309 00310 QPixmap KSystemTray::loadIcon( const QString &icon, KInstance *instance ) 00311 { 00312 KConfig *appCfg = kapp->config(); 00313 KConfigGroupSaver configSaver(appCfg, "System Tray"); 00314 int iconWidth = appCfg->readNumEntry("systrayIconWidth", 22); 00315 return instance->iconLoader()->loadIcon( icon, KIcon::Panel, iconWidth ); 00316 } 00317 00318 void KSystemTray::setPixmap( const QPixmap& p ) 00319 { 00320 QLabel::setPixmap( p ); 00321 #ifdef Q_WS_X11 00322 KWin::setIcons( winId(), p, QPixmap()); 00323 #endif 00324 } 00325 00326 void KSystemTray::setCaption( const QString& s ) 00327 { 00328 QLabel::setCaption( s ); 00329 } 00330 00331 void KSystemTray::virtual_hook( int, void* ) 00332 { /*BASE::virtual_hook( id, data );*/ } 00333 00334 #include "ksystemtray.moc" 00335 #include "kdockwindow.moc"