diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -272,6 +272,10 @@
option(KWIN_BUILD_XRENDER_COMPOSITING "Enable building of KWin with XRender Compositing support" ON)
cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "KF5Activities_FOUND" OFF)
+# TODO FIXME was off in the 5.1 branch
+option(KWIN_BUILD_KAPPMENU "Enable building of KWin with application menu support" ON)
+# cmake_dependent_option(KWIN_BUILD_KAPPMENU "Build without appmenu support" ON "KWIN_BUILD_DECORATIONS" FALSE)
+
# Binary name of KWin
set(KWIN_NAME "kwin")
set(KWIN_INTERNAL_NAME_X11 "kwin_x11")
@@ -439,6 +443,17 @@
)
endif()
+if(KWIN_BUILD_KAPPMENU)
+ set(
+ kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS}
+ appmenu.cpp
+ )
+ qt5_add_dbus_interface(kwin_KDEINIT_SRCS
+ # FIXME TODO figure out all the cmake magic
+ /home/kaiuwe/Projekte/kf5/plasma-workspace/appmenu/org.kde.kappmenu.xml appmenu_interface)
+ #${CMAKE_SOURCE_DIR}/plasma-workspace/appmenu/org.kde.kappmenu.xml appmenu_interface)
+endif()
+
if(UDEV_FOUND)
set(kwin_KDEINIT_SRCS
${kwin_KDEINIT_SRCS}
diff --git a/abstract_client.h b/abstract_client.h
--- a/abstract_client.h
+++ b/abstract_client.h
@@ -244,6 +244,11 @@
* Because of that there is no notify signal.
**/
Q_PROPERTY(bool resizeable READ isResizable)
+
+ // FIXME TODO documentation
+ // FIXME TODO should there be a WRITE accessor?
+ Q_PROPERTY(bool applicationMenuAvailable READ applicationMenuAvailable WRITE setApplicationMenuAvailable)
+
public:
virtual ~AbstractClient();
@@ -583,6 +588,14 @@
// TODO: remove boolean trap
static bool belongToSameApplication(const AbstractClient* c1, const AbstractClient* c2, bool active_hack = false);
+#ifdef KWIN_BUILD_KAPPMENU
+ void setApplicationMenuAvailable(bool applicationMenuAvailable);
+ void showApplicationMenu(const QPoint &p);
+ bool applicationMenuAvailable() const {
+ return m_applicationMenuAvailable;
+ }
+#endif
+
public Q_SLOTS:
virtual void closeWindow() = 0;
@@ -622,6 +635,11 @@
void shadeableChanged(bool);
void maximizeableChanged(bool);
+ void requestShowApplicationMenu();
+ void applicationMenuVisibleChanged(bool applicationMenuVisible);
+
+ void applicationMenuAvailableChanged(bool applicationMenuAvailable);
+
protected:
AbstractClient();
void setFirstInTabBox(bool enable) {
@@ -966,8 +984,12 @@
QElapsedTimer doubleClickTimer;
} m_decoration;
-
static bool s_haveResizeEffect;
+
+#ifdef KWIN_BUILD_KAPPMENU
+ bool m_applicationMenuAvailable = false;
+#endif
+
};
/**
diff --git a/abstract_client.cpp b/abstract_client.cpp
--- a/abstract_client.cpp
+++ b/abstract_client.cpp
@@ -18,6 +18,9 @@
along with this program. If not, see .
*********************************************************************/
#include "abstract_client.h"
+#ifdef KWIN_BUILD_KAPPMENU
+#include "appmenu.h"
+#endif
#include "decorations/decoratedclient.h"
#include "decorations/decorationpalette.h"
#include "decorations/decorationbridge.h"
@@ -1635,4 +1638,19 @@
return Toplevel::inputGeometry();
}
+#ifdef KWIN_BUILD_KAPPMENU
+void AbstractClient::setApplicationMenuAvailable(bool applicationMenuAvailable)
+{
+ if (m_applicationMenuAvailable != applicationMenuAvailable) {
+ m_applicationMenuAvailable = applicationMenuAvailable;
+ emit applicationMenuAvailableChanged(applicationMenuAvailable);
+ }
+}
+
+void AbstractClient::showApplicationMenu(const QPoint &p)
+{
+ ApplicationMenu::self()->showApplicationMenu(p, window());
+}
+#endif
+
}
diff --git a/appmenu.h b/appmenu.h
new file mode 100644
--- /dev/null
+++ b/appmenu.h
@@ -0,0 +1,62 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (c) 2011 Lionel Chauvin
+Copyright (c) 2011,2012 Cédric Bellegarde
+Copyright (C) 2013 Martin Gräßlin
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program. If not, see .
+*********************************************************************/
+#ifndef KWIN_APPLICATIONMENU_H
+#define KWIN_APPLICATIONMENU_H
+// KWin
+#include
+// Qt
+#include
+// xcb
+#include
+
+class QPoint;
+class OrgKdeKappmenuInterface;
+
+namespace KWin
+{
+
+class ApplicationMenu : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual ~ApplicationMenu();
+
+ bool hasMenu(xcb_window_t window);
+ void showApplicationMenu(const QPoint &pos, const xcb_window_t window);
+
+private Q_SLOTS:
+ void slotShowRequest(qulonglong wid);
+ void slotMenuAvailable(qulonglong wid);
+ void slotMenuHidden(qulonglong wid);
+ void slotClearMenus();
+
+private:
+ QList m_windowsMenu;
+ OrgKdeKappmenuInterface *m_appmenuInterface;
+
+ KWIN_SINGLETON(ApplicationMenu)
+};
+
+}
+
+#endif // KWIN_APPLICATIONMENU_H
diff --git a/appmenu.cpp b/appmenu.cpp
new file mode 100644
--- /dev/null
+++ b/appmenu.cpp
@@ -0,0 +1,92 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (c) 2011 Lionel Chauvin
+Copyright (c) 2011,2012 Cédric Bellegarde
+Copyright (C) 2013 Martin Gräßlin
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program. If not, see .
+*********************************************************************/
+#include "appmenu.h"
+#include "client.h"
+#include "workspace.h"
+#include
+
+namespace KWin {
+
+KWIN_SINGLETON_FACTORY(ApplicationMenu)
+
+ApplicationMenu::ApplicationMenu(QObject *parent)
+ : QObject(parent)
+ , m_appmenuInterface(new OrgKdeKappmenuInterface(QStringLiteral("org.kde.kappmenu"), QStringLiteral("/KAppMenu"), QDBusConnection::sessionBus(), this))
+{
+ connect(m_appmenuInterface, &OrgKdeKappmenuInterface::showRequest, this, &ApplicationMenu::slotShowRequest);
+ connect(m_appmenuInterface, &OrgKdeKappmenuInterface::menuAvailable, this, &ApplicationMenu::slotMenuAvailable);
+ connect(m_appmenuInterface, &OrgKdeKappmenuInterface::menuHidden, this, &ApplicationMenu::slotMenuHidden);
+ connect(m_appmenuInterface, &OrgKdeKappmenuInterface::clearMenus, this, &ApplicationMenu::slotClearMenus);
+}
+
+ApplicationMenu::~ApplicationMenu()
+{
+ s_self = nullptr;
+}
+
+bool ApplicationMenu::hasMenu(xcb_window_t window)
+{
+ return m_windowsMenu.removeOne(window);
+}
+
+void ApplicationMenu::slotShowRequest(qulonglong wid)
+{
+ if (Client *c = Workspace::self()->findClient(Predicate::WindowMatch, wid)) {
+ qDebug() << "slot show request" << wid;
+ emit c->requestShowApplicationMenu();
+ }
+}
+
+void ApplicationMenu::slotMenuAvailable(qulonglong wid)
+{
+ if (Client *c = Workspace::self()->findClient(Predicate::WindowMatch, wid)) {
+ c->setApplicationMenuAvailable(true);
+ } else {
+ m_windowsMenu.append(wid);
+ }
+}
+
+void ApplicationMenu::slotMenuHidden(qulonglong wid)
+{
+ if (Client *c = Workspace::self()->findClient(Predicate::WindowMatch, wid)) {
+ emit c->applicationMenuVisibleChanged(false);
+ }
+}
+
+void ApplicationMenu::slotClearMenus()
+{
+ // FIXME TODO qAsConst
+ const auto &clients = Workspace::self()->clientList();
+ for (Client *c : clients) {
+ c->setApplicationMenuAvailable(false);
+ }
+}
+
+void ApplicationMenu::showApplicationMenu(const QPoint &p, const xcb_window_t id)
+{
+ //if (Client *c = Workspace::self()->findClient(Predicate::WindowMatch, wid)) {
+ m_appmenuInterface->showMenu(p.x(), p.y(), id);
+// emit c->applicationMenuVisibleChanged(true);
+// }
+}
+
+} // namespace
diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake
--- a/config-kwin.h.cmake
+++ b/config-kwin.h.cmake
@@ -1,6 +1,7 @@
#cmakedefine KWIN_BUILD_DECORATIONS 1
#cmakedefine KWIN_BUILD_TABBOX 1
#cmakedefine KWIN_BUILD_ACTIVITIES 1
+#cmakedefine KWIN_BUILD_KAPPMENU 1
#define KWIN_NAME "${KWIN_NAME}"
#define KWIN_INTERNAL_NAME_X11 "${KWIN_INTERNAL_NAME_X11}"
#define KWIN_CONFIG "${KWIN_NAME}rc"
diff --git a/decorations/decoratedclient.h b/decorations/decoratedclient.h
--- a/decorations/decoratedclient.h
+++ b/decorations/decoratedclient.h
@@ -69,16 +69,22 @@
Qt::Edges adjacentScreenEdges() const override;
+ bool isApplicationMenuAvailable() const;
+ bool isApplicationMenuVisible() const;
+
void requestClose() override;
void requestContextHelp() override;
void requestToggleMaximization(Qt::MouseButtons buttons) override;
void requestMinimize() override;
void requestShowWindowMenu() override;
+ void requestShowApplicationMenu(const QRect &rect) override;
void requestToggleKeepAbove() override;
void requestToggleKeepBelow() override;
void requestToggleOnAllDesktops() override;
void requestToggleShade() override;
+ void showApplicationMenu();
+
AbstractClient *client() {
return m_client;
}
diff --git a/decorations/decoratedclient.cpp b/decorations/decoratedclient.cpp
--- a/decorations/decoratedclient.cpp
+++ b/decorations/decoratedclient.cpp
@@ -110,6 +110,12 @@
connect(client, &AbstractClient::maximizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::maximizeableChanged);
connect(client, &AbstractClient::paletteChanged, decoratedClient, &KDecoration2::DecoratedClient::paletteChanged);
+
+#ifdef KWIN_BUILD_KAPPMENU
+ connect(client, &AbstractClient::requestShowApplicationMenu, decoratedClient, &KDecoration2::DecoratedClient::showApplicationMenu);
+ connect(client, &AbstractClient::applicationMenuAvailableChanged, decoratedClient, &KDecoration2::DecoratedClient::applicationMenuAvailableChanged);
+ connect(client, &AbstractClient::applicationMenuVisibleChanged, decoratedClient, &KDecoration2::DecoratedClient::applicationMenuVisibleChanged);
+#endif
}
DecoratedClientImpl::~DecoratedClientImpl() = default;
@@ -203,6 +209,16 @@
Workspace::self()->showWindowMenu(QRect(Cursor::pos(), Cursor::pos()), m_client);
}
+void DecoratedClientImpl::requestShowApplicationMenu(const QRect &rect)
+{
+ Workspace::self()->showApplicationMenu(rect, m_client);
+}
+
+void DecoratedClientImpl::showApplicationMenu()
+{
+ m_client->requestShowApplicationMenu();
+}
+
void DecoratedClientImpl::requestToggleMaximization(Qt::MouseButtons buttons)
{
QMetaObject::invokeMethod(this, "delayedRequestToggleMaximization", Qt::QueuedConnection, Q_ARG(Options::WindowOperation, options->operationMaxButtonClick(buttons)));
@@ -265,6 +281,16 @@
return edges;
}
+bool DecoratedClientImpl::isApplicationMenuAvailable() const
+{
+ return m_client->applicationMenuAvailable();
+}
+
+bool DecoratedClientImpl::isApplicationMenuVisible() const
+{
+ return false; // FIXME TODO we don't track state currently
+}
+
void DecoratedClientImpl::createRenderer()
{
if (Compositor::self()->hasScene()) {
diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewclient.h b/kcmkwin/kwindecoration/declarative-plugin/previewclient.h
--- a/kcmkwin/kwindecoration/declarative-plugin/previewclient.h
+++ b/kcmkwin/kwindecoration/declarative-plugin/previewclient.h
@@ -97,6 +97,10 @@
QColor color(ColorGroup group, ColorRole role) const override;
Qt::Edges adjacentScreenEdges() const override;
+ // FIXME TODO find a place to put that into the cpp :)
+ bool isApplicationMenuAvailable() const override { return false; }
+ bool isApplicationMenuVisible() const override { return false; }
+
void requestClose() override;
void requestContextHelp() override;
void requestToggleMaximization(Qt::MouseButtons buttons) override;
@@ -105,8 +109,11 @@
void requestToggleKeepBelow() override;
void requestToggleShade() override;
void requestShowWindowMenu() override;
+ void requestShowApplicationMenu(const QRect &rect) override;
void requestToggleOnAllDesktops() override;
+ void showApplicationMenu();
+
void setCaption(const QString &caption);
void setActive(bool active);
void setCloseable(bool closeable);
@@ -176,6 +183,7 @@
void bordersBottomEdgeChanged(bool);
void showWindowMenuRequested();
+ void showApplicationMenuRequested();
void minimizeRequested();
void closeRequested();
diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp b/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp
--- a/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp
+++ b/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp
@@ -408,6 +408,17 @@
emit showWindowMenuRequested();
}
+void PreviewClient::requestShowApplicationMenu(const QRect &rect)
+{
+ Q_UNUSED(rect);
+ emit showApplicationMenuRequested(); // FIXME TODO pass geometry
+}
+
+void PreviewClient::showApplicationMenu()
+{
+
+}
+
void PreviewClient::requestToggleOnAllDesktops()
{
setDesktop(isOnAllDesktops() ? 1 : -1);
diff --git a/useractions.cpp b/useractions.cpp
--- a/useractions.cpp
+++ b/useractions.cpp
@@ -45,6 +45,9 @@
#include "activities.h"
#include
#endif
+#ifdef KWIN_BUILD_KAPPMENU
+#include "appmenu.h"
+#endif
#include
@@ -1670,6 +1673,12 @@
m_userActionsMenu->show(pos, cl);
}
+void Workspace::showApplicationMenu(const QRect &pos, AbstractClient *c)
+{
+ // FIXME TODO map to global properly, taking into account margins and what not
+ ApplicationMenu::self()->showApplicationMenu(c->geometry().topLeft() + pos.bottomLeft(), c->window());
+}
+
/*!
Closes the popup client
*/
diff --git a/workspace.h b/workspace.h
--- a/workspace.h
+++ b/workspace.h
@@ -285,6 +285,8 @@
return m_userActionsMenu;
}
+ void showApplicationMenu(const QRect &pos, AbstractClient *c);
+
void updateMinimizedOfTransients(AbstractClient*);
void updateOnAllDesktopsOfTransients(AbstractClient*);
void checkTransients(xcb_window_t w);
diff --git a/workspace.cpp b/workspace.cpp
--- a/workspace.cpp
+++ b/workspace.cpp
@@ -27,6 +27,9 @@
#ifdef KWIN_BUILD_ACTIVITIES
#include "activities.h"
#endif
+#ifdef KWIN_BUILD_KAPPMENU
+#include "appmenu.h"
+#endif
#include "atoms.h"
#include "client.h"
#include "composite.h"
@@ -128,6 +131,10 @@
// If KWin was already running it saved its configuration after loosing the selection -> Reread
QFuture reparseConfigFuture = QtConcurrent::run(options, &Options::reparseConfiguration);
+#ifdef KWIN_BUILD_KAPPMENU
+ ApplicationMenu::create(this);
+#endif
+
_self = this;
// first initialize the extensions
@@ -578,6 +585,11 @@
if (TabBox::TabBox::self()->isDisplayed())
TabBox::TabBox::self()->reset(true);
#endif
+#ifdef KWIN_BUILD_KAPPMENU
+ if (ApplicationMenu::self()->hasMenu(c->window())) {
+ c->setApplicationMenuAvailable(true);
+ }
+#endif
}
void Workspace::addUnmanaged(Unmanaged* c)