// Name: src/gtk/menu.cpp
// Purpose: implementation of wxMenuBar and wxMenu classes for wxGTK
// Author: Robert Roebling
-// Id: $Id$
// Copyright: (c) 1998 Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
+ #include "wx/dialog.h"
#include "wx/frame.h"
#include "wx/bitmap.h"
#include "wx/app.h"
static void wxGetGtkAccel(const wxMenuItem*, guint*, GdkModifierType*);
#endif
-static void DoCommonMenuCallbackCode(wxMenu *menu, wxMenuEvent& event)
+// Unity hack: under Ubuntu Unity the global menu bar is not affected by a
+// modal dialog being shown, so the user can select a menu item before hiding
+// the dialog and, in particular, a new instance of the same dialog can be
+// shown again, breaking a lot of programs not expecting this.
+//
+// So explicitly ignore any menu events generated while any modal dialogs
+// are opened except for the events generated by a context menu within the
+// modal dialog itself that should have a dialog as their invoking window.
+static bool IsMenuEventAllowed(wxMenu* menu)
{
- // See the comment about Ubuntu Unity in menuitem_activate().
if ( wxOpenModalDialogsCount )
+ {
+ wxWindow* tlw = wxGetTopLevelParent(menu->GetWindow());
+ if ( !tlw || !wxDynamicCast(tlw, wxDialog) )
+ {
+ // This must be an event from a menu bar of one of the frames.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void DoCommonMenuCallbackCode(wxMenu *menu, wxMenuEvent& event)
+{
+ if ( !IsMenuEventAllowed(menu) )
return;
event.SetEventObject( menu );
}
PostCreation();
-
- GTKApplyWidgetStyle();
#endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2/!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
g_object_ref_sink(m_widget);
namespace
{
+// This should be called when detaching menus to ensure that they don't keep
+// focus grab, because if they do, they continue getting all GTK+ messages
+// which they can't process any more in their (soon to be) unrealized state.
+void
+EnsureNoGrab(GtkWidget* widget)
+{
+#if !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
+ gtk_widget_hide(widget);
+ gtk_grab_remove(widget);
+#endif // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
+}
+
void
DetachFromFrame(wxMenu* menu, wxFrame* frame)
{
DetachFromFrame(menuitem->GetSubMenu(), frame);
node = node->GetNext();
}
+
+ EnsureNoGrab(menu->m_menu);
}
void
node = node->GetNext();
}
+ EnsureNoGrab(m_widget);
+
wxMenuBarBase::Detach();
}
// warnings from Ubuntu libdbusmenu
gtk_container_remove(GTK_CONTAINER(m_menubar), menu->m_owner);
// remove submenu to avoid destroying it when item is destroyed
+#ifdef __WXGTK3__
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->m_owner), NULL);
+#else
+ gtk_menu_item_remove_submenu(GTK_MENU_ITEM(menu->m_owner));
+#endif
gtk_widget_destroy( menu->m_owner );
g_object_unref(menu->m_owner);
if (!item->IsEnabled())
return;
- // Unity hack: under Ubuntu Unity the global menu bar is not affected by a
- // modal dialog being shown, so the user can select a menu item before
- // hiding the dialog and, in particular, a new instance of the same dialog
- // can be shown again, breaking a lot of programs not expecting this.
- //
- // So explicitly ignore any menu events generated while any modal dialogs
- // are opened.
- if ( wxOpenModalDialogsCount )
+ if ( !IsMenuEventAllowed(item->GetMenu()) )
return;
int id = item->GetId();
wxMenu* menu = item->GetMenu();
menu->SendEvent(id, item->IsCheckable() ? item->IsChecked() : -1);
+
+ // A lot of existing code, including any program that closes its main
+ // window from a menu handler and expects the program to exit -- as our own
+ // minimal sample -- relies on getting an idle event after a menu event.
+ // But when using Ubuntu Unity detached menus, we get called from a DBUS
+ // handler called from g_timeout_dispatch() and Glib doesn't send us any
+ // idle events after it. So ask explicitly for an idle event to get one.
+ wxWakeUpIdle();
}
}
wxMenuItem::~wxMenuItem()
{
+ if (m_menuItem)
+ g_object_unref(m_menuItem);
// don't delete menu items, the menus take care of that
}
+void wxMenuItem::SetMenuItem(GtkWidget* menuItem)
+{
+ if (m_menuItem)
+ g_object_unref(m_menuItem);
+ m_menuItem = menuItem;
+ if (menuItem)
+ g_object_ref(menuItem);
+}
+
void wxMenuItem::SetItemLabel( const wxString& str )
{
#if wxUSE_ACCEL
#ifdef __WXGTK3__
gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), NULL);
#else
- if (!gtk_check_version(2,12,0))
- {
- // gtk_menu_item_remove_submenu() is deprecated since 2.12, but
- // gtk_menu_item_set_submenu() can now be used with NULL submenu now so
- // just do use it.
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), NULL);
- }
- else // GTK+ < 2.12
- {
- // In 2.10 calling gtk_menu_item_set_submenu() with NULL submenu
- // results in critical GTK+ error messages so use the old function
- // instead.
- gtk_menu_item_remove_submenu(GTK_MENU_ITEM(mitem));
- }
+ gtk_menu_item_remove_submenu(GTK_MENU_ITEM(mitem));
#endif
gtk_widget_destroy(mitem);