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

KDE's Doxygen guidelines are available online.

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-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal