#include #include #include #include #include #include #include #include #include #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(v.value()); } return 0; } static inline void set_shortcut_for_action(QAction *action, QShortcut *shortcut) { if (shortcut) { action->setProperty("topmenu-shortcut", QVariant::fromValue(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(v.value()); } return 0; } static inline void set_action_for_shortcut(QShortcut *shortcut, QAction *action) { if (action) { shortcut->setProperty("topmenu-action", QVariant::fromValue(action)); } else { shortcut->setProperty("topmenu-action", QVariant()); } } static inline TopMenuMenuBarImpl * get_menubarimpl_for_widget(QWidget *widget) { QVariant v = widget->property("topmenu-impl"); if (v.isValid()) { return static_cast(v.value()); } return 0; } static inline void set_menubarimpl_for_widget(QWidget *widget, TopMenuMenuBarImpl *impl) { if (impl) { widget->setProperty("topmenu-impl", QVariant::fromValue(impl)); } else { widget->setProperty("topmenu-impl", QVariant()); } } TopMenuMenuBarImpl::TopMenuMenuBarImpl(QObject *parent) : MenuProxy(parent), m_window(0), m_menubar(0), m_appmenubar(0), m_appmenu(0), m_disable(false) { // 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(); staticInitialized = true; } m_monitor_connection_id = g_signal_connect(menuMonitor, "notify::available", G_CALLBACK(handleMonitorAvailabilityChanged), this); } TopMenuMenuBarImpl::~TopMenuMenuBarImpl() { if (m_appmenubar) { gtk_widget_destroy(GTK_WIDGET(m_appmenubar)); g_object_unref(m_appmenubar); m_appmenubar = 0; } if (m_window) { if (get_menubarimpl_for_widget(m_window) == this) { set_menubarimpl_for_widget(m_window, 0); } } if (m_monitor_connection_id) { g_signal_handler_disconnect(menuMonitor, m_monitor_connection_id); } } void TopMenuMenuBarImpl::init(QMenuBar *menuBar) { Q_ASSERT(menuBar); Q_ASSERT(!m_menubar); m_menubar = menuBar; Q_ASSERT(!m_appmenubar); m_appmenubar = topmenu_app_menu_bar_new(); g_object_ref_sink(m_appmenubar); m_appmenu = new AppMenu(this); topmenu_app_menu_bar_set_app_menu(m_appmenubar, GTK_WIDGET(m_appmenu->getGtkMenu())); gtk_widget_show(GTK_WIDGET(m_appmenubar)); setTargetMenu(GTK_MENU_SHELL(m_appmenubar)); } void TopMenuMenuBarImpl::setVisible(bool visible) { if (m_menubar) { m_menubar->QWidget::setVisible(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); Q_UNUSED(oldWindow); Q_ASSERT(m_appmenubar); // init() must have been called if (m_window) { GdkWindow *old_window = gdk_window_foreign_new(m_window->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 (get_menubarimpl_for_widget(m_window) == this) { set_menubarimpl_for_widget(m_window, 0); } } if (newWindow) { if (get_menubarimpl_for_widget(newWindow)) { // The new window already has a menubar. Let's not override it. m_window = 0; return; } GdkWindow *new_window = gdk_window_foreign_new(newWindow->winId()); topmenu_client_connect_window_widget(new_window, GTK_WIDGET(m_appmenubar)); Q_FOREACH(QAction *action, m_rootitems) { createMnemonicShortcut(action, newWindow); } m_window = newWindow; set_menubarimpl_for_widget(m_window, this); } else { m_window = 0; } } 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 { //return false; if (m_disable || !m_window || 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::handleMonitorAvailabilityChanged(TopMenuMenuBarImpl *self) { if (self->m_menubar) { self->m_menubar->updateGeometry(); } } void TopMenuMenuBarImpl::handleShortcutActivated() { QShortcut *shortcut = static_cast(sender()); QAction *action = get_action_for_shortcut(shortcut); GtkMenuItem *item = getItemForAction(action); gtk_widget_mnemonic_activate(GTK_WIDGET(item), FALSE); }