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