[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