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
