diff --git a/kcontrol/style/finetuning.ui b/kcontrol/style/finetuning.ui index 2d384bc..e740b3c 100644 --- a/kcontrol/style/finetuning.ui +++ b/kcontrol/style/finetuning.ui @@ -173,7 +173,66 @@ - + + + + Menubar + + + + + + Menubar style: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + comboMenubarStyle + + + + + + + + In application + + + + + Title bar button + + + + + Top screen menubar + + + + + Only export + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical diff --git a/kcontrol/style/kcmstyle.cpp b/kcontrol/style/kcmstyle.cpp index 849a49b..3ab3ac3 100644 --- a/kcontrol/style/kcmstyle.cpp +++ b/kcontrol/style/kcmstyle.cpp @@ -259,6 +259,7 @@ KCMStyle::KCMStyle( QWidget* parent, const QVariantList& ) connect(fineTuningUi.comboGraphicEffectsLevel, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); connect(fineTuningUi.comboToolbarIcons, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); connect(fineTuningUi.comboSecondaryToolbarIcons, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); + connect(fineTuningUi.comboMenubarStyle, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); addWhatsThis(); @@ -400,8 +401,34 @@ void KCMStyle::save() toolbarButtonText(fineTuningUi.comboToolbarIcons->currentIndex())); toolbarStyleGroup.writeEntry("ToolButtonStyleOtherToolbars", toolbarButtonText(fineTuningUi.comboSecondaryToolbarIcons->currentIndex())); + + KConfigGroup menuBarStyleGroup(&_config, "Menubar style"); + + // load kded module if needed + bool load = true; + QString style = menuBarStyleText(fineTuningUi.comboMenubarStyle->currentIndex()); + + menuBarStyleGroup.writeEntry("MenuBarStyle", style); _config.sync(); + QDBusMessage method = QDBusMessage::createMethodCall("org.kde.kded", "/modules/appmenu", "org.kde.kded", "reconfigure"); + QDBusConnection::sessionBus().asyncCall(method); + + if (style == "InApplication") + load = false; + QList args = QList() << "appmenu" << load; + method = QDBusMessage::createMethodCall("org.kde.kded", "/kded", "org.kde.kded", "setModuleAutoloading"); + method.setArguments(args); + QDBusConnection::sessionBus().asyncCall(method); + + args = QList() << "appmenu"; + if (load) + method = QDBusMessage::createMethodCall("org.kde.kded", "/kded", "org.kde.kded", "loadModule"); + else + method = QDBusMessage::createMethodCall("org.kde.kded", "/kded", "org.kde.kded", "unloadModule"); + method.setArguments(args); + QDBusConnection::sessionBus().asyncCall(method); + // Export the changes we made to qtrc, and update all qt-only // applications on the fly, ensuring that we still follow the user's // export fonts/colors settings. @@ -487,6 +514,7 @@ void KCMStyle::defaults() // Effects fineTuningUi.comboToolbarIcons->setCurrentIndex(toolbarButtonIndex("TextBesideIcon")); fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex("TextBesideIcon")); + fineTuningUi.comboMenubarStyle->setCurrentIndex(menuBarStyleIndex("InApplication")); fineTuningUi.cbIconsOnButtons->setChecked(true); fineTuningUi.cbIconsInMenus->setChecked(true); fineTuningUi.comboGraphicEffectsLevel->setCurrentIndex(fineTuningUi.comboGraphicEffectsLevel->findData(((int) KGlobalSettings::graphicEffectsLevelDefault()))); @@ -708,6 +736,33 @@ int KCMStyle::toolbarButtonIndex(const QString &text) return 0; } +QString KCMStyle::menuBarStyleText(int index) +{ + switch (index) { + case 1: + return "ButtonVertical"; + case 2: + return "TopHorizontal"; + case 3: + return "Others"; + } + + return "InApplication"; +} + +int KCMStyle::menuBarStyleIndex(const QString &text) +{ + if (text == "ButtonVertical") { + return 1; + } else if (text == "TopHorizontal") { + return 2; + } else if (text == "Others") { + return 3; + } + + return 0; +} + void KCMStyle::loadEffects( KConfig& config ) { // KDE's Part via KConfig @@ -718,6 +773,10 @@ void KCMStyle::loadEffects( KConfig& config ) tbIcon = configGroup.readEntry("ToolButtonStyleOtherToolbars", "TextBesideIcon"); fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex(tbIcon)); + configGroup = config.group("Menubar style"); + QString menuBarStyle = configGroup.readEntry("MenuBarStyle", "InApplication"); + fineTuningUi.comboMenubarStyle->setCurrentIndex(menuBarStyleIndex(menuBarStyle)); + configGroup = config.group("KDE"); fineTuningUi.cbIconsOnButtons->setChecked(configGroup.readEntry("ShowIconsOnPushButtons", true)); fineTuningUi.cbIconsInMenus->setChecked(configGroup.readEntry("ShowIconsInMenuItems", true)); diff --git a/kcontrol/style/kcmstyle.h b/kcontrol/style/kcmstyle.h index cd1472f..9938915 100644 --- a/kcontrol/style/kcmstyle.h +++ b/kcontrol/style/kcmstyle.h @@ -89,6 +89,8 @@ private: QString currentStyle(); static QString toolbarButtonText(int index); static int toolbarButtonIndex(const QString &text); + static QString menuBarStyleText(int index); + static int menuBarStyleIndex(const QString &text); bool m_bStyleDirty, m_bEffectsDirty; QHash styleEntries; diff --git a/kwin/CMakeLists.txt b/kwin/CMakeLists.txt index ce69e84..3d520af 100644 --- a/kwin/CMakeLists.txt +++ b/kwin/CMakeLists.txt @@ -1,4 +1,5 @@ ########### configure tests ############### +INCLUDE(CMakeDependentOption) OPTION(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON) OPTION(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON) @@ -6,6 +7,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_ACTIVITIES "Enable building of KWin with kactivities support" ON) if(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop") @@ -28,6 +30,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/kwin/bridge.cpp b/kwin/bridge.cpp index 32d4c84..6a537ef 100644 --- a/kwin/bridge.cpp +++ b/kwin/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/kwin/bridge.h b/kwin/bridge.h index 64108e5..9b34fbd 100644 --- a/kwin/bridge.h +++ b/kwin/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/kwin/client.cpp b/kwin/client.cpp index c541595..0978086 100644 --- a/kwin/client.cpp +++ b/kwin/client.cpp @@ -26,6 +26,7 @@ along with this program. If not, see . #include #include #include + #include #include #include @@ -129,6 +130,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 @@ -397,6 +401,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); @@ -2483,6 +2493,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 + } // namespace #include "client.moc" diff --git a/kwin/client.h b/kwin/client.h index f31707b..65963ea 100644 --- a/kwin/client.h +++ b/kwin/client.h @@ -24,6 +24,8 @@ along with this program. If not, see . #include +#include "config-kwin.h" + #include #include #include @@ -640,6 +642,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(); @@ -729,6 +747,26 @@ signals: * another group, but not when a Client gets added or removed to the Client's ClientGroup. **/ void tabGroupChanged(); + +#ifdef KWIN_BUILD_KAPPMENU + /** + * 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(); +#endif + /** * Emitted whenever the demands attention state changes. **/ @@ -963,6 +1001,9 @@ private: bool needsSessionInteract; +#ifdef KWIN_BUILD_KAPPMENU + bool m_menuAvailable; +#endif Window input_window; QPoint input_offset; }; diff --git a/kwin/clients/oxygen/oxygenbutton.cpp b/kwin/clients/oxygen/oxygenbutton.cpp index 28aa8b1..ee523fa 100644 --- a/kwin/clients/oxygen/oxygenbutton.cpp +++ b/kwin/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/kwin/clients/oxygen/oxygenbutton.h b/kwin/clients/oxygen/oxygenbutton.h index ea11717..06259ea 100644 --- a/kwin/clients/oxygen/oxygenbutton.h +++ b/kwin/clients/oxygen/oxygenbutton.h @@ -173,6 +173,9 @@ namespace Oxygen //@} + private slots: + void slotAppMenuHidden(); + private: //! parent client diff --git a/kwin/clients/oxygen/oxygenclient.cpp b/kwin/clients/oxygen/oxygenclient.cpp index 5fbb4fb..76cdce9 100644 --- a/kwin/clients/oxygen/oxygenclient.cpp +++ b/kwin/clients/oxygen/oxygenclient.cpp @@ -210,7 +210,10 @@ namespace Oxygen switch (type) { case MenuButton: - return new Button(*this, i18n("Menu"), ButtonMenu); + return new Button(*this, i18n("Window Menu"), ButtonMenu); + + case AppMenuButton: + return new Button(*this, i18n("Application Menu"), ButtonApplicationMenu); case HelpButton: return new Button(*this, i18n("Help"), ButtonHelp); diff --git a/kwin/clients/oxygen/oxygenfactory.cpp b/kwin/clients/oxygen/oxygenfactory.cpp index 5502a6a..1d04f59 100644 --- a/kwin/clients/oxygen/oxygenfactory.cpp +++ b/kwin/clients/oxygen/oxygenfactory.cpp @@ -144,6 +144,9 @@ namespace Oxygen // buttons case AbilityButtonMenu: +#ifdef KWIN_BUILD_KAPPMENU + case AbilityButtonApplicationMenu: +#endif case AbilityButtonHelp: case AbilityButtonMinimize: case AbilityButtonMaximize: diff --git a/kwin/clients/oxygen/oxygenfactory.h b/kwin/clients/oxygen/oxygenfactory.h index b38b097..5026063 100644 --- a/kwin/clients/oxygen/oxygenfactory.h +++ b/kwin/clients/oxygen/oxygenfactory.h @@ -52,6 +52,7 @@ namespace Oxygen ButtonAbove, ButtonBelow, ButtonShade, + ButtonApplicationMenu, ButtonTypeCount, // Close only one tab diff --git a/kwin/config-kwin.h.cmake b/kwin/config-kwin.h.cmake index e5ed2a6..0eafe35 100644 --- a/kwin/config-kwin.h.cmake +++ b/kwin/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 #define KWIN_NAME "${KWIN_NAME}" #define KWIN_CONFIG "${KWIN_NAME}rc" diff --git a/kwin/kcmkwin/kwindecoration/buttons.cpp b/kwin/kcmkwin/kwindecoration/buttons.cpp index 2d12244..0153e0f 100644 --- a/kwin/kcmkwin/kwindecoration/buttons.cpp +++ b/kwin/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,22 @@ 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 + +#ifdef KWIN_BUILD_KAPPMENU + KConfig config("kdeglobals", KConfig::FullConfig); + KConfigGroup configGroup = config.group("Menubar style"); + QString style = configGroup.readEntry("MenuBarStyle", "InApplication"); + + if (style == "ButtonVertical") { + m_supportedButtons = "MNSHIAX_FBLR"; // support all buttons + new ButtonSourceItem(m_buttonSource, getButton('N', dummy)); + } else { +#endif + m_supportedButtons = "MSHIAX_FBLR"; +#ifdef KWIN_BUILD_KAPPMENU + } +#endif + new ButtonSourceItem(m_buttonSource, getButton('R', dummy)); new ButtonSourceItem(m_buttonSource, getButton('L', dummy)); new ButtonSourceItem(m_buttonSource, getButton('B', dummy)); @@ -741,7 +762,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/kwin/kcmkwin/kwindecoration/preview.cpp b/kwin/kcmkwin/kwindecoration/preview.cpp index 587df7c..0b19986 100644 --- a/kwin/kcmkwin/kwindecoration/preview.cpp +++ b/kwin/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/kwin/kcmkwin/kwindecoration/preview.h b/kwin/kcmkwin/kwindecoration/preview.h index 52645fd..72cf7c1 100644 --- a/kwin/kcmkwin/kwindecoration/preview.h +++ b/kwin/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/kwin/libkdecorations/kcommondecoration.cpp b/kwin/libkdecorations/kcommondecoration.cpp index 13a4c49..d64a7f0 100644 --- a/kwin/libkdecorations/kcommondecoration.cpp +++ b/kwin/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/kwin/libkdecorations/kcommondecoration.h b/kwin/libkdecorations/kcommondecoration.h index 3fe9fcf..a0cb10e 100644 --- a/kwin/libkdecorations/kcommondecoration.h +++ b/kwin/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/kwin/libkdecorations/kdecoration.cpp b/kwin/libkdecorations/kdecoration.cpp index 71f4f8d..70cc2e4 100644 --- a/kwin/libkdecorations/kdecoration.cpp +++ b/kwin/libkdecorations/kdecoration.cpp @@ -38,6 +38,7 @@ DEALINGS IN THE SOFTWARE. #include "kdecorationfactory.h" #include "kdecorationbridge.h" + /* Extending KDecoration: @@ -211,6 +212,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/kwin/libkdecorations/kdecoration.h b/kwin/libkdecorations/kdecoration.h index 614b902..ac8403e 100644 --- a/kwin/libkdecorations/kdecoration.h +++ b/kwin/libkdecorations/kdecoration.h @@ -188,7 +188,7 @@ public: AbilityAnnounceButtons = 0, ///< decoration supports AbilityButton* values (always use) AbilityAnnounceColors = 1, ///< decoration supports AbilityColor* values (always use) // 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 ABILITYCOLOR_FIRST = AbilityColorTitleBack, ///< @internal @@ -352,7 +353,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 @@ -622,6 +624,14 @@ public: */ 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(). */ @@ -789,7 +799,23 @@ Q_SIGNALS: * This signal is emitted whenever the window's keep-below state changes. */ 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(); public: /** * This method is not any more invoked from KWin core since version 4.8. diff --git a/kwin/libkdecorations/kdecorationbridge.h b/kwin/libkdecorations/kdecorationbridge.h index b7d0619..2cb36c9 100644 --- a/kwin/libkdecorations/kdecorationbridge.h +++ b/kwin/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/kwin/useractions.cpp b/kwin/useractions.cpp index a501782..18083f4 100755 --- a/kwin/useractions.cpp +++ b/kwin/useractions.cpp @@ -65,9 +65,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 + //**************************************** // Workspace //**************************************** @@ -1008,6 +1020,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::loadEffect(const QString& name) { if (effects) diff --git a/kwin/workspace.cpp b/kwin/workspace.cpp index cf3f308..67b47de 100644 --- a/kwin/workspace.cpp +++ b/kwin/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; //----------------------------------------------------------------------------- @@ -169,6 +175,17 @@ Workspace::Workspace(bool restore) dbus.connect(QString(), "/KWin", "org.kde.KWin", "reinitCompositing", this, SLOT(slotReinitCompositing())); +#ifdef KWIN_BUILD_KAPPMENU + 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; @@ -615,6 +632,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) @@ -907,7 +928,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/kwin/workspace.h b/kwin/workspace.h index 16630f7..1264e75 100644 --- a/kwin/workspace.h +++ b/kwin/workspace.h @@ -399,6 +399,8 @@ public: void showWindowMenu(QPoint pos, Client* cl); bool windowMenuShown(); + void showApplicationMenu(const QPoint &, const WId); + void updateMinimizedOfTransients(Client*); void updateOnAllDesktopsOfTransients(Client*); void updateOnAllActivitiesOfTransients(Client*); @@ -650,6 +652,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 setupCompositing(); /** * Called from setupCompositing() when the CompositingPrefs are ready. @@ -928,6 +936,11 @@ private: QTimer compositeResetTimer; // for compressing composite resets bool m_finishingCompositing; // finishCompositing() sets this variable while shutting down +#ifdef KWIN_BUILD_KAPPMENU + //used for menu available before window is mapped + QList m_windowsMenu; +#endif + Scripting *m_scripting; private: