• Skip to content
  • Skip to link menu
KDE 4.8 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kstatusnotifieritem.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright 2009 by Marco Martin <notmart@gmail.com>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License (LGPL) as published by the Free Software Foundation;
00007    either version 2 of the License, or (at your option) any later
00008    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 "kstatusnotifieritem.h"
00022 #include "kstatusnotifieritemprivate_p.h"
00023 #include "kstatusnotifieritemdbus_p.h"
00024 
00025 #include <QDBusConnection>
00026 #include <QPixmap>
00027 #include <QImage>
00028 #include <QApplication>
00029 #include <QMovie>
00030 #include <QPainter>
00031 
00032 
00033 #include <kdebug.h>
00034 #include <ksystemtrayicon.h>
00035 #include <kaboutdata.h>
00036 #include <kicon.h>
00037 #include <kmenu.h>
00038 #include <kaction.h>
00039 #include <kwindowinfo.h>
00040 #include <kwindowsystem.h>
00041 #include <kmessagebox.h>
00042 #include <kactioncollection.h>
00043 #include <kstandarddirs.h>
00044 #include <kglobal.h>
00045 
00046 #include <netinet/in.h>
00047 
00048 #include <dbusmenuexporter.h>
00049 
00050 #include "statusnotifieritemadaptor.h"
00051 
00052 static const QString s_statusNotifierWatcherServiceName("org.kde.StatusNotifierWatcher");
00053 
00057 class KDBusMenuExporter : public DBusMenuExporter
00058 {
00059 public:
00060     KDBusMenuExporter(const QString &dbusObjectPath, QMenu *menu, const QDBusConnection &dbusConnection)
00061     : DBusMenuExporter(dbusObjectPath, menu, dbusConnection)
00062     {}
00063 
00064 protected:
00065     virtual QString iconNameForAction(QAction *action)
00066     {
00067         KIcon icon(action->icon());
00068 #if QT_VERSION >= 0x040701
00069         // QIcon::name() is in the 4.7 git branch, but it is not in 4.7 TP.
00070         // If you get a build error here, you need to update your pre-release
00071         // of Qt 4.7.
00072         return icon.isNull() ? QString() : icon.name();
00073 #else
00074         // Qt 4.6: If the icon was created by us, via our engine, serializing it
00075         // will let us get to the name.
00076         if (!icon.isNull()) {
00077             QBuffer encBuf;
00078             encBuf.open(QIODevice::WriteOnly);
00079             QDataStream encode(&encBuf);
00080             encode.setVersion(QDataStream::Qt_4_6);
00081             encode << icon;
00082             encBuf.close();
00083 
00084             if (!encBuf.data().isEmpty()) {
00085                 QDataStream decode(encBuf.data());
00086                 QString key;
00087                 decode >> key;
00088                 if (key == QLatin1String("KIconEngine")) {
00089                     QString name;
00090                     decode >> name;
00091                     return name;
00092                 }
00093             }
00094         }
00095         
00096         return QString();
00097 #endif
00098     }
00099 };
00100 
00101 KStatusNotifierItem::KStatusNotifierItem(QObject *parent)
00102       : QObject(parent),
00103         d(new KStatusNotifierItemPrivate(this))
00104 {
00105     d->init(QString());
00106 }
00107 
00108 
00109 KStatusNotifierItem::KStatusNotifierItem(const QString &id, QObject *parent)
00110       : QObject(parent),
00111         d(new KStatusNotifierItemPrivate(this))
00112 {
00113     d->init(id);
00114 }
00115 
00116 KStatusNotifierItem::~KStatusNotifierItem()
00117 {
00118     delete d->statusNotifierWatcher;
00119     delete d->notificationsClient;
00120     delete d->systemTrayIcon;
00121     delete d->menu;
00122     delete d;
00123     KGlobal::deref();
00124 }
00125 
00126 QString KStatusNotifierItem::id() const
00127 {
00128     //kDebug(299) << "id requested" << d->id;
00129     return d->id;
00130 }
00131 
00132 void KStatusNotifierItem::setCategory(const ItemCategory category)
00133 {
00134     d->category = category;
00135 }
00136 
00137 KStatusNotifierItem::ItemStatus KStatusNotifierItem::status() const
00138 {
00139     return d->status;
00140 }
00141 
00142 KStatusNotifierItem::ItemCategory KStatusNotifierItem::category() const
00143 {
00144     return d->category;
00145 }
00146 
00147 void KStatusNotifierItem::setTitle(const QString &title)
00148 {
00149     d->title = title;
00150 }
00151 
00152 void KStatusNotifierItem::setStatus(const ItemStatus status)
00153 {
00154     if (d->status == status) {
00155         return;
00156     }
00157 
00158     d->status = status;
00159     emit d->statusNotifierItemDBus->NewStatus(metaObject()->enumerator(metaObject()->indexOfEnumerator("ItemStatus")).valueToKey(d->status));
00160 
00161     if (d->systemTrayIcon) {
00162         d->syncLegacySystemTrayIcon();
00163     }
00164 }
00165 
00166 
00167 
00168 //normal icon
00169 
00170 void KStatusNotifierItem::setIconByName(const QString &name)
00171 {
00172     if (d->iconName == name) {
00173         return;
00174     }
00175 
00176     d->serializedIcon = KDbusImageVector();
00177     d->iconName = name;
00178     emit d->statusNotifierItemDBus->NewIcon();
00179     if (d->systemTrayIcon) {
00180         d->systemTrayIcon->setIcon(KIcon(name));
00181     }
00182 }
00183 
00184 QString KStatusNotifierItem::iconName() const
00185 {
00186     return d->iconName;
00187 }
00188 
00189 void KStatusNotifierItem::setIconByPixmap(const QIcon &icon)
00190 {
00191     if (d->iconName.isEmpty() && d->icon.cacheKey() == icon.cacheKey()) {
00192         return;
00193     }
00194 
00195     d->iconName.clear();
00196     d->serializedIcon = d->iconToVector(icon);
00197     emit d->statusNotifierItemDBus->NewIcon();
00198 
00199     d->icon = icon;
00200     if (d->systemTrayIcon) {
00201         d->systemTrayIcon->setIcon(icon);
00202     }
00203 }
00204 
00205 QIcon KStatusNotifierItem::iconPixmap() const
00206 {
00207     return d->icon;
00208 }
00209 
00210 void KStatusNotifierItem::setOverlayIconByName(const QString &name)
00211 {
00212     if (d->overlayIconName == name) {
00213         return;
00214     }
00215 
00216     d->overlayIconName = name;
00217     emit d->statusNotifierItemDBus->NewOverlayIcon();
00218     if (d->systemTrayIcon) {
00219         QPixmap iconPixmap = KIcon(d->iconName).pixmap(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
00220         if (!name.isEmpty()) {
00221             QPixmap overlayPixmap = KIcon(d->overlayIconName).pixmap(KIconLoader::SizeSmallMedium/2, KIconLoader::SizeSmallMedium/2);
00222             QPainter p(&iconPixmap);
00223             p.drawPixmap(iconPixmap.width()-overlayPixmap.width(), iconPixmap.height()-overlayPixmap.height(), overlayPixmap);
00224             p.end();
00225         }
00226         d->systemTrayIcon->setIcon(iconPixmap);
00227     }
00228 }
00229 
00230 QString KStatusNotifierItem::overlayIconName() const
00231 {
00232     return d->overlayIconName;
00233 }
00234 
00235 void KStatusNotifierItem::setOverlayIconByPixmap(const QIcon &icon)
00236 {
00237     if (d->overlayIconName.isEmpty() && d->overlayIcon.cacheKey() == icon.cacheKey()) {
00238         return;
00239     }
00240 
00241     d->overlayIconName.clear();
00242     d->serializedOverlayIcon = d->iconToVector(icon);
00243     emit d->statusNotifierItemDBus->NewOverlayIcon();
00244 
00245     d->overlayIcon = icon;
00246     if (d->systemTrayIcon) {
00247         QPixmap iconPixmap = d->icon.pixmap(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
00248         QPixmap overlayPixmap = d->overlayIcon.pixmap(KIconLoader::SizeSmallMedium/2, KIconLoader::SizeSmallMedium/2);
00249 
00250         QPainter p(&iconPixmap);
00251         p.drawPixmap(iconPixmap.width()-overlayPixmap.width(), iconPixmap.height()-overlayPixmap.height(), overlayPixmap);
00252         p.end();
00253         d->systemTrayIcon->setIcon(iconPixmap);
00254     }
00255 }
00256 
00257 QIcon KStatusNotifierItem::overlayIconPixmap() const
00258 {
00259     return d->overlayIcon;
00260 }
00261 
00262 //Icons and movie for requesting attention state
00263 
00264 void KStatusNotifierItem::setAttentionIconByName(const QString &name)
00265 {
00266     if (d->attentionIconName == name) {
00267         return;
00268     }
00269 
00270     d->serializedAttentionIcon = KDbusImageVector();
00271     d->attentionIconName = name;
00272     emit d->statusNotifierItemDBus->NewAttentionIcon();
00273 }
00274 
00275 QString KStatusNotifierItem::attentionIconName() const
00276 {
00277     return d->attentionIconName;
00278 }
00279 
00280 void KStatusNotifierItem::setAttentionIconByPixmap(const QIcon &icon)
00281 {
00282     if (d->attentionIconName.isEmpty() && d->attentionIcon.cacheKey() == icon.cacheKey()) {
00283         return;
00284     }
00285 
00286     d->attentionIconName.clear();
00287     d->serializedAttentionIcon = d->iconToVector(icon);
00288     d->attentionIcon = icon;
00289     emit d->statusNotifierItemDBus->NewAttentionIcon();
00290 }
00291 
00292 QIcon KStatusNotifierItem::attentionIconPixmap() const
00293 {
00294     return d->attentionIcon;
00295 }
00296 
00297 void KStatusNotifierItem::setAttentionMovieByName(const QString &name)
00298 {
00299     if (d->movieName == name) {
00300         return;
00301     }
00302 
00303     d->movieName = name;
00304 
00305     delete d->movie;
00306     d->movie = 0;
00307 
00308     emit d->statusNotifierItemDBus->NewAttentionIcon();
00309 
00310     if (d->systemTrayIcon) {
00311         d->movie = new QMovie(d->movieName);
00312         d->systemTrayIcon->setMovie(d->movie);
00313     }
00314 }
00315 
00316 QString KStatusNotifierItem::attentionMovieName() const
00317 {
00318     return d->movieName;
00319 }
00320 
00321 //ToolTip
00322 
00323 void KStatusNotifierItem::setToolTip(const QString &iconName, const QString &title, const QString &subTitle)
00324 {
00325     if (d->toolTipIconName == iconName &&
00326         d->toolTipTitle == title &&
00327         d->toolTipSubTitle == subTitle) {
00328         return;
00329     }
00330 
00331     d->serializedToolTipIcon = KDbusImageVector();
00332     d->toolTipIconName = iconName;
00333 
00334     d->toolTipTitle = title;
00335     if (d->systemTrayIcon) {
00336         d->systemTrayIcon->setToolTip(title);
00337     }
00338 
00339     d->toolTipSubTitle = subTitle;
00340     emit d->statusNotifierItemDBus->NewToolTip();
00341 }
00342 
00343 void KStatusNotifierItem::setToolTip(const QIcon &icon, const QString &title, const QString &subTitle)
00344 {
00345     if (d->toolTipIconName.isEmpty() && d->toolTipIcon.cacheKey() == icon.cacheKey() &&
00346         d->toolTipTitle == title &&
00347         d->toolTipSubTitle == subTitle) {
00348         return;
00349     }
00350 
00351     d->toolTipIconName.clear();
00352     d->serializedToolTipIcon = d->iconToVector(icon);
00353     d->toolTipIcon = icon;
00354 
00355     d->toolTipTitle = title;
00356     if (d->systemTrayIcon) {
00357         d->systemTrayIcon->setToolTip(title);
00358     }
00359 
00360     d->toolTipSubTitle = subTitle;
00361     emit d->statusNotifierItemDBus->NewToolTip();
00362 }
00363 
00364 void KStatusNotifierItem::setToolTipIconByName(const QString &name)
00365 {
00366     if (d->toolTipIconName == name) {
00367         return;
00368     }
00369 
00370     d->serializedToolTipIcon = KDbusImageVector();
00371     d->toolTipIconName = name;
00372     emit d->statusNotifierItemDBus->NewToolTip();
00373 }
00374 
00375 QString KStatusNotifierItem::toolTipIconName() const
00376 {
00377     return d->toolTipIconName;
00378 }
00379 
00380 void KStatusNotifierItem::setToolTipIconByPixmap(const QIcon &icon)
00381 {
00382     if (d->toolTipIconName.isEmpty() && d->toolTipIcon.cacheKey() == icon.cacheKey()) {
00383         return;
00384     }
00385 
00386     d->toolTipIconName.clear();
00387     d->serializedToolTipIcon = d->iconToVector(icon);
00388     d->toolTipIcon = icon;
00389     emit d->statusNotifierItemDBus->NewToolTip();
00390 }
00391 
00392 QIcon KStatusNotifierItem::toolTipIconPixmap() const
00393 {
00394     return d->toolTipIcon;
00395 }
00396 
00397 void KStatusNotifierItem::setToolTipTitle(const QString &title)
00398 {
00399     if (d->toolTipTitle == title) {
00400         return;
00401     }
00402 
00403     d->toolTipTitle = title;
00404     emit d->statusNotifierItemDBus->NewToolTip();
00405     if (d->systemTrayIcon) {
00406         d->systemTrayIcon->setToolTip(title);
00407     }
00408 }
00409 
00410 QString KStatusNotifierItem::toolTipTitle() const
00411 {
00412     return d->toolTipTitle;
00413 }
00414 
00415 void KStatusNotifierItem::setToolTipSubTitle(const QString &subTitle)
00416 {
00417     if (d->toolTipSubTitle == subTitle) {
00418         return;
00419     }
00420 
00421     d->toolTipSubTitle = subTitle;
00422     emit d->statusNotifierItemDBus->NewToolTip();
00423 }
00424 
00425 QString KStatusNotifierItem::toolTipSubTitle() const
00426 {
00427     return d->toolTipSubTitle;
00428 }
00429 
00430 void KStatusNotifierItem::setContextMenu(KMenu *menu)
00431 {
00432     if (d->menu && d->menu != menu) {
00433         d->menu->removeEventFilter(this);
00434         delete d->menu;
00435     }
00436 
00437     if (!menu) {
00438         d->menu = 0;
00439         return;
00440     }
00441 
00442     if (d->systemTrayIcon) {
00443         d->systemTrayIcon->setContextMenu(menu);
00444     } else if (d->menu != menu) {
00445         if (getenv("KSNI_NO_DBUSMENU")) {
00446             // This is a hack to make it possible to disable DBusMenu in an
00447             // application. The string "/NO_DBUSMENU" must be the same as in
00448             // DBusSystemTrayWidget::findDBusMenuInterface() in the Plasma
00449             // systemtray applet.
00450             d->menuObjectPath = "/NO_DBUSMENU";
00451             menu->installEventFilter(this);
00452         } else {
00453             d->menuObjectPath = "/MenuBar";
00454             new KDBusMenuExporter(d->menuObjectPath, menu, d->statusNotifierItemDBus->dbusConnection());
00455         }
00456 
00457         connect(menu, SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
00458     }
00459 
00460     d->menu = menu;
00461     d->menu->setParent(0);
00462 }
00463 
00464 KMenu *KStatusNotifierItem::contextMenu() const
00465 {
00466     return d->menu;
00467 }
00468 
00469 void KStatusNotifierItem::setAssociatedWidget(QWidget *associatedWidget)
00470 {
00471     if (associatedWidget) {
00472         d->associatedWidget = associatedWidget->window();
00473     } else {
00474         d->associatedWidget = 0;
00475     }
00476 
00477     if (d->systemTrayIcon) {
00478         delete d->systemTrayIcon;
00479         d->systemTrayIcon = 0;
00480         d->setLegacySystemTrayEnabled(true);
00481     }
00482 
00483     if (d->associatedWidget && d->associatedWidget != d->menu) {
00484         QAction *action = d->actionCollection->action("minimizeRestore");
00485 
00486         if (!action) {
00487             action = d->actionCollection->addAction("minimizeRestore");
00488             action->setText(i18n("&Minimize"));
00489             connect(action, SIGNAL(triggered(bool)), this, SLOT(minimizeRestore()));
00490         }
00491 
00492 #ifdef Q_WS_X11
00493         KWindowInfo info = KWindowSystem::windowInfo(d->associatedWidget->winId(), NET::WMDesktop);
00494         d->onAllDesktops = info.onAllDesktops();
00495 #else
00496         d->onAllDesktops = false;
00497 #endif
00498     } else {
00499         if (d->menu && d->hasQuit) {
00500             QAction *action = d->actionCollection->action("minimizeRestore");
00501             if (action) {
00502                 d->menu->removeAction(action);
00503             }
00504         }
00505 
00506         d->onAllDesktops = false;
00507     }
00508 }
00509 
00510 QWidget *KStatusNotifierItem::associatedWidget() const
00511 {
00512     return d->associatedWidget;
00513 }
00514 
00515 KActionCollection *KStatusNotifierItem::actionCollection() const
00516 {
00517     return d->actionCollection;
00518 }
00519 
00520 void KStatusNotifierItem::setStandardActionsEnabled(bool enabled)
00521 {
00522     if (d->standardActionsEnabled == enabled) {
00523         return;
00524     }
00525 
00526     d->standardActionsEnabled = enabled;
00527 
00528     if (d->menu && !enabled && d->hasQuit) {
00529         QAction *action = d->actionCollection->action("minimizeRestore");
00530         if (action) {
00531             d->menu->removeAction(action);
00532         }
00533 
00534         action = d->actionCollection->action(KStandardAction::name(KStandardAction::Quit));
00535         if (action) {
00536             d->menu->removeAction(action);
00537         }
00538 
00539 
00540         d->hasQuit = false;
00541     }
00542 }
00543 
00544 bool KStatusNotifierItem::standardActionsEnabled() const
00545 {
00546     return d->standardActionsEnabled;
00547 }
00548 
00549 void KStatusNotifierItem::showMessage(const QString & title, const QString & message, const QString &icon, int timeout)
00550 {
00551     if (!d->notificationsClient) {
00552         d->notificationsClient = new org::freedesktop::Notifications("org.freedesktop.Notifications", "/org/freedesktop/Notifications",
00553                                                 QDBusConnection::sessionBus());
00554     }
00555 
00556     uint id = 0;
00557     d->notificationsClient->Notify(d->title, id, icon, title, message, QStringList(), QVariantMap(), timeout);
00558 }
00559 
00560 QString KStatusNotifierItem::title() const
00561 {
00562     return d->title;
00563 }
00564 
00565 
00566 
00567 void KStatusNotifierItem::activate(const QPoint &pos)
00568 {
00569     //if the user activated the icon the NeedsAttention state is no longer necessary
00570     //FIXME: always true?
00571     if (d->status == NeedsAttention) {
00572         d->status = Active;
00573         emit d->statusNotifierItemDBus->NewStatus(metaObject()->enumerator(metaObject()->indexOfEnumerator("ItemStatus")).valueToKey(d->status));
00574     }
00575 
00576     if (d->associatedWidget == d->menu) {
00577         d->statusNotifierItemDBus->ContextMenu(pos.x(), pos.y());
00578         return;
00579     }
00580 
00581     if (d->menu->isVisible()) {
00582         d->menu->hide();
00583     }
00584 
00585     if (!d->associatedWidget) {
00586         emit activateRequested(true, pos);
00587         return;
00588     }
00589 
00590     d->checkVisibility(pos);
00591 }
00592 
00593 bool KStatusNotifierItemPrivate::checkVisibility(QPoint pos, bool perform)
00594 {
00595 #ifdef Q_WS_WIN
00596 #if 0
00597     // the problem is that we lose focus when the systray icon is activated
00598     // and we don't know the former active window
00599     // therefore we watch for activation event and use our stopwatch :)
00600     if(GetTickCount() - dwTickCount < 300) {
00601         // we were active in the last 300ms -> hide it
00602         minimizeRestore(false);
00603         emit activateRequested(false, pos);
00604     } else {
00605         minimizeRestore(true);
00606         emit activateRequested(true, pos);
00607     }
00608 #endif
00609 #elif defined(Q_WS_X11)
00610     KWindowInfo info1 = KWindowSystem::windowInfo(associatedWidget->winId(), NET::XAWMState | NET::WMState | NET::WMDesktop);
00611     // mapped = visible (but possibly obscured)
00612     bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
00613 
00614 //    - not mapped -> show, raise, focus
00615 //    - mapped
00616 //        - obscured -> raise, focus
00617 //        - not obscured -> hide
00618     //info1.mappingState() != NET::Visible -> window on another desktop?
00619     if (!mapped) {
00620         if (perform) {
00621             minimizeRestore(true);
00622             emit q->activateRequested(true, pos);
00623         }
00624 
00625         return true;
00626     } else {
00627         QListIterator< WId > it (KWindowSystem::stackingOrder());
00628         it.toBack();
00629         while (it.hasPrevious()) {
00630             WId id = it.previous();
00631             if (id == associatedWidget->winId()) {
00632                 break;
00633             }
00634 
00635             KWindowInfo info2 = KWindowSystem::windowInfo(id,
00636                 NET::WMDesktop | NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType);
00637 
00638             if (info2.mappingState() != NET::Visible) {
00639                 continue; // not visible on current desktop -> ignore
00640             }
00641 
00642             if (!info2.geometry().intersects(associatedWidget->geometry())) {
00643                 continue; // not obscuring the window -> ignore
00644             }
00645 
00646             if (!info1.hasState(NET::KeepAbove) && info2.hasState(NET::KeepAbove)) {
00647                 continue; // obscured by window kept above -> ignore
00648             }
00649 
00650             NET::WindowType type = info2.windowType(NET::NormalMask | NET::DesktopMask
00651                 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00652                 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask);
00653 
00654             if (type == NET::Dock || type == NET::TopMenu) {
00655                 continue; // obscured by dock or topmenu -> ignore
00656             }
00657 
00658             if (perform) {
00659                 KWindowSystem::raiseWindow(associatedWidget->winId());
00660                 KWindowSystem::forceActiveWindow(associatedWidget->winId());
00661                 emit q->activateRequested(true, pos);
00662             }
00663 
00664             return true;
00665         }
00666 
00667         //not on current desktop?
00668         if (!info1.isOnCurrentDesktop()) {
00669             if (perform) {
00670                 KWindowSystem::activateWindow(associatedWidget->winId());
00671                 emit q->activateRequested(true, pos);
00672             }
00673 
00674             return true;
00675         }
00676 
00677         if (perform) {
00678             minimizeRestore(false); // hide
00679             emit q->activateRequested(false, pos);
00680         }
00681 
00682         return false;
00683     }
00684 #endif
00685 
00686     return true;
00687 }
00688 
00689 bool KStatusNotifierItem::eventFilter(QObject *watched, QEvent *event)
00690 {
00691     if (d->systemTrayIcon == 0) {
00692         //FIXME: ugly ugly workaround to weird QMenu's focus problems
00693         if (watched == d->menu &&
00694             (event->type() == QEvent::WindowDeactivate || (event->type() == QEvent::MouseButtonRelease && static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton))) {
00695             //put at the back of even queue to let the action activate anyways
00696             QTimer::singleShot(0, this, SLOT(hideMenu()));
00697         }
00698     }
00699     return false;
00700 }
00701 
00702 
00703 //KStatusNotifierItemPrivate
00704 
00705 const int KStatusNotifierItemPrivate::s_protocolVersion = 0;
00706 
00707 KStatusNotifierItemPrivate::KStatusNotifierItemPrivate(KStatusNotifierItem *item)
00708     : q(item),
00709       category(KStatusNotifierItem::ApplicationStatus),
00710       status(KStatusNotifierItem::Passive),
00711       movie(0),
00712       menu(0),
00713       titleAction(0),
00714       statusNotifierWatcher(0),
00715       notificationsClient(0),
00716       systemTrayIcon(0),
00717       hasQuit(false),
00718       onAllDesktops(false),
00719       standardActionsEnabled(true)
00720 {
00721 }
00722 
00723 void KStatusNotifierItemPrivate::init(const QString &extraId)
00724 {
00725     // Ensure that closing the last KMainWindow doesn't exit the application
00726     // if a system tray icon is still present.
00727     KGlobal::ref();
00728 
00729     qDBusRegisterMetaType<KDbusImageStruct>();
00730     qDBusRegisterMetaType<KDbusImageVector>();
00731     qDBusRegisterMetaType<KDbusToolTipStruct>();
00732 
00733     actionCollection = new KActionCollection(q);
00734     statusNotifierItemDBus = new KStatusNotifierItemDBus(q);
00735     q->setAssociatedWidget(qobject_cast<QWidget*>(q->parent()));
00736 
00737     QDBusServiceWatcher *watcher = new QDBusServiceWatcher(s_statusNotifierWatcherServiceName,
00738                                                            QDBusConnection::sessionBus(),
00739                                                            QDBusServiceWatcher::WatchForOwnerChange,
00740                                                            q);
00741     QObject::connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00742                      q, SLOT(serviceChange(QString,QString,QString)));
00743 
00744     //create a default menu, just like in KSystemtrayIcon
00745     KMenu *m = new KMenu(associatedWidget);
00746     titleAction = m->addTitle(qApp->windowIcon(), KGlobal::caption());
00747     m->setTitle(KGlobal::mainComponent().aboutData()->programName());
00748     q->setContextMenu(m);
00749 
00750     KStandardAction::quit(q, SLOT(maybeQuit()), actionCollection);
00751 
00752     id = title = KGlobal::mainComponent().aboutData()->programName();
00753 
00754     if (!extraId.isEmpty()) {
00755         id.append('_').append(extraId);
00756     }
00757 
00758     // Init iconThemePath to the app folder for now
00759     QStringList dirs = KGlobal::dirs()->findDirs("appdata", "icons");
00760     if (!dirs.isEmpty()) {
00761         iconThemePath = dirs.first();
00762     }
00763 
00764     registerToDaemon();
00765 }
00766 
00767 void KStatusNotifierItemPrivate::registerToDaemon()
00768 {
00769     kDebug(299) << "Registering a client interface to the KStatusNotifierWatcher";
00770     if (!statusNotifierWatcher) {
00771         statusNotifierWatcher = new org::kde::StatusNotifierWatcher(s_statusNotifierWatcherServiceName, "/StatusNotifierWatcher",
00772                                                                     QDBusConnection::sessionBus());
00773         QObject::connect(statusNotifierWatcher, SIGNAL(StatusNotifierHostRegistered()),
00774                          q, SLOT(checkForRegisteredHosts()));
00775         QObject::connect(statusNotifierWatcher, SIGNAL(StatusNotifierHostUnregistered()),
00776                          q, SLOT(checkForRegisteredHosts()));
00777     }
00778 
00779     if (statusNotifierWatcher->isValid() &&
00780         statusNotifierWatcher->property("ProtocolVersion").toInt() == s_protocolVersion) {
00781 
00782         statusNotifierWatcher->RegisterStatusNotifierItem(statusNotifierItemDBus->service());
00783         setLegacySystemTrayEnabled(false);
00784     } else {
00785         kDebug(299)<<"KStatusNotifierWatcher not reachable";
00786         setLegacySystemTrayEnabled(true);
00787     }
00788 }
00789 
00790 void KStatusNotifierItemPrivate::serviceChange(const QString &name, const QString &oldOwner, const QString &newOwner)
00791 {
00792     Q_UNUSED(name)
00793     if (newOwner.isEmpty()) {
00794         //unregistered
00795         kDebug(299) << "Connection to the KStatusNotifierWatcher lost";
00796         setLegacyMode(true);
00797         delete statusNotifierWatcher;
00798         statusNotifierWatcher = 0;
00799     } else if (oldOwner.isEmpty()) {
00800         //registered
00801        setLegacyMode(false);
00802     }
00803 }
00804 
00805 void KStatusNotifierItemPrivate::checkForRegisteredHosts()
00806 {
00807     setLegacyMode(!statusNotifierWatcher ||
00808                   !statusNotifierWatcher->property("IsStatusNotifierHostRegistered").toBool());
00809 }
00810 
00811 void KStatusNotifierItemPrivate::setLegacyMode(bool legacy)
00812 {
00813     if (legacy == (systemTrayIcon != 0)) {
00814         return;
00815     }
00816 
00817     if (legacy) {
00818         //unregistered
00819         setLegacySystemTrayEnabled(true);
00820     } else {
00821         //registered
00822         registerToDaemon();
00823     }
00824 }
00825 
00826 void KStatusNotifierItemPrivate::legacyWheelEvent(int delta)
00827 {
00828     statusNotifierItemDBus->Scroll(delta, "vertical");
00829 }
00830 
00831 void KStatusNotifierItemPrivate::legacyActivated(QSystemTrayIcon::ActivationReason reason)
00832 {
00833     if (reason == QSystemTrayIcon::MiddleClick) {
00834         emit q->secondaryActivateRequested(systemTrayIcon->geometry().topLeft());
00835     }
00836 }
00837 
00838 void KStatusNotifierItemPrivate::setLegacySystemTrayEnabled(bool enabled)
00839 {
00840     if (enabled == (systemTrayIcon != 0)) {
00841         // already in the correct state
00842         return;
00843     }
00844 
00845     if (enabled) {
00846         if (!systemTrayIcon) {
00847             systemTrayIcon = new KStatusNotifierLegacyIcon(associatedWidget);
00848             syncLegacySystemTrayIcon();
00849             systemTrayIcon->setToolTip(toolTipTitle);
00850             systemTrayIcon->show();
00851             QObject::connect(systemTrayIcon, SIGNAL(wheel(int)), q, SLOT(legacyWheelEvent(int)));
00852             QObject::connect(systemTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), q, SLOT(legacyActivated(QSystemTrayIcon::ActivationReason)));
00853         }
00854 
00855         if (menu) {
00856             menu->setWindowFlags(Qt::Popup);
00857         }
00858     } else {
00859         delete systemTrayIcon;
00860         systemTrayIcon = 0;
00861 
00862         if (menu) {
00863             menu->setWindowFlags(Qt::Window);
00864         }
00865     }
00866 
00867     if (menu) {
00868         KMenu *m = menu;
00869         menu = 0;
00870         q->setContextMenu(m);
00871     }
00872 }
00873 
00874 void KStatusNotifierItemPrivate::syncLegacySystemTrayIcon()
00875 {
00876     if (status == KStatusNotifierItem::NeedsAttention) {
00877         if (!movieName.isNull()) {
00878             if (!movie) {
00879                 movie = new QMovie(movieName);
00880             }
00881             systemTrayIcon->setMovie(movie);
00882         } else if (!attentionIconName.isNull()) {
00883             systemTrayIcon->setIcon(KIcon(attentionIconName));
00884         } else {
00885             systemTrayIcon->setIcon(attentionIcon);
00886         }
00887     } else {
00888         if (!iconName.isNull()) {
00889             systemTrayIcon->setIcon(KIcon(iconName));
00890         } else {
00891             systemTrayIcon->setIcon(icon);
00892         }
00893     }
00894 
00895     systemTrayIcon->setToolTip(toolTipTitle);
00896 }
00897 
00898 void KStatusNotifierItemPrivate::contextMenuAboutToShow()
00899 {
00900     if (!hasQuit && standardActionsEnabled) {
00901         // we need to add the actions to the menu afterwards so that these items
00902         // appear at the _END_ of the menu
00903         menu->addSeparator();
00904         if (associatedWidget && associatedWidget != menu) {
00905             QAction *action = actionCollection->action("minimizeRestore");
00906 
00907             if (action) {
00908                 menu->addAction(action);
00909             }
00910         }
00911 
00912         QAction *action = actionCollection->action(KStandardAction::name(KStandardAction::Quit));
00913 
00914         if (action) {
00915             menu->addAction(action);
00916         }
00917 
00918         hasQuit = true;
00919     }
00920 
00921     if (associatedWidget && associatedWidget != menu) {
00922         QAction* action = actionCollection->action("minimizeRestore");
00923         if (checkVisibility(QPoint(0, 0), false)) {
00924             action->setText(i18n("&Restore"));
00925         } else {
00926             action->setText(i18n("&Minimize"));
00927         }
00928     }
00929 }
00930 
00931 void KStatusNotifierItemPrivate::maybeQuit()
00932 {
00933     QString caption = KGlobal::caption();
00934     QString query = i18n("<qt>Are you sure you want to quit <b>%1</b>?</qt>", caption);
00935 
00936     if (KMessageBox::warningContinueCancel(associatedWidget, query,
00937                                      i18n("Confirm Quit From System Tray"),
00938                                      KStandardGuiItem::quit(),
00939                                      KStandardGuiItem::cancel(),
00940                                      QString("systemtrayquit%1")
00941                                             .arg(caption)) == KMessageBox::Continue) {
00942         qApp->quit();
00943     }
00944 
00945 }
00946 
00947 void KStatusNotifierItemPrivate::minimizeRestore()
00948 {
00949     q->activate(QPoint(0, 0));
00950 }
00951 
00952 void KStatusNotifierItemPrivate::hideMenu()
00953 {
00954     menu->hide();
00955 }
00956 
00957 void KStatusNotifierItemPrivate::minimizeRestore(bool show)
00958 {
00959 #ifdef Q_WS_X11
00960     KWindowInfo info = KWindowSystem::windowInfo(associatedWidget->winId(), NET::WMDesktop | NET::WMFrameExtents);
00961     if (show) {
00962         if (onAllDesktops) {
00963             KWindowSystem::setOnAllDesktops(associatedWidget->winId(), true);
00964         } else {
00965             KWindowSystem::setCurrentDesktop(info.desktop());
00966         }
00967 
00968         associatedWidget->move(info.frameGeometry().topLeft()); // avoid placement policies
00969         associatedWidget->show();
00970         associatedWidget->raise();
00971         KWindowSystem::raiseWindow(associatedWidget->winId());
00972         KWindowSystem::forceActiveWindow(associatedWidget->winId());
00973     } else {
00974         onAllDesktops = info.onAllDesktops();
00975         associatedWidget->hide();
00976     }
00977 #else
00978     if (show) {
00979         associatedWidget->show();
00980         associatedWidget->raise();
00981         KWindowSystem::forceActiveWindow(associatedWidget->winId());
00982     } else {
00983         associatedWidget->hide();
00984     }
00985 #endif
00986 }
00987 
00988 KDbusImageStruct KStatusNotifierItemPrivate::imageToStruct(const QImage &image)
00989 {
00990     KDbusImageStruct icon;
00991     icon.width = image.size().width();
00992     icon.height = image.size().height();
00993     if (image.format() == QImage::Format_ARGB32) {
00994         icon.data = QByteArray((char*)image.bits(), image.numBytes());
00995     } else {
00996         QImage image32 = image.convertToFormat(QImage::Format_ARGB32);
00997         icon.data = QByteArray((char*)image32.bits(), image32.numBytes());
00998     }
00999 
01000     //swap to network byte order if we are little endian
01001     if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
01002         quint32 *uintBuf = (quint32 *) icon.data.data();
01003         for (uint i = 0; i < icon.data.size()/sizeof(quint32); ++i) {
01004             *uintBuf = htonl(*uintBuf);
01005             ++uintBuf;
01006         }
01007     }
01008 
01009     return icon;
01010 }
01011 
01012 KDbusImageVector KStatusNotifierItemPrivate::iconToVector(const QIcon &icon)
01013 {
01014     KDbusImageVector iconVector;
01015 
01016     QPixmap iconPixmap;
01017 
01018     //availableSizes() won't work on KIcon
01019     QList<QSize> allSizes;
01020     allSizes << QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)
01021              << QSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium)
01022              << QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium)
01023              << QSize(KIconLoader::SizeLarge, KIconLoader::SizeLarge);
01024 
01025     //if an icon exactly that size wasn't found don't add it to the vector
01026     foreach (const QSize &size, allSizes) {
01027         //hopefully huge and enormous not necessary right now, since it's quite costly
01028         if (size.width() <= KIconLoader::SizeLarge) {
01029             iconPixmap = icon.pixmap(size);
01030             iconVector.append(imageToStruct(iconPixmap.toImage()));
01031         }
01032     }
01033 
01034     return iconVector;
01035 }
01036 
01037 #include "kstatusnotifieritem.moc"
01038 #include "kstatusnotifieritemprivate_p.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.6.1
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