mirror of https://github.com/cutefishos/statusbar
Integrated dbusmenuqt
parent
5273300134
commit
38ec91fe08
@ -0,0 +1,49 @@
|
|||||||
|
<interface name="com.canonical.dbusmenu">
|
||||||
|
<property name="Version" type="u" access="read"/>
|
||||||
|
<property name="Status" type="s" access="read"/>
|
||||||
|
<signal name="ItemsPropertiesUpdated">
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="DBusMenuItemList"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="DBusMenuItemKeysList"/>
|
||||||
|
<arg type="a(ia{sv})" direction="out"/>
|
||||||
|
<arg type="a(ias)" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="LayoutUpdated">
|
||||||
|
<arg name="revision" type="u" direction="out"/>
|
||||||
|
<arg name="parentId" type="i" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="ItemActivationRequested">
|
||||||
|
<arg name="id" type="i" direction="out"/>
|
||||||
|
<arg name="timeStamp" type="u" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<method name="Event">
|
||||||
|
<arg name="id" type="i" direction="in"/>
|
||||||
|
<arg name="eventId" type="s" direction="in"/>
|
||||||
|
<arg name="data" type="v" direction="in"/>
|
||||||
|
<arg name="timestamp" type="u" direction="in"/>
|
||||||
|
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||||
|
</method>
|
||||||
|
<method name="GetProperty">
|
||||||
|
<arg type="v" direction="out"/>
|
||||||
|
<arg name="id" type="i" direction="in"/>
|
||||||
|
<arg name="property" type="s" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<method name="GetLayout">
|
||||||
|
<arg type="u" direction="out"/>
|
||||||
|
<arg name="parentId" type="i" direction="in"/>
|
||||||
|
<arg name="recursionDepth" type="i" direction="in"/>
|
||||||
|
<arg name="propertyNames" type="as" direction="in"/>
|
||||||
|
<arg name="item" type="(ia{sv}av)" direction="out"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="DBusMenuLayoutItem"/>
|
||||||
|
</method>
|
||||||
|
<method name="GetGroupProperties">
|
||||||
|
<arg type="a(ia{sv})" direction="out"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="DBusMenuItemList"/>
|
||||||
|
<arg name="ids" type="ai" direction="in"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QList<int>"/>
|
||||||
|
<arg name="propertyNames" type="as" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<method name="AboutToShow">
|
||||||
|
<arg type="b" direction="out"/>
|
||||||
|
<arg name="id" type="i" direction="in"/>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
@ -0,0 +1,549 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 "dbusmenuimporter.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusReply>
|
||||||
|
#include <QDBusVariant>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QTime>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QWidgetAction>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "dbusmenushortcut_p.h"
|
||||||
|
#include "dbusmenutypes_p.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
// Generated
|
||||||
|
#include "dbusmenu_interface.h"
|
||||||
|
|
||||||
|
//#define BENCHMARK
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
static QTime sChrono;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DMRETURN_IF_FAIL(cond) \
|
||||||
|
if (!(cond)) { \
|
||||||
|
qCWarning() << "Condition failed: " #cond; \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *DBUSMENU_PROPERTY_ID = "_dbusmenu_id";
|
||||||
|
static const char *DBUSMENU_PROPERTY_ICON_NAME = "_dbusmenu_icon_name";
|
||||||
|
static const char *DBUSMENU_PROPERTY_ICON_DATA_HASH = "_dbusmenu_icon_data_hash";
|
||||||
|
|
||||||
|
static QAction *createKdeTitle(QAction *action, QWidget *parent)
|
||||||
|
{
|
||||||
|
QToolButton *titleWidget = new QToolButton(nullptr);
|
||||||
|
QFont font = titleWidget->font();
|
||||||
|
font.setBold(true);
|
||||||
|
titleWidget->setFont(font);
|
||||||
|
titleWidget->setIcon(action->icon());
|
||||||
|
titleWidget->setText(action->text());
|
||||||
|
titleWidget->setDown(true);
|
||||||
|
titleWidget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||||
|
|
||||||
|
QWidgetAction *titleAction = new QWidgetAction(parent);
|
||||||
|
titleAction->setDefaultWidget(titleWidget);
|
||||||
|
return titleAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DBusMenuImporterPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DBusMenuImporter *q;
|
||||||
|
|
||||||
|
DBusMenuInterface *m_interface;
|
||||||
|
QMenu *m_menu;
|
||||||
|
using ActionForId = QMap<int, QAction *>;
|
||||||
|
ActionForId m_actionForId;
|
||||||
|
QTimer *m_pendingLayoutUpdateTimer;
|
||||||
|
|
||||||
|
QSet<int> m_idsRefreshedByAboutToShow;
|
||||||
|
QSet<int> m_pendingLayoutUpdates;
|
||||||
|
|
||||||
|
QDBusPendingCallWatcher *refresh(int id)
|
||||||
|
{
|
||||||
|
auto call = m_interface->GetLayout(id, 1, QStringList());
|
||||||
|
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, q);
|
||||||
|
watcher->setProperty(DBUSMENU_PROPERTY_ID, id);
|
||||||
|
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, q, &DBusMenuImporter::slotGetLayoutFinished);
|
||||||
|
|
||||||
|
return watcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *createMenu(QWidget *parent)
|
||||||
|
{
|
||||||
|
QMenu *menu = q->createMenu(parent);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init all the immutable action properties here
|
||||||
|
* TODO: Document immutable properties?
|
||||||
|
*
|
||||||
|
* Note: we remove properties we handle from the map (using QMap::take()
|
||||||
|
* instead of QMap::value()) to avoid warnings about these properties in
|
||||||
|
* updateAction()
|
||||||
|
*/
|
||||||
|
QAction *createAction(int id, const QVariantMap &_map, QWidget *parent)
|
||||||
|
{
|
||||||
|
QVariantMap map = _map;
|
||||||
|
QAction *action = new QAction(parent);
|
||||||
|
action->setProperty(DBUSMENU_PROPERTY_ID, id);
|
||||||
|
|
||||||
|
QString type = map.take(QStringLiteral("type")).toString();
|
||||||
|
if (type == QLatin1String("separator")) {
|
||||||
|
action->setSeparator(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.take(QStringLiteral("children-display")).toString() == QLatin1String("submenu")) {
|
||||||
|
QMenu *menu = createMenu(parent);
|
||||||
|
action->setMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toggleType = map.take(QStringLiteral("toggle-type")).toString();
|
||||||
|
if (!toggleType.isEmpty()) {
|
||||||
|
action->setCheckable(true);
|
||||||
|
if (toggleType == QLatin1String("radio")) {
|
||||||
|
QActionGroup *group = new QActionGroup(action);
|
||||||
|
group->addAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isKdeTitle = map.take(QStringLiteral("x-kde-title")).toBool();
|
||||||
|
updateAction(action, map, map.keys());
|
||||||
|
|
||||||
|
if (isKdeTitle) {
|
||||||
|
action = createKdeTitle(action, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update mutable properties of an action. A property may be listed in
|
||||||
|
* requestedProperties but not in map, this means we should use the default value
|
||||||
|
* for this property.
|
||||||
|
*
|
||||||
|
* @param action the action to update
|
||||||
|
* @param map holds the property values
|
||||||
|
* @param requestedProperties which properties has been requested
|
||||||
|
*/
|
||||||
|
void updateAction(QAction *action, const QVariantMap &map, const QStringList &requestedProperties)
|
||||||
|
{
|
||||||
|
Q_FOREACH (const QString &key, requestedProperties) {
|
||||||
|
updateActionProperty(action, key, map.value(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionProperty(QAction *action, const QString &key, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (key == QLatin1String("label")) {
|
||||||
|
updateActionLabel(action, value);
|
||||||
|
} else if (key == QLatin1String("enabled")) {
|
||||||
|
updateActionEnabled(action, value);
|
||||||
|
} else if (key == QLatin1String("toggle-state")) {
|
||||||
|
updateActionChecked(action, value);
|
||||||
|
} else if (key == QLatin1String("icon-name")) {
|
||||||
|
updateActionIconByName(action, value);
|
||||||
|
} else if (key == QLatin1String("icon-data")) {
|
||||||
|
updateActionIconByData(action, value);
|
||||||
|
} else if (key == QLatin1String("visible")) {
|
||||||
|
updateActionVisible(action, value);
|
||||||
|
} else if (key == QLatin1String("shortcut")) {
|
||||||
|
updateActionShortcut(action, value);
|
||||||
|
} else {
|
||||||
|
qDebug() << "Unhandled property update" << key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionLabel(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
QString text = swapMnemonicChar(value.toString(), '_', '&');
|
||||||
|
action->setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionEnabled(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
action->setEnabled(value.isValid() ? value.toBool() : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionChecked(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (action->isCheckable() && value.isValid()) {
|
||||||
|
action->setChecked(value.toInt() == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionIconByName(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
const QString iconName = value.toString();
|
||||||
|
const QString previous = action->property(DBUSMENU_PROPERTY_ICON_NAME).toString();
|
||||||
|
if (previous == iconName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setProperty(DBUSMENU_PROPERTY_ICON_NAME, iconName);
|
||||||
|
if (iconName.isEmpty()) {
|
||||||
|
action->setIcon(QIcon());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setIcon(q->iconForName(iconName));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionIconByData(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
const QByteArray data = value.toByteArray();
|
||||||
|
uint dataHash = qHash(data);
|
||||||
|
uint previousDataHash = action->property(DBUSMENU_PROPERTY_ICON_DATA_HASH).toUInt();
|
||||||
|
if (previousDataHash == dataHash) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setProperty(DBUSMENU_PROPERTY_ICON_DATA_HASH, dataHash);
|
||||||
|
QPixmap pix;
|
||||||
|
if (!pix.loadFromData(data)) {
|
||||||
|
qDebug() << "Failed to decode icon-data property for action" << action->text();
|
||||||
|
action->setIcon(QIcon());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setIcon(QIcon(pix));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionVisible(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
action->setVisible(value.isValid() ? value.toBool() : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionShortcut(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
QDBusArgument arg = value.value<QDBusArgument>();
|
||||||
|
DBusMenuShortcut dmShortcut;
|
||||||
|
arg >> dmShortcut;
|
||||||
|
QKeySequence keySequence = dmShortcut.toKeySequence();
|
||||||
|
action->setShortcut(keySequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *menuForId(int id) const
|
||||||
|
{
|
||||||
|
if (id == 0) {
|
||||||
|
return q->menu();
|
||||||
|
}
|
||||||
|
QAction *action = m_actionForId.value(id);
|
||||||
|
if (!action) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return action->menu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList);
|
||||||
|
|
||||||
|
void sendEvent(int id, const QString &eventId)
|
||||||
|
{
|
||||||
|
m_interface->Event(id, eventId, QDBusVariant(QString()), 0u);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBusMenuImporter::DBusMenuImporter(const QString &service, const QString &path, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, d(new DBusMenuImporterPrivate)
|
||||||
|
{
|
||||||
|
DBusMenuTypes_register();
|
||||||
|
|
||||||
|
d->q = this;
|
||||||
|
d->m_interface = new DBusMenuInterface(service, path, QDBusConnection::sessionBus(), this);
|
||||||
|
d->m_menu = nullptr;
|
||||||
|
|
||||||
|
d->m_pendingLayoutUpdateTimer = new QTimer(this);
|
||||||
|
d->m_pendingLayoutUpdateTimer->setSingleShot(true);
|
||||||
|
connect(d->m_pendingLayoutUpdateTimer, &QTimer::timeout, this, &DBusMenuImporter::processPendingLayoutUpdates);
|
||||||
|
|
||||||
|
connect(d->m_interface, &DBusMenuInterface::LayoutUpdated, this, &DBusMenuImporter::slotLayoutUpdated);
|
||||||
|
connect(d->m_interface, &DBusMenuInterface::ItemActivationRequested, this, &DBusMenuImporter::slotItemActivationRequested);
|
||||||
|
connect(d->m_interface,
|
||||||
|
&DBusMenuInterface::ItemsPropertiesUpdated,
|
||||||
|
this,
|
||||||
|
[this](const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList) {
|
||||||
|
d->slotItemsPropertiesUpdated(updatedList, removedList);
|
||||||
|
});
|
||||||
|
|
||||||
|
d->refresh(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuImporter::~DBusMenuImporter()
|
||||||
|
{
|
||||||
|
// Do not use "delete d->m_menu": even if we are being deleted we should
|
||||||
|
// leave enough time for the menu to finish what it was doing, for example
|
||||||
|
// if it was being displayed.
|
||||||
|
d->m_menu->deleteLater();
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotLayoutUpdated(uint revision, int parentId)
|
||||||
|
{
|
||||||
|
Q_UNUSED(revision)
|
||||||
|
if (d->m_idsRefreshedByAboutToShow.remove(parentId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->m_pendingLayoutUpdates << parentId;
|
||||||
|
if (!d->m_pendingLayoutUpdateTimer->isActive()) {
|
||||||
|
d->m_pendingLayoutUpdateTimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::processPendingLayoutUpdates()
|
||||||
|
{
|
||||||
|
QSet<int> ids = d->m_pendingLayoutUpdates;
|
||||||
|
d->m_pendingLayoutUpdates.clear();
|
||||||
|
Q_FOREACH (int id, ids) {
|
||||||
|
d->refresh(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *DBusMenuImporter::menu() const
|
||||||
|
{
|
||||||
|
if (!d->m_menu) {
|
||||||
|
d->m_menu = d->createMenu(nullptr);
|
||||||
|
}
|
||||||
|
return d->m_menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterPrivate::slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList)
|
||||||
|
{
|
||||||
|
Q_FOREACH (const DBusMenuItem &item, updatedList) {
|
||||||
|
QAction *action = m_actionForId.value(item.id);
|
||||||
|
if (!action) {
|
||||||
|
// We don't know this action. It probably is in a menu we haven't fetched yet.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap::ConstIterator it = item.properties.constBegin(), end = item.properties.constEnd();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
updateActionProperty(action, it.key(), it.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_FOREACH (const DBusMenuItemKeys &item, removedList) {
|
||||||
|
QAction *action = m_actionForId.value(item.id);
|
||||||
|
if (!action) {
|
||||||
|
// We don't know this action. It probably is in a menu we haven't fetched yet.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_FOREACH (const QString &key, item.properties) {
|
||||||
|
updateActionProperty(action, key, QVariant());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *DBusMenuImporter::actionForId(int id) const
|
||||||
|
{
|
||||||
|
return d->m_actionForId.value(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotItemActivationRequested(int id, uint /*timestamp*/)
|
||||||
|
{
|
||||||
|
QAction *action = d->m_actionForId.value(id);
|
||||||
|
// DMRETURN_IF_FAIL(action);
|
||||||
|
actionActivationRequested(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotGetLayoutFinished(QDBusPendingCallWatcher *watcher)
|
||||||
|
{
|
||||||
|
int parentId = watcher->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
watcher->deleteLater();
|
||||||
|
|
||||||
|
QMenu *menu = d->menuForId(parentId);
|
||||||
|
|
||||||
|
QDBusPendingReply<uint, DBusMenuLayoutItem> reply = *watcher;
|
||||||
|
if (!reply.isValid()) {
|
||||||
|
qDebug() << reply.error().message();
|
||||||
|
if (menu) {
|
||||||
|
emit menuUpdated(menu);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
DMDEBUG << "- items received:" << sChrono.elapsed() << "ms";
|
||||||
|
#endif
|
||||||
|
DBusMenuLayoutItem rootItem = reply.argumentAt<1>();
|
||||||
|
|
||||||
|
if (!menu) {
|
||||||
|
qDebug() << "No menu for id" << parentId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove outdated actions
|
||||||
|
QSet<int> newDBusMenuItemIds;
|
||||||
|
newDBusMenuItemIds.reserve(rootItem.children.count());
|
||||||
|
for (const DBusMenuLayoutItem &item : qAsConst(rootItem.children)) {
|
||||||
|
newDBusMenuItemIds << item.id;
|
||||||
|
}
|
||||||
|
for (QAction *action : menu->actions()) {
|
||||||
|
int id = action->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
if (!newDBusMenuItemIds.contains(id)) {
|
||||||
|
// Not calling removeAction() as QMenu will immediately close when it becomes empty,
|
||||||
|
// which can happen when an application completely reloads this menu.
|
||||||
|
// When the action is deleted deferred, it is removed from the menu.
|
||||||
|
action->deleteLater();
|
||||||
|
if (action->menu()) {
|
||||||
|
action->menu()->deleteLater();
|
||||||
|
}
|
||||||
|
d->m_actionForId.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert or update new actions into our menu
|
||||||
|
for (const DBusMenuLayoutItem &dbusMenuItem : qAsConst(rootItem.children)) {
|
||||||
|
DBusMenuImporterPrivate::ActionForId::Iterator it = d->m_actionForId.find(dbusMenuItem.id);
|
||||||
|
QAction *action = nullptr;
|
||||||
|
if (it == d->m_actionForId.end()) {
|
||||||
|
int id = dbusMenuItem.id;
|
||||||
|
action = d->createAction(id, dbusMenuItem.properties, menu);
|
||||||
|
d->m_actionForId.insert(id, action);
|
||||||
|
|
||||||
|
connect(action, &QObject::destroyed, this, [this, id]() {
|
||||||
|
d->m_actionForId.remove(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(action, &QAction::triggered, this, [id, this]() {
|
||||||
|
sendClickedEvent(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (QMenu *menuAction = action->menu()) {
|
||||||
|
connect(menuAction, &QMenu::aboutToShow, this, &DBusMenuImporter::slotMenuAboutToShow, Qt::UniqueConnection);
|
||||||
|
}
|
||||||
|
connect(menu, &QMenu::aboutToHide, this, &DBusMenuImporter::slotMenuAboutToHide, Qt::UniqueConnection);
|
||||||
|
|
||||||
|
menu->addAction(action);
|
||||||
|
} else {
|
||||||
|
action = *it;
|
||||||
|
QStringList filteredKeys = dbusMenuItem.properties.keys();
|
||||||
|
filteredKeys.removeOne("type");
|
||||||
|
filteredKeys.removeOne("toggle-type");
|
||||||
|
filteredKeys.removeOne("children-display");
|
||||||
|
d->updateAction(*it, dbusMenuItem.properties, filteredKeys);
|
||||||
|
// Move the action to the tail so we can keep the order same as the dbus request.
|
||||||
|
menu->removeAction(action);
|
||||||
|
menu->addAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit menuUpdated(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::sendClickedEvent(int id)
|
||||||
|
{
|
||||||
|
d->sendEvent(id, QStringLiteral("clicked"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::updateMenu()
|
||||||
|
{
|
||||||
|
updateMenu(DBusMenuImporter::menu());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::updateMenu(QMenu *menu)
|
||||||
|
{
|
||||||
|
Q_ASSERT(menu);
|
||||||
|
|
||||||
|
QAction *action = menu->menuAction();
|
||||||
|
Q_ASSERT(action);
|
||||||
|
|
||||||
|
int id = action->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
|
||||||
|
auto call = d->m_interface->AboutToShow(id);
|
||||||
|
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||||
|
watcher->setProperty(DBUSMENU_PROPERTY_ID, id);
|
||||||
|
connect(watcher, &QDBusPendingCallWatcher::finished, this, &DBusMenuImporter::slotAboutToShowDBusCallFinished);
|
||||||
|
|
||||||
|
// Firefox deliberately ignores "aboutToShow" whereas Qt ignores" opened", so we'll just send both all the time...
|
||||||
|
d->sendEvent(id, QStringLiteral("opened"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotAboutToShowDBusCallFinished(QDBusPendingCallWatcher *watcher)
|
||||||
|
{
|
||||||
|
int id = watcher->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
watcher->deleteLater();
|
||||||
|
|
||||||
|
QMenu *menu = d->menuForId(id);
|
||||||
|
if (!menu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDBusPendingReply<bool> reply = *watcher;
|
||||||
|
if (reply.isError()) {
|
||||||
|
qDebug() << "Call to AboutToShow() failed:" << reply.error().message();
|
||||||
|
Q_EMIT menuUpdated(menu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Note, this isn't used by Qt's QPT - but we get a LayoutChanged emitted before
|
||||||
|
// this returns, which equates to the same thing
|
||||||
|
bool needRefresh = reply.argumentAt<0>();
|
||||||
|
|
||||||
|
if (needRefresh || menu->actions().isEmpty()) {
|
||||||
|
d->m_idsRefreshedByAboutToShow << id;
|
||||||
|
d->refresh(id);
|
||||||
|
} else if (menu) {
|
||||||
|
Q_EMIT menuUpdated(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotMenuAboutToHide()
|
||||||
|
{
|
||||||
|
QMenu *menu = qobject_cast<QMenu *>(sender());
|
||||||
|
Q_ASSERT(menu);
|
||||||
|
|
||||||
|
QAction *action = menu->menuAction();
|
||||||
|
Q_ASSERT(action);
|
||||||
|
|
||||||
|
int id = action->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
d->sendEvent(id, QStringLiteral("closed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotMenuAboutToShow()
|
||||||
|
{
|
||||||
|
QMenu *menu = qobject_cast<QMenu *>(sender());
|
||||||
|
Q_ASSERT(menu);
|
||||||
|
|
||||||
|
updateMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *DBusMenuImporter::createMenu(QWidget *parent)
|
||||||
|
{
|
||||||
|
return new QMenu(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon DBusMenuImporter::iconForName(const QString & /*name*/)
|
||||||
|
{
|
||||||
|
return QIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_dbusmenuimporter.cpp"
|
||||||
@ -0,0 +1,111 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 DBUSMENUIMPORTER_H
|
||||||
|
#define DBUSMENUIMPORTER_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
class QDBusPendingCallWatcher;
|
||||||
|
class QIcon;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
|
class DBusMenuImporterPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DBusMenuImporter instance can recreate a menu serialized over DBus by
|
||||||
|
* DBusMenuExporter
|
||||||
|
*/
|
||||||
|
class DBusMenuImporter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a DBusMenuImporter listening over DBus on service, path
|
||||||
|
*/
|
||||||
|
DBusMenuImporter(const QString &service, const QString &path, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
~DBusMenuImporter() override;
|
||||||
|
|
||||||
|
QAction *actionForId(int id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu created from listening to the DBusMenuExporter over DBus
|
||||||
|
*/
|
||||||
|
QMenu *menu() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
/**
|
||||||
|
* Load the menu
|
||||||
|
*
|
||||||
|
* Will emit menuUpdated() when complete.
|
||||||
|
* This should be done before showing a menu
|
||||||
|
*/
|
||||||
|
void updateMenu();
|
||||||
|
|
||||||
|
void updateMenu(QMenu *menu);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
/**
|
||||||
|
* Emitted after a call to updateMenu().
|
||||||
|
* @see updateMenu()
|
||||||
|
*/
|
||||||
|
void menuUpdated(QMenu *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when the exporter was asked to activate an action
|
||||||
|
*/
|
||||||
|
void actionActivationRequested(QAction *);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Must create a menu, may be customized to fit host appearance.
|
||||||
|
* Default implementation creates a simple QMenu.
|
||||||
|
*/
|
||||||
|
virtual QMenu *createMenu(QWidget *parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must convert a name into an icon.
|
||||||
|
* Default implementation returns a null icon.
|
||||||
|
*/
|
||||||
|
virtual QIcon iconForName(const QString &);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void sendClickedEvent(int);
|
||||||
|
void slotMenuAboutToShow();
|
||||||
|
void slotMenuAboutToHide();
|
||||||
|
void slotAboutToShowDBusCallFinished(QDBusPendingCallWatcher *);
|
||||||
|
void slotItemActivationRequested(int id, uint timestamp);
|
||||||
|
void processPendingLayoutUpdates();
|
||||||
|
void slotLayoutUpdated(uint revision, int parentId);
|
||||||
|
void slotGetLayoutFinished(QDBusPendingCallWatcher *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(DBusMenuImporter)
|
||||||
|
DBusMenuImporterPrivate *const d;
|
||||||
|
friend class DBusMenuImporterPrivate;
|
||||||
|
|
||||||
|
// Use Q_PRIVATE_SLOT to avoid exposing DBusMenuItemList
|
||||||
|
Q_PRIVATE_SLOT(d, void slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList))
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENUIMPORTER_H */
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 "dbusmenushortcut_p.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QKeySequence>
|
||||||
|
|
||||||
|
static const int QT_COLUMN = 0;
|
||||||
|
static const int DM_COLUMN = 1;
|
||||||
|
|
||||||
|
static void processKeyTokens(QStringList *tokens, int srcCol, int dstCol)
|
||||||
|
{
|
||||||
|
struct Row {
|
||||||
|
const char *zero;
|
||||||
|
const char *one;
|
||||||
|
const char *operator[](int col) const
|
||||||
|
{
|
||||||
|
return col == 0 ? zero : one;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static const Row table[] = {{"Meta", "Super"},
|
||||||
|
{"Ctrl", "Control"},
|
||||||
|
// Special cases for compatibility with libdbusmenu-glib which uses
|
||||||
|
// "plus" for "+" and "minus" for "-".
|
||||||
|
// cf https://bugs.launchpad.net/libdbusmenu-qt/+bug/712565
|
||||||
|
{"+", "plus"},
|
||||||
|
{"-", "minus"},
|
||||||
|
{nullptr, nullptr}};
|
||||||
|
|
||||||
|
const Row *ptr = table;
|
||||||
|
for (; ptr->zero != nullptr; ++ptr) {
|
||||||
|
const char *from = (*ptr)[srcCol];
|
||||||
|
const char *to = (*ptr)[dstCol];
|
||||||
|
tokens->replaceInStrings(from, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuShortcut DBusMenuShortcut::fromKeySequence(const QKeySequence &sequence)
|
||||||
|
{
|
||||||
|
QString string = sequence.toString();
|
||||||
|
DBusMenuShortcut shortcut;
|
||||||
|
QStringList tokens = string.split(QStringLiteral(", "));
|
||||||
|
Q_FOREACH (QString token, tokens) {
|
||||||
|
// Hack: Qt::CTRL | Qt::Key_Plus is turned into the string "Ctrl++",
|
||||||
|
// but we don't want the call to token.split() to consider the
|
||||||
|
// second '+' as a separator so we replace it with its final value.
|
||||||
|
token.replace(QLatin1String("++"), QLatin1String("+plus"));
|
||||||
|
QStringList keyTokens = token.split('+');
|
||||||
|
processKeyTokens(&keyTokens, QT_COLUMN, DM_COLUMN);
|
||||||
|
shortcut << keyTokens;
|
||||||
|
}
|
||||||
|
return shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
QKeySequence DBusMenuShortcut::toKeySequence() const
|
||||||
|
{
|
||||||
|
QStringList tmp;
|
||||||
|
Q_FOREACH (const QStringList &keyTokens_, *this) {
|
||||||
|
QStringList keyTokens = keyTokens_;
|
||||||
|
processKeyTokens(&keyTokens, DM_COLUMN, QT_COLUMN);
|
||||||
|
tmp << keyTokens.join(QLatin1String("+"));
|
||||||
|
}
|
||||||
|
QString string = tmp.join(QLatin1String(", "));
|
||||||
|
return QKeySequence::fromString(string);
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 DBUSMENUSHORTCUT_H
|
||||||
|
#define DBUSMENUSHORTCUT_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class QKeySequence;
|
||||||
|
|
||||||
|
class DBusMenuShortcut : public QList<QStringList>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QKeySequence toKeySequence() const;
|
||||||
|
static DBusMenuShortcut fromKeySequence(const QKeySequence &);
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuShortcut)
|
||||||
|
|
||||||
|
#endif /* DBUSMENUSHORTCUT_H */
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 "dbusmenutypes_p.h"
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "dbusmenushortcut_p.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QDBusArgument>
|
||||||
|
#include <QDBusMetaType>
|
||||||
|
|
||||||
|
//// DBusMenuItem
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << obj.id << obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> obj.id >> obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// DBusMenuItemKeys
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItemKeys &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << obj.id << obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItemKeys &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> obj.id >> obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// DBusMenuLayoutItem
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << obj.id << obj.properties;
|
||||||
|
argument.beginArray(qMetaTypeId<QDBusVariant>());
|
||||||
|
Q_FOREACH (const DBusMenuLayoutItem &child, obj.children) {
|
||||||
|
argument << QDBusVariant(QVariant::fromValue<DBusMenuLayoutItem>(child));
|
||||||
|
}
|
||||||
|
argument.endArray();
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> obj.id >> obj.properties;
|
||||||
|
argument.beginArray();
|
||||||
|
while (!argument.atEnd()) {
|
||||||
|
QDBusVariant dbusVariant;
|
||||||
|
argument >> dbusVariant;
|
||||||
|
QDBusArgument childArgument = dbusVariant.variant().value<QDBusArgument>();
|
||||||
|
|
||||||
|
DBusMenuLayoutItem child;
|
||||||
|
childArgument >> child;
|
||||||
|
obj.children.append(child);
|
||||||
|
}
|
||||||
|
argument.endArray();
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// DBusMenuShortcut
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuShortcut &obj)
|
||||||
|
{
|
||||||
|
argument.beginArray(qMetaTypeId<QStringList>());
|
||||||
|
typename QList<QStringList>::ConstIterator it = obj.constBegin();
|
||||||
|
typename QList<QStringList>::ConstIterator end = obj.constEnd();
|
||||||
|
for (; it != end; ++it)
|
||||||
|
argument << *it;
|
||||||
|
argument.endArray();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuShortcut &obj)
|
||||||
|
{
|
||||||
|
argument.beginArray();
|
||||||
|
obj.clear();
|
||||||
|
while (!argument.atEnd()) {
|
||||||
|
QStringList item;
|
||||||
|
argument >> item;
|
||||||
|
obj.push_back(item);
|
||||||
|
}
|
||||||
|
argument.endArray();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuTypes_register()
|
||||||
|
{
|
||||||
|
static bool registered = false;
|
||||||
|
if (registered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDBusRegisterMetaType<DBusMenuItem>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuItemList>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuItemKeys>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuItemKeysList>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuLayoutItem>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuLayoutItemList>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuShortcut>();
|
||||||
|
registered = true;
|
||||||
|
}
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 DBUSMENUTYPES_P_H
|
||||||
|
#define DBUSMENUTYPES_P_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QList>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
class QDBusArgument;
|
||||||
|
|
||||||
|
//// DBusMenuItem
|
||||||
|
/**
|
||||||
|
* Internal struct used to communicate on DBus
|
||||||
|
*/
|
||||||
|
struct DBusMenuItem {
|
||||||
|
int id;
|
||||||
|
QVariantMap properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItem)
|
||||||
|
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItem &item);
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItem &item);
|
||||||
|
|
||||||
|
typedef QList<DBusMenuItem> DBusMenuItemList;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItemList)
|
||||||
|
|
||||||
|
//// DBusMenuItemKeys
|
||||||
|
/**
|
||||||
|
* Represents a list of keys for a menu item
|
||||||
|
*/
|
||||||
|
struct DBusMenuItemKeys {
|
||||||
|
int id;
|
||||||
|
QStringList properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItemKeys)
|
||||||
|
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItemKeys &);
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItemKeys &);
|
||||||
|
|
||||||
|
typedef QList<DBusMenuItemKeys> DBusMenuItemKeysList;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItemKeysList)
|
||||||
|
|
||||||
|
//// DBusMenuLayoutItem
|
||||||
|
/**
|
||||||
|
* Represents an item with its children. GetLayout() returns a
|
||||||
|
* DBusMenuLayoutItemList.
|
||||||
|
*/
|
||||||
|
struct DBusMenuLayoutItem;
|
||||||
|
struct DBusMenuLayoutItem {
|
||||||
|
int id;
|
||||||
|
QVariantMap properties;
|
||||||
|
QList<DBusMenuLayoutItem> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuLayoutItem)
|
||||||
|
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &);
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &);
|
||||||
|
|
||||||
|
typedef QList<DBusMenuLayoutItem> DBusMenuLayoutItemList;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuLayoutItemList)
|
||||||
|
|
||||||
|
//// DBusMenuShortcut
|
||||||
|
|
||||||
|
class DBusMenuShortcut;
|
||||||
|
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuShortcut &);
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuShortcut &);
|
||||||
|
|
||||||
|
void DBusMenuTypes_register();
|
||||||
|
#endif /* DBUSMENUTYPES_P_H */
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 "utils.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
QString swapMnemonicChar(const QString &in, const char src, const char dst)
|
||||||
|
{
|
||||||
|
QString out;
|
||||||
|
bool mnemonicFound = false;
|
||||||
|
|
||||||
|
for (int pos = 0; pos < in.length();) {
|
||||||
|
QChar ch = in[pos];
|
||||||
|
if (ch == src) {
|
||||||
|
if (pos == in.length() - 1) {
|
||||||
|
// 'src' at the end of string, skip it
|
||||||
|
++pos;
|
||||||
|
} else {
|
||||||
|
if (in[pos + 1] == src) {
|
||||||
|
// A real 'src'
|
||||||
|
out += src;
|
||||||
|
pos += 2;
|
||||||
|
} else if (!mnemonicFound) {
|
||||||
|
// We found the mnemonic
|
||||||
|
mnemonicFound = true;
|
||||||
|
out += dst;
|
||||||
|
++pos;
|
||||||
|
} else {
|
||||||
|
// We already have a mnemonic, just skip the char
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ch == dst) {
|
||||||
|
// Escape 'dst'
|
||||||
|
out += dst;
|
||||||
|
out += dst;
|
||||||
|
++pos;
|
||||||
|
} else {
|
||||||
|
out += ch;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) 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 UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
class QString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap mnemonic char: Qt uses '&', while dbusmenu uses '_'
|
||||||
|
*/
|
||||||
|
QString swapMnemonicChar(const QString &in, const char src, const char dst);
|
||||||
|
|
||||||
|
#endif /* UTILS_P_H */
|
||||||
Loading…
Reference in New Issue