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