// 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();
}
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();
}
}