diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -416,6 +416,7 @@ wayland_server.cpp wayland_cursor_theme.cpp virtualkeyboard.cpp + appmenu.cpp ) if(KWIN_BUILD_TABBOX) @@ -466,6 +467,11 @@ qt5_add_dbus_interface( kwin_KDEINIT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/org.freedesktop.ScreenSaver.xml screenlocker_interface) +qt5_add_dbus_interface(kwin_KDEINIT_SRCS + # FIXME TODO figure out all the cmake magic + /home/broulik/Projekte/kf5/plasma-workspace/appmenu/org.kde.kappmenu.xml appmenu_interface +) + qt5_add_resources( kwin_KDEINIT_SRCS resources.qrc ) ki18n_wrap_ui(kwin_KDEINIT_SRCS diff --git a/abstract_client.h b/abstract_client.h --- a/abstract_client.h +++ b/abstract_client.h @@ -244,6 +244,15 @@ * Because of that there is no notify signal. **/ Q_PROPERTY(bool resizeable READ isResizable) + /** + * Whether an application menu is available for this Client + */ + Q_PROPERTY(bool hasApplicationMenu READ hasApplicationMenu NOTIFY hasApplicationMenuChanged) + /** + * Whether the application menu for this Client is currently opened + */ + Q_PROPERTY(bool applicationMenuActive READ applicationMenuActive NOTIFY applicationMenuActiveChanged) + public: virtual ~AbstractClient(); @@ -602,6 +611,19 @@ // TODO: remove boolean trap static bool belongToSameApplication(const AbstractClient* c1, const AbstractClient* c2, bool active_hack = false); + bool hasApplicationMenu() const; + bool applicationMenuActive() const { + return m_applicationMenuActive; + } + void setApplicationMenuActive(bool applicationMenuActive); + + QString applicationMenuServiceName() const { + return m_applicationMenuServiceName; + } + QString applicationMenuObjectPath() const { + return m_applicationMenuObjectPath; + } + public Q_SLOTS: virtual void closeWindow() = 0; @@ -640,6 +662,9 @@ void minimizeableChanged(bool); void shadeableChanged(bool); void maximizeableChanged(bool); + void hasApplicationMenuChanged(bool); + void applicationMenuActiveChanged(bool); + void showApplicationMenuRequested(); protected: AbstractClient(); @@ -918,6 +943,9 @@ void startDecorationDoubleClickTimer(); void invalidateDecorationDoubleClickTimer(); + void updateApplicationMenuServiceName(const QString &serviceName); + void updateApplicationMenuObjectPath(const QString &objectPath); + private: void handlePaletteChange(); QSharedPointer m_tabBoxClient; @@ -985,8 +1013,12 @@ QElapsedTimer doubleClickTimer; } m_decoration; - static bool s_haveResizeEffect; + + bool m_applicationMenuActive = false; + QString m_applicationMenuServiceName; + QString m_applicationMenuObjectPath; + }; /** diff --git a/abstract_client.cpp b/abstract_client.cpp --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -18,6 +18,8 @@ along with this program. If not, see . *********************************************************************/ #include "abstract_client.h" + +#include "appmenu.h" #include "decorations/decoratedclient.h" #include "decorations/decorationpalette.h" #include "decorations/decorationbridge.h" @@ -1639,4 +1641,43 @@ return false; } +bool AbstractClient::hasApplicationMenu() const +{ + return !m_applicationMenuServiceName.isEmpty() && !m_applicationMenuObjectPath.isEmpty(); +} + +void AbstractClient::updateApplicationMenuServiceName(const QString &serviceName) +{ + const bool old_hasApplicationMenu = hasApplicationMenu(); + + m_applicationMenuServiceName = serviceName; + + const bool new_hasApplicationMenu = hasApplicationMenu(); + + if (old_hasApplicationMenu != new_hasApplicationMenu) { + emit hasApplicationMenuChanged(new_hasApplicationMenu); + } +} + +void AbstractClient::updateApplicationMenuObjectPath(const QString &objectPath) +{ + const bool old_hasApplicationMenu = hasApplicationMenu(); + + m_applicationMenuObjectPath = objectPath; + + const bool new_hasApplicationMenu = hasApplicationMenu(); + + if (old_hasApplicationMenu != new_hasApplicationMenu) { + emit hasApplicationMenuChanged(new_hasApplicationMenu); + } +} + +void AbstractClient::setApplicationMenuActive(bool applicationMenuActive) +{ + if (m_applicationMenuActive != applicationMenuActive) { + m_applicationMenuActive = applicationMenuActive; + emit applicationMenuActiveChanged(applicationMenuActive); + } +} + } diff --git a/appmenu.h b/appmenu.h new file mode 100644 --- /dev/null +++ b/appmenu.h @@ -0,0 +1,64 @@ +/******************************************************************** + 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; +class QDBusObjectPath; + +namespace KWin +{ + +class AbstractClient; + +class ApplicationMenu : public QObject +{ + Q_OBJECT + +public: + ~ApplicationMenu() override; + + void showApplicationMenu(const QPoint &pos, AbstractClient *c); + +private Q_SLOTS: + void slotShowRequest(const QString &serviceName, const QDBusObjectPath &menuObjectPath); + void slotMenuShown(const QString &serviceName, const QDBusObjectPath &menuObjectPath); + void slotMenuHidden(const QString &serviceName, const QDBusObjectPath &menuObjectPath); + +private: + OrgKdeKappmenuInterface *m_appmenuInterface; + + AbstractClient *findAbstractClientWithApplicationMenu(const QString &serviceName, const QDBusObjectPath &menuObjectPath); + + 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,79 @@ +/******************************************************************** + 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 + +#include + +using 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::menuShown, this, &ApplicationMenu::slotMenuShown); + connect(m_appmenuInterface, &OrgKdeKappmenuInterface::menuHidden, this, &ApplicationMenu::slotMenuHidden); +} + +ApplicationMenu::~ApplicationMenu() +{ + s_self = nullptr; +} + +void ApplicationMenu::slotShowRequest(const QString &serviceName, const QDBusObjectPath &menuObjectPath) +{ + if (AbstractClient *c = findAbstractClientWithApplicationMenu(serviceName, menuObjectPath)) { + emit c->showApplicationMenuRequested(); + } +} + +void ApplicationMenu::slotMenuShown(const QString &serviceName, const QDBusObjectPath &menuObjectPath) +{ + if (AbstractClient *c = findAbstractClientWithApplicationMenu(serviceName, menuObjectPath)) { + c->setApplicationMenuActive(true); + } +} + +void ApplicationMenu::slotMenuHidden(const QString &serviceName, const QDBusObjectPath &menuObjectPath) +{ + if (AbstractClient *c = findAbstractClientWithApplicationMenu(serviceName, menuObjectPath)) { + c->setApplicationMenuActive(false); + } +} + +void ApplicationMenu::showApplicationMenu(const QPoint &p, AbstractClient *c) +{ + m_appmenuInterface->showMenu(p.x(), p.y(), c->applicationMenuServiceName(), QDBusObjectPath(c->applicationMenuObjectPath())); +} + +AbstractClient *ApplicationMenu::findAbstractClientWithApplicationMenu(const QString &serviceName, const QDBusObjectPath &menuObjectPath) +{ + return Workspace::self()->findAbstractClient([&](const AbstractClient *c) { + return c->applicationMenuServiceName() == serviceName + && c->applicationMenuObjectPath() == menuObjectPath.path(); + }); +} diff --git a/atoms.h b/atoms.h --- a/atoms.h +++ b/atoms.h @@ -68,6 +68,8 @@ Xcb::Atom kwin_dbus_service; Xcb::Atom utf8_string; Xcb::Atom wl_surface_id; + Xcb::Atom kde_net_wm_appmenu_service_name; + Xcb::Atom kde_net_wm_appmenu_object_path; /** * @internal diff --git a/atoms.cpp b/atoms.cpp --- a/atoms.cpp +++ b/atoms.cpp @@ -59,6 +59,8 @@ , kwin_dbus_service(QByteArrayLiteral("_ORG_KDE_KWIN_DBUS_SERVICE")) , utf8_string(QByteArrayLiteral("UTF8_STRING")) , wl_surface_id(QByteArrayLiteral("WL_SURFACE_ID")) + , kde_net_wm_appmenu_service_name(QByteArrayLiteral("_KDE_NET_WM_APPMENU_SERVICE_NAME")) + , kde_net_wm_appmenu_object_path(QByteArrayLiteral("_KDE_NET_WM_APPMENU_OBJECT_PATH")) , m_dtSmWindowInfo(QByteArrayLiteral("_DT_SM_WINDOW_INFO")) , m_motifSupport(QByteArrayLiteral("_MOTIF_WM_INFO")) , m_helpersRetrieved(false) diff --git a/client.h b/client.h --- a/client.h +++ b/client.h @@ -331,6 +331,14 @@ **/ void showOnScreenEdge() override; + Xcb::StringProperty fetchApplicationMenuServiceName() const; + void readApplicationMenuServiceName(Xcb::StringProperty &property); + void checkApplicationMenuServiceName(); + + Xcb::StringProperty fetchApplicationMenuObjectPath() const; + void readApplicationMenuObjectPath(Xcb::StringProperty &property); + void checkApplicationMenuObjectPath(); + static void cleanupX11(); public Q_SLOTS: diff --git a/client.cpp b/client.cpp --- a/client.cpp +++ b/client.cpp @@ -2145,5 +2145,37 @@ return m_geometryHints.resizeIncrements(); } +Xcb::StringProperty Client::fetchApplicationMenuServiceName() const +{ + return Xcb::StringProperty(m_client, atoms->kde_net_wm_appmenu_service_name); +} + +void Client::readApplicationMenuServiceName(Xcb::StringProperty &property) +{ + updateApplicationMenuServiceName(QString::fromUtf8(property)); +} + +void Client::checkApplicationMenuServiceName() +{ + Xcb::StringProperty property = fetchApplicationMenuServiceName(); + readApplicationMenuServiceName(property); +} + +Xcb::StringProperty Client::fetchApplicationMenuObjectPath() const +{ + return Xcb::StringProperty(m_client, atoms->kde_net_wm_appmenu_object_path); +} + +void Client::readApplicationMenuObjectPath(Xcb::StringProperty &property) +{ + updateApplicationMenuObjectPath(QString::fromUtf8(property)); +} + +void Client::checkApplicationMenuObjectPath() +{ + Xcb::StringProperty property = fetchApplicationMenuObjectPath(); + readApplicationMenuObjectPath(property); +} + } // namespace diff --git a/cmake/modules/FindQt5PlatformSupport.cmake b/cmake/modules/FindQt5PlatformSupport.cmake deleted file mode 100644 --- a/cmake/modules/FindQt5PlatformSupport.cmake +++ /dev/null @@ -1,121 +0,0 @@ -#.rst: -# FindQt5PlatformSupport -# ------- -# -# Try to find Qt5PlatformSupport on a Unix system. -# -# This will define the following variables: -# -# ``Qt5PlatformSupport_FOUND`` -# True if (the requested version of) Qt5PlatformSupport is available -# ``Qt5PlatformSupport_VERSION`` -# The version of Qt5PlatformSupport -# ``Qt5PlatformSupport_LIBRARIES`` -# This can be passed to target_link_libraries() instead of the ``Qt5PlatformSupport::Qt5PlatformSupport`` -# target -# ``Qt5PlatformSupport_INCLUDE_DIRS`` -# This should be passed to target_include_directories() if the target is not -# used for linking -# ``Qt5PlatformSupport_DEFINITIONS`` -# This should be passed to target_compile_options() if the target is not -# used for linking -# -# If ``Qt5PlatformSupport_FOUND`` is TRUE, it will also define the following imported target: -# -# ``Qt5PlatformSupport::Qt5PlatformSupport`` -# The Qt5PlatformSupport library -# -# In general we recommend using the imported target, as it is easier to use. -# Bear in mind, however, that if the target is in the link interface of an -# exported library, it must be made available by the package config file. - -#============================================================================= -# Copyright 2014 Alex Merry -# Copyright 2014 Martin Gräßlin -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#============================================================================= - -if(CMAKE_VERSION VERSION_LESS 2.8.12) - message(FATAL_ERROR "CMake 2.8.12 is required by FindQt5PlatformSupport.cmake") -endif() -if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) - message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use FindQt5PlatformSupport.cmake") -endif() - -# Use pkg-config to get the directories and then use these values -# in the FIND_PATH() and FIND_LIBRARY() calls -find_package(PkgConfig) -pkg_check_modules(PKG_Qt5PlatformSupport QUIET Qt5Gui) - -set(Qt5PlatformSupport_DEFINITIONS ${PKG_Qt5PlatformSupport_CFLAGS_OTHER}) -set(Qt5PlatformSupport_VERSION ${PKG_Qt5PlatformSupport_VERSION}) - -find_path(Qt5PlatformSupport_INCLUDE_DIR - NAMES - QtPlatformSupport/private/qfontconfigdatabase_p.h - HINTS - ${PKG_Qt5PlatformSupport_INCLUDEDIR}/QtPlatformSupport/${PKG_Qt5PlatformSupport_VERSION}/ -) -find_library(Qt5PlatformSupport_LIBRARY - NAMES - Qt5PlatformSupport - HINTS - ${PKG_Qt5PlatformSupport_LIBRARY_DIRS} -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Qt5PlatformSupport - FOUND_VAR - Qt5PlatformSupport_FOUND - REQUIRED_VARS - Qt5PlatformSupport_LIBRARY - Qt5PlatformSupport_INCLUDE_DIR - VERSION_VAR - Qt5PlatformSupport_VERSION -) - -if(Qt5PlatformSupport_FOUND AND NOT TARGET Qt5PlatformSupport::Qt5PlatformSupport) - add_library(Qt5PlatformSupport::Qt5PlatformSupport UNKNOWN IMPORTED) - set_target_properties(Qt5PlatformSupport::Qt5PlatformSupport PROPERTIES - IMPORTED_LOCATION "${Qt5PlatformSupport_LIBRARY}" - INTERFACE_COMPILE_OPTIONS "${Qt5PlatformSupport_DEFINITIONS}" - INTERFACE_INCLUDE_DIRECTORIES "${Qt5PlatformSupport_INCLUDE_DIR}" - ) -endif() - -mark_as_advanced(Qt5PlatformSupport_LIBRARY Qt5PlatformSupport_INCLUDE_DIR) - -# compatibility variables -set(Qt5PlatformSupport_LIBRARIES ${Qt5PlatformSupport_LIBRARY}) -set(Qt5PlatformSupport_INCLUDE_DIRS ${Qt5PlatformSupport_INCLUDE_DIR}) -set(Qt5PlatformSupport_VERSION_STRING ${Qt5PlatformSupport_VERSION}) - - -include(FeatureSummary) -set_package_properties(Qt5PlatformSupport PROPERTIES - URL "http://www.qt.io" - DESCRIPTION "Qt PlatformSupport module." -) - 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 hasApplicationMenu() const override; + bool isApplicationMenuActive() const override; + 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 @@ -30,8 +30,6 @@ #include #include -#include - namespace KWin { namespace Decoration @@ -110,6 +108,10 @@ connect(client, &AbstractClient::maximizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::maximizeableChanged); connect(client, &AbstractClient::paletteChanged, decoratedClient, &KDecoration2::DecoratedClient::paletteChanged); + + connect(client, &AbstractClient::showApplicationMenuRequested, decoratedClient, &KDecoration2::DecoratedClient::showApplicationMenu); + connect(client, &AbstractClient::hasApplicationMenuChanged, decoratedClient, &KDecoration2::DecoratedClient::hasApplicationMenuChanged); + connect(client, &AbstractClient::applicationMenuActiveChanged, decoratedClient, &KDecoration2::DecoratedClient::applicationMenuActiveChanged); } DecoratedClientImpl::~DecoratedClientImpl() = default; @@ -203,6 +205,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() +{ + decoration()->showApplicationMenu(); +} + void DecoratedClientImpl::requestToggleMaximization(Qt::MouseButtons buttons) { QMetaObject::invokeMethod(this, "delayedRequestToggleMaximization", Qt::QueuedConnection, Q_ARG(Options::WindowOperation, options->operationMaxButtonClick(buttons))); @@ -265,6 +277,16 @@ return edges; } +bool DecoratedClientImpl::hasApplicationMenu() const +{ + return m_client->hasApplicationMenu(); +} + +bool DecoratedClientImpl::isApplicationMenuActive() const +{ + return m_client->applicationMenuActive(); +} + void DecoratedClientImpl::createRenderer() { if (Compositor::self()->hasScene()) { diff --git a/events.cpp b/events.cpp --- a/events.cpp +++ b/events.cpp @@ -927,6 +927,10 @@ updateShowOnScreenEdge(); else if (e->atom == atoms->gtk_frame_extents) detectGtkFrameExtents(); + else if (e->atom == atoms->kde_net_wm_appmenu_service_name) + checkApplicationMenuServiceName(); + else if (e->atom == atoms->kde_net_wm_appmenu_object_path) + checkApplicationMenuObjectPath(); break; } } 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 hasApplicationMenu() const override { return false; } + bool isApplicationMenuActive() 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/manage.cpp b/manage.cpp --- a/manage.cpp +++ b/manage.cpp @@ -103,6 +103,9 @@ auto firstInTabBoxCookie = fetchFirstInTabBox(); auto transientCookie = fetchTransient(); auto activitiesCookie = fetchActivities(); + auto applicationMenuServiceNameCookie = fetchApplicationMenuServiceName(); + auto applicationMenuObjectPathCookie = fetchApplicationMenuObjectPath(); + m_geometryHints.init(window()); m_motif.init(window()); info = new WinInfo(this, m_client, rootWindow(), properties, properties2); @@ -387,6 +390,9 @@ readColorScheme(colorSchemeCookie); + readApplicationMenuServiceName(applicationMenuServiceNameCookie); + readApplicationMenuObjectPath(applicationMenuObjectPathCookie); + updateDecoration(false); // Also gravitates // TODO: Is CentralGravity right here, when resizing is done after gravitating? plainResize(rules()->checkSize(sizeForClientSize(geom.size()), !isMapped)); diff --git a/plugins/qpa/CMakeLists.txt b/plugins/qpa/CMakeLists.txt --- a/plugins/qpa/CMakeLists.txt +++ b/plugins/qpa/CMakeLists.txt @@ -1,5 +1,6 @@ include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS}) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) +include_directories(${Qt5PlatformSupport_PRIVATE_INCLUDE_DIRS}) add_definitions(-DQ_FONTCONFIGDATABASE) set(QPA_SOURCES @@ -22,7 +23,7 @@ target_link_libraries(KWinQpaPlugin kwin KF5::WaylandClient - Qt5PlatformSupport::Qt5PlatformSupport + Qt5::PlatformSupport ${FONTCONFIG_LIBRARIES} ${FREETYPE_LIBRARIES} ) diff --git a/shell_client.h b/shell_client.h --- a/shell_client.h +++ b/shell_client.h @@ -135,6 +135,8 @@ // TODO: const-ref void placeIn(QRect &area); + void updateApplicationMenu(); + protected: void addDamage(const QRegion &damage) override; bool belongsToSameApplication(const AbstractClient *other, bool active_hack) const override; diff --git a/shell_client.cpp b/shell_client.cpp --- a/shell_client.cpp +++ b/shell_client.cpp @@ -51,6 +51,8 @@ using namespace KWayland::Server; static const QByteArray s_schemePropertyName = QByteArrayLiteral("KDE_COLOR_SCHEME_PATH"); +static const QByteArray s_appMenuServiceNamePropertyName = QByteArrayLiteral("KDE_APPMENU_SERVICE_NAME"); +static const QByteArray s_appMenuObjectPathPropertyName = QByteArrayLiteral("KDE_APPMENU_OBJECT_PATH"); namespace KWin { @@ -246,6 +248,7 @@ } updateColorScheme(QString()); + updateApplicationMenu(); } void ShellClient::destroyClient() @@ -1162,6 +1165,10 @@ QDynamicPropertyChangeEvent *pe = static_cast(event); if (pe->propertyName() == s_schemePropertyName) { updateColorScheme(rules()->checkDecoColor(m_qtExtendedSurface->property(pe->propertyName().constData()).toString())); + } else if (pe->propertyName() == s_appMenuServiceNamePropertyName) { + updateApplicationMenuServiceName(m_qtExtendedSurface->property(pe->propertyName().constData()).toString()); + } else if (pe->propertyName() == s_appMenuObjectPathPropertyName) { + updateApplicationMenuObjectPath(m_qtExtendedSurface->property(pe->propertyName().constData()).toString()); } } return false; @@ -1383,4 +1390,12 @@ return false; } +void ShellClient::updateApplicationMenu() +{ + if (m_qtExtendedSurface) { + updateApplicationMenuServiceName(m_qtExtendedSurface->property(s_appMenuObjectPathPropertyName).toString()); + updateApplicationMenuObjectPath(m_qtExtendedSurface->property(s_appMenuServiceNamePropertyName).toString()); + } +} + } diff --git a/useractions.cpp b/useractions.cpp --- a/useractions.cpp +++ b/useractions.cpp @@ -45,6 +45,7 @@ #include "activities.h" #include #endif +#include "appmenu.h" #include @@ -1676,6 +1677,13 @@ 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); + c->setApplicationMenuActive(true); +} + /*! 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,7 @@ #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" #endif +#include "appmenu.h" #include "atoms.h" #include "client.h" #include "composite.h" @@ -128,6 +129,8 @@ // If KWin was already running it saved its configuration after loosing the selection -> Reread QFuture reparseConfigFuture = QtConcurrent::run(options, &Options::reparseConfiguration); + ApplicationMenu::create(this); + _self = this; // first initialize the extensions