kdeui: replace libdbusmenu-qt dependency with custom classes

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2023-05-27 20:42:29 +03:00
parent 3db230c695
commit 819cca1e41
19 changed files with 760 additions and 117 deletions

View file

@ -107,13 +107,6 @@ if(X11_FOUND)
endif(NOT HAVE_XSYNC AND NOT HAVE_XSCREENSAVER)
endif(X11_FOUND)
kde4_optional_find_package(DBusMenuQt)
set_package_properties(DBusMenuQt PROPERTIES
DESCRIPTION "Support for notification area menus via the DBusMenu protocol"
URL "https://osdn.net/projects/kde/"
TYPE RECOMMENDED
)
kde4_optional_find_package(MPV 0.23.0)
set_package_properties(MPV PROPERTIES
DESCRIPTION "A fork of mplayer2 and MPlayer"

View file

@ -15,7 +15,6 @@ include(CMakePushCheckState)
# definitions like _GNU_SOURCE that are needed on each platform.
set(CMAKE_REQUIRED_DEFINITIONS ${_KDE4_PLATFORM_DEFINITIONS})
kde4_bool_to_01(DBUSMENUQT_FOUND HAVE_DBUSMENUQT) # kdeui
kde4_bool_to_01(LibArchive_FOUND HAVE_LIBARCHIVE) # karchive
kde4_bool_to_01(BZIP2_FOUND HAVE_BZIP2) # karchive
kde4_bool_to_01(LIBLZMA_FOUND HAVE_LIBLZMA) # karchive

View file

@ -27,7 +27,6 @@ set(cmakeFilesDontInstall
# compatible).
set(cmakeFiles
cmake-modules-styleguide.txt
FindDBusMenuQt.cmake
FindDjVuLibre.cmake
FindEPub.cmake
FindExiv2.cmake

View file

@ -1,47 +0,0 @@
# Try to find the DBusMenuQt library, once done this will define:
#
# DBUSMENUQT_FOUND - system has DBusMenuQt
# DBUSMENUQT_INCLUDE_DIR - the DBusMenuQt include directory
# DBUSMENUQT_LIBRARIES - the libraries needed to use DBusMenuQt
# DBUSMENUQT_DEFINITIONS - compiler switches required for using DBusMenuQt
#
# Copyright (c) 2020 Ivailo Monev <xakepa10@gmail.com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
set(DBUSMENU_QT_NAMES dbusmenu-katie dbusmenu-qt dbusmenu-qtd)
find_package(PkgConfig REQUIRED)
foreach(name ${DBUSMENU_QT_NAMES})
if(NOT PC_DBUSMENUQT_FOUND)
pkg_check_modules(PC_DBUSMENUQT QUIET ${name})
set(DBUSMENUQT_INCLUDE_DIR ${PC_DBUSMENUQT_INCLUDE_DIRS})
set(DBUSMENUQT_LIBRARIES ${PC_DBUSMENUQT_LIBRARIES})
endif()
endforeach()
set(DBUSMENUQT_VERSION ${PC_DBUSMENUQT_VERSION})
set(DBUSMENUQT_DEFINITIONS ${PC_DBUSMENUQT_CFLAGS_OTHER})
if(NOT DBUSMENUQT_INCLUDE_DIR OR NOT DBUSMENUQT_LIBRARIES)
find_path(DBUSMENUQT_INCLUDE_DIR
NAMES dbusmenuexporter.h
PATH_SUFFIXES ${DBUSMENU_QT_NAMES}
HINTS $ENV{DBUSMENUQTDIR}/include
)
find_library(DBUSMENUQT_LIBRARIES
NAMES ${DBUSMENU_QT_NAMES}
HINTS $ENV{DBUSMENUQTDIR}/lib
)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DBusMenuQt
VERSION_VAR DBUSMENUQT_VERSION
REQUIRED_VARS DBUSMENUQT_LIBRARIES DBUSMENUQT_INCLUDE_DIR
)
mark_as_advanced(DBUSMENUQT_INCLUDE_DIR DBUSMENUQT_LIBRARIES)

View file

@ -38,9 +38,6 @@
/* Define to 1 if you have the XSync extension */
#cmakedefine HAVE_XSYNC 1
/* Define to 1 if you have DBusMenuQt */
#cmakedefine HAVE_DBUSMENUQT 1
/* Define to 1 if you have libarchive */
#cmakedefine HAVE_LIBARCHIVE 1

View file

@ -93,6 +93,8 @@ install(
KDateTimeWidget
KDateValidator
KDateWidget
KDBusMenuExporter
KDBusMenuImporter
KDesktopFile
KDialog
KDialogButtonBox

View file

@ -0,0 +1 @@
#include "../kdbusmenuexporter.h"

View file

@ -0,0 +1 @@
#include "../kdbusmenuimporter.h"

View file

@ -30,6 +30,7 @@
297 kdeui (KNotificationRestrictions)
299 kdeui (KNotification)
300 kdeui (KConfigDialogManager)
301 kdeui (KDBusMenu)
700 kutils (KSettings::Dialog)
701 kutils (KSettings::Dispatcher)
702 kutils (KPluginSelector)

View file

@ -154,6 +154,9 @@ set(kdeui_LIB_SRCS
notifications/knotification.cpp
notifications/knotificationmanager.cpp
notifications/knotificationrestrictions.cpp
notifications/kdbusmenuexporter.cpp
notifications/kdbusmenuimporter.cpp
notifications/kdbusmenu_p.cpp
paged/kpagedialog.cpp
paged/kpagemodel.cpp
paged/kpageview.cpp
@ -258,15 +261,6 @@ set(kdeui_LIB_SRCS
notifications/kstatusnotifieritemdbus_p.cpp
)
if(DBUSMENUQT_FOUND)
include_directories(${DBUSMENUQT_INCLUDE_DIR})
set(KDEUI_EXTRA_LIBS
${KDEUI_EXTRA_LIBS}
${DBUSMENUQT_LIBRARIES}
)
endif()
qt4_add_dbus_interface(kdeui_LIB_SRCS
notifications/org.kde.StatusNotifierWatcher.xml
statusnotifierwatcher_interface
@ -478,6 +472,8 @@ install(
notifications/ksystemtrayicon.h
notifications/knotification.h
notifications/knotificationrestrictions.h
notifications/kdbusmenuexporter.h
notifications/kdbusmenuimporter.h
paged/kpagedialog.h
paged/kpagemodel.h
paged/kpageview.h

View file

@ -0,0 +1,71 @@
/* This file is part of the KDE libraries
Copyright (C) 2023 smil3y <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kdbusmenu_p.h"
QDBusArgument& operator<<(QDBusArgument &argument, const KDBusMenu &kdbusmenu)
{
argument.beginStructure();
argument << kdbusmenu.icon;
argument << kdbusmenu.title;
argument << kdbusmenu.icondata;
argument.endStructure();
return argument;
}
const QDBusArgument& operator>>(const QDBusArgument &argument, KDBusMenu &kdbusmenu)
{
argument.beginStructure();
argument >> kdbusmenu.icon;
argument >> kdbusmenu.title;
argument >> kdbusmenu.icondata;
argument.endStructure();
return argument;
}
QDBusArgument& operator<<(QDBusArgument &argument, const KDBusMenuAction &kdbusmenuaction)
{
argument.beginStructure();
argument << kdbusmenuaction.id;
argument << kdbusmenuaction.text << kdbusmenuaction.icon;
argument << kdbusmenuaction.tooltip << kdbusmenuaction.statustip << kdbusmenuaction.whatsthis;
argument << kdbusmenuaction.separator << kdbusmenuaction.checkable << kdbusmenuaction.checked << kdbusmenuaction.enabled << kdbusmenuaction.visible;
argument << kdbusmenuaction.shortcuts;
argument << kdbusmenuaction.icondata;
argument << kdbusmenuaction.title;
argument << kdbusmenuaction.exclusive;
argument.endStructure();
return argument;
}
const QDBusArgument& operator>>(const QDBusArgument &argument, KDBusMenuAction &kdbusmenuaction)
{
argument.beginStructure();
argument >> kdbusmenuaction.id;
argument >> kdbusmenuaction.text >> kdbusmenuaction.icon;
argument >> kdbusmenuaction.tooltip >> kdbusmenuaction.statustip >> kdbusmenuaction.whatsthis;
argument >> kdbusmenuaction.separator >> kdbusmenuaction.checkable >> kdbusmenuaction.checked >> kdbusmenuaction.enabled >> kdbusmenuaction.visible;
argument >> kdbusmenuaction.shortcuts;
argument >> kdbusmenuaction.icondata;
argument >> kdbusmenuaction.title;
argument >> kdbusmenuaction.exclusive;
argument.endStructure();
return argument;
}

View file

@ -0,0 +1,76 @@
/* This file is part of the KDE libraries
Copyright (C) 2023 smil3y <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KDBUSMENU_H
#define KDBUSMENU_H
#include "kiconloader.h"
#include <QString>
#include <QStringList>
#include <QDBusArgument>
#include <QAction>
#include <QImageWriter>
static const int s_kdbusmenuiconsize = KIconLoader::SizeSmall;
static const QByteArray s_kdbusmenuiconformat = QImageWriter::defaultImageFormat();
// see kdebug.areas
static const int s_kdbusmenuarea = 301;
struct KDBusMenu
{
QString icon;
QString title;
QByteArray icondata;
};
Q_DECLARE_METATYPE(KDBusMenu);
QDBusArgument& operator<<(QDBusArgument &argument, const KDBusMenu &kdbusmenu);
const QDBusArgument& operator>>(const QDBusArgument &argument, KDBusMenu &kdbusmenu);
struct KDBusMenuAction
{
quint64 id;
QString text;
QString icon;
QString tooltip;
QString statustip;
QString whatsthis;
bool separator;
bool checkable;
bool checked;
bool enabled;
bool visible;
QStringList shortcuts;
QByteArray icondata;
bool title;
bool exclusive;
};
Q_DECLARE_METATYPE(KDBusMenuAction);
Q_DECLARE_METATYPE(QList<KDBusMenuAction>);
QDBusArgument& operator<<(QDBusArgument &argument, const KDBusMenuAction &kdbusmenuaction);
const QDBusArgument& operator>>(const QDBusArgument &argument, KDBusMenuAction &kdbusmenuaction);
static quint64 kDBusMenuActionID(const QAction *action)
{
return quint64(quintptr(action));
}
#endif // KDBUSMENU_H

View file

@ -0,0 +1,261 @@
/* This file is part of the KDE libraries
Copyright (C) 2023 smil3y <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kdbusmenuexporter.h"
#include "kdebug.h"
#include "kdbusmenu_p.h"
#include <QDBusAbstractAdaptor>
#include <QPointer>
#include <QBuffer>
#include <QToolButton>
#include <QWidgetAction>
#include <qdbusmetatype.h>
class KDBusMenuAdaptor: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.DBusMenu")
public:
KDBusMenuAdaptor(KDBusMenuExporter *exporter, QMenu* menu);
public Q_SLOTS:
QString status() const;
void setStatus(const QString &status);
KDBusMenu menu() const;
QList<KDBusMenuAction> actions() const;
bool triggerAction(quint64 actionid) const;
private:
KDBusMenuExporter* m_exporter;
QString m_status;
QPointer<QMenu> m_menu;
};
KDBusMenuAdaptor::KDBusMenuAdaptor(KDBusMenuExporter *exporter, QMenu* menu)
: QDBusAbstractAdaptor(exporter),
m_exporter(exporter),
m_status(QString::fromLatin1("normal")),
m_menu(menu)
{
qDBusRegisterMetaType<KDBusMenu>();
qDBusRegisterMetaType<KDBusMenuAction>();
qDBusRegisterMetaType<QList<KDBusMenuAction>>();
}
QString KDBusMenuAdaptor::status() const
{
return m_status;
}
void KDBusMenuAdaptor::setStatus(const QString &status)
{
kDebug(s_kdbusmenuarea) << "Changing status to" << status;
if (status != QLatin1String("normal") && status != QLatin1String("notice")) {
kWarning(s_kdbusmenuarea) << "Invalid status" << status;
}
m_status = status;
}
KDBusMenu KDBusMenuAdaptor::menu() const
{
KDBusMenu result;
if (m_menu.isNull()) {
kWarning(s_kdbusmenuarea) << "Menu is null";
return result;
}
// NOTE: KStatusNotifierItem adds actions to the menu when aboutToShow is emitted
const bool menusignaled = QMetaObject::invokeMethod(m_menu.data(), "aboutToShow", Qt::DirectConnection);
if (!menusignaled) {
kWarning(s_kdbusmenuarea) << "Could not invoke menu aboutToShow() signal";
}
const QIcon menuicon = m_menu->icon();
result.icon = menuicon.name();
result.title = m_menu->title();
if (result.icon.isEmpty()) {
QBuffer iconbuffer;
QPixmap iconpixmap = menuicon.pixmap(s_kdbusmenuiconsize);
if (iconpixmap.isNull()) {
kWarning(s_kdbusmenuarea) << "Menu icon name is empty and icon pixmap is null";
} else {
const bool savedicon = iconpixmap.save(&iconbuffer, s_kdbusmenuiconformat);
if (!savedicon) {
kWarning(s_kdbusmenuarea) << "Could not save menu icon pixmap";
} else {
result.icondata = iconbuffer.data();
}
}
}
return result;
}
QList<KDBusMenuAction> KDBusMenuAdaptor::actions() const
{
QList<KDBusMenuAction> result;
if (m_menu.isNull()) {
kWarning(s_kdbusmenuarea) << "Menu is null";
return result;
}
foreach (QAction* action, m_menu->actions()) {
const quint64 actionid = kDBusMenuActionID(action);
kDebug(s_kdbusmenuarea) << "Exporting action" << actionid;
const QMenu* actionmenu = action->menu();
if (actionmenu) {
kWarning(s_kdbusmenuarea) << "Menu actions are not supported";
continue;
}
KDBusMenuAction actionproperties;
// see kdeui/widgets/kmenu.cpp
actionproperties.title = (action->objectName() == QLatin1String("kmenu_title"));
if (actionproperties.title) {
const QWidgetAction *actionwidget = qobject_cast<QWidgetAction*>(action);
if (!actionwidget) {
kWarning(s_kdbusmenuarea) << "Title has no widget" << actionid;
} else {
const QToolButton *actionbutton = qobject_cast<QToolButton*>(actionwidget->defaultWidget());
if (!actionbutton) {
kWarning(s_kdbusmenuarea) << "Title has no button" << actionid;
} else {
action = actionbutton->defaultAction();
}
}
}
actionproperties.id = actionid;
actionproperties.text = action->text();
actionproperties.icon = m_exporter->iconNameForAction(action);
actionproperties.tooltip = action->toolTip();
actionproperties.statustip = action->statusTip();
actionproperties.whatsthis = action->whatsThis();
actionproperties.separator = action->isSeparator();
actionproperties.checkable = action->isCheckable();
actionproperties.checked = action->isChecked();
actionproperties.enabled = action->isEnabled();
actionproperties.visible = action->isVisible();
QStringList shortcuts;
foreach (const QKeySequence &keysequence, action->shortcuts()) {
shortcuts.append(keysequence.toString());
}
actionproperties.shortcuts = shortcuts;
if (actionproperties.icon.isEmpty()) {
QBuffer iconbuffer;
QPixmap iconpixmap = action->icon().pixmap(s_kdbusmenuiconsize);
if (iconpixmap.isNull()) {
kWarning(s_kdbusmenuarea) << "Icon name is empty and icon pixmap is null" << actionid;
} else {
const bool savedicon = iconpixmap.save(&iconbuffer, s_kdbusmenuiconformat);
if (!savedicon) {
kWarning(s_kdbusmenuarea) << "Could not save icon pixmap" << actionid;
} else {
actionproperties.icondata = iconbuffer.data();
}
}
}
const QActionGroup* actiongroup = action->actionGroup();
actionproperties.exclusive = (actiongroup && actiongroup->isExclusive());
result.append(actionproperties);
}
return result;
}
bool KDBusMenuAdaptor::triggerAction(quint64 actionid) const
{
kDebug(s_kdbusmenuarea) << "Triggering action" << actionid;
if (m_menu.isNull()) {
kWarning(s_kdbusmenuarea) << "Menu is null";
return false;
}
foreach (QAction* action, m_menu->actions()) {
const quint64 itactionid = kDBusMenuActionID(action);
if (itactionid == actionid) {
return QMetaObject::invokeMethod(action, "triggered");
}
}
kWarning(s_kdbusmenuarea) << "Could not find action for" << actionid;
return false;
}
class KDBusMenuExporterPrivate
{
public:
KDBusMenuExporterPrivate();
KDBusMenuAdaptor* adaptor;
QString objectpath;
QString connectionname;
};
KDBusMenuExporterPrivate::KDBusMenuExporterPrivate()
: adaptor(nullptr)
{
}
KDBusMenuExporter::KDBusMenuExporter(const QString &objectpath, QMenu *menu, const QDBusConnection &connection)
: QObject(menu),
d(new KDBusMenuExporterPrivate())
{
kDebug(s_kdbusmenuarea) << "Exporting menu" << objectpath;
d->adaptor = new KDBusMenuAdaptor(this, menu);
d->objectpath = objectpath;
d->connectionname = connection.name();
QDBusConnection dbusconnection(connection.name());
dbusconnection.registerObject(objectpath, this);
}
KDBusMenuExporter::~KDBusMenuExporter()
{
QDBusConnection dbusconnection(d->connectionname);
dbusconnection.unregisterObject(d->objectpath);
delete d;
}
QString KDBusMenuExporter::status() const
{
return d->adaptor->status();
}
void KDBusMenuExporter::setStatus(const QString &status)
{
d->adaptor->setStatus(status);
}
void KDBusMenuExporter::activateAction(QAction *action)
{
const quint64 actionid = kDBusMenuActionID(action);
d->adaptor->triggerAction(actionid);
}
QString KDBusMenuExporter::iconNameForAction(QAction *action)
{
if (!action) {
return QString();
}
const QIcon icon = action->icon();
if (action->isIconVisibleInMenu() && !icon.isNull()) {
return icon.name();
}
return QString();
}
#include "kdbusmenuexporter.moc"

View file

@ -0,0 +1,53 @@
/* This file is part of the KDE libraries
Copyright (C) 2023 smil3y <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KDBUSMENUEXPORTER_H
#define KDBUSMENUEXPORTER_H
#include "kdeui_export.h"
#include <QDBusConnection>
#include <QMenu>
#include <QAction>
class KDBusMenuExporterPrivate;
class KDEUI_EXPORT KDBusMenuExporter : public QObject
{
Q_OBJECT
public:
KDBusMenuExporter(const QString &objectpath, QMenu *menu, const QDBusConnection &connection = QDBusConnection::sessionBus());
virtual ~KDBusMenuExporter();
QString status() const;
void setStatus(const QString &status);
void activateAction(QAction *action);
protected:
virtual QString iconNameForAction(QAction *action);
private:
KDBusMenuExporterPrivate *d;
Q_DISABLE_COPY(KDBusMenuExporter);
friend class KDBusMenuAdaptor;
};
#endif // KDBUSMENUEXPORTER_H

View file

@ -0,0 +1,173 @@
/* This file is part of the KDE libraries
Copyright (C) 2023 smil3y <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kdbusmenuimporter.h"
#include "kicon.h"
#include "kmenu.h"
#include "kdebug.h"
#include "kdbusmenu_p.h"
#include <QDBusInterface>
#include <QDBusReply>
#include <qdbusmetatype.h>
class KDBusMenuImporterPrivate
{
public:
KDBusMenuImporterPrivate();
QDBusInterface* interface;
QMenu* menu;
};
KDBusMenuImporterPrivate::KDBusMenuImporterPrivate()
: interface(nullptr),
menu(nullptr)
{
}
KDBusMenuImporter::KDBusMenuImporter(const QString &service, const QString &path, QObject *parent)
: QObject(parent),
d(new KDBusMenuImporterPrivate())
{
kDebug(s_kdbusmenuarea) << "Importing menu" << service << path;
qDBusRegisterMetaType<KDBusMenu>();
qDBusRegisterMetaType<KDBusMenuAction>();
qDBusRegisterMetaType<QList<KDBusMenuAction>>();
QDBusConnection dbusconnection = QDBusConnection::sessionBus();
d->interface = new QDBusInterface(service, path, QString::fromLatin1("org.kde.DBusMenu"), dbusconnection, this);
}
KDBusMenuImporter::~KDBusMenuImporter()
{
delete d;
}
QMenu* KDBusMenuImporter::menu() const
{
return d->menu;
}
void KDBusMenuImporter::updateMenu()
{
kDebug(s_kdbusmenuarea) << "Updating menu";
if (d->menu) {
delete d->menu;
d->menu = nullptr;
}
d->menu = KDBusMenuImporter::createMenu(nullptr);
QDBusReply<KDBusMenu> menureply = d->interface->call("menu");
if (!menureply.isValid()) {
kWarning(s_kdbusmenuarea) << "Invalid menu reply" << menureply.error();
return;
}
const KDBusMenu menuproperties = menureply.value();
d->menu->setTitle(menuproperties.title);
QIcon menuicon = KDBusMenuImporter::iconForName(menuproperties.icon);
if (menuicon.isNull() && !menuproperties.icondata.isEmpty()) {
QPixmap menupixmap;
const bool pixmaploaded = menupixmap.loadFromData(menuproperties.icondata, s_kdbusmenuiconformat);
if (!pixmaploaded) {
kWarning(s_kdbusmenuarea) << "Could not load menu icon pixmap";
} else {
menuicon = QIcon(menupixmap);
}
}
d->menu->setIcon(menuicon);
QDBusReply<QList<KDBusMenuAction>> actionsreply = d->interface->call("actions");
if (!actionsreply.isValid()) {
kWarning(s_kdbusmenuarea) << "Invalid actions reply" << actionsreply.error();
return;
}
foreach (const KDBusMenuAction &actionproperties, actionsreply.value()) {
const quint64 actionid = actionproperties.id;
kDebug(s_kdbusmenuarea) << "Importing action" << actionid;
QIcon actionicon = KDBusMenuImporter::iconForName(actionproperties.icon);
if (actionicon.isNull() && !actionproperties.icondata.isEmpty()) {
QPixmap actionpixmap;
const bool pixmaploaded = actionpixmap.loadFromData(actionproperties.icondata, s_kdbusmenuiconformat);
if (!pixmaploaded) {
kWarning(s_kdbusmenuarea) << "Could not load icon pixmap" << actionid;
} else {
actionicon = QIcon(actionpixmap);
}
}
QAction* action = nullptr;
if (actionproperties.title) {
// see kdeui/widgets/kmenu.cpp
action = KMenu::titleAction(actionicon, actionproperties.text, d->menu);
} else {
action = new QAction(d->menu);
action->setText(actionproperties.text);
action->setIcon(actionicon);
action->setToolTip(actionproperties.tooltip);
action->setStatusTip(actionproperties.statustip);
action->setWhatsThis(actionproperties.whatsthis);
action->setSeparator(actionproperties.separator);
action->setCheckable(actionproperties.checkable);
action->setChecked(actionproperties.checked);
action->setEnabled(actionproperties.enabled);
action->setVisible(actionproperties.visible);
QList<QKeySequence> shortcuts;
foreach (const QString &keysequence, actionproperties.shortcuts) {
shortcuts.append(QKeySequence::fromString(keysequence));
}
action->setShortcuts(shortcuts);
if (actionproperties.exclusive) {
QActionGroup *actiongroup = new QActionGroup(action);
actiongroup->addAction(action);
}
}
action->setData(QVariant(actionid));
connect(action, SIGNAL(triggered()), this, SLOT(slotActionTriggered()));
d->menu->addAction(action);
}
emit menuUpdated();
}
QMenu* KDBusMenuImporter::createMenu(QWidget *parent)
{
return new QMenu(parent);
}
QIcon KDBusMenuImporter::iconForName(const QString &name)
{
return QIcon::fromTheme(name);
}
void KDBusMenuImporter::slotActionTriggered()
{
QAction* action = qobject_cast<QAction*>(sender());
const quint64 actionid = action->data().toULongLong();
kDebug(s_kdbusmenuarea) << "Action triggered" << actionid;
QDBusReply<bool> reply = d->interface->call("triggerAction", actionid);
if (!reply.isValid()) {
kWarning(s_kdbusmenuarea) << "Invalid action trigger reply" << reply.error();
return;
}
if (reply.value() != true) {
kWarning(s_kdbusmenuarea) << "Could not trigger action" << actionid;
return;
}
emit actionActivationRequested(action);
}

View file

@ -0,0 +1,60 @@
/* This file is part of the KDE libraries
Copyright (C) 2023 smil3y <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KDBUSMENUIMPORTER_H
#define KDBUSMENUIMPORTER_H
#include "kdeui_export.h"
#include <QMenu>
#include <QIcon>
#include <QWidget>
#include <QAction>
class KDBusMenuImporterPrivate;
class KDEUI_EXPORT KDBusMenuImporter : public QObject
{
Q_OBJECT
public:
KDBusMenuImporter(const QString &service, const QString &path, QObject *parent = 0);
virtual ~KDBusMenuImporter();
QMenu* menu() const;
public Q_SLOTS:
void updateMenu();
Q_SIGNALS:
void menuUpdated();
void actionActivationRequested(QAction *action);
protected:
virtual QMenu *createMenu(QWidget *parent);
virtual QIcon iconForName(const QString &name);
private Q_SLOTS:
void slotActionTriggered();
private:
KDBusMenuImporterPrivate *d;
Q_DISABLE_COPY(KDBusMenuImporter);
};
#endif // KDBUSMENUIMPORTER_H

View file

@ -40,6 +40,7 @@
#include <kactioncollection.h>
#include <kstandarddirs.h>
#include <kglobal.h>
#include <kdbusmenuexporter.h>
#include <netinet/in.h>
@ -47,10 +48,6 @@
static const QString s_statusNotifierWatcherServiceName("org.kde.StatusNotifierWatcher");
#ifdef HAVE_DBUSMENUQT
# include <dbusmenuexporter.h>
#endif
KStatusNotifierItem::KStatusNotifierItem(QObject *parent)
: QObject(parent),
d(new KStatusNotifierItemPrivate(this))
@ -373,23 +370,17 @@ void KStatusNotifierItem::setContextMenu(KMenu *menu)
if (d->systemTrayIcon) {
d->systemTrayIcon->setContextMenu(menu);
} else if (d->menu != menu) {
#ifdef HAVE_DBUSMENUQT
if (getenv("KSNI_NO_DBUSMENU")) {
#else
d->setLegacySystemTrayEnabled(true);
#endif
// This is a hack to make it possible to disable DBusMenu in an
// application. The string "/NO_DBUSMENU" must be the same as in
// DBusSystemTrayWidget::findDBusMenuInterface() in the Plasma
// systemtray applet.
d->menuObjectPath = "/NO_DBUSMENU";
menu->installEventFilter(this);
#ifdef HAVE_DBUSMENUQT
} else {
d->menuObjectPath = "/MenuBar";
new DBusMenuExporter(d->menuObjectPath, menu, d->statusNotifierItemDBus->dbusConnection());
new KDBusMenuExporter(d->menuObjectPath, menu, d->statusNotifierItemDBus->dbusConnection());
}
#endif
connect(menu, SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
}

View file

@ -42,28 +42,24 @@
static const char KMENU_TITLE[] = "kmenu_title";
class KMenu::KMenuPrivate
: public QObject
/**
* @internal
*
* The event filter which is installed on the widget prevent clicks (what would
* change down and focus properties on the title) on the title of the menu.
*
* @author Rafael Fernández López <ereslibre@kde.org>
*/
class KMenuToolButton : public QToolButton
{
Q_OBJECT
public:
KMenuPrivate (KMenu *_parent);
~KMenuPrivate ();
KMenuToolButton(QWidget *parent) : QToolButton(parent)
{
// prevent clicks on the title of the menu
installEventFilter(this);
}
void resetKeyboardVars(bool noMatches = false);
void actionHovered(QAction* action);
void showCtxMenu(const QPoint &pos);
void skipTitles(QKeyEvent *event);
/**
* @internal
*
* This event filter which is installed
* on the title of the menu, which is a QToolButton. This will
* prevent clicks (what would change down and focus properties on
* the title) on the title of the menu.
*
* @author Rafael Fernández López <ereslibre@kde.org>
*/
bool eventFilter(QObject *object, QEvent *event)
{
Q_UNUSED(object);
@ -77,6 +73,19 @@ public:
event->accept();
return true;
}
};
class KMenu::KMenuPrivate
: public QObject
{
public:
KMenuPrivate (KMenu *_parent);
~KMenuPrivate ();
void resetKeyboardVars(bool noMatches = false);
void actionHovered(QAction* action);
void showCtxMenu(const QPoint &pos);
void skipTitles(QKeyEvent *event);
KMenu *parent;
@ -172,22 +181,7 @@ QAction* KMenu::addTitle(const QString &text, QAction* before)
QAction* KMenu::addTitle(const QIcon &icon, const QString &text, QAction* before)
{
QAction *buttonAction = new QAction(this);
QFont font = buttonAction->font();
font.setBold(true);
buttonAction->setFont(font);
buttonAction->setText(text);
buttonAction->setIcon(icon);
QWidgetAction *action = new QWidgetAction(this);
action->setObjectName(KMENU_TITLE);
QToolButton *titleButton = new QToolButton(this);
titleButton->installEventFilter(d); // prevent clicks on the title of the menu
titleButton->setDefaultAction(buttonAction);
titleButton->setDown(true); // prevent hover style changes in some styles
titleButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
action->setDefaultWidget(titleButton);
QAction *action = KMenu::titleAction(icon, text, this);
insertAction(before, action);
return action;
}
@ -555,6 +549,25 @@ QAction * KMenu::contextMenuFocusAction( )
return 0L;
}
QAction* KMenu::titleAction(const QIcon &icon, const QString &text, QWidget* parent)
{
QAction *buttonAction = new QAction(parent);
QFont font = buttonAction->font();
font.setBold(true);
buttonAction->setFont(font);
buttonAction->setText(text);
buttonAction->setIcon(icon);
QWidgetAction *action = new QWidgetAction(parent);
action->setObjectName(KMENU_TITLE);
KMenuToolButton *titleButton = new KMenuToolButton(parent);
titleButton->setDefaultAction(buttonAction);
titleButton->setDown(true); // prevent hover style changes in some styles
titleButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
action->setDefaultWidget(titleButton);
return action;
}
void KMenu::contextMenuEvent(QContextMenuEvent* e)
{
if (d->ctxMenu)
@ -598,9 +611,6 @@ void KMenu::hideEvent(QHideEvent *e)
*/
KMenuContext::KMenuContext( )
: m_menu(0L)
, m_action(0L)
@ -620,3 +630,4 @@ KMenuContext::KMenuContext(QPointer<KMenu> menu,QPointer<QAction> action)
}
#include "moc_kmenu.cpp"
#include "kmenu.moc"

View file

@ -120,6 +120,11 @@ public:
*/
static QAction* contextMenuFocusAction();
/**
* returns QAction for use as title
*/
static QAction* titleAction(const QIcon &icon, const QString &text, QWidget* parent);
/**
* Return the state of the mouse buttons when the last menuitem was activated.
*/