X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9ff9d30c0aab3b281ef9b380eac17435556c5088..256e97fb7d55aba8fe10c4c375a0228cbbdb7d86:/src/gtk/menu.cpp diff --git a/src/gtk/menu.cpp b/src/gtk/menu.cpp index bbbd626e99..a7d37044c4 100644 --- a/src/gtk/menu.cpp +++ b/src/gtk/menu.cpp @@ -48,9 +48,10 @@ static void DoCommonMenuCallbackCode(wxMenu *menu, wxMenuEvent& event) if (handler && handler->SafelyProcessEvent(event)) return; - wxWindow *win = menu->GetInvokingWindow(); - if (win) - win->HandleWindowEvent( event ); + wxWindow *win = menu->GetWindow(); + wxCHECK_RET( win, "event for a menu without associated window?" ); + + win->HandleWindowEvent( event ); } //----------------------------------------------------------------------------- @@ -61,14 +62,12 @@ IMPLEMENT_DYNAMIC_CLASS(wxMenuBar,wxWindow) void wxMenuBar::Init(size_t n, wxMenu *menus[], const wxString titles[], long style) { - m_invokingWindow = NULL; - -#if wxUSE_LIBHILDON +#if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 // Hildon window uses a single menu instead of a menu bar, so wxMenuBar is // the same as menu in this case m_widget = m_menubar = gtk_menu_new(); -#else // !wxUSE_LIBHILDON +#else // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 if (!PreCreation( NULL, wxDefaultPosition, wxDefaultSize ) || !CreateBase( NULL, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("menubar") )) { @@ -91,8 +90,8 @@ void wxMenuBar::Init(size_t n, wxMenu *menus[], const wxString titles[], long st PostCreation(); - ApplyWidgetStyle(); -#endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON + GTKApplyWidgetStyle(); +#endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2/!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 g_object_ref(m_widget); @@ -115,20 +114,20 @@ wxMenuBar::wxMenuBar() Init(0, NULL, NULL, 0); } -wxMenuBar::~wxMenuBar() +// recursive helpers for wxMenuBar::Attach() and Detach(): they are called to +// associate the menus with the frame they belong to or dissociate them from it +namespace { -} -static void -wxMenubarUnsetInvokingWindow(wxMenu* menu, wxWindow* win, GtkWindow* tlw = NULL) +void +DetachFromFrame(wxMenu* menu, wxFrame* frame) { - menu->SetInvokingWindow( (wxWindow*) NULL ); - // support for native hot keys if (menu->m_accel) { - if (tlw == NULL) - tlw = GTK_WINDOW(wxGetTopLevelParent(win)->m_widget); + // Note that wxGetTopLevelParent() is really needed because this frame + // can be an MDI child frame which is a fake frame and not a TLW at all + GtkWindow * const tlw = GTK_WINDOW(wxGetTopLevelParent(frame)->m_widget); if (g_slist_find(menu->m_accel->acceleratables, tlw)) gtk_window_remove_accel_group(tlw, menu->m_accel); } @@ -138,21 +137,18 @@ wxMenubarUnsetInvokingWindow(wxMenu* menu, wxWindow* win, GtkWindow* tlw = NULL) { wxMenuItem *menuitem = node->GetData(); if (menuitem->IsSubMenu()) - wxMenubarUnsetInvokingWindow(menuitem->GetSubMenu(), win, tlw); + DetachFromFrame(menuitem->GetSubMenu(), frame); node = node->GetNext(); } } -static void -wxMenubarSetInvokingWindow(wxMenu* menu, wxWindow* win, GtkWindow* tlw = NULL) +void +AttachToFrame(wxMenu* menu, wxFrame* frame) { - menu->SetInvokingWindow( win ); - // support for native hot keys if (menu->m_accel) { - if (tlw == NULL) - tlw = GTK_WINDOW(wxGetTopLevelParent(win)->m_widget); + GtkWindow * const tlw = GTK_WINDOW(wxGetTopLevelParent(frame)->m_widget); if (!g_slist_find(menu->m_accel->acceleratables, tlw)) gtk_window_add_accel_group(tlw, menu->m_accel); } @@ -162,23 +158,12 @@ wxMenubarSetInvokingWindow(wxMenu* menu, wxWindow* win, GtkWindow* tlw = NULL) { wxMenuItem *menuitem = node->GetData(); if (menuitem->IsSubMenu()) - wxMenubarSetInvokingWindow(menuitem->GetSubMenu(), win, tlw); + AttachToFrame(menuitem->GetSubMenu(), frame); node = node->GetNext(); } } -void wxMenuBar::SetInvokingWindow( wxWindow *win ) -{ - m_invokingWindow = win; - - wxMenuList::compatibility_iterator node = m_menus.GetFirst(); - while (node) - { - wxMenu *menu = node->GetData(); - wxMenubarSetInvokingWindow( menu, win ); - node = node->GetNext(); - } -} +} // anonymous namespace void wxMenuBar::SetLayoutDirection(wxLayoutDirection dir) { @@ -221,20 +206,28 @@ void wxMenuBar::Attach(wxFrame *frame) { wxMenuBarBase::Attach(frame); + wxMenuList::compatibility_iterator node = m_menus.GetFirst(); + while (node) + { + wxMenu *menu = node->GetData(); + AttachToFrame( menu, frame ); + node = node->GetNext(); + } + SetLayoutDirection(wxLayout_Default); } -void wxMenuBar::UnsetInvokingWindow( wxWindow *win ) +void wxMenuBar::Detach() { - m_invokingWindow = (wxWindow*) NULL; - wxMenuList::compatibility_iterator node = m_menus.GetFirst(); while (node) { wxMenu *menu = node->GetData(); - wxMenubarUnsetInvokingWindow( menu, win ); + DetachFromFrame( menu, m_menuBarFrame ); node = node->GetNext(); } + + wxMenuBarBase::Detach(); } bool wxMenuBar::Append( wxMenu *menu, const wxString &title ) @@ -249,7 +242,7 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title, int pos) { menu->SetLayoutDirection(GetLayoutDirection()); -#if wxUSE_LIBHILDON +#if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 // if the menu has only one item, append it directly to the top level menu // instead of inserting a useless submenu if ( menu->GetMenuItemCount() == 1 ) @@ -269,7 +262,7 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title, int pos) item->SetMenuItem(menu->m_owner); } else -#endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON +#endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2 /!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 { const wxString str(wxConvertMnemonicsToGTK(title)); @@ -289,10 +282,8 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title, int pos) else gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar), menu->m_owner, pos ); - // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables - // addings menu later on. - if (m_invokingWindow) - wxMenubarSetInvokingWindow( menu, m_invokingWindow ); + if ( m_menuBarFrame ) + AttachToFrame( menu, m_menuBarFrame ); return true; } @@ -316,7 +307,7 @@ wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) wxMenu *menuOld = Remove(pos); if ( menuOld && !Insert(pos, menu, title) ) { - return (wxMenu*) NULL; + return NULL; } // either Insert() succeeded or Remove() failed and menuOld is NULL @@ -327,7 +318,7 @@ wxMenu *wxMenuBar::Remove(size_t pos) { wxMenu *menu = wxMenuBarBase::Remove(pos); if ( !menu ) - return (wxMenu*) NULL; + return NULL; gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->m_owner), NULL); gtk_container_remove(GTK_CONTAINER(m_menubar), menu->m_owner); @@ -335,15 +326,14 @@ wxMenu *wxMenuBar::Remove(size_t pos) gtk_widget_destroy( menu->m_owner ); menu->m_owner = NULL; - if (m_invokingWindow) - wxMenubarUnsetInvokingWindow( menu, m_invokingWindow ); + DetachFromFrame( menu, m_menuBarFrame ); return menu; } static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString, const wxString &itemString ) { - if (wxMenuItem::GetLabelText(wxConvertMnemonicsFromGTK(menu->GetTitle())) == wxMenuItem::GetLabelText(menuString)) + if (wxMenuItem::GetLabelText(menu->GetTitle()) == wxMenuItem::GetLabelText(menuString)) { int res = menu->FindItem( itemString ); if (res != wxNOT_FOUND) @@ -410,7 +400,7 @@ wxMenuItem* wxMenuBar::FindItem( int id, wxMenu **menuForItem ) const if ( menuForItem ) { - *menuForItem = result ? result->GetMenu() : (wxMenu *)NULL; + *menuForItem = result ? result->GetMenu() : NULL; } return result; @@ -436,7 +426,7 @@ wxString wxMenuBar::GetMenuLabel( size_t pos ) const wxMenu* menu = node->GetData(); - return wxConvertMnemonicsFromGTK(menu->GetTitle()); + return menu->GetTitle(); } void wxMenuBar::SetMenuLabel( size_t pos, const wxString& label ) @@ -505,16 +495,8 @@ static void menuitem_select(GtkWidget*, wxMenuItem* item) if (!item->IsEnabled()) return; - wxMenu* menu = item->GetMenu(); wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item->GetId()); - event.SetEventObject( menu ); - - wxEvtHandler* handler = menu->GetEventHandler(); - if (handler && handler->SafelyProcessEvent(event)) - return; - - wxWindow *win = menu->GetInvokingWindow(); - if (win) win->HandleWindowEvent( event ); + DoCommonMenuCallbackCode(item->GetMenu(), event); } } @@ -528,17 +510,8 @@ static void menuitem_deselect(GtkWidget*, wxMenuItem* item) if (!item->IsEnabled()) return; - wxMenu* menu = item->GetMenu(); wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, -1 ); - event.SetEventObject( menu ); - - wxEvtHandler* handler = menu->GetEventHandler(); - if (handler && handler->SafelyProcessEvent(event)) - return; - - wxWindow *win = menu->GetInvokingWindow(); - if (win) - win->HandleWindowEvent( event ); + DoCommonMenuCallbackCode(item->GetMenu(), event); } } @@ -652,7 +625,7 @@ void wxMenuItem::Check( bool check ) break; default: - wxFAIL_MSG( _T("can't check this item") ); + wxFAIL_MSG( wxT("can't check this item") ); } } @@ -695,6 +668,16 @@ static void menu_hide(GtkWidget*, wxMenu* menu) } } +// "can_activate_accel" from menu item +extern "C" { +static gboolean can_activate_accel(GtkWidget*, guint, wxMenu* menu) +{ + menu->UpdateUI(); + // always allow our "activate" handler to be called + return true; +} +} + IMPLEMENT_DYNAMIC_CLASS(wxMenu,wxEvtHandler) void wxMenu::Init() @@ -708,7 +691,7 @@ void wxMenu::Init() g_object_ref(m_menu); gtk_object_sink(GTK_OBJECT(m_menu)); - m_owner = (GtkWidget*) NULL; + m_owner = NULL; // Tearoffs are entries, just like separators. So if we want this // menu to be a tear-off one, we just append a tearoff entry @@ -736,6 +719,11 @@ void wxMenu::Init() wxMenu::~wxMenu() { + // Destroying a menu generates a "hide" signal even if it's not shown + // currently, so disconnect it to avoid dummy wxEVT_MENU_CLOSE events + // generation. + g_signal_handlers_disconnect_by_func(m_menu, (gpointer)menu_hide, this); + // see wxMenu::Init g_object_unref(m_menu); @@ -759,6 +747,11 @@ wxLayoutDirection wxMenu::GetLayoutDirection() const return wxWindow::GTKGetLayout(m_owner); } +wxString wxMenu::GetTitle() const +{ + return wxConvertMnemonicsFromGTK(wxMenuBase::GetTitle()); +} + bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos) { GtkWidget *menuItem; @@ -823,15 +816,11 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos) gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), mitem->GetSubMenu()->m_menu ); gtk_widget_show( mitem->GetSubMenu()->m_menu ); - - // if adding a submenu to a menu already existing in the menu bar, we - // must set invoking window to allow processing events from this - // submenu - if ( m_invokingWindow ) - wxMenubarSetInvokingWindow(mitem->GetSubMenu(), m_invokingWindow); } else { + g_signal_connect(menuItem, "can_activate_accel", + G_CALLBACK(can_activate_accel), this); g_signal_connect (menuItem, "activate", G_CALLBACK(menuitem_activate), mitem);