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