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)