aboutsummaryrefslogtreecommitdiff
path: root/module
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2014-01-28 17:21:16 +0100
committerJavier <dev.git@javispedro.com>2014-01-28 17:21:16 +0100
commit982ebc96f2c77c1f9dbddd6a4c0a776c74b425de (patch)
tree6800326ba4da9c84dc14f0b442f088b1c2fb63bf /module
downloadtopmenu-qt-982ebc96f2c77c1f9dbddd6a4c0a776c74b425de.tar.gz
topmenu-qt-982ebc96f2c77c1f9dbddd6a4c0a776c74b425de.zip
initial import
Diffstat (limited to 'module')
-rw-r--r--module/appmenu.cc154
-rw-r--r--module/appmenu.h32
-rw-r--r--module/menuproxy.cc286
-rw-r--r--module/menuproxy.h48
-rw-r--r--module/module.pro24
-rw-r--r--module/qtkeysyms.cc313
-rw-r--r--module/qtkeysyms.h6
-rw-r--r--module/topmenumenubarimpl.cc252
-rw-r--r--module/topmenumenubarimpl.h71
-rw-r--r--module/topmenumenubarimplfactory.cc16
-rw-r--r--module/topmenumenubarimplfactory.h16
11 files changed, 1218 insertions, 0 deletions
diff --git a/module/appmenu.cc b/module/appmenu.cc
new file mode 100644
index 0000000..4902533
--- /dev/null
+++ b/module/appmenu.cc
@@ -0,0 +1,154 @@
+#include <gtk/gtk.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtGui/QMenuBar>
+
+#include "appmenu.h"
+
+AppMenu::AppMenu(QObject *parent)
+ : MenuProxy(parent), m_menu(0)
+
+{
+}
+
+AppMenu::~AppMenu()
+{
+ if (m_menu) {
+ gtk_widget_destroy(GTK_WIDGET(m_menu));
+ }
+}
+
+GtkMenu * AppMenu::getGtkMenu()
+{
+ if (!m_menu) {
+ m_menu = GTK_MENU(gtk_menu_new());
+ g_object_ref_sink(m_menu);
+ setTargetMenu(GTK_MENU_SHELL(m_menu));
+ addDefaultItems();
+ }
+ return m_menu;
+}
+
+GtkMenuItem * AppMenu::addAction(QAction* action)
+{
+ QAction::MenuRole role = detectRole(action);
+ if (role == QAction::NoRole)
+ return 0; // Item should not appear in appmenu
+
+ // If we just inserted a custom quit item, remove the default one.
+ if (role == QAction::QuitRole) {
+ removeAction(m_def_quit);
+ }
+
+ uint order = orderForRole(role);
+ QMap<uint, QAction*>::iterator it = m_actions.insert(order, action);
+
+ // Get the previous element
+ QAction *before = 0;
+ if (it != m_actions.begin()) {
+ --it;
+ before = it.value();
+ }
+
+ return MenuProxy::addAction(action, before, 0);
+}
+
+GtkMenuItem * AppMenu::addAction(QAction* action, QAction* before, QMenu* parent)
+{
+ if (parent) {
+ return MenuProxy::addAction(action, before, parent);
+ } else {
+ // Never add an action to the root menu here.
+ return 0;
+ }
+}
+
+void AppMenu::removeAction(QAction *action)
+{
+ if (getItemForAction(action)) {
+ MenuProxy::removeAction(action);
+ m_actions.remove(orderForRole(action->menuRole()), action);
+ }
+}
+
+void AppMenu::updateAction(QAction *action)
+{
+ GtkMenuItem *item = getItemForAction(action);
+
+ if (item) {
+ MenuProxy::updateAction(action);
+ } else {
+ QAction::MenuRole role = detectRole(action);
+ if (role != QAction::NoRole) {
+ // The item now has a role!
+ addAction(action);
+ }
+ }
+}
+
+void AppMenu::addDefaultItems()
+{
+ QAction *separator = new QAction(this);
+ separator->setSeparator(true);
+ m_actions.insert(15, separator);
+ MenuProxy::addAction(separator, 0, 0);
+
+ m_def_quit = new QAction(QIcon::fromTheme("application-exit"),
+ QMenuBar::tr("Quit"), this);
+ m_actions.insert(11, m_def_quit);
+ MenuProxy::addAction(m_def_quit, 0, 0);
+
+ connect(m_def_quit, SIGNAL(triggered()),
+ QCoreApplication::instance(), SLOT(quit()));
+}
+
+uint AppMenu::orderForRole(QAction::MenuRole role)
+{
+ switch (role) {
+ case QAction::AboutRole:
+ return 50;
+ case QAction::AboutQtRole:
+ return 40;
+ case QAction::PreferencesRole:
+ return 30;
+ case QAction::ApplicationSpecificRole:
+ return 20;
+ case QAction::QuitRole:
+ return 10;
+ default:
+ return 0;
+ }
+}
+
+QAction::MenuRole AppMenu::detectRole(QAction *action)
+{
+ QAction::MenuRole role = action->menuRole();
+
+ if (action->isSeparator()) return QAction::NoRole;
+
+ if (role == QAction::TextHeuristicRole) {
+ QString t = action->text().toLower().remove('&');
+
+ QString aboutString = QMenuBar::tr("About").toLower();
+ if (t.startsWith(aboutString) || t.endsWith(aboutString)) {
+ if (t.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) {
+ return QAction::AboutRole;
+ } else {
+ return QAction::AboutQtRole;
+ }
+ } else if (t.startsWith(QMenuBar::tr("Config").toLower())
+ || t.startsWith(QMenuBar::tr("Preference").toLower())
+ || t.startsWith(QMenuBar::tr("Options").toLower())
+ || t.startsWith(QMenuBar::tr("Setting").toLower())
+ || t.startsWith(QMenuBar::tr("Setup").toLower())) {
+ return QAction::PreferencesRole;
+ } else if (t.startsWith(QMenuBar::tr("Quit").toLower())
+ || t.startsWith(QMenuBar::tr("Exit").toLower())) {
+ return QAction::QuitRole;
+ }
+
+ return QAction::NoRole;
+ } else {
+ return role;
+ }
+}
diff --git a/module/appmenu.h b/module/appmenu.h
new file mode 100644
index 0000000..bc7171d
--- /dev/null
+++ b/module/appmenu.h
@@ -0,0 +1,32 @@
+#ifndef APPMENU_H
+#define APPMENU_H
+
+#include "menuproxy.h"
+
+class AppMenu : public MenuProxy
+{
+ Q_OBJECT
+
+public:
+ AppMenu(QObject *parent = 0);
+ ~AppMenu();
+
+ GtkMenu * getGtkMenu();
+
+ GtkMenuItem * addAction(QAction *action);
+ GtkMenuItem * addAction(QAction* action, QAction* before, QMenu* parent);
+ void removeAction(QAction* action);
+ void updateAction(QAction* action);
+
+private:
+ void addDefaultItems();
+ static uint orderForRole(QAction::MenuRole role);
+ static QAction::MenuRole detectRole(QAction *action);
+
+private:
+ GtkMenu *m_menu;
+ QMultiMap<uint, QAction*> m_actions;
+ QAction *m_def_quit;
+};
+
+#endif // APPMENU_H
diff --git a/module/menuproxy.cc b/module/menuproxy.cc
new file mode 100644
index 0000000..5536bf5
--- /dev/null
+++ b/module/menuproxy.cc
@@ -0,0 +1,286 @@
+#include <gtk/gtk.h>
+#include <QtCore/QDebug>
+#include <QtGui/QActionEvent>
+
+#include "menuproxy.h"
+#include "qtkeysyms.h"
+
+static inline int index_of_menu_item(GtkMenuShell *shell, GtkMenuItem *item)
+{
+ return g_list_index(shell->children, item);
+}
+
+static inline GtkMenuItem * get_nth_menu_item(GtkMenuShell *shell, int i)
+{
+ return GTK_MENU_ITEM(g_list_nth_data(shell->children, i));
+}
+
+static bool transform_key_sequence(const QKeySequence &keys, guint *keyp, GdkModifierType *modsp)
+{
+ uint count = keys.count();
+ if (count != 1) return false; // TODO
+
+ guint mods = 0;
+ guint key = 0;
+
+ for (uint i = 0; i < count; i++) {
+ const uint qt_key = keys[i];
+ if (qt_key & Qt::CTRL) mods |= GDK_CONTROL_MASK;
+ if (qt_key & Qt::ALT) mods |= GDK_MOD1_MASK;
+ if (qt_key & Qt::SHIFT) mods |= GDK_SHIFT_MASK;
+
+ key = qt_to_gdk_key(qt_key & ~Qt::MODIFIER_MASK);
+ }
+
+ *keyp = key;
+ *modsp = GdkModifierType(mods);
+
+ return true;
+}
+
+static void destroy_image_data(guchar *pixels, gpointer data)
+{
+ Q_UNUSED(data);
+ g_free(pixels);
+}
+
+MenuProxy::MenuProxy(QObject *parent)
+ : QObject(parent), m_target(0), m_accel(0)
+{
+}
+
+MenuProxy::~MenuProxy()
+{
+ Q_FOREACH(GtkMenu *menu, m_menus) {
+ gtk_widget_destroy(GTK_WIDGET(menu));
+ }
+ Q_FOREACH(GtkMenuItem *item, m_items) {
+ gtk_widget_destroy(GTK_WIDGET(item));
+ }
+ if (m_accel) {
+ g_object_unref(m_accel);
+ m_accel = 0;
+ }
+}
+
+void MenuProxy::setTargetMenu(GtkMenuShell *shell)
+{
+ m_target = shell;
+ if (!m_accel) {
+ m_accel = gtk_accel_group_new();
+ }
+}
+
+GtkMenuItem * MenuProxy::addAction(QAction* action, QAction* before, QMenu* parent)
+{
+ GtkMenuShell *g_parent;
+ if (parent) {
+ g_parent = GTK_MENU_SHELL(m_menus.value(parent));
+ } else {
+ g_parent = m_target;
+ }
+
+ GtkMenuItem *item;
+ if (action->isSeparator()) {
+ item = GTK_MENU_ITEM(gtk_separator_menu_item_new());
+ } else if (action->isCheckable()) {
+ QString label = transformMnemonic(action->text());
+ item = GTK_MENU_ITEM(gtk_check_menu_item_new_with_mnemonic(label.toUtf8().constData()));
+ if (action->actionGroup() && action->actionGroup()->isExclusive()) {
+ gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(item), TRUE);
+ }
+ } else {
+ QString label = transformMnemonic(action->text());
+ QIcon icon = action->icon();
+ if (!icon.isNull()) {
+ QImage image = icon.pixmap(16, 16).toImage().convertToFormat(QImage::Format_ARGB32).rgbSwapped();
+ gsize size = image.byteCount();
+ guchar *data = (guchar*) g_malloc(size);
+ memcpy(data, image.constBits(), size);
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB,
+ image.hasAlphaChannel(), 8,
+ image.width(), image.height(),
+ image.bytesPerLine(),
+ destroy_image_data, NULL);
+ item = GTK_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(label.toUtf8().constData()));
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
+ gtk_image_new_from_pixbuf(pixbuf));
+ g_object_unref(pixbuf);
+ } else {
+ item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(label.toUtf8().constData()));
+ }
+ }
+
+ m_items.insert(action, item);
+ g_object_ref_sink(item);
+
+ if (before) {
+ GtkMenuItem *g_before = m_items.value(before);
+ Q_ASSERT(g_before);
+ gint position = index_of_menu_item(g_parent, g_before);
+ gtk_menu_shell_insert(g_parent, GTK_WIDGET(item), position);
+ } else {
+ gtk_menu_shell_append(g_parent, GTK_WIDGET(item));
+ }
+
+ QMenu *menu = action->menu();
+ if (menu) {
+ GtkMenu * g_menu = addMenu(menu);
+ gtk_menu_item_set_submenu(item, GTK_WIDGET(g_menu));
+ }
+
+ updateAction(action);
+
+ return item;
+}
+
+GtkMenu * MenuProxy::addMenu(QMenu *menu)
+{
+ menu->installEventFilter(this);
+
+ GtkMenu *g_menu = GTK_MENU(gtk_menu_new());
+
+ m_menus.insert(menu, g_menu);
+ g_object_ref_sink(g_menu);
+
+ // Items might have been added already
+ foreach (QAction *action, menu->actions()) {
+ addAction(action, 0, menu);
+ }
+
+ return g_menu;
+}
+
+void MenuProxy::removeAction(QAction *action)
+{
+ QMenu* menu = action->menu();
+
+ if (menu) {
+ removeMenu(menu);
+ }
+
+ GtkMenuItem *item = m_items.value(action);
+ if (!item) {
+ return;
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(item));
+ m_items.remove(action);
+}
+
+void MenuProxy::removeMenu(QMenu *menu)
+{
+ GtkMenu *g_menu = m_menus.value(menu);
+ Q_ASSERT(g_menu);
+ GtkWidget *g_item = gtk_menu_get_attach_widget(g_menu);
+ Q_ASSERT(g_item);
+ GtkMenu *g_parent = GTK_MENU(gtk_widget_get_parent(g_item));
+ Q_ASSERT(g_parent),
+
+ menu->removeEventFilter(this);
+
+ gtk_widget_destroy(GTK_WIDGET(g_menu));
+ m_menus.remove(menu);
+}
+
+void MenuProxy::updateAction(QAction *action)
+{
+ GtkMenuItem *item = m_items.value(action);
+ Q_ASSERT(item);
+
+ g_signal_handlers_disconnect_by_data(item, action);
+
+ if (action->isSeparator()) {
+ // TODO Decide visibility of separators using Qt rules.
+ gtk_widget_set_visible(GTK_WIDGET(item), action->isVisible());
+ } else {
+ QString label = action->text().replace(QChar('&'), QChar('_'));
+ gtk_menu_item_set_label(item, label.toUtf8().constData());
+
+ if (GTK_IS_CHECK_MENU_ITEM(item)) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),
+ action->isChecked());
+ }
+
+ GtkWidget *child = gtk_bin_get_child(GTK_BIN(item));
+ if (GTK_IS_ACCEL_LABEL(child)) {
+ Q_FOREACH(const QKeySequence& shortcut, action->shortcuts()) {
+ guint key;
+ GdkModifierType mods;
+ if (transform_key_sequence(shortcut, &key, &mods)) {
+ gtk_widget_add_accelerator(GTK_WIDGET(item), "activate", m_accel,
+ key, mods,
+ GTK_ACCEL_VISIBLE);
+ }
+ }
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(item), action->isEnabled());
+ gtk_widget_set_visible(GTK_WIDGET(item), action->isVisible());
+ }
+
+ g_signal_connect(item, "activate",
+ G_CALLBACK(handleMenuItemActivated), action);
+ g_signal_connect(item, "select",
+ G_CALLBACK(handleMenuItemSelected), action);
+ g_signal_connect(item, "deselect",
+ G_CALLBACK(handleMenuItemDeselected), action);
+}
+
+GtkMenuItem *MenuProxy::getItemForAction(QAction *action)
+{
+ return m_items.value(action, 0);
+}
+
+QString MenuProxy::transformMnemonic(const QString &text)
+{
+ QString s(text);
+ return s.replace(QChar('&'), QChar('_'));
+}
+
+bool MenuProxy::eventFilter(QObject* src, QEvent* event)
+{
+ QActionEvent *actionEvent;
+ switch (event->type()) {
+ case QEvent::ActionAdded:
+ actionEvent = static_cast<QActionEvent *>(event);
+ addAction(actionEvent->action(), actionEvent->before(), static_cast<QMenu*>(src));
+ break;
+ case QEvent::ActionRemoved:
+ actionEvent = static_cast<QActionEvent *>(event);
+ removeAction(actionEvent->action());
+ break;
+ case QEvent::ActionChanged:
+ actionEvent = static_cast<QActionEvent *>(event);
+ updateAction(actionEvent->action());
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+void MenuProxy::handleMenuItemActivated(GtkMenuItem *item, QAction *action)
+{
+ Q_UNUSED(item);
+ action->activate(QAction::Trigger);
+}
+
+void MenuProxy::handleMenuItemSelected(GtkMenuItem *item, QAction *action)
+{
+ Q_UNUSED(item);
+ action->activate(QAction::Hover);
+ QMenu *submenu = action->menu();
+ if (submenu) {
+ QMetaObject::invokeMethod(submenu, "aboutToShow");
+ }
+}
+
+void MenuProxy::handleMenuItemDeselected(GtkMenuItem *item, QAction *action)
+{
+ Q_UNUSED(item);
+ QMenu *submenu = action->menu();
+ if (submenu) {
+ QMetaObject::invokeMethod(submenu, "aboutToHide");
+ }
+}
diff --git a/module/menuproxy.h b/module/menuproxy.h
new file mode 100644
index 0000000..6b968ed
--- /dev/null
+++ b/module/menuproxy.h
@@ -0,0 +1,48 @@
+#ifndef MENUPROXY_H
+#define MENUPROXY_H
+
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QShortcut>
+
+typedef struct _GtkMenu GtkMenu;
+typedef struct _GtkMenuShell GtkMenuShell;
+typedef struct _GtkMenuItem GtkMenuItem;
+typedef struct _GtkAccelGroup GtkAccelGroup;
+
+class MenuProxy : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit MenuProxy(QObject *parent = 0);
+ ~MenuProxy();
+
+ void setTargetMenu(GtkMenuShell *shell);
+
+public:
+ virtual GtkMenuItem * addAction(QAction* action, QAction* before, QMenu* parent);
+ virtual GtkMenu * addMenu(QMenu* menu);
+ virtual void removeAction(QAction* action);
+ virtual void removeMenu(QMenu* menu);
+ virtual void updateAction(QAction* action);
+
+ GtkMenuItem *getItemForAction(QAction *action);
+
+ static QString transformMnemonic(const QString &text);
+
+ bool eventFilter(QObject*, QEvent*);
+
+private:
+ static void handleMenuItemActivated(GtkMenuItem *item, QAction *action);
+ static void handleMenuItemSelected(GtkMenuItem *item, QAction *action);
+ static void handleMenuItemDeselected(GtkMenuItem *item, QAction *action);
+
+private:
+ GtkMenuShell *m_target;
+ QHash<QMenu*, GtkMenu*> m_menus;
+ QHash<QAction*, GtkMenuItem*> m_items;
+ GtkAccelGroup *m_accel;
+};
+
+#endif // MENUPROXY_H
diff --git a/module/module.pro b/module/module.pro
new file mode 100644
index 0000000..81a2d92
--- /dev/null
+++ b/module/module.pro
@@ -0,0 +1,24 @@
+TEMPLATE = lib
+TARGET = topmenu-qt4-module
+QT += core gui
+CONFIG += plugin debug link_pkgconfig
+
+SOURCES += topmenumenubarimpl.cc \
+ topmenumenubarimplfactory.cc \
+ qtkeysyms.cc \
+ appmenu.cc \
+ menuproxy.cc
+HEADERS += topmenumenubarimpl.h \
+ topmenumenubarimplfactory.h \
+ qtkeysyms.h \
+ appmenu.h \
+ menuproxy.h
+
+LIBS += -ltopmenu-client
+PKGCONFIG += gtk+-2.0 gthread-2.0
+
+target.path += $$[QT_INSTALL_PLUGINS]/menubar
+INSTALLS += target
+
+QMAKE_STRIP = echo
+# Remove for release
diff --git a/module/qtkeysyms.cc b/module/qtkeysyms.cc
new file mode 100644
index 0000000..59f8f17
--- /dev/null
+++ b/module/qtkeysyms.cc
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2006 TROLLTECH ASA. All rights reserved.
+**
+** This file is part of the Phone Edition of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <gdk/gdkkeysyms.h>
+#include <QtCore/qcoreevent.h>
+
+unsigned int qt_to_gdk_key(unsigned int qt_key) {
+ unsigned int keysym = 0;
+ switch (qt_key) {
+ case Qt::Key_Escape: keysym = GDK_KEY_Escape; break;
+ case Qt::Key_Tab: keysym = GDK_KEY_Tab; break;
+ case Qt::Key_Backtab: keysym = GDK_KEY_ISO_Left_Tab; break;
+ case Qt::Key_Backspace: keysym = GDK_KEY_BackSpace; break;
+ case Qt::Key_Return: keysym = GDK_KEY_Return; break;
+ case Qt::Key_Enter: keysym = GDK_KEY_KP_Enter; break;
+ case Qt::Key_Insert: keysym = GDK_KEY_KP_Insert; break;
+ case Qt::Key_Delete: keysym = GDK_KEY_KP_Delete; break;
+ case Qt::Key_Pause: keysym = GDK_KEY_Pause; break;
+ case Qt::Key_Print: keysym = GDK_KEY_Print; break;
+ case Qt::Key_SysReq: keysym = 0x1005FF60; break;
+ case Qt::Key_Clear: keysym = GDK_KEY_KP_Begin; break;
+ case Qt::Key_Home: keysym = GDK_KEY_Home; break;
+ case Qt::Key_End: keysym = GDK_KEY_End; break;
+ case Qt::Key_Left: keysym = GDK_KEY_Left; break;
+ case Qt::Key_Up: keysym = GDK_KEY_Up; break;
+ case Qt::Key_Right: keysym = GDK_KEY_Right; break;
+ case Qt::Key_Down: keysym = GDK_KEY_Down; break;
+ case Qt::Key_PageUp: keysym = GDK_KEY_Prior; break;
+ case Qt::Key_PageDown: keysym = GDK_KEY_Next; break;
+ case Qt::Key_Shift: keysym = GDK_KEY_Shift_L; break;
+ case Qt::Key_Control: keysym = GDK_KEY_Control_L; break;
+ case Qt::Key_Meta: keysym = GDK_KEY_Meta_L; break;
+ case Qt::Key_Alt: keysym = GDK_KEY_Alt_L; break;
+ case Qt::Key_CapsLock: keysym = GDK_KEY_Caps_Lock; break;
+ case Qt::Key_NumLock: keysym = GDK_KEY_Num_Lock; break;
+ case Qt::Key_ScrollLock: keysym = GDK_KEY_Scroll_Lock; break;
+ case Qt::Key_F1: keysym = GDK_KEY_F1; break;
+ case Qt::Key_F2: keysym = GDK_KEY_F2; break;
+ case Qt::Key_F3: keysym = GDK_KEY_F3; break;
+ case Qt::Key_F4: keysym = GDK_KEY_F4; break;
+ case Qt::Key_F5: keysym = GDK_KEY_F5; break;
+ case Qt::Key_F6: keysym = GDK_KEY_F6; break;
+ case Qt::Key_F7: keysym = GDK_KEY_F7; break;
+ case Qt::Key_F8: keysym = GDK_KEY_F8; break;
+ case Qt::Key_F9: keysym = GDK_KEY_F9; break;
+ case Qt::Key_F10: keysym = GDK_KEY_F10; break;
+ case Qt::Key_F11: keysym = GDK_KEY_F11; break;
+ case Qt::Key_F12: keysym = GDK_KEY_F12; break;
+ case Qt::Key_F13: keysym = GDK_KEY_F13; break;
+ case Qt::Key_F14: keysym = GDK_KEY_F14; break;
+ case Qt::Key_F15: keysym = GDK_KEY_F15; break;
+ case Qt::Key_F16: keysym = GDK_KEY_F16; break;
+ case Qt::Key_F17: keysym = GDK_KEY_F17; break;
+ case Qt::Key_F18: keysym = GDK_KEY_F18; break;
+ case Qt::Key_F19: keysym = GDK_KEY_F19; break;
+ case Qt::Key_F20: keysym = GDK_KEY_F20; break;
+ case Qt::Key_F21: keysym = GDK_KEY_F21; break;
+ case Qt::Key_F22: keysym = GDK_KEY_F22; break;
+ case Qt::Key_F23: keysym = GDK_KEY_F23; break;
+ case Qt::Key_F24: keysym = GDK_KEY_F24; break;
+ case Qt::Key_F25: keysym = GDK_KEY_F25; break;
+ case Qt::Key_F26: keysym = GDK_KEY_F26; break;
+ case Qt::Key_F27: keysym = GDK_KEY_F27; break;
+ case Qt::Key_F28: keysym = GDK_KEY_F28; break;
+ case Qt::Key_F29: keysym = GDK_KEY_F29; break;
+ case Qt::Key_F30: keysym = GDK_KEY_F30; break;
+ case Qt::Key_F31: keysym = GDK_KEY_F31; break;
+ case Qt::Key_F32: keysym = GDK_KEY_F32; break;
+ case Qt::Key_F33: keysym = GDK_KEY_F33; break;
+ case Qt::Key_F34: keysym = GDK_KEY_F34; break;
+ case Qt::Key_F35: keysym = GDK_KEY_F35; break;
+ case Qt::Key_Super_L: keysym = GDK_KEY_Super_L; break;
+ case Qt::Key_Super_R: keysym = GDK_KEY_Super_R; break;
+ case Qt::Key_Menu: keysym = GDK_KEY_Menu; break;
+ case Qt::Key_Hyper_L: keysym = GDK_KEY_Hyper_L; break;
+ case Qt::Key_Hyper_R: keysym = GDK_KEY_Hyper_R; break;
+ case Qt::Key_Help: keysym = GDK_KEY_Help; break;
+
+ case Qt::Key_Space: keysym = GDK_KEY_space; break;
+ case Qt::Key_Exclam: keysym = GDK_KEY_exclam; break;
+ case Qt::Key_QuoteDbl: keysym = GDK_KEY_quotedbl; break;
+ case Qt::Key_NumberSign: keysym = GDK_KEY_numbersign; break;
+ case Qt::Key_Dollar: keysym = GDK_KEY_dollar; break;
+ case Qt::Key_Percent: keysym = GDK_KEY_percent; break;
+ case Qt::Key_Ampersand: keysym = GDK_KEY_ampersand; break;
+ case Qt::Key_Apostrophe: keysym = GDK_KEY_apostrophe; break;
+ case Qt::Key_ParenLeft: keysym = GDK_KEY_parenleft; break;
+ case Qt::Key_ParenRight: keysym = GDK_KEY_parenright; break;
+ case Qt::Key_Asterisk: keysym = GDK_KEY_asterisk; break;
+ case Qt::Key_Plus: keysym = GDK_KEY_plus; break;
+ case Qt::Key_Comma: keysym = GDK_KEY_comma; break;
+ case Qt::Key_Minus: keysym = GDK_KEY_minus; break;
+ case Qt::Key_Period: keysym = GDK_KEY_period; break;
+ case Qt::Key_Slash: keysym = GDK_KEY_slash; break;
+ case Qt::Key_0: keysym = GDK_KEY_0; break;
+ case Qt::Key_1: keysym = GDK_KEY_1; break;
+ case Qt::Key_2: keysym = GDK_KEY_2; break;
+ case Qt::Key_3: keysym = GDK_KEY_3; break;
+ case Qt::Key_4: keysym = GDK_KEY_4; break;
+ case Qt::Key_5: keysym = GDK_KEY_5; break;
+ case Qt::Key_6: keysym = GDK_KEY_6; break;
+ case Qt::Key_7: keysym = GDK_KEY_7; break;
+ case Qt::Key_8: keysym = GDK_KEY_8; break;
+ case Qt::Key_9: keysym = GDK_KEY_9; break;
+ case Qt::Key_Colon: keysym = GDK_KEY_colon; break;
+ case Qt::Key_Semicolon: keysym = GDK_KEY_semicolon; break;
+ case Qt::Key_Less: keysym = GDK_KEY_less; break;
+ case Qt::Key_Equal: keysym = GDK_KEY_equal; break;
+ case Qt::Key_Greater: keysym = GDK_KEY_greater; break;
+ case Qt::Key_Question: keysym = GDK_KEY_question; break;
+ case Qt::Key_At: keysym = GDK_KEY_at; break;
+ case Qt::Key_A: keysym = GDK_KEY_a; break; // Must be lower case keysyms
+ case Qt::Key_B: keysym = GDK_KEY_b; break; // for correct shift handling.
+ case Qt::Key_C: keysym = GDK_KEY_c; break;
+ case Qt::Key_D: keysym = GDK_KEY_d; break;
+ case Qt::Key_E: keysym = GDK_KEY_e; break;
+ case Qt::Key_F: keysym = GDK_KEY_f; break;
+ case Qt::Key_G: keysym = GDK_KEY_g; break;
+ case Qt::Key_H: keysym = GDK_KEY_h; break;
+ case Qt::Key_I: keysym = GDK_KEY_i; break;
+ case Qt::Key_J: keysym = GDK_KEY_j; break;
+ case Qt::Key_K: keysym = GDK_KEY_k; break;
+ case Qt::Key_L: keysym = GDK_KEY_l; break;
+ case Qt::Key_M: keysym = GDK_KEY_m; break;
+ case Qt::Key_N: keysym = GDK_KEY_n; break;
+ case Qt::Key_O: keysym = GDK_KEY_o; break;
+ case Qt::Key_P: keysym = GDK_KEY_p; break;
+ case Qt::Key_Q: keysym = GDK_KEY_q; break;
+ case Qt::Key_R: keysym = GDK_KEY_r; break;
+ case Qt::Key_S: keysym = GDK_KEY_s; break;
+ case Qt::Key_T: keysym = GDK_KEY_t; break;
+ case Qt::Key_U: keysym = GDK_KEY_u; break;
+ case Qt::Key_V: keysym = GDK_KEY_v; break;
+ case Qt::Key_W: keysym = GDK_KEY_w; break;
+ case Qt::Key_X: keysym = GDK_KEY_x; break;
+ case Qt::Key_Y: keysym = GDK_KEY_y; break;
+ case Qt::Key_Z: keysym = GDK_KEY_z; break;
+ case Qt::Key_BracketLeft: keysym = GDK_KEY_bracketleft; break;
+ case Qt::Key_Backslash: keysym = GDK_KEY_backslash; break;
+ case Qt::Key_BracketRight: keysym = GDK_KEY_bracketright; break;
+ case Qt::Key_AsciiCircum: keysym = GDK_KEY_asciicircum; break;
+ case Qt::Key_Underscore: keysym = GDK_KEY_underscore; break;
+ case Qt::Key_QuoteLeft: keysym = GDK_KEY_quoteleft; break;
+ case Qt::Key_BraceLeft: keysym = GDK_KEY_braceleft; break;
+ case Qt::Key_Bar: keysym = GDK_KEY_bar; break;
+ case Qt::Key_BraceRight: keysym = GDK_KEY_braceright; break;
+ case Qt::Key_AsciiTilde: keysym = GDK_KEY_asciitilde; break;
+
+ case Qt::Key_nobreakspace: keysym = GDK_KEY_nobreakspace; break;
+ case Qt::Key_exclamdown: keysym = GDK_KEY_exclamdown; break;
+ case Qt::Key_cent: keysym = GDK_KEY_cent; break;
+ case Qt::Key_sterling: keysym = GDK_KEY_sterling; break;
+ case Qt::Key_currency: keysym = GDK_KEY_currency; break;
+ case Qt::Key_yen: keysym = GDK_KEY_yen; break;
+ case Qt::Key_brokenbar: keysym = GDK_KEY_brokenbar; break;
+ case Qt::Key_section: keysym = GDK_KEY_section; break;
+ case Qt::Key_diaeresis: keysym = GDK_KEY_diaeresis; break;
+ case Qt::Key_copyright: keysym = GDK_KEY_copyright; break;
+ case Qt::Key_ordfeminine: keysym = GDK_KEY_ordfeminine; break;
+ case Qt::Key_guillemotleft: keysym = GDK_KEY_guillemotleft; break;
+ case Qt::Key_notsign: keysym = GDK_KEY_notsign; break;
+ case Qt::Key_hyphen: keysym = GDK_KEY_hyphen; break;
+ case Qt::Key_registered: keysym = GDK_KEY_registered; break;
+ case Qt::Key_macron: keysym = GDK_KEY_macron; break;
+ case Qt::Key_degree: keysym = GDK_KEY_degree; break;
+ case Qt::Key_plusminus: keysym = GDK_KEY_plusminus; break;
+ case Qt::Key_twosuperior: keysym = GDK_KEY_twosuperior; break;
+ case Qt::Key_threesuperior: keysym = GDK_KEY_threesuperior; break;
+ case Qt::Key_acute: keysym = GDK_KEY_acute; break;
+ case Qt::Key_mu: keysym = GDK_KEY_mu; break;
+ case Qt::Key_paragraph: keysym = GDK_KEY_paragraph; break;
+ case Qt::Key_periodcentered: keysym = GDK_KEY_periodcentered; break;
+ case Qt::Key_cedilla: keysym = GDK_KEY_cedilla; break;
+ case Qt::Key_onesuperior: keysym = GDK_KEY_onesuperior; break;
+ case Qt::Key_masculine: keysym = GDK_KEY_masculine; break;
+ case Qt::Key_guillemotright: keysym = GDK_KEY_guillemotright; break;
+ case Qt::Key_onequarter: keysym = GDK_KEY_onequarter; break;
+ case Qt::Key_onehalf: keysym = GDK_KEY_onehalf; break;
+ case Qt::Key_threequarters: keysym = GDK_KEY_threequarters; break;
+ case Qt::Key_questiondown: keysym = GDK_KEY_questiondown; break;
+ case Qt::Key_Agrave: keysym = GDK_KEY_agrave; break; // Lower case keysyms
+ case Qt::Key_Aacute: keysym = GDK_KEY_aacute; break; // for shift handling.
+ case Qt::Key_Acircumflex: keysym = GDK_KEY_acircumflex; break;
+ case Qt::Key_Atilde: keysym = GDK_KEY_atilde; break;
+ case Qt::Key_Adiaeresis: keysym = GDK_KEY_adiaeresis; break;
+ case Qt::Key_Aring: keysym = GDK_KEY_aring; break;
+ case Qt::Key_AE: keysym = GDK_KEY_ae; break;
+ case Qt::Key_Ccedilla: keysym = GDK_KEY_ccedilla; break;
+ case Qt::Key_Egrave: keysym = GDK_KEY_egrave; break;
+ case Qt::Key_Eacute: keysym = GDK_KEY_eacute; break;
+ case Qt::Key_Ecircumflex: keysym = GDK_KEY_ecircumflex; break;
+ case Qt::Key_Ediaeresis: keysym = GDK_KEY_ediaeresis; break;
+ case Qt::Key_Igrave: keysym = GDK_KEY_igrave; break;
+ case Qt::Key_Iacute: keysym = GDK_KEY_iacute; break;
+ case Qt::Key_Icircumflex: keysym = GDK_KEY_icircumflex; break;
+ case Qt::Key_Idiaeresis: keysym = GDK_KEY_idiaeresis; break;
+ case Qt::Key_ETH: keysym = GDK_KEY_eth; break;
+ case Qt::Key_Ntilde: keysym = GDK_KEY_ntilde; break;
+ case Qt::Key_Ograve: keysym = GDK_KEY_ograve; break;
+ case Qt::Key_Oacute: keysym = GDK_KEY_oacute; break;
+ case Qt::Key_Ocircumflex: keysym = GDK_KEY_ocircumflex; break;
+ case Qt::Key_Otilde: keysym = GDK_KEY_otilde; break;
+ case Qt::Key_Odiaeresis: keysym = GDK_KEY_odiaeresis; break;
+ case Qt::Key_multiply: keysym = GDK_KEY_multiply; break;
+ case Qt::Key_Ooblique: keysym = GDK_KEY_ooblique; break;
+ case Qt::Key_Ugrave: keysym = GDK_KEY_ugrave; break;
+ case Qt::Key_Uacute: keysym = GDK_KEY_uacute; break;
+ case Qt::Key_Ucircumflex: keysym = GDK_KEY_ucircumflex; break;
+ case Qt::Key_Udiaeresis: keysym = GDK_KEY_udiaeresis; break;
+ case Qt::Key_Yacute: keysym = GDK_KEY_yacute; break;
+ case Qt::Key_THORN: keysym = GDK_KEY_thorn; break;
+ case Qt::Key_ssharp: keysym = GDK_KEY_ssharp; break;
+ case Qt::Key_division: keysym = GDK_KEY_division; break;
+ case Qt::Key_ydiaeresis: keysym = GDK_KEY_ydiaeresis; break;
+
+ case Qt::Key_AltGr: keysym = GDK_KEY_ISO_Level3_Shift; break;
+ case Qt::Key_Multi_key: keysym = GDK_KEY_Multi_key; break;
+ case Qt::Key_Codeinput: keysym = GDK_KEY_Codeinput; break;
+ case Qt::Key_SingleCandidate: keysym = GDK_KEY_SingleCandidate; break;
+ case Qt::Key_MultipleCandidate: keysym = GDK_KEY_MultipleCandidate; break;
+ case Qt::Key_PreviousCandidate: keysym = GDK_KEY_PreviousCandidate; break;
+
+ case Qt::Key_Mode_switch: keysym = GDK_KEY_Mode_switch; break;
+
+ case Qt::Key_Kanji: keysym = GDK_KEY_Kanji; break;
+ case Qt::Key_Muhenkan: keysym = GDK_KEY_Muhenkan; break;
+ case Qt::Key_Henkan: keysym = GDK_KEY_Henkan; break;
+ case Qt::Key_Romaji: keysym = GDK_KEY_Romaji; break;
+ case Qt::Key_Hiragana: keysym = GDK_KEY_Hiragana; break;
+ case Qt::Key_Katakana: keysym = GDK_KEY_Katakana; break;
+ case Qt::Key_Hiragana_Katakana: keysym = GDK_KEY_Hiragana_Katakana; break;
+ case Qt::Key_Zenkaku: keysym = GDK_KEY_Zenkaku; break;
+ case Qt::Key_Hankaku: keysym = GDK_KEY_Hankaku; break;
+ case Qt::Key_Zenkaku_Hankaku: keysym = GDK_KEY_Zenkaku_Hankaku; break;
+ case Qt::Key_Touroku: keysym = GDK_KEY_Touroku; break;
+ case Qt::Key_Massyo: keysym = GDK_KEY_Massyo; break;
+ case Qt::Key_Kana_Lock: keysym = GDK_KEY_Kana_Lock; break;
+ case Qt::Key_Kana_Shift: keysym = GDK_KEY_Kana_Shift; break;
+ case Qt::Key_Eisu_Shift: keysym = GDK_KEY_Eisu_Shift; break;
+ case Qt::Key_Eisu_toggle: keysym = GDK_KEY_Eisu_toggle; break;
+
+ case Qt::Key_Hangul: keysym = GDK_KEY_Hangul; break;
+ case Qt::Key_Hangul_Start: keysym = GDK_KEY_Hangul_Start; break;
+ case Qt::Key_Hangul_End: keysym = GDK_KEY_Hangul_End; break;
+ case Qt::Key_Hangul_Hanja: keysym = GDK_KEY_Hangul_Hanja; break;
+ case Qt::Key_Hangul_Jamo: keysym = GDK_KEY_Hangul_Jamo; break;
+ case Qt::Key_Hangul_Romaja: keysym = GDK_KEY_Hangul_Romaja; break;
+ case Qt::Key_Hangul_Jeonja: keysym = GDK_KEY_Hangul_Jeonja; break;
+ case Qt::Key_Hangul_Banja: keysym = GDK_KEY_Hangul_Banja; break;
+ case Qt::Key_Hangul_PreHanja: keysym = GDK_KEY_Hangul_PreHanja; break;
+ case Qt::Key_Hangul_PostHanja: keysym = GDK_KEY_Hangul_PostHanja; break;
+ case Qt::Key_Hangul_Special: keysym = GDK_KEY_Hangul_Special; break;
+
+ case Qt::Key_Dead_Grave: keysym = GDK_KEY_dead_grave; break;
+ case Qt::Key_Dead_Acute: keysym = GDK_KEY_dead_acute; break;
+ case Qt::Key_Dead_Circumflex: keysym = GDK_KEY_dead_circumflex; break;
+ case Qt::Key_Dead_Tilde: keysym = GDK_KEY_dead_tilde; break;
+ case Qt::Key_Dead_Macron: keysym = GDK_KEY_dead_macron; break;
+ case Qt::Key_Dead_Breve: keysym = GDK_KEY_dead_breve; break;
+ case Qt::Key_Dead_Abovedot: keysym = GDK_KEY_dead_abovedot; break;
+ case Qt::Key_Dead_Diaeresis: keysym = GDK_KEY_dead_diaeresis; break;
+ case Qt::Key_Dead_Abovering: keysym = GDK_KEY_dead_abovering; break;
+ case Qt::Key_Dead_Doubleacute: keysym = GDK_KEY_dead_doubleacute; break;
+ case Qt::Key_Dead_Caron: keysym = GDK_KEY_dead_caron; break;
+ case Qt::Key_Dead_Cedilla: keysym = GDK_KEY_dead_cedilla; break;
+ case Qt::Key_Dead_Ogonek: keysym = GDK_KEY_dead_ogonek; break;
+ case Qt::Key_Dead_Iota: keysym = GDK_KEY_dead_iota; break;
+ case Qt::Key_Dead_Voiced_Sound: keysym = GDK_KEY_dead_voiced_sound; break;
+ case Qt::Key_Dead_Semivoiced_Sound: keysym = GDK_KEY_dead_semivoiced_sound; break;
+ case Qt::Key_Dead_Belowdot: keysym = GDK_KEY_dead_belowdot; break;
+ case Qt::Key_Dead_Hook: keysym = GDK_KEY_dead_hook; break;
+ case Qt::Key_Dead_Horn: keysym = GDK_KEY_dead_horn; break;
+ }
+
+ return keysym;
+}
diff --git a/module/qtkeysyms.h b/module/qtkeysyms.h
new file mode 100644
index 0000000..3f9ae22
--- /dev/null
+++ b/module/qtkeysyms.h
@@ -0,0 +1,6 @@
+#ifndef QTKEYSYMS_H
+#define QTKEYSYMS_H
+
+unsigned int qt_to_gdk_key(unsigned int qt_key);
+
+#endif // QTKEYSYMS_H
diff --git a/module/topmenumenubarimpl.cc b/module/topmenumenubarimpl.cc
new file mode 100644
index 0000000..1753394
--- /dev/null
+++ b/module/topmenumenubarimpl.cc
@@ -0,0 +1,252 @@
+#include <gtk/gtk.h>
+#include <topmenu-client.h>
+#include <topmenu-monitor.h>
+#include <topmenu-appmenubar.h>
+#include <QtCore/QDebug>
+#include <QtGui/QActionEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QX11Info>
+
+#include "topmenumenubarimpl.h"
+#include "appmenu.h"
+#include "qtkeysyms.h"
+
+bool TopMenuMenuBarImpl::staticInitialized = false;
+TopMenuMonitor * TopMenuMenuBarImpl::menuMonitor;
+
+static inline QShortcut * get_shortcut_for_action(QAction *action)
+{
+ QVariant v = action->property("topmenu-shortcut");
+ if (v.isValid()) {
+ return static_cast<QShortcut*>(v.value<QObject*>());
+ }
+ return 0;
+}
+
+static inline void set_shortcut_for_action(QAction *action, QShortcut *shortcut)
+{
+ if (shortcut) {
+ action->setProperty("topmenu-shortcut", QVariant::fromValue<QObject*>(shortcut));
+ } else {
+ action->setProperty("topmenu-shortcut", QVariant());
+ }
+}
+
+static inline QAction * get_action_for_shortcut(QShortcut *shortcut)
+{
+ QVariant v = shortcut->property("topmenu-action");
+ if (v.isValid()) {
+ return static_cast<QAction*>(v.value<QObject*>());
+ }
+ return 0;
+}
+
+static inline void set_action_for_shortcut(QShortcut *shortcut, QAction *action)
+{
+ if (shortcut) {
+ shortcut->setProperty("topmenu-action", QVariant::fromValue<QObject*>(action));
+ } else {
+ shortcut->setProperty("topmenu-action", QVariant());
+ }
+}
+
+TopMenuMenuBarImpl::TopMenuMenuBarImpl(QObject *parent) :
+ MenuProxy(parent),
+ m_window(0), m_menubar(0), m_appmenu(0),
+ m_disable(false), m_visible(true)
+{
+ // A new instance of this class will be created for each window.
+ if (!staticInitialized) {
+ XErrorHandler qt_x_errhandler = XSetErrorHandler(0);
+ gtk_init(NULL, NULL);
+ XSetErrorHandler(qt_x_errhandler);
+
+ menuMonitor = topmenu_monitor_get_instance();
+ // TODO g_signal_connect()
+
+ staticInitialized = true;
+ }
+}
+
+TopMenuMenuBarImpl::~TopMenuMenuBarImpl()
+{
+ if (m_menubar) {
+ g_object_unref(m_menubar);
+ m_menubar = 0;
+ }
+}
+
+void TopMenuMenuBarImpl::init(QMenuBar *menuBar)
+{
+ Q_ASSERT(menuBar);
+ Q_ASSERT(!m_menubar);
+ m_menubar = topmenu_app_menu_bar_new();
+ g_object_ref_sink(m_menubar);
+ m_appmenu = new AppMenu(this);
+ topmenu_app_menu_bar_set_app_menu(m_menubar,
+ GTK_WIDGET(m_appmenu->getGtkMenu()));
+ gtk_widget_show(GTK_WIDGET(m_menubar));
+ setTargetMenu(GTK_MENU_SHELL(m_menubar));
+}
+
+void TopMenuMenuBarImpl::setVisible(bool visible)
+{
+ m_visible = visible;
+}
+
+void TopMenuMenuBarImpl::actionEvent(QActionEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::ActionAdded:
+ addAction(e->action(), e->before(), 0);
+ break;
+ case QEvent::ActionRemoved:
+ removeAction(e->action());
+ break;
+ case QEvent::ActionChanged:
+ updateAction(e->action());
+ break;
+ default:
+ break;
+ }
+}
+
+void TopMenuMenuBarImpl::handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow)
+{
+ Q_UNUSED(oldParent);
+ Q_UNUSED(newParent);
+
+ if (oldWindow) {
+ GdkWindow *old_window = gdk_window_foreign_new(oldWindow->winId());
+ topmenu_client_disconnect_window(old_window);
+
+ Q_FOREACH(QAction *action, m_rootitems) {
+ QShortcut *shortcut = get_shortcut_for_action(action);
+ if (shortcut) {
+ set_shortcut_for_action(action, 0);
+ delete shortcut;
+ }
+ }
+ }
+
+ if (newWindow) {
+ Q_ASSERT(m_menubar);
+ GdkWindow *new_window = gdk_window_foreign_new(newWindow->winId());
+ topmenu_client_connect_window_widget(new_window, GTK_WIDGET(m_menubar));
+
+ Q_FOREACH(QAction *action, m_rootitems) {
+ createMnemonicShortcut(action, newWindow);
+ }
+ }
+
+ m_window = newWindow;
+}
+
+bool TopMenuMenuBarImpl::allowCornerWidgets() const
+{
+ return !isNativeMenuBar();
+}
+
+void TopMenuMenuBarImpl::popupAction(QAction *act)
+{
+ qDebug() << "TODO Popup action: " << act->text();
+}
+
+void TopMenuMenuBarImpl::setNativeMenuBar(bool value)
+{
+ m_disable = !value;
+}
+
+bool TopMenuMenuBarImpl::isNativeMenuBar() const
+{
+ if (m_disable || QCoreApplication::instance()->testAttribute(Qt::AA_DontUseNativeMenuBar))
+ return false;
+ return menuMonitor->available;
+}
+
+bool TopMenuMenuBarImpl::shortcutsHandledByNativeMenuBar() const
+{
+ return false;
+}
+
+bool TopMenuMenuBarImpl::menuBarEventFilter(QObject *src, QEvent *event)
+{
+ Q_UNUSED(src);
+ Q_UNUSED(event);
+ return false;
+}
+
+GtkMenuItem * TopMenuMenuBarImpl::addAction(QAction* action, QAction* before, QMenu* parent)
+{
+ if (!parent) {
+ m_rootitems.append(action);
+
+ if (m_window) {
+ createMnemonicShortcut(action, m_window);
+ }
+ }
+
+ if (m_appmenu) {
+ m_appmenu->addAction(action);
+ }
+
+ return MenuProxy::addAction(action, before, parent);
+}
+
+void TopMenuMenuBarImpl::removeAction(QAction *action)
+{
+ m_rootitems.removeAll(action);
+ QShortcut *shortcut = get_shortcut_for_action(action);
+ if (shortcut) {
+ set_shortcut_for_action(action, 0);
+ delete shortcut;
+ }
+
+ if (m_appmenu) {
+ m_appmenu->removeAction(action);
+ }
+
+ MenuProxy::removeAction(action);
+}
+
+void TopMenuMenuBarImpl::updateAction(QAction *action)
+{
+ if (!action->isSeparator() && m_rootitems.contains(action) && m_window) {
+ QShortcut *shortcut = get_shortcut_for_action(action);
+ if (shortcut) {
+ shortcut->setKey(QKeySequence::mnemonic(action->text()));
+ } else {
+ shortcut = createMnemonicShortcut(action, m_window);
+ }
+ shortcut->setEnabled(action->isEnabled());
+ }
+
+ if (m_appmenu) {
+ m_appmenu->updateAction(action);
+ }
+
+ MenuProxy::updateAction(action);
+}
+
+QShortcut * TopMenuMenuBarImpl::createMnemonicShortcut(QAction *action, QWidget *parent)
+{
+ QShortcut *shortcut = new QShortcut(parent);
+
+ set_shortcut_for_action(action, shortcut);
+ set_action_for_shortcut(shortcut, action);
+
+ shortcut->setKey(QKeySequence::mnemonic(action->text()));
+
+ connect(shortcut, SIGNAL(activated()),
+ this, SLOT(handleShortcutActivated()));
+
+ return shortcut;
+}
+
+void TopMenuMenuBarImpl::handleShortcutActivated()
+{
+ QShortcut *shortcut = static_cast<QShortcut*>(sender());
+ QAction *action = get_action_for_shortcut(shortcut);
+ GtkMenuItem *item = getItemForAction(action);
+ gtk_widget_mnemonic_activate(GTK_WIDGET(item), FALSE);
+}
diff --git a/module/topmenumenubarimpl.h b/module/topmenumenubarimpl.h
new file mode 100644
index 0000000..7573f76
--- /dev/null
+++ b/module/topmenumenubarimpl.h
@@ -0,0 +1,71 @@
+#ifndef TOPMENUMENUBARIMPL_H
+#define TOPMENUMENUBARIMPL_H
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDateTime>
+#include <QtCore/QHash>
+#include <QtCore/QTimer>
+#include <QtGui/QAction>
+#include <QtGui/QShortcut>
+#include <QtGui/QX11Info>
+#include <QtGui/private/qabstractplatformmenubar_p.h>
+#include <QtGui/private/qt_x11_p.h>
+
+#include "menuproxy.h"
+
+class AppMenu;
+typedef struct _TopMenuMonitor TopMenuMonitor;
+typedef struct _TopMenuAppMenuBar TopMenuAppMenuBar;
+
+class TopMenuMenuBarImpl : public MenuProxy, public QAbstractPlatformMenuBar {
+ Q_OBJECT
+
+public:
+ explicit TopMenuMenuBarImpl(QObject *parent = 0);
+ ~TopMenuMenuBarImpl();
+
+ void init(QMenuBar *);
+
+ void setVisible(bool visible);
+
+ void actionEvent(QActionEvent*);
+
+ void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow);
+
+ bool allowCornerWidgets() const;
+
+ void popupAction(QAction*);
+
+ void setNativeMenuBar(bool);
+ bool isNativeMenuBar() const;
+
+ bool shortcutsHandledByNativeMenuBar() const;
+ bool menuBarEventFilter(QObject *, QEvent *event);
+
+protected:
+ GtkMenuItem * addAction(QAction* action, QAction* before, QMenu* parent);
+ void removeAction(QAction* action);
+ void updateAction(QAction* action);
+
+private:
+ QShortcut * createMnemonicShortcut(QAction *action, QWidget *parent);
+
+private slots:
+ void handleShortcutActivated();
+
+private:
+ static bool staticInitialized;
+ static TopMenuMonitor *menuMonitor;
+
+ QWidget *m_window;
+ TopMenuAppMenuBar *m_menubar;
+
+ QList<QAction*> m_rootitems;
+
+ AppMenu *m_appmenu;
+
+ bool m_disable : 1;
+ bool m_visible : 1;
+};
+
+#endif // TOPMENUMENUBARIMPL_H
diff --git a/module/topmenumenubarimplfactory.cc b/module/topmenumenubarimplfactory.cc
new file mode 100644
index 0000000..ce577c7
--- /dev/null
+++ b/module/topmenumenubarimplfactory.cc
@@ -0,0 +1,16 @@
+#include <QtCore/QDebug>
+
+#include "topmenumenubarimplfactory.h"
+#include "topmenumenubarimpl.h"
+
+QAbstractPlatformMenuBar* TopMenuMenuBarImplFactory::create()
+{
+ return new TopMenuMenuBarImpl;
+}
+
+QStringList TopMenuMenuBarImplFactory::keys() const
+{
+ return QStringList() << QLatin1String("default");
+}
+
+Q_EXPORT_PLUGIN2(topmenu-qt4-module, TopMenuMenuBarImplFactory)
diff --git a/module/topmenumenubarimplfactory.h b/module/topmenumenubarimplfactory.h
new file mode 100644
index 0000000..7d43b26
--- /dev/null
+++ b/module/topmenumenubarimplfactory.h
@@ -0,0 +1,16 @@
+#ifndef TOPMENUMENUBARIMPLFACTORY_H
+#define TOPMENUMENUBARIMPLFACTORY_H
+
+#include <QtCore/QObject>
+#include <QtGui/private/qabstractplatformmenubar_p.h>
+
+class Q_GUI_EXPORT TopMenuMenuBarImplFactory : public QObject, public QPlatformMenuBarFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QPlatformMenuBarFactoryInterface:QFactoryInterface)
+public:
+ QAbstractPlatformMenuBar* create();
+ QStringList keys() const;
+};
+
+#endif // TOPMENUMENUBARIMPLFACTORY_H