diff --git a/CMakeLists.txt b/CMakeLists.txt index 1576f6d..3bc3240 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,134 +1,146 @@ cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) project(liquidshell) find_package(ECM 1.3.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(ECMInstallIcons) find_package(Qt5 5.6 CONFIG REQUIRED COMPONENTS Core Widgets DBus X11Extras ) find_package(KF5 REQUIRED COMPONENTS WindowSystem WidgetsAddons ConfigWidgets Config KIO IconThemes ItemViews Archive Notifications I18n NetworkManagerQt Service Solid BluezQt KCMUtils Crash DBusAddons NewStuff ) -find_package(packagekitqt5 REQUIRED) - set(SOURCES desktop.cxx DesktopWidget.cxx DesktopPanel.cxx OnScreenVolume.cxx ConfigureDesktopDialog.cxx StartMenu.cxx Launcher.cxx QuickLaunch.cxx IconButton.cxx AppMenu.cxx Pager.cxx PagerButton.cxx WindowList.cxx ClockWidget.cxx ClockWidgetConfigureDialog.cxx TaskBar.cxx TaskBarButton.cxx LockLogout.cxx SysTray.cxx SysTrayItem.cxx SysTrayNotifyItem.cxx DBusTypes.cxx SysLoad.cxx NotificationServer.cxx NotificationList.cxx Network.cxx NetworkList.cxx DeviceNotifier.cxx DeviceList.cxx Battery.cxx Bluetooth.cxx PopupMenu.cxx - PkUpdates.cxx - PkUpdateList.cxx KdeConnect.cxx DesktopApplet.cxx WeatherApplet.cxx WeatherAppletConfigureDialog.cxx DiskUsageApplet.cxx DiskUsageAppletConfigureDialog.cxx PictureFrameApplet.cxx PictureFrameAppletConfigureDialog.cxx ) +find_package(packagekitqt5 QUIET) + +if ( packagekitqt5_FOUND ) + set(SOURCES ${SOURCES} + PkUpdates.cxx + PkUpdateList.cxx + ) + + add_definitions(-DWITH_PACKAGEKIT) +else() + message(WARNING "PackageKit integration not available. packagekitqt5 development files not found") +endif() + # e.g. on openSuse Leap 42.3 compile fails as a GLib header included uses signals as var add_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS) ki18n_wrap_ui(UI_FILES ConfigureDesktopDialog.ui WeatherAppletConfigureDialog.ui DiskUsageAppletConfigureDialog.ui PictureFrameAppletConfigureDialog.ui ) set(statusnotifieritem_xml ${KNOTIFICATIONS_DBUS_INTERFACES_DIR}/kf5_org.kde.StatusNotifierItem.xml) set_source_files_properties(${statusnotifieritem_xml} PROPERTIES INCLUDE "DBusTypes.hxx" CLASSNAME OrgKdeStatusNotifierItem ) qt5_add_dbus_interface(SOURCES ${statusnotifieritem_xml} statusnotifieritem_interface) qt5_add_dbus_adaptor(SOURCES org.freedesktop.Notifications.xml NotificationServer.hxx NotificationServer) set(TARGET liquidshell) add_executable(${TARGET} ${SOURCES} ${UI_FILES}) set_property(TARGET ${TARGET} PROPERTY CXX_STANDARD 11) target_link_libraries(${TARGET} Qt5::Core Qt5::Widgets Qt5::DBus Qt5::X11Extras KF5::WindowSystem KF5::WidgetsAddons KF5::ConfigWidgets KF5::ConfigCore KF5::KIOCore KF5::KIOWidgets KF5::IconThemes KF5::Notifications KF5::I18n KF5::NetworkManagerQt KF5::Service KF5::Solid KF5::BluezQt KF5::KCMUtils KF5::Crash KF5::DBusAddons KF5::ItemViews KF5::Archive KF5::NewStuff - PK::packagekitqt5 ) +if ( packagekitqt5_FOUND ) + target_link_libraries(${TARGET} PK::packagekitqt5) +endif() + install(TARGETS ${TARGET} ${INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.${TARGET}.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES liquidshell.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) ecm_install_icons(ICONS 48-apps-liquidshell.png DESTINATION ${ICON_INSTALL_DIR} THEME hicolor) diff --git a/SysTray.cxx b/SysTray.cxx index d3d02e8..63dd9b2 100644 --- a/SysTray.cxx +++ b/SysTray.cxx @@ -1,257 +1,264 @@ /* Copyright 2017 Martin Koller, kollix@aon.at This file is part of liquidshell. liquidshell is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liquidshell is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with liquidshell. If not, see . */ #include #include #include #include #include #include #include + +#ifdef WITH_PACKAGEKIT #include +#endif #include #include #include #include #include #include //-------------------------------------------------------------------------------- static const QLatin1String WATCHER_SERVICE("org.kde.StatusNotifierWatcher"); //-------------------------------------------------------------------------------- SysTray::SysTray(DesktopPanel *parent) : QFrame(parent) { qRegisterMetaType("KDbusImageStruct"); qRegisterMetaType("KDbusImageVector"); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); setFrameShape(QFrame::StyledPanel); connect(parent, &DesktopPanel::rowsChanged, this, &SysTray::fill); QHBoxLayout *hbox = new QHBoxLayout(this); hbox->setContentsMargins(QMargins(4, 0, 4, 0)); vbox = new QVBoxLayout; vbox->setContentsMargins(QMargins()); vbox->setSpacing(4); QFrame *separator = new QFrame; separator->setFrameStyle(QFrame::Plain); separator->setFrameShape(QFrame::VLine); appsVbox = new QVBoxLayout; appsVbox->setContentsMargins(QMargins()); appsVbox->setSpacing(4); hbox->addLayout(vbox); hbox->addWidget(separator); hbox->addLayout(appsVbox); if ( QDBusConnection::sessionBus().isConnected() ) { serviceName = QString("org.kde.StatusNotifierHost-%1").arg(QApplication::applicationPid()); QDBusConnection::sessionBus().registerService(serviceName); registerWatcher(); } fill(); } //-------------------------------------------------------------------------------- void SysTray::fill() { // delete all internal widgets QLayoutItem *child; while ( (child = vbox->takeAt(0)) ) { if ( child->layout() ) { while ( QLayoutItem *widgetItem = child->layout()->takeAt(0) ) delete widgetItem->widget(); } delete child; } const int MAX_ROWS = qobject_cast(parentWidget())->getRows(); QVector rowsLayout(MAX_ROWS); for (int i = 0; i < MAX_ROWS; i++) { rowsLayout[i] = new QHBoxLayout; rowsLayout[i]->setContentsMargins(QMargins()); rowsLayout[i]->setSpacing(4); vbox->addLayout(rowsLayout[i]); } if ( MAX_ROWS == 1 ) { rowsLayout[0]->addWidget(new NotificationServer(this), 0, Qt::AlignLeft); rowsLayout[0]->addWidget(new Network(this), 0, Qt::AlignLeft); rowsLayout[0]->addWidget(new DeviceNotifier(this), 0, Qt::AlignLeft); rowsLayout[0]->addWidget(new Battery(this), 0, Qt::AlignLeft); rowsLayout[0]->addWidget(new Bluetooth(this), 0, Qt::AlignLeft); +#ifdef WITH_PACKAGEKIT rowsLayout[0]->addWidget(new PkUpdates(this), 0, Qt::AlignLeft); +#endif } else if ( MAX_ROWS >= 2 ) { rowsLayout[0]->addWidget(new NotificationServer(this), 0, Qt::AlignLeft); rowsLayout[0]->addWidget(new DeviceNotifier(this), 0, Qt::AlignLeft); rowsLayout[0]->addWidget(new Bluetooth(this), 0, Qt::AlignLeft); rowsLayout[1]->addWidget(new Network(this), 0, Qt::AlignLeft); rowsLayout[1]->addWidget(new Battery(this), 0, Qt::AlignLeft); +#ifdef WITH_PACKAGEKIT rowsLayout[1]->addWidget(new PkUpdates(this), 0, Qt::AlignLeft); +#endif } // notifier items qDeleteAll(appsRows); appsRows.clear(); appsRows.resize(MAX_ROWS); for (int i = 0; i < MAX_ROWS; i++) { appsRows[i] = new QHBoxLayout; appsRows[i]->setContentsMargins(QMargins()); appsRows[i]->setSpacing(4); appsVbox->addLayout(appsRows[i]); } for (SysTrayNotifyItem *item : items) itemInitialized(item); } //-------------------------------------------------------------------------------- void SysTray::registerWatcher() { QDBusMessage msg = QDBusMessage::createMethodCall(WATCHER_SERVICE, "/StatusNotifierWatcher", "org.kde.StatusNotifierWatcher", "RegisterStatusNotifierHost"); msg << serviceName; QDBusConnection::sessionBus().send(msg); // get list of currently existing items msg = QDBusMessage::createMethodCall(WATCHER_SERVICE, "/StatusNotifierWatcher", "org.freedesktop.DBus.Properties", "Get"); msg << "org.kde.StatusNotifierWatcher" << "RegisteredStatusNotifierItems"; QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(msg); QDBusPendingCallWatcher *pendingCallWatcher = new QDBusPendingCallWatcher(call, this); connect(pendingCallWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *w) { w->deleteLater(); QDBusPendingReply reply = *w; QStringList items = reply.value().variant().toStringList(); for (const QString &item : items) itemRegistered(item); } ); // connect for new items QDBusConnection::sessionBus(). connect(WATCHER_SERVICE, "/StatusNotifierWatcher", "org.kde.StatusNotifierWatcher", "StatusNotifierItemRegistered", this, SLOT(itemRegistered(QString))); // connect for removed items QDBusConnection::sessionBus(). connect(WATCHER_SERVICE, "/StatusNotifierWatcher", "org.kde.StatusNotifierWatcher", "StatusNotifierItemUnregistered", this, SLOT(itemUnregistered(QString))); } //-------------------------------------------------------------------------------- void SysTray::itemRegistered(QString item) { //qDebug() << "itemRegistered" << item; int slash = item.indexOf('/'); if ( slash < 1 ) return; QString service = item.left(slash); QString path = item.mid(slash); // create item but insert it into the layout just when it was initialized // since it might be an invalid item which has no StatusNotifierItem path // and will delete itself on error SysTrayNotifyItem *sysItem = new SysTrayNotifyItem(this, service, path); sysItem->setObjectName(item); sysItem->setFixedSize(QSize(22, 22)); connect(sysItem, &SysTrayNotifyItem::initialized, this, &SysTray::itemInitialized); } //-------------------------------------------------------------------------------- void SysTray::itemInitialized(SysTrayNotifyItem *item) { // TODO count only visible items int lowestCount = 0; int lowestCountAt = 0; for (int i = 0; i < appsRows.count(); i++) { if ( i == 0 ) lowestCount = appsRows[i]->count(); else if ( appsRows[i]->count() < lowestCount ) { lowestCount = appsRows[i]->count(); lowestCountAt = i; } } appsRows[lowestCountAt]->addWidget(item, 0, Qt::AlignLeft); if ( !items.contains(item->objectName()) ) { items.insert(item->objectName(), item); disconnect(item, &SysTrayNotifyItem::initialized, this, &SysTray::itemInitialized); } } //-------------------------------------------------------------------------------- void SysTray::itemUnregistered(QString item) { //qDebug() << "itemUnregistered" << item; if ( items.contains(item) ) delete items.take(item); } //--------------------------------------------------------------------------------