From 53ae2b91e29f888422cd69d28415f3c6992c7463 Mon Sep 17 00:00:00 2001 From: Cedric Bellegarde Date: Fri, 9 Nov 2012 13:44:50 +0100 Subject: [PATCH] GUI: Kwin appmenu support: - Add support for application menu button in Kwin - Add kded appmenu configuration in kcm_style --- CMakeLists.txt | 4 ++ bridge.cpp | 16 +++++++ bridge.h | 2 + client.cpp | 30 +++++++++++++ client.h | 39 ++++++++++++++++ clients/oxygen/oxygenbutton.cpp | 20 +++++++-- clients/oxygen/oxygenbutton.h | 3 ++ clients/oxygen/oxygenclient.cpp | 5 ++- clients/oxygen/oxygenfactory.cpp | 1 + clients/oxygen/oxygenfactory.h | 1 + config-kwin.h.cmake | 1 + kcmkwin/kwindecoration/buttons.cpp | 28 +++++++++++- kcmkwin/kwindecoration/preview.cpp | 9 ++++ kcmkwin/kwindecoration/preview.h | 2 + libkdecorations/kcommondecoration.cpp | 64 +++++++++++++++++++++++++-- libkdecorations/kcommondecoration.h | 4 ++ libkdecorations/kdecoration.cpp | 11 +++++ libkdecorations/kdecoration.h | 32 +++++++++++++- libkdecorations/kdecorationbridge.h | 2 + useractions.cpp | 20 +++++++++ workspace.cpp | 49 ++++++++++++++++++++ workspace.h | 13 ++++++ 22 files changed, 344 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b341427c24..11c47b208d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ ########### configure tests ############### +INCLUDE(CMakeDependentOption) OPTION(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON) OPTION(KWIN_BUILD_OXYGEN "Enable building of default decoration Oxygen" ON) @@ -7,6 +8,7 @@ OPTION(KWIN_MOBILE_EFFECTS "Only build effects relevant for mobile devices" OFF) OPTION(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON) OPTION(KWIN_BUILD_SCREENEDGES "Enable building of KWin with screen edge support" ON) OPTION(KWIN_BUILD_SCRIPTING "Enable building of KWin with scripting support" ON) +OPTION(KWIN_BUILD_KAPPMENU "Enable building of KWin with application menu support" ON) OPTION(KWIN_BUILD_XRENDER_COMPOSITING "Enable building of KWin with XRender Compositing support" ON) OPTION(KWIN_BUILD_OPENGL_1_COMPOSITING "Enable support for OpenGL 1.x, automatically disabled when building for OpenGL ES 2.0" ON) OPTION(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON) @@ -30,6 +32,8 @@ if(KWIN_PLASMA_ACTIVE) set(KWIN_NAME "kwinactive") endif(KWIN_PLASMA_ACTIVE) +cmake_dependent_option(KWIN_BUILD_KAPPMENU "Build without appmenu support" ON "KWIN_BUILD_DECORATIONS" FALSE) + # KWIN_HAVE_XRENDER_COMPOSITING - whether XRender-based compositing support is available: may be disabled if( KWIN_BUILD_XRENDER_COMPOSITING ) set( KWIN_HAVE_XRENDER_COMPOSITING 1 ) diff --git a/bridge.cpp b/bridge.cpp index 78a1fe1d6c..d54f059287 100644 --- a/bridge.cpp +++ b/bridge.cpp @@ -113,6 +113,22 @@ void Bridge::showWindowMenu(const QRect &p) c->workspace()->showWindowMenu(p, c); } +void Bridge::showApplicationMenu(const QPoint &p) +{ +#ifdef KWIN_BUILD_KAPPMENU + c->showApplicationMenu(p); +#endif +} + +bool Bridge::menuAvailable() const +{ +#ifdef KWIN_BUILD_KAPPMENU + return c->menuAvailable(); +#else + return false; +#endif +} + void Bridge::performWindowOperation(WindowOperation op) { c->workspace()->performWindowOperation(c, op); diff --git a/bridge.h b/bridge.h index 64108e5e32..9b34fbde57 100644 --- a/bridge.h +++ b/bridge.h @@ -53,6 +53,8 @@ public: virtual void processMousePressEvent(QMouseEvent*); virtual void showWindowMenu(const QPoint &); virtual void showWindowMenu(const QRect &); + virtual void showApplicationMenu(const QPoint &); + virtual bool menuAvailable() const; virtual void performWindowOperation(WindowOperation); virtual void setMask(const QRegion&, int); virtual bool isPreview() const; diff --git a/client.cpp b/client.cpp index 8aa072f015..bff13094e7 100644 --- a/client.cpp +++ b/client.cpp @@ -26,10 +26,12 @@ along with this program. If not, see . #include #include #include + #ifdef KWIN_BUILD_SCRIPTING #include #include #endif + #include #include #include @@ -133,6 +135,9 @@ Client::Client(Workspace* ws) , electricMaximizing(false) , activitiesDefined(false) , needsSessionInteract(false) +#ifdef KWIN_BUILD_KAPPMENU + , m_menuAvailable(false) +#endif , input_window(None) { // TODO: Do all as initialization @@ -405,6 +410,12 @@ void Client::updateDecoration(bool check_workspace_pos, bool force) if (!noBorder()) { setMask(QRegion()); // Reset shape mask decoration = workspace()->createDecoration(bridge); +#ifdef KWIN_BUILD_KAPPMENU + connect(this, SIGNAL(showRequest()), decoration, SIGNAL(showRequest())); + connect(this, SIGNAL(appMenuAvailable()), decoration, SIGNAL(appMenuAvailable())); + connect(this, SIGNAL(appMenuUnavailable()), decoration, SIGNAL(appMenuUnavailable())); + connect(this, SIGNAL(menuHidden()), decoration, SIGNAL(menuHidden())); +#endif // TODO: Check decoration's minimum size? decoration->init(); decoration->widget()->installEventFilter(this); @@ -2401,6 +2412,25 @@ bool Client::isClient() const return true; } +#ifdef KWIN_BUILD_KAPPMENU +void Client::setAppMenuAvailable() +{ + m_menuAvailable = true; + emit appMenuAvailable(); +} + +void Client::setAppMenuUnavailable() +{ + m_menuAvailable = false; + emit appMenuUnavailable(); +} + +void Client::showApplicationMenu(const QPoint &p) +{ + workspace()->showApplicationMenu(p, window()); +} +#endif + NET::WindowType Client::windowType(bool direct, int supportedTypes) const { // TODO: does it make sense to cache the returned window type for SUPPORTED_MANAGED_WINDOW_TYPES_MASK? diff --git a/client.h b/client.h index ced58d7c38..51419b9693 100644 --- a/client.h +++ b/client.h @@ -24,6 +24,8 @@ along with this program. If not, see . #include +#include "config-kwin.h" + #include #include #include @@ -634,6 +636,22 @@ public: void setSessionInteract(bool needed); virtual bool isClient() const; +#ifdef KWIN_BUILD_KAPPMENU + // Used by workspace + void emitShowRequest() { + emit showRequest(); + } + void emitMenuHidden() { + emit menuHidden(); + } + void setAppMenuAvailable(); + void setAppMenuUnavailable(); + void showApplicationMenu(const QPoint&); + bool menuAvailable() { + return m_menuAvailable; + } +#endif + public slots: void closeWindow(); @@ -723,6 +741,24 @@ signals: * another group, but not when a Client gets added or removed to the Client's ClientGroup. **/ void tabGroupChanged(); + + /** + * Emitted whenever the Client want to show it menu + */ + void showRequest(); + /** + * Emitted whenever the Client's menu is closed + */ + void menuHidden(); + /** + * Emitted whenever the Client's menu is available + **/ + void appMenuAvailable(); + /** + * Emitted whenever the Client's menu is unavailable + */ + void appMenuUnavailable(); + /** * Emitted whenever the demands attention state changes. **/ @@ -952,6 +988,9 @@ private: bool needsSessionInteract; +#ifdef KWIN_BUILD_KAPPMENU + bool m_menuAvailable; +#endif Window input_window; QPoint input_offset; }; diff --git a/clients/oxygen/oxygenbutton.cpp b/clients/oxygen/oxygenbutton.cpp index 28aa8b191a..ee523fa815 100644 --- a/clients/oxygen/oxygenbutton.cpp +++ b/clients/oxygen/oxygenbutton.cpp @@ -215,9 +215,11 @@ namespace Oxygen //___________________________________________________ void Button::mouseReleaseEvent( QMouseEvent* event ) { - - _status &= ~Pressed; - parentUpdate(); + if (_type != ButtonApplicationMenu) + { + _status &= ~Pressed; + parentUpdate(); + } KCommonDecorationButton::mouseReleaseEvent( event ); } @@ -338,6 +340,12 @@ namespace Oxygen painter->translate(-1.5, -1.5); break; + case ButtonApplicationMenu: + painter->drawLine(QPointF(7.5, 7.5), QPointF(13.5, 7.5)); + painter->drawLine(QPointF(7.5, 10.5), QPointF(13.5, 10.5)); + painter->drawLine(QPointF(7.5, 13.5), QPointF(13.5, 13.5)); + break; + case ButtonMin: painter->drawLine(QPointF( 7.5, 9.5), QPointF(10.5,12.5)); painter->drawLine(QPointF(10.5,12.5), QPointF(13.5, 9.5)); @@ -410,4 +418,10 @@ namespace Oxygen return; } + void Button::slotAppMenuHidden() + { + _status = Normal; + update(); + } + } diff --git a/clients/oxygen/oxygenbutton.h b/clients/oxygen/oxygenbutton.h index ea11717134..06259ea0c7 100644 --- a/clients/oxygen/oxygenbutton.h +++ b/clients/oxygen/oxygenbutton.h @@ -173,6 +173,9 @@ namespace Oxygen //@} + private slots: + void slotAppMenuHidden(); + private: //! parent client diff --git a/clients/oxygen/oxygenclient.cpp b/clients/oxygen/oxygenclient.cpp index 05e786ee83..4cd500642f 100644 --- a/clients/oxygen/oxygenclient.cpp +++ b/clients/oxygen/oxygenclient.cpp @@ -212,7 +212,10 @@ namespace Oxygen switch (type) { case MenuButton: - return new Button(*this, i18n("Menu"), ButtonMenu); + return new Button(*this, i18n("Window Actions Menu"), ButtonMenu); + + case AppMenuButton: + return new Button(*this, i18n("Application Menu"), ButtonApplicationMenu); case HelpButton: return new Button(*this, i18n("Help"), ButtonHelp); diff --git a/clients/oxygen/oxygenfactory.cpp b/clients/oxygen/oxygenfactory.cpp index 73d3ac780d..4e2505be23 100644 --- a/clients/oxygen/oxygenfactory.cpp +++ b/clients/oxygen/oxygenfactory.cpp @@ -144,6 +144,7 @@ namespace Oxygen // buttons case AbilityButtonMenu: + case AbilityButtonApplicationMenu: case AbilityButtonHelp: case AbilityButtonMinimize: case AbilityButtonMaximize: diff --git a/clients/oxygen/oxygenfactory.h b/clients/oxygen/oxygenfactory.h index b38b097b72..5026063486 100644 --- a/clients/oxygen/oxygenfactory.h +++ b/clients/oxygen/oxygenfactory.h @@ -52,6 +52,7 @@ namespace Oxygen ButtonAbove, ButtonBelow, ButtonShade, + ButtonApplicationMenu, ButtonTypeCount, // Close only one tab diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake index c48f569e6f..e33548846d 100644 --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -3,6 +3,7 @@ #cmakedefine KWIN_BUILD_DESKTOPCHANGEOSD 1 #cmakedefine KWIN_BUILD_SCREENEDGES 1 #cmakedefine KWIN_BUILD_SCRIPTING 1 +#cmakedefine KWIN_BUILD_KAPPMENU 1 #cmakedefine KWIN_BUILD_ACTIVITIES 1 #cmakedefine KWIN_BUILD_OXYGEN 1 #define KWIN_NAME "${KWIN_NAME}" diff --git a/kcmkwin/kwindecoration/buttons.cpp b/kcmkwin/kwindecoration/buttons.cpp index 2d12244b79..a4ebf9e8c7 100644 --- a/kcmkwin/kwindecoration/buttons.cpp +++ b/kcmkwin/kwindecoration/buttons.cpp @@ -31,6 +31,7 @@ #include "buttons.h" #include "pixmaps.h" +#include "config-kwin.h" #include #include @@ -42,6 +43,11 @@ #include #include +#ifdef KWIN_BUILD_KAPPMENU +#include +#include +#endif + #include @@ -680,7 +686,19 @@ ButtonPositionWidget::ButtonPositionWidget(QWidget *parent) // insert all possible buttons into the source (backwards to keep the preferred order...) bool dummy; - m_supportedButtons = "MSHIAX_FBLR"; // support all buttons + + m_supportedButtons = "MSHIAX_FBLR"; +#ifdef KWIN_BUILD_KAPPMENU + KConfig config("kdeglobals", KConfig::FullConfig); + KConfigGroup configGroup = config.group("Appmenu Style"); + QString style = configGroup.readEntry("Style", "InApplication"); + + if (style == "ButtonVertical") { + m_supportedButtons = "MNSHIAX_FBLR"; // support all buttons + new ButtonSourceItem(m_buttonSource, getButton('N', dummy)); + } +#endif + new ButtonSourceItem(m_buttonSource, getButton('R', dummy)); new ButtonSourceItem(m_buttonSource, getButton('L', dummy)); new ButtonSourceItem(m_buttonSource, getButton('B', dummy)); @@ -741,7 +759,13 @@ Button ButtonPositionWidget::getButton(QChar type, bool& success) } else if (type == 'M') { QBitmap bmp = QBitmap::fromData(QSize(menu_width, menu_height), menu_bits); bmp.createMaskFromColor(Qt::white); - return Button(i18n("Menu"), bmp, 'M', false, m_supportedButtons.contains('M')); + return Button(i18nc("Button showing window actions menu", "Window Menu"), bmp, 'M', false, m_supportedButtons.contains('M')); +#ifdef KWIN_BUILD_KAPPMENU + } else if (type == 'N') { + QBitmap bmp = QBitmap::fromData(QSize(menu_width, menu_height), menu_bits); + bmp.createMaskFromColor(Qt::white); + return Button(i18nc("Button showing application menu imported from dbusmenu", "Application Menu"), bmp, 'N', false, m_supportedButtons.contains('N')); +#endif } else if (type == '_') { QBitmap bmp = QBitmap::fromData(QSize(spacer_width, spacer_height), spacer_bits); bmp.createMaskFromColor(Qt::white); diff --git a/kcmkwin/kwindecoration/preview.cpp b/kcmkwin/kwindecoration/preview.cpp index 587df7c5b7..0b19986419 100644 --- a/kcmkwin/kwindecoration/preview.cpp +++ b/kcmkwin/kwindecoration/preview.cpp @@ -385,6 +385,15 @@ void KDecorationPreviewBridge::showWindowMenu(const QPoint &) { } +void KDecorationPreviewBridge::showApplicationMenu(const QPoint &) +{ +} + +bool KDecorationPreviewBridge::menuAvailable() const +{ + return false; +} + void KDecorationPreviewBridge::performWindowOperation(WindowOperation) { } diff --git a/kcmkwin/kwindecoration/preview.h b/kcmkwin/kwindecoration/preview.h index 52645fd767..72cf7c1448 100644 --- a/kcmkwin/kwindecoration/preview.h +++ b/kcmkwin/kwindecoration/preview.h @@ -95,6 +95,8 @@ public: virtual void processMousePressEvent(QMouseEvent*); virtual void showWindowMenu(const QRect &); virtual void showWindowMenu(const QPoint &); + virtual void showApplicationMenu(const QPoint &); + virtual bool menuAvailable() const; virtual void performWindowOperation(WindowOperation); virtual void setMask(const QRegion&, int); virtual bool isPreview() const; diff --git a/libkdecorations/kcommondecoration.cpp b/libkdecorations/kcommondecoration.cpp index 9f30c8d320..31bf397579 100644 --- a/libkdecorations/kcommondecoration.cpp +++ b/libkdecorations/kcommondecoration.cpp @@ -377,7 +377,7 @@ void KCommonDecoration::addButtons(ButtonContainer &btnContainer, const QString& if (!m_button[MenuButton]) { btn = createButton(MenuButton); if (!btn) break; - btn->setTipText(i18n("Menu")); + btn->setTipText(i18nc("Button showing window actions menu", "Window Menu")); btn->setRealizeButtons(Qt::LeftButton | Qt::RightButton); connect(btn, SIGNAL(pressed()), SLOT(menuButtonPressed())); connect(btn, SIGNAL(released()), this, SLOT(menuButtonReleased())); @@ -388,6 +388,27 @@ void KCommonDecoration::addButtons(ButtonContainer &btnContainer, const QString& m_button[MenuButton] = btn; } break; + case 'N': // Application Menu button + if (!m_button[AppMenuButton]) { + btn = createButton(AppMenuButton); + if (!btn) break; + btn->setTipText(i18nc("Button showing application menu", "Application Menu")); + btn->setRealizeButtons(Qt::LeftButton); + connect(btn, SIGNAL(pressed()), SLOT(appMenuButtonPressed())); + // Application want to show it menu + connect(decoration(), SIGNAL(showRequest()), this, SLOT(appMenuButtonPressed()), Qt::UniqueConnection); + // Wait for menu to become available before displaying any button + connect(decoration(), SIGNAL(appMenuAvailable()), this, SLOT(slotAppMenuAvailable()), Qt::UniqueConnection); + // On Kded module shutdown, hide application menu button + connect(decoration(), SIGNAL(appMenuUnavailable()), this, SLOT(slotAppMenuUnavailable()), Qt::UniqueConnection); + // Application menu button may need to be modified on this signal + connect(decoration(), SIGNAL(menuHidden()), btn, SLOT(slotAppMenuHidden()), Qt::UniqueConnection); + + // fix double deletion, see objDestroyed() + connect(btn, SIGNAL(destroyed(QObject*)), this, SLOT(objDestroyed(QObject*))); + m_button[AppMenuButton] = btn; + } + break; case 'S': // OnAllDesktops button if (!m_button[OnAllDesktopsButton]) { btn = createButton(OnAllDesktopsButton); @@ -516,7 +537,13 @@ void KCommonDecoration::addButtons(ButtonContainer &btnContainer, const QString& if (btn) { btn->setLeft(isLeft); btn->setSize(QSize(layoutMetric(LM_ButtonWidth, true, btn), layoutMetric(LM_ButtonHeight, true, btn))); - btn->show(); + // will be shown later on window registration + if (btn->type() == AppMenuButton && !wrapper->menuAvailable()) { + btn->hide(); + } else { + btn->show(); + } + btnContainer.append(btn); } @@ -532,7 +559,7 @@ void KCommonDecoration::calcHiddenButtons() btnHideLastWidth = width(); //Hide buttons in the following order: - KCommonDecorationButton* btnArray[] = { m_button[HelpButton], m_button[ShadeButton], m_button[BelowButton], + KCommonDecorationButton* btnArray[] = { m_button[HelpButton], m_button[AppMenuButton], m_button[ShadeButton], m_button[BelowButton], m_button[AboveButton], m_button[OnAllDesktopsButton], m_button[MaxButton], m_button[MinButton], m_button[MenuButton], m_button[CloseButton] }; @@ -557,7 +584,8 @@ void KCommonDecoration::calcHiddenButtons() if (! btnArray[i]->isHidden()) break; // all buttons shown... - btnArray[i]->show(); + if (btnArray[i]->type() != AppMenuButton || wrapper->menuAvailable()) + btnArray[i]->show(); } } } @@ -755,6 +783,34 @@ void KCommonDecoration::doShowWindowMenu() showWindowMenu(QRect(menutop, menubottom)); } + +void KCommonDecoration::appMenuButtonPressed() +{ + QRect menuRect = m_button[AppMenuButton]->rect(); + wrapper->showApplicationMenu(m_button[AppMenuButton]->mapToGlobal(menuRect.bottomLeft())); + + KDecorationFactory* f = factory(); + if (!f->exists(decoration())) // 'this' was deleted + return; + m_button[AppMenuButton]->setDown(false); +} + +void KCommonDecoration::slotAppMenuAvailable() +{ + if (m_button[AppMenuButton]) { + m_button[AppMenuButton]->show(); + updateLayout(); + } +} + +void KCommonDecoration::slotAppMenuUnavailable() +{ + if (m_button[AppMenuButton]) { + m_button[AppMenuButton]->hide(); + updateLayout(); + } +} + void KCommonDecoration::resizeEvent(QResizeEvent */*e*/) { if (decorationBehaviour(DB_ButtonHide)) diff --git a/libkdecorations/kcommondecoration.h b/libkdecorations/kcommondecoration.h index 97bdfff095..6919f292c4 100644 --- a/libkdecorations/kcommondecoration.h +++ b/libkdecorations/kcommondecoration.h @@ -44,6 +44,7 @@ enum ButtonType { AboveButton, BelowButton, ShadeButton, + AppMenuButton, NumButtons, ItemCloseButton = 100, // Close only one tab ItemMenuButton // shows the window menu for one tab @@ -274,6 +275,9 @@ public Q_SLOTS: void slotKeepBelow(); void menuButtonPressed(); void menuButtonReleased(); + void appMenuButtonPressed(); + void slotAppMenuAvailable(); + void slotAppMenuUnavailable(); public: virtual Position mousePosition(const QPoint &point) const; diff --git a/libkdecorations/kdecoration.cpp b/libkdecorations/kdecoration.cpp index 125d6c82da..505824f5a9 100644 --- a/libkdecorations/kdecoration.cpp +++ b/libkdecorations/kdecoration.cpp @@ -38,6 +38,7 @@ DEALINGS IN THE SOFTWARE. #include "kdecorationfactory.h" #include "kdecorationbridge.h" + /* Extending KDecoration: @@ -222,6 +223,16 @@ void KDecoration::showWindowMenu(QPoint pos) bridge_->showWindowMenu(pos); } +void KDecoration::showApplicationMenu(const QPoint &p) +{ + bridge_->showApplicationMenu(p); +} + +bool KDecoration::menuAvailable() const +{ + return bridge_->menuAvailable(); +} + void KDecoration::performWindowOperation(WindowOperation op) { bridge_->performWindowOperation(op); diff --git a/libkdecorations/kdecoration.h b/libkdecorations/kdecoration.h index aefa91fe27..2e156744fd 100644 --- a/libkdecorations/kdecoration.h +++ b/libkdecorations/kdecoration.h @@ -188,7 +188,7 @@ public: AbilityAnnounceButtons = 0, ///< decoration supports AbilityButton* values (always use) AbilityAnnounceColors = 1, ///< decoration supports AbilityColor* values (always use), @deprecated @todo remove KDE5 // buttons - AbilityButtonMenu = 1000, ///< decoration supports the menu button + AbilityButtonMenu = 1000, ///< decoration supports the window menu button AbilityButtonOnAllDesktops = 1001, ///< decoration supports the on all desktops button AbilityButtonSpacer = 1002, ///< decoration supports inserting spacers between buttons AbilityButtonHelp = 1003, ///< decoration supports what's this help button @@ -199,6 +199,7 @@ public: AbilityButtonBelowOthers = 1008, ///< decoration supports a below button AbilityButtonShade = 1009, ///< decoration supports a shade button AbilityButtonResize = 1010, ///< decoration supports a resize button + AbilityButtonApplicationMenu = 1011, ///< decoration supports the application menu button // colors AbilityColorTitleBack = 2000, ///< decoration supports titlebar background color, @deprecated @todo remove KDE5 ABILITYCOLOR_FIRST = AbilityColorTitleBack, ///< @internal, @deprecated @todo remove KDE5 @@ -354,7 +355,8 @@ public: * If customButtonPositions() returns true, titleButtonsLeft * returns which buttons should be on the left side of the titlebar from left * to right. Characters in the returned string have this meaning : - * @li 'M' menu button + * @li 'N' application menu button + * @li 'M' window menu button * @li 'S' on_all_desktops button * @li 'H' quickhelp button * @li 'I' minimize ( iconify ) button @@ -623,6 +625,14 @@ public: * Overloaded version of the above. */ void showWindowMenu(QPoint pos); + /** + * show application menu at p + */ + void showApplicationMenu(const QPoint& p); + /** + * Returns @a true if menu available for client + */ + bool menuAvailable() const; /** * This function performs the given window operation. This function may destroy * the current decoration object, just like showWindowMenu(). @@ -808,6 +818,24 @@ Q_SIGNALS: */ void keepBelowChanged(bool); + /** + * This signal is emitted whenever application menu is closed + * Application menu button may need to be modified on this signal + */ + void menuHidden(); + /** + * This signal is emitted whenever application want to show it menu + */ + void showRequest(); + /** + * This signal is emitted whenever application menu becomes available + */ + void appMenuAvailable(); + /** + * This signal is emitted whenever application menu becomes unavailable + */ + void appMenuUnavailable(); + /** * This signal is emitted whenever the decoration changes it's alpha enabled * change. Only relevant in case the decoration provides AbilityAnnounceAlphaChannel. diff --git a/libkdecorations/kdecorationbridge.h b/libkdecorations/kdecorationbridge.h index b7d061997d..2cb36c9e65 100644 --- a/libkdecorations/kdecorationbridge.h +++ b/libkdecorations/kdecorationbridge.h @@ -65,6 +65,8 @@ public: virtual void processMousePressEvent(QMouseEvent*) = 0; virtual void showWindowMenu(const QRect &) = 0; virtual void showWindowMenu(const QPoint &) = 0; + virtual void showApplicationMenu(const QPoint&) = 0; + virtual bool menuAvailable() const = 0; virtual void performWindowOperation(WindowOperation) = 0; virtual void setMask(const QRegion&, int) = 0; virtual bool isPreview() const = 0; diff --git a/useractions.cpp b/useractions.cpp index 8fcdba2e3d..7ce01b005b 100755 --- a/useractions.cpp +++ b/useractions.cpp @@ -73,9 +73,21 @@ along with this program. If not, see . #include "tabbox.h" #endif +#ifdef KWIN_BUILD_KAPPMENU +#include +#include +#include +#endif + namespace KWin { +#ifdef KWIN_BUILD_KAPPMENU +static const char *KDED_SERVICE = "org.kde.kded"; +static const char *KDED_APPMENU_PATH = "/modules/appmenu"; +static const char *KDED_INTERFACE = "org.kde.kded"; +#endif + UserActionsMenu::UserActionsMenu(QObject *parent) : QObject(parent) , m_menu(NULL) @@ -1231,6 +1243,14 @@ void Workspace::showWindowMenuAt(unsigned long, int, int) slotWindowOperations(); } +void Workspace::showApplicationMenu(const QPoint &p, const WId id) +{ + QList args = QList() << p.x() << p.y() << qulonglong(id); + QDBusMessage method = QDBusMessage::createMethodCall(KDED_SERVICE, KDED_APPMENU_PATH, KDED_INTERFACE, "showMenu"); + method.setArguments(args); + QDBusConnection::sessionBus().asyncCall(method); +} + void Workspace::slotActivateAttentionWindow() { if (attention_chain.count() > 0) diff --git a/workspace.cpp b/workspace.cpp index 5983d0b61c..5e5bd7bb97 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -83,6 +83,12 @@ namespace KWin extern int screen_number; static const int KWIN_MAX_NUMBER_DESKTOPS = 20; +#ifdef KWIN_BUILD_KAPPMENU +static const char *KDED_SERVICE = "org.kde.kded"; +static const char *KDED_APPMENU_PATH = "/modules/appmenu"; +static const char *KDED_INTERFACE = "org.kde.kded"; +#endif + Workspace* Workspace::_self = 0; //----------------------------------------------------------------------------- @@ -148,6 +154,18 @@ Workspace::Workspace(bool restore) // 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 + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.connect(KDED_SERVICE, KDED_APPMENU_PATH, KDED_INTERFACE, "showRequest", + this, SLOT(slotShowRequest(qulonglong))); + dbus.connect(KDED_SERVICE, KDED_APPMENU_PATH, KDED_INTERFACE, "menuAvailable", + this, SLOT(slotMenuAvailable(qulonglong))); + dbus.connect(KDED_SERVICE, KDED_APPMENU_PATH, KDED_INTERFACE, "menuHidden", + this, SLOT(slotMenuHidden(qulonglong))); + dbus.connect(KDED_SERVICE, KDED_APPMENU_PATH, KDED_INTERFACE, "clearMenus", + this, SLOT(slotClearMenus())); +#endif + // Initialize desktop grid array desktopGrid_[0] = 0; desktopGrid_[1] = 0; @@ -622,6 +640,10 @@ void Workspace::addClient(Client* c, allowed_t) if (tabBox()->isDisplayed()) tab_box->reset(true); #endif +#ifdef KWIN_BUILD_KAPPMENU + if (m_windowsMenu.removeOne(c->window())) + c->setAppMenuAvailable(); +#endif } void Workspace::addUnmanaged(Unmanaged* c, allowed_t) @@ -918,7 +940,34 @@ void Workspace::slotReloadConfig() { reconfigure(); } +#ifdef KWIN_BUILD_KAPPMENU +void Workspace::slotShowRequest(qulonglong wid) +{ + if (Client *c = findClient(WindowMatchPredicate(wid))) + c->emitShowRequest(); +} +void Workspace::slotMenuAvailable(qulonglong wid) +{ + if (Client *c = findClient(WindowMatchPredicate(wid))) + c->setAppMenuAvailable(); + else + m_windowsMenu.append(wid); +} + +void Workspace::slotMenuHidden(qulonglong wid) +{ + if (Client *c = findClient(WindowMatchPredicate(wid))) + c->emitMenuHidden(); +} + +void Workspace::slotClearMenus() +{ + foreach (Client *c, clients) { + c->setAppMenuUnavailable(); + } +} +#endif void Workspace::reconfigure() { reconfigureTimer.start(200); diff --git a/workspace.h b/workspace.h index d0f6f9bfd6..efe9a63467 100644 --- a/workspace.h +++ b/workspace.h @@ -419,6 +419,8 @@ public: return m_userActionsMenu; } + void showApplicationMenu(const QPoint &, const WId); + void updateMinimizedOfTransients(Client*); void updateOnAllDesktopsOfTransients(Client*); void updateOnAllActivitiesOfTransients(Client*); @@ -625,6 +627,12 @@ private slots: void writeWindowRules(); void slotBlockShortcuts(int data); void slotReloadConfig(); +#ifdef KWIN_BUILD_KAPPMENU + void slotShowRequest(qulonglong wid); + void slotMenuAvailable(qulonglong wid); + void slotMenuHidden(qulonglong wid); + void slotClearMenus(); +#endif void resetCursorPosTime(); void updateCurrentActivity(const QString &new_activity); void slotActivityRemoved(const QString &activity); @@ -852,6 +860,11 @@ private: QSlider* transSlider; QPushButton* transButton; +#ifdef KWIN_BUILD_KAPPMENU + //used for menu available before window is mapped + QList m_windowsMenu; +#endif + Scripting *m_scripting; private: