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: