diff options
author | Javier <dev.git@javispedro.com> | 2014-01-28 17:21:16 +0100 |
---|---|---|
committer | Javier <dev.git@javispedro.com> | 2014-01-28 17:21:16 +0100 |
commit | 982ebc96f2c77c1f9dbddd6a4c0a776c74b425de (patch) | |
tree | 6800326ba4da9c84dc14f0b442f088b1c2fb63bf /module | |
download | topmenu-qt-982ebc96f2c77c1f9dbddd6a4c0a776c74b425de.tar.gz topmenu-qt-982ebc96f2c77c1f9dbddd6a4c0a776c74b425de.zip |
initial import
Diffstat (limited to 'module')
-rw-r--r-- | module/appmenu.cc | 154 | ||||
-rw-r--r-- | module/appmenu.h | 32 | ||||
-rw-r--r-- | module/menuproxy.cc | 286 | ||||
-rw-r--r-- | module/menuproxy.h | 48 | ||||
-rw-r--r-- | module/module.pro | 24 | ||||
-rw-r--r-- | module/qtkeysyms.cc | 313 | ||||
-rw-r--r-- | module/qtkeysyms.h | 6 | ||||
-rw-r--r-- | module/topmenumenubarimpl.cc | 252 | ||||
-rw-r--r-- | module/topmenumenubarimpl.h | 71 | ||||
-rw-r--r-- | module/topmenumenubarimplfactory.cc | 16 | ||||
-rw-r--r-- | module/topmenumenubarimplfactory.h | 16 |
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 |