[kde-doc-english] [kde-workspace] /: GUI: Add support for appmenu: kded-appmenu.
Cedric Bellegarde
gnumdk at gmail.com
Wed Oct 3 09:13:36 UTC 2012
Git commit 455dbea1e1775c71e4d6c24431b918c8b4872f91 by Cedric Bellegarde.
Committed on 03/10/2012 at 10:38.
Pushed by cedric into branch 'master'.
GUI: Add support for appmenu: kded-appmenu.
This module export menubar through dbus:
- it can display a global menubar at top screen
- it can display a popup menu at a wanted position (see next kwin commit)
- it can be used by applications like krunner-appmenu or plasma-widget-menubar
M +1 -0 CMakeLists.txt
A +35 -0 appmenu/CMakeLists.txt
A +367 -0 appmenu/appmenu.cpp [License: BSD X11 (BSD like)]
A +46 -0 appmenu/appmenu.desktop
A +147 -0 appmenu/appmenu.h [License: BSD X11 (BSD like)]
A +69 -0 appmenu/appmenu_dbus.cpp [License: BSD X11 (BSD like)]
A +100 -0 appmenu/appmenu_dbus.h [License: BSD X11 (BSD like)]
A +56 -0 appmenu/com.canonical.AppMenu.Registrar.xml
A +110 -0 appmenu/glowbar.cpp [License: BSD X11 (BSD like)]
A +53 -0 appmenu/glowbar.h [License: BSD X11 (BSD like)]
A +146 -0 appmenu/gtkicons.h [License: BSD X11 (BSD like)]
A +75 -0 appmenu/kdbusimporter.h [License: BSD X11 (BSD like)]
A +139 -0 appmenu/menubar.cpp [License: BSD X11 (BSD like)]
A +82 -0 appmenu/menubar.h [License: BSD X11 (BSD like)]
A +51 -0 appmenu/menubutton.cpp [License: BSD X11 (BSD like)]
A +62 -0 appmenu/menubutton.h [License: BSD X11 (BSD like)]
A +217 -0 appmenu/menuimporter.cpp [License: BSD X11 (BSD like)]
A +98 -0 appmenu/menuimporter.h [License: BSD X11 (BSD like)]
A +259 -0 appmenu/menuwidget.cpp [License: BSD X11 (BSD like)]
A +111 -0 appmenu/menuwidget.h [License: BSD X11 (BSD like)]
A +31 -0 appmenu/org.kde.kded.appmenu.xml
A +118 -0 appmenu/topmenubar.cpp [License: BSD X11 (BSD like)]
A +67 -0 appmenu/topmenubar.h [License: BSD X11 (BSD like)]
A +62 -0 appmenu/verticalmenu.cpp [License: BSD X11 (BSD like)]
A +55 -0 appmenu/verticalmenu.h [License: BSD X11 (BSD like)]
http://commits.kde.org/kde-workspace/455dbea1e1775c71e4d6c24431b918c8b4872f91
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b83413f..efdfc07 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -165,6 +165,7 @@ if(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop")
macro_optional_add_subdirectory(khotkeys)
macro_optional_add_subdirectory(kwrited)
macro_optional_add_subdirectory(ksystraycmd)
+ macro_optional_add_subdirectory(appmenu)
# data
macro_optional_add_subdirectory(cursors)
endif(NOT WIN32)
diff --git a/appmenu/CMakeLists.txt b/appmenu/CMakeLists.txt
new file mode 100644
index 0000000..305bc42
--- /dev/null
+++ b/appmenu/CMakeLists.txt
@@ -0,0 +1,35 @@
+include_directories(
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}
+ )
+include_directories(${DBUSMENUQT_INCLUDE_DIR})
+
+set(kded_appmenu_SRCS
+ appmenu.cpp
+ menuimporter.cpp
+ appmenu_dbus.cpp
+ menubutton.cpp
+ menuwidget.cpp
+ menubar.cpp
+ topmenubar.cpp
+ glowbar.cpp
+ verticalmenu.cpp
+ )
+
+qt4_add_dbus_adaptor(kded_appmenu_SRCS com.canonical.AppMenu.Registrar.xml
+ menuimporter.h MenuImporter menuimporteradaptor MenuImporterAdaptor)
+
+qt4_add_dbus_adaptor(kded_appmenu_SRCS org.kde.kded.appmenu.xml
+ appmenu_dbus.h AppmenuDBus appmenuadaptor AppmenuAdaptor)
+
+kde4_add_plugin(kded_appmenu ${kded_appmenu_SRCS})
+
+target_link_libraries(kded_appmenu ${KDE4_KIO_LIBS} ${X11_LIBRARIES} ${DBUSMENUQT_LIBRARIES} ${KDE4_PLASMA_LIBS})
+
+install(TARGETS kded_appmenu DESTINATION ${PLUGIN_INSTALL_DIR} )
+
+########### install files ###############
+
+install( FILES appmenu.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded )
+install( FILES com.canonical.AppMenu.Registrar.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
+install( FILES org.kde.kded.appmenu.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
diff --git a/appmenu/appmenu.cpp b/appmenu/appmenu.cpp
new file mode 100644
index 0000000..b5e2624
--- /dev/null
+++ b/appmenu/appmenu.cpp
@@ -0,0 +1,367 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "appmenu.h"
+#include "kdbusimporter.h"
+#include "menuimporteradaptor.h"
+#include "appmenuadaptor.h"
+#include "appmenu_dbus.h"
+#include "topmenubar.h"
+#include "verticalmenu.h"
+
+#include <QDBusInterface>
+#include <QDBusReply>
+#include <QDBusPendingCallWatcher>
+#include <QMenu>
+#include <QApplication>
+#include <QDesktopWidget>
+
+#include <KDebug>
+#include <KWindowSystem>
+#include <KWindowInfo>
+#include <KConfig>
+#include <KConfigGroup>
+#include <kpluginfactory.h>
+#include <kpluginloader.h>
+#include <netwm.h>
+
+K_PLUGIN_FACTORY(AppMenuFactory,
+ registerPlugin<AppMenuModule>();
+ )
+K_EXPORT_PLUGIN(AppMenuFactory("appmenu"))
+
+AppMenuModule::AppMenuModule(QObject* parent, const QList<QVariant>&)
+ : KDEDModule(parent),
+ m_parent(parent),
+ m_menuImporter(0),
+ m_appmenuDBus(new AppmenuDBus(parent)),
+ m_menubar(0),
+ m_menu(0),
+ m_menuTimer(new QTimer(this)),
+ m_screenTimer(new QTimer(this)),
+ m_waitingAction(0),
+ m_currentScreen(-1)
+{
+ reconfigure();
+
+ m_appmenuDBus->connectToBus();
+
+ m_currentScreen = currentScreen();
+
+ connect(m_appmenuDBus, SIGNAL(appShowMenu(int, int, WId)), SLOT(slotShowMenu(int, int, WId)));
+ connect(m_appmenuDBus, SIGNAL(moduleReconfigure()), SLOT(reconfigure()));
+
+ // transfer our signals to dbus
+ connect(this, SIGNAL(showRequest(qulonglong)), m_appmenuDBus, SIGNAL(showRequest(qulonglong)));
+ connect(this, SIGNAL(menuAvailable(qulonglong)), m_appmenuDBus, SIGNAL(menuAvailable(qulonglong)));
+ connect(this, SIGNAL(clearMenus()), m_appmenuDBus, SIGNAL(clearMenus()));
+ connect(this, SIGNAL(menuHidden(qulonglong)), m_appmenuDBus, SIGNAL(menuHidden(qulonglong)));
+ connect(this, SIGNAL(WindowRegistered(qulonglong, const QString&, const QDBusObjectPath&)),
+ m_appmenuDBus, SIGNAL(WindowRegistered(qulonglong, const QString&, const QDBusObjectPath&)));
+ connect(this, SIGNAL(WindowUnregistered(qulonglong)), m_appmenuDBus, SIGNAL(WindowUnregistered(qulonglong)));
+
+ connect(m_menuTimer, SIGNAL(timeout()), this, SLOT(slotShowCurrentWindowMenu()));
+}
+
+AppMenuModule::~AppMenuModule()
+{
+ emit clearMenus();
+ hideMenubar(m_menubar);
+ delete m_menuImporter;
+ delete m_appmenuDBus;
+}
+
+void AppMenuModule::slotShowMenu(int x, int y, WId id)
+{
+ // If menu visible, hide it
+ if (m_menu && m_menu->isVisible()) {
+ m_menu->hide();
+ return;
+ }
+
+ //dbus call by user (for khotkey shortcut)
+ if (x == -1 || y == -1) {
+ // We do not know kwin button position, so tell kwin to show menu
+ emit showRequest(KWindowSystem::self()->activeWindow());
+ return;
+ }
+
+ KDBusMenuImporter *importer = getImporter(id);
+ QMenu *menu = importer ? importer->menu() : 0;
+
+ // Window do not have menu
+ if (!menu) {
+ return;
+ }
+
+ m_menu = new VerticalMenu();
+ m_menu->setMenuBarParentWid(id);
+ // Populate menu
+ foreach (QAction *action, menu->actions()) {
+ m_menu->addAction(action);
+ }
+ m_menu->popup(QPoint(x, y));
+ // Activate waiting action if exist
+ if (m_waitingAction) {
+ m_menu->setActiveAction(m_waitingAction);
+ m_waitingAction = 0;
+ }
+ connect(m_menu, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHide()));
+ // Application may crash and original menu destroyed
+ connect(menu, SIGNAL(destroyed()), this, SLOT(slotAboutToHide()), Qt::UniqueConnection);
+}
+
+void AppMenuModule::slotAboutToHide()
+{
+ if (m_menu) {
+ emit menuHidden(m_menu->menuBarParentWid());
+ m_menu->deleteLater();
+ m_menu = 0;
+ }
+}
+
+// New window registered
+// Do not get importer here as it can freeze module on session loading
+void AppMenuModule::slotWindowRegistered(WId id, const QString& service, const QDBusObjectPath& path)
+{
+ KDBusMenuImporter* importer = m_importers.take(id);
+ if (importer) {
+ delete importer;
+ }
+
+ if (m_menuStyle == "ButtonVertical") {
+ // Tell Kwin menu is available
+ emit menuAvailable(id);
+ } else if ( m_menuStyle == "TopMenuBar" && id == KWindowSystem::self()->activeWindow()) {
+ // Application already active so check if we need create menubar
+ slotActiveWindowChanged(id);
+ }
+ // Send a signal on bus for others dbus interface registrars
+ emit WindowRegistered(id, service, path);
+}
+
+// Window unregistered
+void AppMenuModule::slotWindowUnregistered(WId id)
+{
+ KDBusMenuImporter* importer = m_importers.take(id);
+
+ if (importer) {
+ importer->deleteLater();
+ }
+
+ if (m_menubar && m_menubar->menuBarParentWid() == id) {
+ hideMenubar(m_menubar);
+ }
+ // Send a signal on bus for others dbus interface registrars
+ emit WindowUnregistered(id);
+}
+
+// Keyboard activation requested, transmit it to menu
+void AppMenuModule::slotActionActivationRequested(QAction* a)
+{
+ // If we have a topmenubar, activate action
+ if (m_menubar) {
+ m_menubar->setActiveAction(a);
+ m_menubar->show();
+ } else { // else send request to kwin or others dbus interface registrars
+ m_waitingAction = a;
+ emit showRequest(KWindowSystem::self()->activeWindow());
+ }
+}
+
+// Current window change, update menubar
+// See comments in slotWindowRegistered() for why we get importers here
+void AppMenuModule::slotActiveWindowChanged(WId id)
+{
+ bool firstCall = !m_menuTimer->isActive();
+ KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMWindowType);
+ unsigned long mask = NET::AllTypesMask;
+
+ // Active window changed, miss previous menu
+ if (m_menuTimer->isActive()) {
+ m_menuTimer->stop();
+ }
+
+ if (id == 0) {// Ignore root window
+ return;
+ } else if (info.windowType(mask) & NET::Dock) { // hide immediatly menubar for docks (krunner)
+ hideMenubar(m_menubar);
+ return;
+ }
+
+ if (!m_menuImporter->serviceExist(id)) { // No menu exist, check for another menu for application
+ if (! (id = m_menuImporter->recursiveMenuId(id))) {
+ if (firstCall) {
+ // Some windows (gtk) get menu after being actives,
+ // try another time before hiding previous menubar
+ m_menuTimer->start(1000);
+ } else {
+ // Window do not seems to have a menu
+ hideMenubar(m_menubar);
+ }
+ return;
+ }
+ }
+
+ KDBusMenuImporter *importer = getImporter(id);
+
+ QMenu *menu = importer->menu();
+ // length == 0 means menu not ready
+ // Start a m_menuTimer looking for menu to be ready
+ if(menu->actions().length()) {
+ showTopMenuBar(menu);
+ m_menubar->setMenuBarParentWid(id);
+ } else {
+ m_menuTimer->start(500);
+ }
+}
+
+void AppMenuModule::slotShowCurrentWindowMenu()
+{
+ slotActiveWindowChanged(KWindowSystem::self()->activeWindow());
+}
+
+void AppMenuModule::slotCurrentScreenChanged()
+{
+ if (m_currentScreen != currentScreen()) {
+ if (m_menubar) {
+ m_menubar->setMenuBarParentWid(0);
+ }
+ slotActiveWindowChanged(KWindowSystem::self()->activeWindow());
+ }
+}
+
+// reload settings
+void AppMenuModule::reconfigure()
+{
+ KConfig config( "kdeglobals", KConfig::FullConfig );
+ KConfigGroup configGroup = config.group("Appmenu Style");
+ m_menuStyle = configGroup.readEntry("Style", "InApplication");
+
+ // Clean up current menu
+ m_waitingAction = 0;
+ hideMenubar(m_menubar); // hide menubar if exist
+ slotAboutToHide(); // hide vertical menu if exist
+
+ // Disconnect all options specifics signals
+ disconnect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(slotActiveWindowChanged(WId)));
+ disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(slotShowCurrentWindowMenu()));
+ disconnect(m_screenTimer, SIGNAL(timeout()), this, SLOT(slotCurrentScreenChanged()));
+
+ m_screenTimer->stop();
+
+ // Tell kwin to clean its titlebar
+ emit clearMenus();
+
+ if (m_menuStyle == "InApplication") {
+ if (m_menuImporter) {
+ delete m_menuImporter;
+ m_menuImporter = 0;
+ }
+ return;
+ }
+
+ // Setup a menu importer if needed
+ if (!m_menuImporter) {
+ m_menuImporter = new MenuImporter(m_parent);
+ connect(m_menuImporter, SIGNAL(WindowRegistered(WId, const QString&, const QDBusObjectPath&)),
+ SLOT(slotWindowRegistered(WId, const QString&, const QDBusObjectPath&)));
+ connect(m_menuImporter, SIGNAL(WindowUnregistered(WId)),
+ SLOT(slotWindowUnregistered(WId)));
+ m_menuImporter->connectToBus();
+ }
+
+ if( m_menuStyle == "ButtonVertical" ) {
+ foreach(WId id, m_menuImporter->ids()) {
+ emit menuAvailable(id);
+ }
+ }
+
+ // Setup top menubar if needed
+ if (m_menuStyle == "TopMenuBar") {
+ connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(slotActiveWindowChanged(WId)));
+ connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(slotShowCurrentWindowMenu()));
+ connect(m_screenTimer, SIGNAL(timeout()), this, SLOT(slotCurrentScreenChanged()));
+ m_screenTimer->start(1000);
+ slotShowCurrentWindowMenu();
+ }
+}
+
+KDBusMenuImporter* AppMenuModule::getImporter(WId id)
+{
+ KDBusMenuImporter* importer = 0;
+ if (m_importers.contains(id)) { // importer already exist
+ importer = m_importers.value(id);
+ } else { // get importer
+ importer = new KDBusMenuImporter(id, m_menuImporter->serviceForWindow(id), &m_icons,
+ m_menuImporter->pathForWindow(id), this);
+ m_importers.insert(id, importer);
+ connect(importer, SIGNAL(actionActivationRequested(QAction*)),
+ SLOT(slotActionActivationRequested(QAction*)));
+ QMetaObject::invokeMethod(importer, "updateMenu", Qt::DirectConnection);
+ }
+ return importer;
+}
+
+void AppMenuModule::showTopMenuBar(QMenu *menu)
+{
+ TopMenuBar *previous = m_menubar;
+
+ m_menubar = new TopMenuBar(menu);
+
+ QDesktopWidget *desktop = QApplication::desktop();
+ m_currentScreen = currentScreen();
+ QRect screen = desktop->availableGeometry(m_currentScreen);
+ int x = screen.center().x() - m_menubar->sizeHint().width()/2;
+ m_menubar->move(QPoint(x, screen.topLeft().y()));
+ m_menubar->enableMouseTracking();
+ hideMenubar(previous);
+}
+
+void AppMenuModule::hideMenubar(TopMenuBar *menubar)
+{
+ if (menubar) {
+ if (menubar->isVisible()) {
+ menubar->hide();
+ }
+ delete menubar;
+ if (m_menubar == menubar) {
+ m_menubar = 0;
+ }
+ }
+}
+
+int AppMenuModule::currentScreen()
+{
+ KWindowInfo info = KWindowSystem::windowInfo(KWindowSystem::self()->activeWindow(),
+ NET::WMGeometry);
+ int x = info.geometry().x();
+ int y = info.geometry().y();
+
+ QDesktopWidget *desktop = QApplication::desktop();
+ return desktop->screenNumber(QPoint(x,y));
+}
+
+#include "appmenu.moc"
diff --git a/appmenu/appmenu.desktop b/appmenu/appmenu.desktop
new file mode 100644
index 0000000..d0e1382
--- /dev/null
+++ b/appmenu/appmenu.desktop
@@ -0,0 +1,46 @@
+[Desktop Entry]
+Type=Service
+Name=Application menus daemon
+Name[da]=Dæmon til programmenuer
+Name[el]=Δαίμονας μενού εφαρμογών
+Name[es]=Demonio de menús de aplicaciones
+Name[et]=Rakenduste menüü deemon
+Name[fi]=Sovellusvalikon palvelu
+Name[fr]=Démon des menus d'applications
+Name[hu]=Alkalmazásmenü démon
+Name[km]=ដេមិនម៉ឺនុយកម្មវិធី
+Name[nl]=Daemon voor menu's van toepassingen
+Name[pl]=Demon menu programów
+Name[pt]=Servidor dos menus da aplicação
+Name[pt_BR]=Servidor dos menus do aplicativo
+Name[sk]=Démon ponúk aplikácie
+Name[sv]=Demon för programmenyer
+Name[uk]=Фонова служба меню програм
+Name[x-test]=xxApplication menus daemonxx
+Name[zh_TW]=應用程式選單伺服程式
+Comment=Transfers application's menu to the desktop
+Comment[cs]=Přesouvá nabídku aplikací na plochu
+Comment[da]=Overfører programmenuer til skrivebordet
+Comment[de]=Überträgt Anwendungsmenüs auf die Arbeitsfläche
+Comment[el]=Μεταφέρει το μενού της εφαρμογής στην επιφάνεια εργασίας
+Comment[es]=Transfiere menús de aplicaciones al escritorio
+Comment[et]=Rakenduste menüü paigutamine töölauale
+Comment[fi]=Siirtää sovelluksen valikon työpöydälle
+Comment[fr]=Transfère le menu de l'application sur le bureau
+Comment[hu]=Átviszi az alkalmazások menüjét az asztalra
+Comment[km]=ផ្ទេរម៉ឺនុយរបស់កម្មវិធីទៅផ្ទៃតុ
+Comment[nl]=Verplaatst menu's van toepassingen naar het bureaublad
+Comment[pl]=Przenosi menu aplikacji na pulpit
+Comment[pt]=Transfere o menu da aplicação para o ecrã
+Comment[pt_BR]=Transfere o menu do aplicativo para a área de trabalho
+Comment[sk]=Presunúť ponuky aplikácie na plochu
+Comment[sv]=Överför programmets meny till skrivbordet
+Comment[uk]=Передає меню програм на стільницю
+Comment[x-test]=xxTransfers application's menu to the desktopxx
+Comment[zh_TW]=將應用程式選單傳送到桌面
+X-KDE-ServiceTypes=KDEDModule
+X-KDE-Library=appmenu
+X-KDE-DBus-ModuleName=appmenu
+X-KDE-Kded-autoload=true
+X-KDE-Kded-load-on-demand=false
+
diff --git a/appmenu/appmenu.h b/appmenu/appmenu.h
new file mode 100644
index 0000000..3b5026a
--- /dev/null
+++ b/appmenu/appmenu.h
@@ -0,0 +1,147 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef APPMENUMODULE_H
+#define APPMENUMODULE_H
+
+#include <kdedmodule.h>
+#include "menuimporter.h"
+#include "gtkicons.h"
+
+class QDBusPendingCallWatcher;
+class KDBusMenuImporter;
+class AppmenuDBus;
+class TopMenuBar;
+class VerticalMenu;
+
+class AppMenuModule : public KDEDModule,
+ protected QDBusContext
+{
+ Q_OBJECT
+public:
+ AppMenuModule(QObject* parent, const QList<QVariant>& list);
+ virtual ~AppMenuModule();
+
+Q_SIGNALS:
+ /**
+ * We do not know where is menu decoration button, so tell kwin to show menu
+ */
+ void showRequest(qulonglong);
+ /**
+ * This signal is emitted whenever application menu becomes available
+ */
+ void menuAvailable(qulonglong);
+ /**
+ * This signal is emitted whenever menus are unavailables
+ */
+ void clearMenus();
+ /**
+ * This signal is emitted whenever popup menu/menubar is hidden
+ * Useful for decorations to know if menu button should be release
+ */
+ void menuHidden(qulonglong);
+ /**
+ * This signal is emitted whenever a window register to appmenu
+ */
+ void WindowRegistered(qulonglong wid, const QString& service, const QDBusObjectPath&);
+ /**
+ * This signal is emitted whenever a window unregister from appmenu
+ */
+ void WindowUnregistered(qulonglong wid);
+
+private Q_SLOTS:
+ /**
+ * Show menu at QPoint(x,y) for id
+ * if x or y == -1, show in application window
+ */
+ void slotShowMenu(int x, int y, WId);
+ /**
+ * Send menuHidden signal over bus when menu is about to hide
+ */
+ void slotAboutToHide();
+ /**
+ * New window registered to appmenu
+ * Emit WindowRegistered signal over bus
+ */
+ void slotWindowRegistered(WId id, const QString& service, const QDBusObjectPath& path);
+ /**
+ * Window unregistered from appmenu
+ * Emit WindowUnregistered signal over bus
+ */
+ void slotWindowUnregistered(WId id);
+ /**
+ * Open a action in current menu
+ */
+ void slotActionActivationRequested(QAction* a);
+ /**
+ * Active window changed, update menubar
+ */
+ void slotActiveWindowChanged(WId id);
+ /**
+ * Update menubar with current window menu
+ */
+ void slotShowCurrentWindowMenu();
+ /**
+ * Current screen changed, update menubar
+ */
+ void slotCurrentScreenChanged();
+ /**
+ * Reconfigure module
+ */
+ void reconfigure();
+
+private:
+ /**
+ * return an importer for window id
+ */
+ KDBusMenuImporter* getImporter(WId id);
+ /**
+ * Show top menubar with menu
+ */
+ void showTopMenuBar(QMenu *menu);
+ /**
+ * Hide menubar. Delete object
+ */
+ void hideMenubar(TopMenuBar* menubar);
+ /**
+ * Return current screen
+ */
+ int currentScreen();
+
+ QObject* m_parent;
+ MenuImporter* m_menuImporter;
+ AppmenuDBus* m_appmenuDBus;
+ QHash<WId, KDBusMenuImporter*> m_importers;
+ GtkIcons m_icons;
+ QString m_menuStyle;
+ TopMenuBar* m_menubar;
+ VerticalMenu* m_menu;
+ QTimer* m_menuTimer;
+ QTimer* m_screenTimer;
+ QAction *m_waitingAction;
+ int m_currentScreen;
+};
+
+#endif
diff --git a/appmenu/appmenu_dbus.cpp b/appmenu/appmenu_dbus.cpp
new file mode 100644
index 0000000..3b62732
--- /dev/null
+++ b/appmenu/appmenu_dbus.cpp
@@ -0,0 +1,69 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "appmenu_dbus.h"
+#include "kdbusimporter.h"
+#include "appmenuadaptor.h"
+
+#include <QApplication>
+#include <QDBusMessage>
+#include <QDBusObjectPath>
+#include <QDBusServiceWatcher>
+
+static const char* DBUS_SERVICE = "org.kde.kded";
+static const char* DBUS_OBJECT_PATH = "/modules/appmenu";
+
+AppmenuDBus::AppmenuDBus(QObject* parent)
+: QObject(parent)
+{
+}
+
+AppmenuDBus::~AppmenuDBus()
+{
+}
+
+bool AppmenuDBus::connectToBus(const QString& service, const QString& path)
+{
+ m_service = service.isEmpty() ? DBUS_SERVICE : service;
+ QString newPath = path.isEmpty() ? DBUS_OBJECT_PATH : path;
+
+ if (!QDBusConnection::sessionBus().registerService(m_service)) {
+ return false;
+ }
+ new AppmenuAdaptor(this);
+ QDBusConnection::sessionBus().registerObject(newPath, this);
+
+ return true;
+}
+
+void AppmenuDBus::showMenu(int x, int y, WId id)
+{
+ emit appShowMenu(x, y, id);
+}
+
+void AppmenuDBus::reconfigure()
+{
+ emit moduleReconfigure();
+}
\ No newline at end of file
diff --git a/appmenu/appmenu_dbus.h b/appmenu/appmenu_dbus.h
new file mode 100644
index 0000000..2d5bb7e
--- /dev/null
+++ b/appmenu/appmenu_dbus.h
@@ -0,0 +1,100 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef APPMENU_DBUS_H
+#define APPMENU_DBUS_H
+
+// Qt
+#include <QDBusContext>
+#include <QDBusObjectPath>
+#include <QObject>
+#include <QDebug>
+#include <qwindowdefs.h>
+
+class KDBusMenuImporter;
+
+class AppmenuDBus : public QObject, protected QDBusContext
+{
+ Q_OBJECT
+
+public:
+ AppmenuDBus(QObject*);
+ ~AppmenuDBus();
+
+ bool connectToBus(const QString& service = QString(), const QString& path = QString());
+
+ /**
+ * DBus method showing menu at QPoint(x,y) for id
+ * if x or y == -1, show in application window
+ */
+ void showMenu(int x, int y, WId id);
+ /**
+ * DBus method reconfiguring kded module
+ */
+ void reconfigure();
+
+Q_SIGNALS:
+ /**
+ * This signal is emitted on showMenu() request
+ */
+ void appShowMenu(int x, int y, WId id);
+ /**
+ * This signal is emitted on reconfigure() request
+ */
+ void moduleReconfigure();
+
+ // Dbus signals
+ /**
+ * This signal is emitted whenever kded want to show menu
+ * We do not know where is menu decoration button, so tell kwin to show menu
+ */
+ void showRequest(qulonglong);
+ /**
+ * This signal is emitted whenever application menu becomes available
+ */
+ void menuAvailable(qulonglong);
+ /**
+ * This signal is emitted whenever menus are unavailables
+ */
+ void clearMenus();
+ /**
+ * This signal is emitted whenever popup menu/menubar is hidden
+ * Useful for decorations to know if menu button should be release
+ */
+ void menuHidden(qulonglong);
+ /**
+ * This signal is emitted whenever a window register to appmenu
+ */
+ void WindowRegistered(qulonglong wid, const QString& service, const QDBusObjectPath&);
+ /**
+ * This signal is emitted whenever a window unregister from appmenu
+ */
+ void WindowUnregistered(qulonglong wid);
+
+private:
+ QString m_service;
+};
+
+#endif // APPMENU_DBUS_H
diff --git a/appmenu/com.canonical.AppMenu.Registrar.xml b/appmenu/com.canonical.AppMenu.Registrar.xml
new file mode 100644
index 0000000..bc2be43
--- /dev/null
+++ b/appmenu/com.canonical.AppMenu.Registrar.xml
@@ -0,0 +1,56 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node xmlns:dox="http://www.ayatana.org/dbus/dox.dtd">
+ <dox:d><![CDATA[
+ @mainpage
+
+ An interface to register menus that are associated with a window in an application. The
+ main interface is docuemented here: @ref com::canonical::AppMenu::Registrar.
+
+ The actual menus are transported using the dbusmenu protocol which is available
+ here: @ref com::canonical::dbusmenu.
+ ]]></dox:d>
+ <interface name="com.canonical.AppMenu.Registrar" xmlns:dox="http://www.ayatana.org/dbus/dox.dtd">
+ <dox:d>
+ An interface to register a menu from an application's window to be displayed in another
+ window. This manages that association between XWindow Window IDs and the dbus
+ address and object that provides the menu using the dbusmenu dbus interface.
+ </dox:d>
+ <method name="RegisterWindow">
+ <dox:d><![CDATA[
+ Associates a dbusmenu with a window
+
+ /note this method assumes that the connection from the caller is the DBus connection
+ to use for the object. Applications that use multiple DBus connections will need to
+ ensure this method is called with the same connection that implmenets the object.
+ ]]></dox:d>
+ <arg name="windowId" type="u" direction="in">
+ <dox:d>The XWindow ID of the window</dox:d>
+ </arg>
+ <arg name="menuObjectPath" type="o" direction="in">
+ <dox:d>The object on the dbus interface implementing the dbusmenu interface</dox:d>
+ </arg>
+ </method>
+ <method name="UnregisterWindow">
+ <dox:d>
+ A method to allow removing a window from the database. Windows will also be removed
+ when the client drops off DBus so this is not required. It is polite though. And
+ important for testing.
+ </dox:d>
+ <arg name="windowId" type="u" direction="in">
+ <dox:d>The XWindow ID of the window</dox:d>
+ </arg>
+ </method>
+ <method name="GetMenuForWindow">
+ <dox:d>Gets the registered menu for a given window ID.</dox:d>
+ <arg name="windowId" type="u" direction="in">
+ <dox:d>The XWindow ID of the window to get</dox:d>
+ </arg>
+ <arg name="service" type="s" direction="out">
+ <dox:d>The address of the connection on DBus (e.g. :1.23 or org.example.service)</dox:d>
+ </arg>
+ <arg name="menuObjectPath" type="o" direction="out">
+ <dox:d>The path to the object which implements the com.canonical.dbusmenu interface.</dox:d>
+ </arg>
+ </method>
+ </interface>
+</node>
diff --git a/appmenu/glowbar.cpp b/appmenu/glowbar.cpp
new file mode 100644
index 0000000..48bcc45
--- /dev/null
+++ b/appmenu/glowbar.cpp
@@ -0,0 +1,110 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "glowbar.h"
+
+#include <X11/extensions/shape.h>
+#include <fixx11h.h>
+
+#include <Plasma/Svg>
+#include <KWindowSystem>
+#include <KDebug>
+
+#include <QTimer>
+#include <QDebug>
+#include <QPainter>
+#include <QX11Info>
+
+
+GlowBar::GlowBar(const QPoint pos, uint width)
+ : QWidget(0),
+ m_svg(new Plasma::Svg(this))
+{
+ m_svg->setImagePath("widgets/glowbar");
+
+ setWindowFlags(Qt::Tool | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint);
+ setAttribute(Qt::WA_TranslucentBackground);
+ setAutoFillBackground(false);
+ KWindowSystem::setType(winId(), NET::Dock);
+
+ QPalette pal = palette();
+ pal.setColor(backgroundRole(), Qt::transparent);
+ setPalette(pal);
+
+ QRect zone = QRect(pos, QSize(width, 10));
+ setGeometry(zone);
+ m_buffer = QPixmap(zone.size());
+
+ setInputMask();
+
+ static QTimer timer;
+ connect(&timer, SIGNAL(timeout()), this, SIGNAL(destroy()));
+ timer.start(30000);
+}
+
+GlowBar::~GlowBar()
+{
+}
+
+void GlowBar::paintEvent(QPaintEvent*)
+{
+ QPixmap l, r, c;
+ QPoint pixmapPosition(0, 0);
+
+ m_buffer.fill(QColor(0, 0, 0, int(qreal(255)*0.3)));
+ QPainter p(&m_buffer);
+ p.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ l = m_svg->pixmap("bottomleft");
+ r = m_svg->pixmap("bottomright");
+ c = m_svg->pixmap("bottom");
+ p.drawPixmap(pixmapPosition, l);
+ p.drawTiledPixmap(QRect(l.width(), pixmapPosition.y(), width() - l.width() - r.width(), c.height()), c);
+ p.drawPixmap(QPoint(width() - r.width(), pixmapPosition.y()), r);
+ p.end();
+ p.begin(this);
+ p.drawPixmap(QPoint(0, 0), m_buffer);
+}
+
+void GlowBar::setInputMask()
+{
+ // Create an empty input mask to achieve click-through effect
+ // Thanks to MacSlow for this!
+ Pixmap mask;
+
+ mask = XCreatePixmap(QX11Info::display(),
+ winId(),
+ 1, /* width */
+ 1, /* height */
+ 1 /* depth */);
+ XShapeCombineMask(QX11Info::display(),
+ winId(),
+ ShapeInput,
+ 0, /* x-offset */
+ 0, /* y-offset */
+ mask,
+ ShapeSet);
+ XFreePixmap(QX11Info::display(), mask);
+}
+#include "glowbar.moc"
diff --git a/appmenu/glowbar.h b/appmenu/glowbar.h
new file mode 100644
index 0000000..af242b0
--- /dev/null
+++ b/appmenu/glowbar.h
@@ -0,0 +1,53 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef GLOWBAR__H
+#define GLOWBAR__H
+
+#include <QWidget>
+
+namespace Plasma
+{
+ class Svg;
+}
+
+class GlowBar : public QWidget
+{
+Q_OBJECT
+public:
+ GlowBar(const QPoint pos, uint width);
+ ~GlowBar();
+
+ void paintEvent(QPaintEvent*);
+
+Q_SIGNALS:
+ void destroy();
+
+private:
+ void setInputMask();
+ Plasma::Svg *m_svg;
+ QPixmap m_buffer;
+};
+#endif
\ No newline at end of file
diff --git a/appmenu/gtkicons.h b/appmenu/gtkicons.h
new file mode 100644
index 0000000..d11d73d
--- /dev/null
+++ b/appmenu/gtkicons.h
@@ -0,0 +1,146 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef GTKICONS_H
+#define GTKICONS_H
+
+#include <QtCore/QMap>
+
+class GtkIcons : public QMap<QString, QString>
+{
+ public:
+ GtkIcons( void ) : QMap<QString, QString> ()
+ {
+ insert(QString("gnome-fs-directory"), QString("folder.png"));
+ insert(QString("gnome-fs-regular.png"), QString("application-x-zerosize.png"));
+ insert(QString("gtk-about"), QString("help-about.png"));
+ insert(QString("gtk-add"), QString("list-add.png"));
+ insert(QString("gtk-apply"), QString("dialog-ok-apply.png ok-apply.png apply.png"));
+ insert(QString("gtk-bold"), QString("format-text-bold.png"));
+ insert(QString("gtk-cancel"), QString("dialog-cancel.png cancel.png"));
+ insert(QString("gtk-cdrom"), QString("media-optical.png"));
+ insert(QString("gtk-clear"), QString("edit-clear.png"));
+ insert(QString("gtk-close"), QString("window-close.png"));
+ insert(QString("gtk-color-picker"), QString("color-picker.png"));
+ insert(QString("gtk-connect"), QString("network-connect.png"));
+ insert(QString("gtk-convert"), QString("document-export.png"));
+ insert(QString("gtk-copy"), QString("edit-copy.png"));
+ insert(QString("gtk-cut"), QString("edit-cut.png"));
+ insert(QString("gtk-delete"), QString("edit-delete.png"));
+ insert(QString("gtk-dialog-authentication"), QString("dialog-password.png document-encrypt.png object-locked.png"));
+ insert(QString("gtk-dialog-error"), QString("dialog-error.png"));
+ insert(QString("gtk-dialog-info"), QString("dialog-information.png"));
+ insert(QString("gtk-dialog-question"), QString("dialog-information.png"));
+ insert(QString("gtk-dialog-warning"), QString("dialog-warning.png"));
+ insert(QString("gtk-directory"), QString("folder.png"));
+ insert(QString("gtk-disconnect"), QString("network-disconnect.png"));
+ insert(QString("gtk-dnd"), QString("application-x-zerosize.png"));
+ insert(QString("gtk-dnd-multiple"), QString("document-multiple.png"));
+ insert(QString("gtk-edit"), QString("document-properties.png"));
+ insert(QString("gtk-execute"), QString("fork.png"));
+ insert(QString("gtk-file"), QString("application-x-zerosize.png"));
+ insert(QString("gtk-find"), QString("edit-find.png"));
+ insert(QString("gtk-find-and-replace"), QString("edit-find-replace.png"));
+ insert(QString("gtk-floppy"), QString("media-floppy.png"));
+ insert(QString("gtk-fullscreen"), QString("view-fullscreen.png"));
+ insert(QString("gtk-goto-bottom"), QString("go-bottom.png"));
+ insert(QString("gtk-goto-first"), QString("go-first.png"));
+ insert(QString("gtk-goto-last"), QString("go-last.png"));
+ insert(QString("gtk-goto-top"), QString("go-top.png"));
+ insert(QString("gtk-go-back"), QString("go-previous.png"));
+ insert(QString("gtk-go-back-ltr"), QString("go-previous.png"));
+ insert(QString("gtk-go-back-rtl"), QString("go-next.png"));
+ insert(QString("gtk-go-down"), QString("go-down.png"));
+ insert(QString("gtk-go-forward"), QString("go-next.png"));
+ insert(QString("gtk-go-forward-ltr"), QString("go-next.png"));
+ insert(QString("gtk-go-forward-rtl"), QString("go-previous.png"));
+ insert(QString("gtk-go-up"), QString("go-up.png"));
+ insert(QString("gtk-harddisk"), QString("drive-harddisk.png"));
+ insert(QString("gtk-help"), QString("help-contents.png"));
+ insert(QString("gtk-home"), QString("go-home.png"));
+ insert(QString("gtk-indent"), QString("format-indent-more.png"));
+ insert(QString("gtk-index"), QString("help-contents.png"));
+ insert(QString("gtk-info"), QString("help-about.png"));
+ insert(QString("gtk-italic"), QString("format-text-italic.png"));
+ insert(QString("gtk-jump-to"), QString("go-jump.png"));
+ insert(QString("gtk-justify-center"), QString("format-justify-center.png"));
+ insert(QString("gtk-justify-fill"), QString("format-justify-fill.png"));
+ insert(QString("gtk-justify-left"), QString("format-justify-left.png"));
+ insert(QString("gtk-justify-right"), QString("format-justify-right.png"));
+ insert(QString("gtk-leave-fullscreen"), QString("view-restore.png"));
+ insert(QString("gtk-media-forward"), QString("media-seek-forward.png"));
+ insert(QString("gtk-media-next"), QString("media-skip-forward.png"));
+ insert(QString("gtk-media-pause"), QString("media-playback-pause.png"));
+ insert(QString("gtk-media-play"), QString("media-playback-start.png"));
+ insert(QString("gtk-media-previous"), QString("media-skip-backward.png"));
+ insert(QString("gtk-media-record"), QString("media-record.png"));
+ insert(QString("gtk-media-rewind"), QString("media-seek-backward.png"));
+ insert(QString("gtk-media-stop"), QString("media-playback-stop.png"));
+ insert(QString("gtk-missing-image"), QString("unknown.png"));
+ insert(QString("gtk-network"), QString("network-server.png"));
+ insert(QString("gtk-new"), QString("document-new.png"));
+ insert(QString("gtk-no"), QString("edit-delete.png"));
+ insert(QString("gtk-ok"), QString("dialog-ok.png ok.png"));
+ insert(QString("gtk-open"), QString("document-open.png"));
+ insert(QString("gtk-paste"), QString("edit-paste.png"));
+ insert(QString("gtk-preferences"), QString("configure.png"));
+ insert(QString("gtk-print"), QString("document-print.png"));
+ insert(QString("gtk-print-preview"), QString("document-print-preview.png"));
+ insert(QString("gtk-properties"), QString("document-properties.png"));
+ insert(QString("gtk-quit"), QString("application-exit.png"));
+ insert(QString("gtk-redo"), QString("edit-redo.png"));
+ insert(QString("gtk-refresh"), QString("view-refresh.png"));
+ insert(QString("gtk-remove"), QString("edit-delete.png"));
+ insert(QString("gtk-revert-to-saved"), QString("document-revert.png"));
+ insert(QString("gtk-save"), QString("document-save.png"));
+ insert(QString("gtk-save-as"), QString("document-save-as.png"));
+ insert(QString("gtk-select-all"), QString("edit-select-all.png"));
+ insert(QString("gtk-select-color"), QString("color-picker.png"));
+ insert(QString("gtk-select-font"), QString("preferences-desktop-font.png"));
+ insert(QString("gtk-sort-ascending"), QString("view-sort-ascending.png"));
+ insert(QString("gtk-sort-descending"), QString("view-sort-descending.png"));
+ insert(QString("gtk-spell-check"), QString("tools-check-spelling.png"));
+ insert(QString("gtk-stop"), QString("process-stop.png"));
+ insert(QString("gtk-strikethrough"), QString("format-text-strikethrough.png"));
+ insert(QString("gtk-undelete"), QString("edit-undo.png"));
+ insert(QString("gtk-underline"), QString("format-text-underline.png"));
+ insert(QString("gtk-undo"), QString("edit-undo.png"));
+ insert(QString("gtk-unindent"), QString("format-indent-less.png"));
+ insert(QString("gtk-yes"), QString("dialog-ok.png ok.png"));
+ insert(QString("gtk-zoom-100"), QString("zoom-original.png"));
+ insert(QString("gtk-zoom-fit"), QString("zoom-fit-best.png"));
+ insert(QString("gtk-zoom-in"), QString("zoom-in.png"));
+ insert(QString("gtk-zoom-out"), QString("zoom-out.png"));
+ insert(QString("stock_edit-bookmark"), QString("bookmarks-organize.png"));
+ insert(QString("gimp-edit"), QString("edit.png"));
+ insert(QString("gimp-info"), QString("dialog-information.png"));
+ insert(QString("gimp-reset"), QString("reload.png"));
+ insert(QString("gimp-warning"), QString("dialog-warning.png"));
+ insert(QString("gimp-tool-options"), QString("tool.png"));
+ insert(QString("gimp-images"), QString("image.png"));
+ }
+};
+
+#endif // GTKICONS_H
\ No newline at end of file
diff --git a/appmenu/kdbusimporter.h b/appmenu/kdbusimporter.h
new file mode 100644
index 0000000..986783b
--- /dev/null
+++ b/appmenu/kdbusimporter.h
@@ -0,0 +1,75 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KDBUSMENUIMPORTER_H
+#define KDBUSMENUIMPORTER_H
+
+#include "gtkicons.h"
+
+#include <KIcon>
+#include <KIconLoader>
+
+#include <QDBusArgument>
+
+#include <dbusmenuimporter.h>
+
+class KDBusMenuImporter : public DBusMenuImporter
+{
+
+public:
+ KDBusMenuImporter(WId wid, const QString &service, GtkIcons *icons, const QString &path, QObject *parent)
+ : DBusMenuImporter(service, path, parent)
+ , m_service(service)
+ , m_path(path)
+ , m_WId(wid)
+ {
+ m_icons = icons;
+ }
+
+ QString service() const { return m_service; }
+ QString path() const { return m_path; }
+ WId wid() const { return m_WId; }
+
+protected:
+ virtual QIcon iconForName(const QString &name)
+ {
+ KIcon icon;
+ if(m_icons->contains(name)){
+ icon = KIcon(m_icons->value(name));
+ }
+ else if(!KIconLoader::global()->iconPath(name, 1, true ).isNull()){
+ icon = KIcon(name);
+ }
+ return icon;
+ }
+
+private:
+ GtkIcons *m_icons;
+ QString m_service;
+ QString m_path;
+ WId m_WId;
+};
+
+#endif //KDBUSMENUIMPORTER_H
\ No newline at end of file
diff --git a/appmenu/menubar.cpp b/appmenu/menubar.cpp
new file mode 100644
index 0000000..764773d
--- /dev/null
+++ b/appmenu/menubar.cpp
@@ -0,0 +1,139 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "menubar.h"
+
+#include <QGraphicsLinearLayout>
+#include <QPainter>
+#include <QMenu>
+#include <QDesktopWidget>
+
+#include <KWindowSystem>
+#include <Plasma/FrameSvg>
+#include <Plasma/Label>
+#include <Plasma/Meter>
+#include <Plasma/Theme>
+#include <Plasma/WindowEffects>
+#include <KApplication>
+
+MenuBar::MenuBar(QMenu *menu)
+ : QGraphicsView(),
+ m_hideTimer(new QTimer(this)),
+ m_background(new Plasma::FrameSvg(this)),
+ m_scene(new QGraphicsScene(this)),
+ m_container(new MenuWidget(this, menu))
+{
+ qreal left, top, right, bottom;
+
+ //Setup the window properties
+ setWindowFlags(Qt::Tool|Qt::X11BypassWindowManagerHint|Qt::WindowStaysOnTopHint);
+ setAttribute(Qt::WA_TranslucentBackground);
+ KWindowSystem::setType(winId(), NET::Dock);
+ setFrameStyle(QFrame::NoFrame);
+ viewport()->setAutoFillBackground(false);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ //Setup the widgets
+ m_background->setImagePath("widgets/tooltip");
+ m_background->setEnabledBorders(Plasma::FrameSvg::BottomBorder|Plasma::FrameSvg::LeftBorder|Plasma::FrameSvg::RightBorder);
+ m_container->updateLayout();
+
+ m_scene->addItem(m_container);
+
+ setScene(m_scene);
+
+ m_background->getMargins(left, top, right, bottom);
+ m_container->layout()->setContentsMargins(left, top, right, bottom);
+ resize(sizeHint());
+
+ connect(m_container, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHide()));
+ connect(m_hideTimer, SIGNAL(timeout()), this, SLOT(slotAboutToHide()));
+}
+
+MenuBar::~MenuBar()
+{
+}
+
+QSize MenuBar::sizeHint() const
+{
+ QSizeF size = m_container->minimumSize();
+ return QSize(size.width(), size.height());
+}
+
+void MenuBar::show()
+{
+ m_hideTimer->start(1000);
+ QGraphicsView::show();
+
+}
+
+void MenuBar::hide()
+{
+ emit aboutToHide();
+ m_hideTimer->stop();
+ QGraphicsView::hide();
+}
+
+void MenuBar::slotAboutToHide()
+{
+ if (m_container->aMenuIsVisible()) { // MenuBar::m_hideTimer
+ m_hideTimer->stop(); // menu is visible, menubar will be hidden by another aboutToHide() signal
+ }
+ else if (!cursorInMenuBar()) { //MenuWidget::AboutToHide signal
+ hide();
+ emit aboutToHide();
+ } else if (!m_hideTimer->isActive()){ //use click on menubar button while a popup was shown
+ m_hideTimer->start(1000);
+ }
+}
+
+bool MenuBar::cursorInMenuBar()
+{
+ return QRect(pos(), size()).contains(QCursor::pos());
+}
+
+void MenuBar::drawBackground(QPainter *painter, const QRectF &/*rectF*/)
+{
+ painter->save();
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+ m_background->paintFrame(painter);
+ painter->restore();
+}
+
+void MenuBar::resizeEvent(QResizeEvent*)
+{
+ m_background->resizeFrame(size());
+ m_scene->setSceneRect(0, 0, width(), height());
+ if (!KWindowSystem::compositingActive()) {
+ setMask(m_background->mask());
+ }
+}
+
+void MenuBar::showEvent(QShowEvent *)
+{
+ Plasma::WindowEffects::overrideShadow(winId(), true);
+ Plasma::WindowEffects::enableBlurBehind(winId(), true, m_background->mask());
+}
\ No newline at end of file
diff --git a/appmenu/menubar.h b/appmenu/menubar.h
new file mode 100644
index 0000000..0977097
--- /dev/null
+++ b/appmenu/menubar.h
@@ -0,0 +1,82 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MENUBAR__H
+#define MENUBAR__H
+
+#include "menuwidget.h"
+
+#include <QGraphicsView>
+
+class QMenu;
+
+namespace Plasma
+{
+class FrameSvg;
+class Label;
+class Meter;
+}
+
+class MenuBar : public QGraphicsView
+{
+Q_OBJECT
+public:
+ MenuBar(QMenu *menu = 0);
+ ~MenuBar();
+
+ /**
+ * Auto open menu items on mouse over
+ */
+ void autoOpen() { m_container->autoOpen(); }
+
+ /**
+ * set action as active menubar action
+ */
+ void setActiveAction(QAction *action) { m_container->setActiveAction(action); }
+
+ virtual QSize sizeHint() const;
+ virtual void show();
+ virtual void hide();
+
+private Q_SLOTS:
+ void slotAboutToHide();
+Q_SIGNALS:
+ void aboutToHide();
+protected:
+ /**
+ * Return true if cursor in menubar
+ */
+ virtual bool cursorInMenuBar();
+ virtual void drawBackground(QPainter* painter, const QRectF &rectF);
+ virtual void resizeEvent(QResizeEvent* event);
+ virtual void showEvent(QShowEvent* event);
+private:
+ QTimer* m_hideTimer;
+ Plasma::FrameSvg* m_background;
+ QGraphicsScene* m_scene;
+ MenuWidget* m_container;
+};
+
+#endif
diff --git a/appmenu/menubutton.cpp b/appmenu/menubutton.cpp
new file mode 100644
index 0000000..389236e
--- /dev/null
+++ b/appmenu/menubutton.cpp
@@ -0,0 +1,51 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "menubutton.h"
+
+void MenuButton::setHovered(bool hovered)
+{
+ if (hovered) {
+ hoverEnterEvent(0);
+ } else {
+ hoverLeaveEvent(0);
+ }
+}
+
+void MenuButton::hoverEnterEvent(QGraphicsSceneHoverEvent *e)
+{
+ m_enterEvent = true;
+ Plasma::ToolButton::hoverEnterEvent(e);
+}
+
+void MenuButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *e)
+{
+ if (m_enterEvent) {
+ m_enterEvent = false;
+ Plasma::ToolButton::hoverLeaveEvent(e);
+ }
+}
+
+#include "menubutton.moc"
\ No newline at end of file
diff --git a/appmenu/menubutton.h b/appmenu/menubutton.h
new file mode 100644
index 0000000..256d2e1
--- /dev/null
+++ b/appmenu/menubutton.h
@@ -0,0 +1,62 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MENUBUTTON__H
+#define MENUBUTTON__H
+
+#include <Plasma/ToolButton>
+#include <QToolButton>
+
+class MenuButton : public Plasma::ToolButton
+{
+Q_OBJECT
+public:
+ MenuButton(QGraphicsWidget *parent):
+ Plasma::ToolButton(parent),
+ m_enterEvent(false),
+ m_menu(0)
+ {}
+
+ void setMenu(QMenu *menu) { m_menu = menu; }
+ QMenu *menu() { return m_menu; }
+ void setHovered(bool hovered);
+
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
+ {
+ QSizeF sh = Plasma::ToolButton::sizeHint(which, constraint);
+ if (which == Qt::MinimumSize || which == Qt::PreferredSize) {
+ sh.setHeight(nativeWidget()->fontMetrics().height());
+ }
+ return sh;
+ }
+
+protected:
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *);
+private:
+ bool m_enterEvent;
+ QMenu *m_menu;
+};
+#endif
diff --git a/appmenu/menuimporter.cpp b/appmenu/menuimporter.cpp
new file mode 100644
index 0000000..a1d1477
--- /dev/null
+++ b/appmenu/menuimporter.cpp
@@ -0,0 +1,217 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "menuimporter.h"
+#include "menuimporteradaptor.h"
+
+#include <QApplication>
+#include <QDBusMessage>
+#include <QDBusObjectPath>
+#include <QDBusServiceWatcher>
+
+#include <KDebug>
+#include <KWindowSystem>
+#include <KWindowInfo>
+
+static const char* DBUS_SERVICE = "com.canonical.AppMenu.Registrar";
+static const char* DBUS_OBJECT_PATH = "/com/canonical/AppMenu/Registrar";
+
+// Marshalling code for DBusMenuLayoutItem
+QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &obj)
+{
+ argument.beginStructure();
+ argument << obj.id << obj.properties;
+ argument.beginArray(qMetaTypeId<QDBusVariant>());
+ Q_FOREACH(const DBusMenuLayoutItem& child, obj.children) {
+ argument << QDBusVariant(QVariant::fromValue<DBusMenuLayoutItem>(child));
+ }
+ argument.endArray();
+ argument.endStructure();
+ return argument;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &obj)
+{
+ argument.beginStructure();
+ argument >> obj.id >> obj.properties;
+ argument.beginArray();
+ while (!argument.atEnd()) {
+ QDBusVariant dbusVariant;
+ argument >> dbusVariant;
+ QDBusArgument childArgument = dbusVariant.variant().value<QDBusArgument>();
+
+ DBusMenuLayoutItem child;
+ childArgument >> child;
+ obj.children.append(child);
+ }
+ argument.endArray();
+ argument.endStructure();
+ return argument;
+}
+
+MenuImporter::MenuImporter(QObject* parent)
+: QObject(parent)
+, m_serviceWatcher(new QDBusServiceWatcher(this))
+{
+ qDBusRegisterMetaType<DBusMenuLayoutItem>();
+ m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
+ m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
+ connect(m_serviceWatcher, SIGNAL(serviceUnregistered(const QString&)), SLOT(slotServiceUnregistered(const QString&)));
+
+ QDBusConnection::sessionBus().connect("", "", "com.canonical.dbusmenu", "LayoutUpdated",
+ this, SLOT(slotLayoutUpdated(uint,int)));
+}
+
+MenuImporter::~MenuImporter()
+{
+ QDBusConnection::sessionBus().unregisterService(DBUS_SERVICE);
+ QDBusConnection::sessionBus().disconnect("", "", "com.canonical.dbusmenu", "LayoutUpdated",
+ this, SLOT(slotLayoutUpdated(uint,int)));
+}
+
+bool MenuImporter::connectToBus()
+{
+ if (!QDBusConnection::sessionBus().registerService(DBUS_SERVICE)) {
+ return false;
+ }
+ new MenuImporterAdaptor(this);
+ QDBusConnection::sessionBus().registerObject(DBUS_OBJECT_PATH, this);
+
+ return true;
+}
+
+WId MenuImporter::recursiveMenuId(WId id)
+{
+ KWindowInfo info = KWindowSystem::windowInfo(id, 0, NET::WM2WindowClass);
+ QString classClass = info.windowClassClass();
+ WId classId = 0;
+
+ // First look at transient windows
+ WId tid = KWindowSystem::transientFor(id);
+ while (tid) {
+ if (serviceExist(tid)) {
+ classId = tid;
+ break;
+ }
+ tid = KWindowSystem::transientFor(tid);
+ }
+
+ if (classId == 0) {
+ // Look at friends windows
+ QHashIterator<WId, QString> i(m_windowClasses);
+ while (i.hasNext()) {
+ i.next();
+ if (i.value() == classClass) {
+ classId = i.key();
+ }
+ }
+ }
+
+ return classId;
+}
+
+void MenuImporter::RegisterWindow(WId id, const QDBusObjectPath& path)
+{
+ if (path.path().isEmpty()) //prevent bad dbusmenu usage
+ return;
+
+ QString service = message().service();
+ KWindowInfo info = KWindowSystem::windowInfo(id, 0, NET::WM2WindowClass);
+ QString classClass = info.windowClassClass();
+
+ // Should this happen ?
+ m_menuServices.remove(id);
+ m_menuPaths.remove(id);
+
+ m_menuServices.insert(id, service);
+ m_menuPaths.insert(id, path);
+ m_windowClasses.insert(id, classClass);
+ m_serviceWatcher->addWatchedService(service);
+ WindowRegistered(id, service, path);
+}
+
+void MenuImporter::UnregisterWindow(WId id)
+{
+ m_menuServices.remove(id);
+ m_menuPaths.remove(id);
+ m_windowClasses.remove(id);
+
+ WindowUnregistered(id);
+}
+
+QString MenuImporter::GetMenuForWindow(WId id, QDBusObjectPath& path)
+{
+ path = m_menuPaths.value(id);
+ return m_menuServices.value(id);
+}
+
+void MenuImporter::slotServiceUnregistered(const QString& service)
+{
+ WId id = m_menuServices.key(service);
+ m_menuServices.remove(id);
+ m_menuPaths.remove(id);
+ WindowUnregistered(id);
+ m_serviceWatcher->removeWatchedService(service);
+}
+
+void MenuImporter::slotLayoutUpdated(uint /*revision*/, int parentId)
+{
+ // Fake unity-panel-service weird behavior of calling aboutToShow on
+ // startup. This is necessary for Firefox menubar to work correctly at
+ // startup.
+ // See: https://bugs.launchpad.net/plasma-idget-menubar/+bug/878165
+
+ if (parentId == 0) { //root menu
+ fakeUnityAboutToShow();
+ }
+}
+
+void MenuImporter::fakeUnityAboutToShow()
+{
+ QDBusInterface iface(message().service(), message().path(), "com.canonical.dbusmenu");
+ QDBusPendingCall call = iface.asyncCall("GetLayout", 0, 1, QStringList());
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(call, this);
+ watcher->setProperty("service", message().service());
+ watcher->setProperty("path", message().path());
+ connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finishFakeUnityAboutToShow(QDBusPendingCallWatcher*)));
+}
+
+void MenuImporter::finishFakeUnityAboutToShow(QDBusPendingCallWatcher* watcher)
+{
+ QDBusPendingReply<uint, DBusMenuLayoutItem> reply = *watcher;
+ if (reply.isError()) {
+ kWarning() << "Call to GetLayout failed:" << reply.error().message();
+ return;
+ }
+ QString service = watcher->property("service").toString();
+ QString path = watcher->property("path").toString();
+ DBusMenuLayoutItem root = reply.argumentAt<1>();
+
+ QDBusInterface iface(service, path, "com.canonical.dbusmenu");
+ Q_FOREACH(const DBusMenuLayoutItem& dbusMenuItem, root.children) {
+ iface.asyncCall("AboutToShow", dbusMenuItem.id);
+ }
+}
diff --git a/appmenu/menuimporter.h b/appmenu/menuimporter.h
new file mode 100644
index 0000000..adfc542
--- /dev/null
+++ b/appmenu/menuimporter.h
@@ -0,0 +1,98 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MENUIMPORTER_H
+#define MENUIMPORTER_H
+
+// Qt
+#include <QDBusContext>
+#include <QDBusObjectPath>
+#include <QObject>
+#include <QWidget> // For WId
+
+class QDBusObjectPath;
+class QDBusPendingCallWatcher;
+class QDBusServiceWatcher;
+class QMenu;
+
+/**
+ * Represents an item with its children. GetLayout() returns a
+ * DBusMenuLayoutItemList.
+ */
+struct DBusMenuLayoutItem
+{
+ int id;
+ QVariantMap properties;
+ QList<DBusMenuLayoutItem> children;
+};
+Q_DECLARE_METATYPE(DBusMenuLayoutItem)
+
+class MenuImporter : public QObject, protected QDBusContext
+{
+ Q_OBJECT
+
+public:
+ MenuImporter(QObject*);
+ ~MenuImporter();
+
+ bool connectToBus();
+
+ bool serviceExist(WId id) { return m_menuServices.contains(id); }
+ QString serviceForWindow(WId id) { return m_menuServices.value(id); }
+
+ bool pathExist(WId id) { return m_menuPaths.contains(id); }
+ QString pathForWindow(WId id) { return m_menuPaths.value(id).path(); }
+
+ QList<WId> ids() { return m_menuServices.keys(); }
+
+ /**
+ * Return id of first transient/friend window with a menu available
+ */
+ WId recursiveMenuId(WId id);
+
+Q_SIGNALS:
+ void WindowRegistered(WId id, const QString& service, const QDBusObjectPath&);
+ void WindowUnregistered(WId id);
+
+public Q_SLOTS:
+ Q_NOREPLY void RegisterWindow(WId id, const QDBusObjectPath& path);
+ Q_NOREPLY void UnregisterWindow(WId id);
+ QString GetMenuForWindow(WId id, QDBusObjectPath& path);
+
+private Q_SLOTS:
+ void slotServiceUnregistered(const QString& service);
+ void slotLayoutUpdated(uint revision, int parentId);
+ void finishFakeUnityAboutToShow(QDBusPendingCallWatcher*);
+
+private:
+ QDBusServiceWatcher* m_serviceWatcher;
+ QHash<WId, QString> m_menuServices;
+ QHash<WId, QDBusObjectPath> m_menuPaths;
+ QHash<WId, QString> m_windowClasses;
+
+ void fakeUnityAboutToShow();
+};
+
+#endif /* MENUIMPORTER_H */
diff --git a/appmenu/menuwidget.cpp b/appmenu/menuwidget.cpp
new file mode 100644
index 0000000..3af0e5e
--- /dev/null
+++ b/appmenu/menuwidget.cpp
@@ -0,0 +1,259 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "menubutton.h"
+#include "menuwidget.h"
+
+#include <QMenu>
+#include <QDesktopWidget>
+#include <QGraphicsView>
+#include <QGraphicsLinearLayout>
+
+#include <KWindowSystem>
+#include <KDebug>
+#include <KApplication>
+
+MenuWidget::MenuWidget(QGraphicsView *view, QMenu *menu) :
+ QGraphicsWidget(),
+ m_mouseTimer(new QTimer(this)),
+ m_view(view),
+ m_layout(new QGraphicsLinearLayout(this)),
+ m_currentButton(0),
+ m_aMenuIsVisible(false),
+ m_menu(menu)
+{
+ connect(m_mouseTimer, SIGNAL(timeout()), SLOT(slotCheckActiveItem()));
+
+ m_layout->setContentsMargins(0, 0, 0, 0);
+}
+
+MenuWidget::~MenuWidget()
+{
+ delete m_mouseTimer;
+ while (!m_buttons.isEmpty()) {
+ delete m_buttons.front();
+ m_buttons.pop_front();
+ }
+}
+
+void MenuWidget::updateLayout()
+{
+ foreach( QAction* action, m_menu->actions() )
+ {
+ QMenu *menu = action->menu();
+ action->setShortcut(QKeySequence());
+ MenuButton* button;
+ if( action->isSeparator() || !menu )
+ continue;
+
+ //Create a new button, we do not set menu here as it may have changed on showMenu()
+ button = new MenuButton(this);
+ button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ button->setText(action->text());
+ button->setMenu(action->menu());
+ connect(button, SIGNAL(clicked()), SLOT(slotButtonClicked()));
+ m_layout->addItem(button);
+ m_buttons << button;
+ }
+}
+
+bool MenuWidget::eventFilter(QObject* object, QEvent* event)
+{
+ QMenu *menu = static_cast<QMenu*>(object);
+
+ if (event->type() == QEvent::KeyPress) {
+ menu->removeEventFilter(this);
+ QApplication::sendEvent(menu, event);
+ menu->installEventFilter(this);
+ if (!event->isAccepted()) {
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+ switch (keyEvent->key()) {
+ case Qt::Key_Left:
+ showLeftRightMenu(false);
+ break;
+ case Qt::Key_Right:
+ showLeftRightMenu(true);
+ break;
+ case Qt::Key_Escape:
+ menu->hide();
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+void MenuWidget::slotCheckActiveItem()
+{
+ MenuButton* buttonBelow = 0;
+ QPoint pos = m_view->mapFromGlobal(QCursor::pos());
+ QGraphicsItem* item = m_view->itemAt(pos);
+
+ if (item)
+ buttonBelow = qobject_cast<MenuButton*>(item->toGraphicsObject());
+
+ if (!buttonBelow)
+ return;
+
+ if (buttonBelow != m_currentButton) {
+ if (m_currentButton) {
+ m_currentButton->nativeWidget()->setDown(false);
+ m_currentButton->setHovered( false );
+ QMenu *menu = m_currentButton->menu();
+ if (menu) {
+ disconnect(menu, SIGNAL(aboutToHide()), this, SLOT(slotMenuAboutToHide()));
+ menu->hide();
+ m_aMenuIsVisible = false;
+ }
+ }
+ m_currentButton = buttonBelow;
+ m_currentButton->nativeWidget()->setDown(true);
+ showMenu();
+ }
+}
+
+void MenuWidget::slotMenuAboutToHide()
+{
+ m_currentButton->setDown( false );
+ if (m_mouseTimer->isActive())
+ m_mouseTimer->stop();
+ m_aMenuIsVisible = false;
+ emit aboutToHide();
+}
+
+void MenuWidget::slotButtonClicked()
+{
+ m_currentButton = qobject_cast<MenuButton*>(sender());
+
+ m_currentButton->nativeWidget()->setDown(true);
+ showMenu();
+ // Start auto navigation after click
+ if (!m_mouseTimer->isActive())
+ m_mouseTimer->start(100);
+}
+
+void MenuWidget::setActiveAction(QAction *action)
+{
+ m_currentButton = m_buttons.first();
+
+ if (action) {
+ QMenu *menu;
+ foreach (MenuButton *button, m_buttons) {
+ menu = button->menu();
+ if (menu && menu == action->menu()) {
+ m_currentButton = button;
+ break;
+ }
+ }
+ }
+ m_currentButton->nativeWidget()->animateClick();
+}
+
+void MenuWidget::hide()
+{
+ if (m_mouseTimer->isActive())
+ m_mouseTimer->stop();
+ QGraphicsWidget::hide();
+}
+
+void MenuWidget::showMenu()
+{
+ QMenu *menu = 0;
+ //Look for submenu, we do not use m_currentButton->menu() as menu may have changed.
+ foreach (QAction *action, m_menu->actions()) {
+ if (m_currentButton->text() == action->text()) {
+ menu = action->menu();
+ break;
+ }
+ }
+
+ if (menu) {
+ QPoint globalPos = m_view->mapToGlobal(QPoint(0,0));
+ QPointF parentPos = m_currentButton->mapFromParent(QPoint(0,0));
+ QRect screen = KApplication::desktop()->screenGeometry();
+ int x = globalPos.x() - parentPos.x();
+ int y = globalPos.y() + m_currentButton->size().height() - parentPos.y();
+
+ m_currentButton->setMenu(menu);
+ menu->popup(QPoint(x, y));
+ m_aMenuIsVisible = true;
+
+ // Fix offscreen menu
+ if (menu->size().height() + y > screen.height() + screen.y()) {
+ y = globalPos.y() - parentPos.y() - menu->size().height();
+ if (menu->size().width() + x > screen.width() + screen.x())
+ x = screen.width() + screen.x() - menu->size().width();
+ else if (menu->size().width() + x < screen.x())
+ x = screen.x();
+ menu->move(x, y);
+ }
+
+ connect(menu, SIGNAL(aboutToHide()), this, SLOT(slotMenuAboutToHide()));
+
+ installEventFilterForAll(menu, this);
+ }
+}
+
+void MenuWidget::showLeftRightMenu(bool next)
+{
+ int index = m_buttons.indexOf(m_currentButton);
+ if (index == -1) {
+ kWarning() << "Couldn't find button!";
+ return;
+ }
+ if (next) {
+ index = (index + 1) % m_buttons.count();
+ } else {
+ index = (index == 0 ? m_buttons.count() : index) - 1;
+ }
+
+ QMenu *menu = m_currentButton->menu();
+
+ if (menu) {
+ disconnect(menu, SIGNAL(aboutToHide()), this, SLOT(slotMenuAboutToHide()));
+ m_aMenuIsVisible = false;
+ menu->hide();
+ }
+
+ m_currentButton->setDown(false);
+ m_currentButton = m_buttons.at(index);
+ m_currentButton->nativeWidget()->setDown(true);
+ showMenu();
+}
+
+void MenuWidget::installEventFilterForAll(QMenu *menu, QObject *object)
+{
+ menu->installEventFilter(this);
+
+ foreach (QAction *action, menu->actions()) {
+ if (action->menu())
+ installEventFilterForAll(action->menu(), object);
+ }
+}
+
+#include "menuwidget.moc"
\ No newline at end of file
diff --git a/appmenu/menuwidget.h b/appmenu/menuwidget.h
new file mode 100644
index 0000000..e2c5255
--- /dev/null
+++ b/appmenu/menuwidget.h
@@ -0,0 +1,111 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MENUWIDGET__H
+#define MENUWIDGET__H
+
+#include <QGraphicsWidget>
+#include <QTimer>
+
+class QGraphicsLinearLayout;
+class QGraphicsView;
+class MenuButton;
+
+class MenuWidget : public QGraphicsWidget
+{
+Q_OBJECT
+public:
+ MenuWidget(QGraphicsView *view = 0, QMenu *menu = 0);
+ ~MenuWidget();
+
+ /**
+ * Update layout with root menu
+ */
+ void updateLayout();
+ /**
+ * Return true if layout is valid and populated
+ */
+ bool layoutValid();
+ /**
+ * True if a menu is visible in menubar
+ */
+ bool aMenuIsVisible() { return m_aMenuIsVisible; }
+
+ /**
+ * Activate action, or first action if null
+ */
+ void setActiveAction(QAction *action);
+
+ /**
+ * Auto open menu items on mouse over
+ */
+ void autoOpen() { m_mouseTimer->start(100); }
+
+ void hide();
+protected:
+ /**
+ * Use to get keyboard events
+ */
+ virtual bool eventFilter(QObject*, QEvent*);
+private Q_SLOTS:
+ /**
+ * Check hovered item and active it
+ */
+ void slotCheckActiveItem();
+ /**
+ * a menu is hidding
+ */
+ void slotMenuAboutToHide();
+ /**
+ * menubar button clicked
+ */
+ void slotButtonClicked();
+Q_SIGNALS:
+ void aboutToHide();
+private:
+ /**
+ * Show current button menu
+ */
+ void showMenu();
+ /**
+ * Show next menu if next, otherwise previous
+ */
+ void showLeftRightMenu(bool next);
+ /**
+ * Install event filter for menu and it submenus
+ */
+ void installEventFilterForAll(QMenu *menu, QObject *object);
+
+ //Follow mouse position
+ QTimer *m_mouseTimer;
+ QGraphicsView *m_view;
+ QGraphicsLinearLayout *m_layout;
+ QList<MenuButton*> m_buttons;
+ MenuButton *m_currentButton;
+ bool m_aMenuIsVisible;
+ QMenu *m_menu;
+};
+
+#endif //MENUWIDGET__H
diff --git a/appmenu/org.kde.kded.appmenu.xml b/appmenu/org.kde.kded.appmenu.xml
new file mode 100644
index 0000000..8056fba
--- /dev/null
+++ b/appmenu/org.kde.kded.appmenu.xml
@@ -0,0 +1,31 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.kde.kded">
+ <method name="showMenu">
+ <arg name="x" type="i" direction="in"/>
+ <arg name="y" type="i" direction="in"/>
+ <arg name="WId" type="t" direction="in"/>
+ </method>
+ <method name="reconfigure">
+ </method>
+ <signal name="showRequest">
+ <arg name="WId" type="t"/>
+ </signal>
+ <signal name="menuAvailable">
+ <arg name="WId" type="t"/>
+ </signal>
+ <signal name="clearMenus">
+ </signal>
+ <signal name="menuHidden">
+ <arg name="WId" type="t"/>
+ </signal>
+ <signal name="WindowRegistered">
+ <arg name="windowId" type="t" direction="out"/>
+ <arg name="service" type="s" direction="out"/>
+ <arg name="menuObjectPath" type="o" direction="out"/>
+ </signal>
+ <signal name="WindowUnregistered">
+ <arg name="windowId" type="t" direction="out"/>
+ </signal>
+ </interface>
+</node>
diff --git a/appmenu/topmenubar.cpp b/appmenu/topmenubar.cpp
new file mode 100644
index 0000000..9cf51b1
--- /dev/null
+++ b/appmenu/topmenubar.cpp
@@ -0,0 +1,118 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "topmenubar.h"
+#include "glowbar.h"
+
+//KDE
+#include <Plasma/Svg>
+#include <KWindowSystem>
+
+// Qt
+#include <QMenu>
+#include <QTimer>
+#include <QDebug>
+
+TopMenuBar::TopMenuBar(QMenu *menu)
+ : MenuBar(menu),
+ m_mouseTracker(new QTimer(this)),
+ m_glowBar(0)
+{
+ connect(this, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHide()));
+ connect(m_mouseTracker, SIGNAL(timeout()), this, SLOT(slotMouseTracker()));
+}
+
+TopMenuBar::~TopMenuBar()
+{
+ disconnect(m_mouseTracker, SIGNAL(timeout()), this, SLOT(slotMouseTracker()));
+ delete m_mouseTracker;
+ if (m_glowBar) {
+ m_glowBar->hide();
+ delete m_glowBar;
+ m_glowBar = 0;
+ }
+}
+
+void TopMenuBar::enableMouseTracking(bool enable) {
+ if (enable) {
+ m_mouseTracker->start(250);
+ slotDestroyGlowBar();
+ m_glowBar = new GlowBar(triggerRect().topLeft(), triggerRect().width());
+ connect(m_glowBar, SIGNAL(destroy()), this, SLOT(slotDestroyGlowBar()));
+ m_glowBar->show();
+ }
+ else
+ m_mouseTracker->stop();
+}
+
+bool TopMenuBar::cursorInMenuBar()
+{
+ if (m_mouseTracker->isActive()) {
+ return triggerRect().contains(QCursor::pos());
+ } else {
+ return MenuBar::cursorInMenuBar();
+ }
+}
+
+void TopMenuBar::slotAboutToHide()
+{
+ enableMouseTracking();
+}
+
+void TopMenuBar::slotMouseTracker()
+{
+ static QPoint prevCursorPos;
+
+ if (cursorInMenuBar()) {
+ m_mouseTracker->stop();
+ slotDestroyGlowBar();
+ show();
+ } else {
+ QPoint cursorPos = QCursor::pos();
+ // if cursor move, show glow bar
+ if (!m_glowBar && cursorPos != prevCursorPos) {
+ m_glowBar = new GlowBar(triggerRect().topLeft(), triggerRect().width());
+ connect(m_glowBar, SIGNAL(destroy()), this, SLOT(slotDestroyGlowBar()));
+ m_glowBar->show();
+ }
+ prevCursorPos = cursorPos;
+ }
+}
+
+void TopMenuBar::slotDestroyGlowBar()
+{
+ if (m_glowBar) {
+ m_glowBar->hide();
+ delete m_glowBar;
+ m_glowBar = 0;
+ }
+}
+QRect TopMenuBar::triggerRect()
+{
+ QPoint triggerPoint = QPoint(x(), y());
+ QSize triggerSize = QSize(sizeHint().width(), 5);
+ return QRect(triggerPoint, triggerSize);
+}
+#include "topmenubar.moc"
\ No newline at end of file
diff --git a/appmenu/topmenubar.h b/appmenu/topmenubar.h
new file mode 100644
index 0000000..d0c493d
--- /dev/null
+++ b/appmenu/topmenubar.h
@@ -0,0 +1,67 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef TOPMENUBAR__H
+#define TOPMENUBAR__H
+
+#include "menubar.h"
+
+class QTimer;
+class GlowBar;
+
+class TopMenuBar : public MenuBar
+{
+Q_OBJECT
+public:
+ TopMenuBar(QMenu *menu = 0);
+ ~TopMenuBar();
+
+ /**
+ * Start mouse tracking (hide/show on mouse event)
+ */
+ void enableMouseTracking(bool enable = true);
+
+ /**
+ * Set menubar parent window id
+ */
+ void setMenuBarParentWid(WId id) { m_wid = id; }
+ /**
+ * Get menubar parent window id
+ */
+ WId menuBarParentWid() { return m_wid; }
+protected:
+ bool cursorInMenuBar();
+private Q_SLOTS:
+ void slotAboutToHide();
+ void slotMouseTracker();
+ void slotDestroyGlowBar();
+private:
+ QRect triggerRect();
+ WId m_wid;
+ QTimer* m_mouseTracker;
+ GlowBar* m_glowBar;
+};
+
+#endif
diff --git a/appmenu/verticalmenu.cpp b/appmenu/verticalmenu.cpp
new file mode 100644
index 0000000..ad0e95f
--- /dev/null
+++ b/appmenu/verticalmenu.cpp
@@ -0,0 +1,62 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "verticalmenu.h"
+
+#include <QMenu>
+#include <QEvent>
+
+#include <KWindowSystem>
+#include <netwm.h>
+
+VerticalMenu::VerticalMenu(QWidget* parent) :
+ QMenu(parent)
+{
+}
+
+VerticalMenu::~VerticalMenu()
+{
+}
+
+void VerticalMenu::popup(QPoint p)
+{
+ // This flags are mandatory to get focus.
+ // Qt::Popup will fail to grab input here
+ setWindowFlags(Qt::Dialog|Qt::CustomizeWindowHint|Qt::WindowStaysOnTopHint);
+ QMenu::popup(p);
+ KWindowSystem::forceActiveWindow(winId());
+}
+
+bool VerticalMenu::event(QEvent *e)
+{
+ if (e->type() == QEvent::WindowDeactivate) {
+ hide();
+ } else if (e->type() == QEvent::Show) {
+ KWindowSystem::setState(winId(), NET::SkipTaskbar|NET::SkipPager);
+ }
+ return QMenu::event(e);
+}
+
+#include "verticalmenu.moc"
\ No newline at end of file
diff --git a/appmenu/verticalmenu.h b/appmenu/verticalmenu.h
new file mode 100644
index 0000000..ce9b7a0
--- /dev/null
+++ b/appmenu/verticalmenu.h
@@ -0,0 +1,55 @@
+/*
+ This file is part of the KDE project.
+
+ Copyright (c) 2011 Lionel Chauvin <megabigbug at yahoo.fr>
+ Copyright (c) 2011,2012 Cédric Bellegarde <gnumdk at gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef VERTICALMENU_H
+#define VERTICALMENU_H
+
+#include <QMenu>
+
+class QMenu;
+
+class VerticalMenu : public QMenu
+{
+Q_OBJECT
+public:
+ VerticalMenu(QWidget * parent = 0);
+ ~VerticalMenu();
+
+ void popup(QPoint);
+ bool event(QEvent *);
+
+ /**
+ * Set menubar parent window id
+ */
+ void setMenuBarParentWid(WId id) { m_wid = id; }
+ /**
+ * Get menubar parent window id
+ */
+ WId menuBarParentWid() { return m_wid; }
+private:
+ WId m_wid;
+};
+
+#endif //VERTICALMENU_H
More information about the kde-doc-english
mailing list