X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/02822c8cdfad75d044faed32f3103b6935ed01c5..4f433feff9251ded00bba26b633f93e660cd44c4:/src/gtk1/menu.cpp diff --git a/src/gtk1/menu.cpp b/src/gtk1/menu.cpp index 88eb8cf728..7fd48a50d4 100644 --- a/src/gtk1/menu.cpp +++ b/src/gtk1/menu.cpp @@ -7,16 +7,19 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "menu.h" -#pragma implementation "menuitem.h" +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) + #pragma implementation "menu.h" + #pragma implementation "menuitem.h" #endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#include "wx/menu.h" #include "wx/log.h" #include "wx/intl.h" #include "wx/app.h" #include "wx/bitmap.h" -#include "wx/menu.h" #if wxUSE_ACCEL #include "wx/accel.h" @@ -30,19 +33,22 @@ #ifdef __WXGTK20__ #include - #define gtk_accel_group_attach(g, o) _gtk_accel_group_attach((g), (o)) - #define gtk_accel_group_detach(g, o) _gtk_accel_group_detach((g), (o)) + #define gtk_accel_group_attach(g, o) gtk_window_add_accel_group((o), (g)) + #define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g)) #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m) - #define ACCEL_OBJECT GObject + #define ACCEL_OBJECT GtkWindow #define ACCEL_OBJECTS(a) (a)->acceleratables - #define ACCEL_OBJ_CAST(obj) G_OBJECT(obj) + #define ACCEL_OBJ_CAST(obj) ((GtkWindow*) obj) #else // GTK+ 1.x #define ACCEL_OBJECT GtkObject #define ACCEL_OBJECTS(a) (a)->attach_objects #define ACCEL_OBJ_CAST(obj) GTK_OBJECT(obj) #endif +// we use normal item but with a special id for the menu title +static const int wxGTK_TITLE_ID = -3; + //----------------------------------------------------------------------------- // idle system //----------------------------------------------------------------------------- @@ -50,20 +56,15 @@ extern void wxapp_install_idle_handler(); extern bool g_isIdle; -#if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL - static wxString GetHotKey( const wxMenuItem& item ); +#if wxUSE_ACCEL +static wxString GetGtkHotKey( const wxMenuItem& item ); #endif //----------------------------------------------------------------------------- // substitute for missing GtkPixmapMenuItem //----------------------------------------------------------------------------- -// FIXME: I can't make this compile with GTK+ 2.0, disabling for now (VZ) #ifndef __WXGTK20__ - #define USE_MENU_BITMAPS -#endif - -#ifdef USE_MENU_BITMAPS #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ()) #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem)) @@ -95,13 +96,14 @@ struct _GtkPixmapMenuItemClass guint have_pixmap_count; }; - -GtkType gtk_pixmap_menu_item_get_type (void); +extern "C" { +GtkType gtk_pixmap_menu_item_get_type (void); GtkWidget* gtk_pixmap_menu_item_new (void); void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem *menu_item, - GtkWidget *pixmap); + GtkWidget *pixmap); +} -#endif // USE_MENU_BITMAPS +#endif // !__WXGTK20__ //----------------------------------------------------------------------------- // idle system @@ -111,7 +113,7 @@ static wxString wxReplaceUnderscore( const wxString& title ) { const wxChar *pc; - /* GTK 1.2 wants to have "_" instead of "&" for accelerators */ + // GTK 1.2 wants to have "_" instead of "&" for accelerators wxString str; pc = title; while (*pc != wxT('\0')) @@ -124,40 +126,24 @@ static wxString wxReplaceUnderscore( const wxString& title ) } else if (*pc == wxT('&')) { -#if GTK_CHECK_VERSION(1, 2, 0) str << wxT('_'); -#endif } -#if GTK_CHECK_VERSION(2, 0, 0) - else if (*pc == wxT('/')) - { - str << wxT("\\/"); - } - else if (*pc == wxT('\\')) - { - str << wxT("\\\\"); - } -#elif GTK_CHECK_VERSION(1, 2, 0) - else if (*pc == wxT('/')) - { - str << wxT('\\'); - } -#endif else { -#ifdef __WXGTK12__ if ( *pc == wxT('_') ) { // underscores must be doubled to prevent them from being // interpreted as accelerator character prefix by GTK str << *pc; } -#endif // GTK+ 1.2 str << *pc; } ++pc; } + + // wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() ); + return str; } @@ -165,11 +151,12 @@ static wxString wxReplaceUnderscore( const wxString& title ) // activate message from GTK //----------------------------------------------------------------------------- +extern "C" { static void gtk_menu_open_callback( GtkWidget *widget, wxMenu *menu ) { if (g_isIdle) wxapp_install_idle_handler(); - wxMenuEvent event( wxEVT_MENU_OPEN, -1 ); + wxMenuEvent event( wxEVT_MENU_OPEN, -1, menu ); event.SetEventObject( menu ); wxEvtHandler* handler = menu->GetEventHandler(); @@ -179,6 +166,7 @@ static void gtk_menu_open_callback( GtkWidget *widget, wxMenu *menu ) wxWindow *win = menu->GetInvokingWindow(); if (win) win->GetEventHandler()->ProcessEvent( event ); } +} //----------------------------------------------------------------------------- // wxMenuBar @@ -186,9 +174,9 @@ static void gtk_menu_open_callback( GtkWidget *widget, wxMenu *menu ) IMPLEMENT_DYNAMIC_CLASS(wxMenuBar,wxWindow) -wxMenuBar::wxMenuBar( long style ) +void wxMenuBar::Init(size_t n, wxMenu *menus[], const wxString titles[], long style) { - /* the parent window is known after wxFrame::SetMenu() */ + // the parent window is known after wxFrame::SetMenu() m_needParent = FALSE; m_style = style; m_invokingWindow = (wxWindow*) NULL; @@ -200,15 +188,9 @@ wxMenuBar::wxMenuBar( long style ) return; } - m_menus.DeleteContents( TRUE ); - - /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ -#if GTK_CHECK_VERSION(1, 2, 1) - m_accel = gtk_accel_group_new(); - m_factory = gtk_item_factory_new( GTK_TYPE_MENU_BAR, "
", m_accel ); - m_menubar = gtk_item_factory_get_widget( m_factory, "
" ); -#else m_menubar = gtk_menu_bar_new(); +#ifndef __WXGTK20__ + m_accel = gtk_accel_group_new(); #endif if (style & wxMB_DOCKABLE) @@ -225,43 +207,28 @@ wxMenuBar::wxMenuBar( long style ) PostCreation(); ApplyWidgetStyle(); + + for (size_t i = 0; i < n; ++i ) + Append(menus[i], titles[i]); } -wxMenuBar::wxMenuBar() +wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxString titles[], long style) { - /* the parent window is known after wxFrame::SetMenu() */ - m_needParent = FALSE; - m_style = 0; - m_invokingWindow = (wxWindow*) NULL; - - if (!PreCreation( (wxWindow*) NULL, wxDefaultPosition, wxDefaultSize ) || - !CreateBase( (wxWindow*) NULL, -1, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, wxT("menubar") )) - { - wxFAIL_MSG( wxT("wxMenuBar creation failed") ); - return; - } - - m_menus.DeleteContents( TRUE ); - - /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ -#if GTK_CHECK_VERSION(1, 2, 1) - m_accel = gtk_accel_group_new(); - m_factory = gtk_item_factory_new( GTK_TYPE_MENU_BAR, "
", m_accel ); - m_menubar = gtk_item_factory_get_widget( m_factory, "
" ); -#else - m_menubar = gtk_menu_bar_new(); -#endif - - m_widget = GTK_WIDGET(m_menubar); + Init(n, menus, titles, style); +} - PostCreation(); +wxMenuBar::wxMenuBar(long style) +{ + Init(0, NULL, NULL, style); +} - ApplyWidgetStyle(); +wxMenuBar::wxMenuBar() +{ + Init(0, NULL, NULL, 0); } wxMenuBar::~wxMenuBar() { -// gtk_object_unref( GTK_OBJECT(m_factory) ); why not ? } static void wxMenubarUnsetInvokingWindow( wxMenu *menu, wxWindow *win ) @@ -272,10 +239,12 @@ static void wxMenubarUnsetInvokingWindow( wxMenu *menu, wxWindow *win ) while (top_frame->GetParent() && !(top_frame->IsTopLevel())) top_frame = top_frame->GetParent(); - /* support for native hot keys */ +#ifndef __WXGTK20__ + // support for native hot keys gtk_accel_group_detach( menu->m_accel, ACCEL_OBJ_CAST(top_frame->m_widget) ); +#endif - wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst(); while (node) { wxMenuItem *menuitem = node->GetData(); @@ -289,18 +258,16 @@ static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win ) { menu->SetInvokingWindow( win ); -#if GTK_CHECK_VERSION(1, 2, 1) wxWindow *top_frame = win; while (top_frame->GetParent() && !(top_frame->IsTopLevel())) top_frame = top_frame->GetParent(); - /* support for native hot keys */ + // support for native hot keys ACCEL_OBJECT *obj = ACCEL_OBJ_CAST(top_frame->m_widget); if ( !g_slist_find( ACCEL_OBJECTS(menu->m_accel), obj ) ) gtk_accel_group_attach( menu->m_accel, obj ); -#endif // GTK+ 1.2.1+ - wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst(); while (node) { wxMenuItem *menuitem = node->GetData(); @@ -313,18 +280,18 @@ static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win ) void wxMenuBar::SetInvokingWindow( wxWindow *win ) { m_invokingWindow = win; -#if GTK_CHECK_VERSION(1, 2, 1) wxWindow *top_frame = win; while (top_frame->GetParent() && !(top_frame->IsTopLevel())) top_frame = top_frame->GetParent(); - /* support for native key accelerators indicated by underscroes */ +#ifndef __WXGTK20__ + // support for native key accelerators indicated by underscroes ACCEL_OBJECT *obj = ACCEL_OBJ_CAST(top_frame->m_widget); if ( !g_slist_find( ACCEL_OBJECTS(m_accel), obj ) ) gtk_accel_group_attach( m_accel, obj ); -#endif // GTK+ 1.2.1+ +#endif - wxMenuList::Node *node = m_menus.GetFirst(); + wxMenuList::compatibility_iterator node = m_menus.GetFirst(); while (node) { wxMenu *menu = node->GetData(); @@ -336,16 +303,16 @@ void wxMenuBar::SetInvokingWindow( wxWindow *win ) void wxMenuBar::UnsetInvokingWindow( wxWindow *win ) { m_invokingWindow = (wxWindow*) NULL; -#if GTK_CHECK_VERSION(1, 2, 1) wxWindow *top_frame = win; while (top_frame->GetParent() && !(top_frame->IsTopLevel())) top_frame = top_frame->GetParent(); +#ifndef __WXGTK20__ // support for native key accelerators indicated by underscroes gtk_accel_group_detach( m_accel, ACCEL_OBJ_CAST(top_frame->m_widget) ); -#endif // GTK+ 1.2.1+ +#endif - wxMenuList::Node *node = m_menus.GetFirst(); + wxMenuList::compatibility_iterator node = m_menus.GetFirst(); while (node) { wxMenu *menu = node->GetData(); @@ -362,54 +329,42 @@ bool wxMenuBar::Append( wxMenu *menu, const wxString &title ) return GtkAppend(menu, title); } -bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title) +bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title, int pos) { wxString str( wxReplaceUnderscore( title ) ); // This doesn't have much effect right now. menu->SetTitle( str ); - // GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. -#if GTK_CHECK_VERSION(1, 2, 1) - - wxString buf; - buf << wxT('/') << str.c_str(); - - // local buffer in multibyte form - char cbuf[400]; - strcpy(cbuf, wxGTK_CONV(buf) ); - - GtkItemFactoryEntry entry; - entry.path = (gchar *)cbuf; // const_cast - entry.accelerator = (gchar*) NULL; - entry.callback = (GtkItemFactoryCallback) NULL; - entry.callback_action = 0; - entry.item_type = (char *)""; - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); // what is 2 ? - // in order to get the pointer to the item we need the item text _without_ underscores - wxString tmp = wxT("
/"); - const wxChar *pc; - for ( pc = str; *pc != wxT('\0'); pc++ ) + // The "m_owner" is the "menu item" +#ifdef __WXGTK20__ + menu->m_owner = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str ) ); +#else + menu->m_owner = gtk_menu_item_new_with_label( wxGTK_CONV( str ) ); + GtkLabel *label = GTK_LABEL( GTK_BIN(menu->m_owner)->child ); + // set new text + gtk_label_set_text( label, wxGTK_CONV( str ) ); + // reparse key accel + guint accel_key = gtk_label_parse_uline (GTK_LABEL(label), wxGTK_CONV( str ) ); + if (accel_key != GDK_VoidSymbol) { - // contrary to the common sense, we must throw out _all_ underscores, - // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we - // might naively think). IMHO it's a bug in GTK+ (VZ) - while (*pc == wxT('_')) - pc++; - tmp << *pc; + gtk_widget_add_accelerator (menu->m_owner, + "activate_item", + m_accel,//gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)), + accel_key, + GDK_MOD1_MASK, + GTK_ACCEL_LOCKED); } - menu->m_owner = gtk_item_factory_get_item( m_factory, wxGTK_CONV( tmp ) ); - gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu->m_owner), menu->m_menu ); -#else +#endif - menu->m_owner = gtk_menu_item_new_with_label( wxGTK_CONV( str ) ); gtk_widget_show( menu->m_owner ); - gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu->m_owner), menu->m_menu ); - gtk_menu_bar_append( GTK_MENU_BAR(m_menubar), menu->m_owner ); + gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu->m_owner), menu->m_menu ); -#endif + if (pos == -1) + gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar), menu->m_owner ); + else + gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar), menu->m_owner, pos ); gtk_signal_connect( GTK_OBJECT(menu->m_owner), "activate", GTK_SIGNAL_FUNC(gtk_menu_open_callback), @@ -441,19 +396,10 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) if ( !wxMenuBarBase::Insert(pos, menu, title) ) return FALSE; - // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as - // of version 1.2.6), so we first append the item and then change its - // index - if ( !GtkAppend(menu, title) ) - return FALSE; - - if (pos+1 >= m_menus.GetCount()) - return TRUE; + // TODO - GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget); - gpointer data = g_list_last(menu_shell->children)->data; - menu_shell->children = g_list_remove(menu_shell->children, data); - menu_shell->children = g_list_insert(menu_shell->children, data, pos); + if ( !GtkAppend(menu, title, (int)pos) ) + return FALSE; return TRUE; } @@ -471,72 +417,24 @@ wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) return menuOld; } -static wxMenu *CopyMenu (wxMenu *menu) -{ - wxMenu *menucopy = new wxMenu (); - wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); - while (node) - { - wxMenuItem *item = node->GetData(); - int itemid = item->GetId(); - wxString text = item->GetText(); - text.Replace(wxT("_"), wxT("&")); - wxMenu *submenu = item->GetSubMenu(); - if (!submenu) - { - wxMenuItem* itemcopy = new wxMenuItem(menucopy, - itemid, text, - menu->GetHelpString(itemid)); - itemcopy->SetBitmap(item->GetBitmap()); - itemcopy->SetCheckable(item->IsCheckable()); - menucopy->Append(itemcopy); - } - else - menucopy->Append (itemid, text, CopyMenu(submenu), - menu->GetHelpString(itemid)); - - node = node->GetNext(); - } - - return menucopy; -} - wxMenu *wxMenuBar::Remove(size_t pos) { wxMenu *menu = wxMenuBarBase::Remove(pos); if ( !menu ) return (wxMenu*) NULL; -/* - GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget); - - printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) ); - printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) ); -*/ - - wxMenu *menucopy = CopyMenu( menu ); - - // unparent calls unref() and that would delete the widget so we raise - // the ref count to 2 artificially before invoking unparent. - gtk_widget_ref( menu->m_menu ); - gtk_widget_unparent( menu->m_menu ); + gtk_menu_item_remove_submenu( GTK_MENU_ITEM(menu->m_owner) ); + gtk_container_remove(GTK_CONTAINER(m_menubar), menu->m_owner); gtk_widget_destroy( menu->m_owner ); - delete menu; - - menu = menucopy; -/* - printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) ); - printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) ); -*/ + menu->m_owner = NULL; if (m_invokingWindow) { - // OPTIMISE ME: see comment in GtkAppend - - wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame ); + // OPTIMISE ME: see comment in GtkAppend + wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame ); - if( frame ) + if( frame ) frame->UpdateMenuBarSize(); } @@ -552,7 +450,7 @@ static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString return res; } - wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst(); while (node) { wxMenuItem *item = node->GetData(); @@ -567,7 +465,7 @@ static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString int wxMenuBar::FindMenuItem( const wxString &menuString, const wxString &itemString ) const { - wxMenuList::Node *node = m_menus.GetFirst(); + wxMenuList::compatibility_iterator node = m_menus.GetFirst(); while (node) { wxMenu *menu = node->GetData(); @@ -585,7 +483,7 @@ static wxMenuItem* FindMenuItemByIdRecursive(const wxMenu* menu, int id) { wxMenuItem* result = menu->FindChildItem(id); - wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst(); while ( node && result == NULL ) { wxMenuItem *item = node->GetData(); @@ -602,7 +500,7 @@ static wxMenuItem* FindMenuItemByIdRecursive(const wxMenu* menu, int id) wxMenuItem* wxMenuBar::FindItem( int id, wxMenu **menuForItem ) const { wxMenuItem* result = 0; - wxMenuList::Node *node = m_menus.GetFirst(); + wxMenuList::compatibility_iterator node = m_menus.GetFirst(); while (node && result == 0) { wxMenu *menu = node->GetData(); @@ -620,7 +518,7 @@ wxMenuItem* wxMenuBar::FindItem( int id, wxMenu **menuForItem ) const void wxMenuBar::EnableTop( size_t pos, bool flag ) { - wxMenuList::Node *node = m_menus.Item( pos ); + wxMenuList::compatibility_iterator node = m_menus.Item( pos ); wxCHECK_RET( node, wxT("menu not found") ); @@ -632,7 +530,7 @@ void wxMenuBar::EnableTop( size_t pos, bool flag ) wxString wxMenuBar::GetLabelTop( size_t pos ) const { - wxMenuList::Node *node = m_menus.Item( pos ); + wxMenuList::compatibility_iterator node = m_menus.Item( pos ); wxCHECK_MSG( node, wxT("invalid"), wxT("menu not found") ); @@ -659,7 +557,7 @@ wxString wxMenuBar::GetLabelTop( size_t pos ) const void wxMenuBar::SetLabelTop( size_t pos, const wxString& label ) { - wxMenuList::Node *node = m_menus.Item( pos ); + wxMenuList::compatibility_iterator node = m_menus.Item( pos ); wxCHECK_RET( node, wxT("menu not found") ); @@ -687,6 +585,7 @@ void wxMenuBar::SetLabelTop( size_t pos, const wxString& label ) // "activate" //----------------------------------------------------------------------------- +extern "C" { static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu ) { if (g_isIdle) @@ -701,56 +600,69 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu ) if (!menu->IsEnabled(id)) return; - // Is this menu on a menubar? (possibly nested) - wxFrame* frame = NULL; - wxMenu* pm = menu; - while ( pm && !frame ) - { - if ( pm->IsAttached() ) - frame = pm->GetMenuBar()->GetFrame(); - else - pm = pm->GetParent(); - } + wxMenuItem* item = menu->FindChildItem( id ); + wxCHECK_RET( item, wxT("error in menu item callback") ); - // If it is then let the frame send the event - if (frame) + if ( item->GetId() == wxGTK_TITLE_ID ) { - frame->ProcessCommand(id); + // ignore events from the menu title + return; } - // otherwise let the menu have it - else + + if (item->IsCheckable()) { - wxMenuItem* item = menu->FindChildItem( id ); - wxCHECK_RET( item, wxT("error in menu item callback") ); + bool isReallyChecked = item->IsChecked(), + isInternallyChecked = item->wxMenuItemBase::IsChecked(); - if (item->IsCheckable()) + // ensure that the internal state is always consistent with what is + // shown on the screen + item->wxMenuItemBase::Check(isReallyChecked); + + // we must not report the events for the radio button going up nor the + // events resulting from the calls to wxMenuItem::Check() + if ( (item->GetKind() == wxITEM_RADIO && !isReallyChecked) || + (isInternallyChecked == isReallyChecked) ) { - bool isReallyChecked = item->IsChecked(), - isInternallyChecked = item->wxMenuItemBase::IsChecked(); + return; + } + } - // ensure that the internal state is always consistent with what is - // shown on the screen - item->wxMenuItemBase::Check(isReallyChecked); - // we must not report the events for the radio button going up nor the - // events resulting from the calls to wxMenuItem::Check() - if ( (item->GetKind() == wxITEM_RADIO && !isReallyChecked) || - (isInternallyChecked == isReallyChecked) ) - { - return; - } + // Is this menu on a menubar? (possibly nested) + wxFrame* frame = NULL; + if(menu->IsAttached()) + frame = menu->GetMenuBar()->GetFrame(); - // the user pressed on the menu item: report the event below - } + // FIXME: why do we have to call wxFrame::GetEventHandler() directly here? + // normally wxMenu::SendEvent() should be enough, if it doesn't work + // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which + // should be fixed instead of working around it here... + if (frame) + { + // If it is attached then let the frame send the event. + // Don't call frame->ProcessCommand(id) because it toggles + // checkable items and we've already done that above. + wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id); + commandEvent.SetEventObject(frame); + if (item->IsCheckable()) + commandEvent.SetInt(item->IsChecked()); + commandEvent.SetEventObject(menu); + frame->GetEventHandler()->ProcessEvent(commandEvent); + } + else + { + // otherwise let the menu have it menu->SendEvent(id, item->IsCheckable() ? item->IsChecked() : -1); } } +} //----------------------------------------------------------------------------- // "select" //----------------------------------------------------------------------------- +extern "C" { static void gtk_menu_hilight_callback( GtkWidget *widget, wxMenu *menu ) { if (g_isIdle) wxapp_install_idle_handler(); @@ -772,11 +684,13 @@ static void gtk_menu_hilight_callback( GtkWidget *widget, wxMenu *menu ) wxWindow *win = menu->GetInvokingWindow(); if (win) win->GetEventHandler()->ProcessEvent( event ); } +} //----------------------------------------------------------------------------- // "deselect" //----------------------------------------------------------------------------- +extern "C" { static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu ) { if (g_isIdle) wxapp_install_idle_handler(); @@ -799,6 +713,7 @@ static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu ) if (win) win->GetEventHandler()->ProcessEvent( event ); } +} //----------------------------------------------------------------------------- // wxMenuItem @@ -860,6 +775,9 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text) for ( const wxChar *pc = text.c_str(); *pc; pc++ ) { + if ( *pc == wxT('\t')) + break; + if ( *pc == wxT('_') ) { // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx" @@ -868,7 +786,7 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text) continue; } -#if GTK_CHECK_VERSION(2, 0, 0) +#ifdef __WXGTK20__ if ( *pc == wxT('\\') ) { // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx" @@ -888,7 +806,7 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text) label += *pc; } - // wxPrintf( L"text %s label %s\n", text.c_str(), label.c_str() ); + // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() ); return label; } @@ -897,14 +815,18 @@ void wxMenuItem::SetText( const wxString& str ) { // Some optimization to avoid flicker wxString oldLabel = m_text; - oldLabel = wxStripMenuCodes(oldLabel.BeforeFirst('\t')); + oldLabel = wxStripMenuCodes(oldLabel); oldLabel.Replace(wxT("_"), wxT("")); - wxString label1 = wxStripMenuCodes(str.BeforeFirst('\t')); - if (oldLabel == label1) - return; + wxString label1 = wxStripMenuCodes(str); + wxString oldhotkey = GetHotKey(); // Store the old hotkey in Ctrl-foo format + wxCharBuffer oldbuf = wxGTK_CONV( GetGtkHotKey(*this) ); // and as foo DoSetText(str); + if (oldLabel == label1 && + oldhotkey == GetHotKey()) // Make sure we can change a hotkey even if the label is unaltered + return; + if (m_menuItem) { GtkLabel *label; @@ -913,16 +835,8 @@ void wxMenuItem::SetText( const wxString& str ) else label = GTK_LABEL( GTK_BIN(m_menuItem)->child ); -#if GTK_CHECK_VERSION(2, 0, 0) - // We have to imitate item_factory_unescape_label here - wxString tmp; - for (size_t n = 0; n < m_text.Len(); n++) - { - if (m_text[n] != wxT('\\')) - tmp += m_text[n]; - } - - gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV(tmp) ); +#ifdef __WXGTK20__ + gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV(m_text) ); #else // set new text gtk_label_set( label, wxGTK_CONV( m_text ) ); @@ -932,6 +846,29 @@ void wxMenuItem::SetText( const wxString& str ) gtk_accel_label_refetch( GTK_ACCEL_LABEL(label) ); #endif } + + guint accel_key; + GdkModifierType accel_mods; + gtk_accelerator_parse( (const char*) oldbuf, &accel_key, &accel_mods); + if (accel_key != 0) + { + gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem), + m_parentMenu->m_accel, + accel_key, + accel_mods ); + } + + wxCharBuffer buf = wxGTK_CONV( GetGtkHotKey(*this) ); + gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods); + if (accel_key != 0) + { + gtk_widget_add_accelerator( GTK_WIDGET(m_menuItem), + "activate", + m_parentMenu->m_accel, + accel_key, + accel_mods, + GTK_ACCEL_VISIBLE); + } } // it's valid for this function to be called even if m_menuItem == NULL @@ -952,38 +889,17 @@ void wxMenuItem::DoSetText( const wxString& str ) { m_text << wxT('_'); } -#if GTK_CHECK_VERSION(2, 0, 0) - else if ( *pc == wxT('_') ) // escape underscores - { - // m_text << wxT("__"); doesn't work - m_text << wxT("__"); - } - else if (*pc == wxT('/')) // we have to escape slashes - { - m_text << wxT("\\/"); - } - else if (*pc == wxT('\\')) // we have to double backslashes - { - m_text << wxT("\\\\"); - } -#else else if ( *pc == wxT('_') ) // escape underscores { m_text << wxT("__"); } - else if (*pc == wxT('/')) /* we have to filter out slashes ... */ + else { - m_text << wxT('\\'); /* ... and replace them with back slashes */ - } -#endif - else { m_text << *pc; } ++pc; } - // wxPrintf( L"str %s m_text %s\n", str.c_str(), m_text.c_str() ); - m_hotKey = wxT(""); if(*pc == wxT('\t')) @@ -991,6 +907,8 @@ void wxMenuItem::DoSetText( const wxString& str ) pc++; m_hotKey = pc; } + + // wxPrintf( wxT("DoSetText(): str %s m_text %s hotkey %s\n"), str.c_str(), m_text.c_str(), m_hotKey.c_str() ); } #if wxUSE_ACCEL @@ -1051,33 +969,6 @@ bool wxMenuItem::IsChecked() const return ((GtkCheckMenuItem*)m_menuItem)->active != 0; } -wxString wxMenuItem::GetFactoryPath() const -{ - // In order to get the pointer to the item we need the item - // text _without_ underscores in GTK 1.2 - wxString path( wxT("
/") ); - - for ( const wxChar *pc = m_text.c_str(); *pc; pc++ ) - { - if ( *pc == wxT('_') ) - { -#ifdef __WXGTK20__ - pc++; -#else - // remove '_' unconditionally - continue; -#endif - } - - // don't remove ampersands '&' since if we have them in the menu item title - // it means that they were doubled to indicate "&" instead of accelerator - - path += *pc; - } - - return path; -} - //----------------------------------------------------------------------------- // wxMenu //----------------------------------------------------------------------------- @@ -1087,223 +978,207 @@ IMPLEMENT_DYNAMIC_CLASS(wxMenu,wxEvtHandler) void wxMenu::Init() { m_accel = gtk_accel_group_new(); - m_factory = gtk_item_factory_new( GTK_TYPE_MENU, "
", m_accel ); - m_menu = gtk_item_factory_get_widget( m_factory, "
" ); + m_menu = gtk_menu_new(); + // NB: keep reference to the menu so that it is not destroyed behind + // our back by GTK+ e.g. when it is removed from menubar: + gtk_widget_ref(m_menu); m_owner = (GtkWidget*) 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 // immediately. - if(m_style & wxMENU_TEAROFF) + if ( m_style & wxMENU_TEAROFF ) { - GtkItemFactoryEntry entry; - entry.path = (char *)"/tearoff"; - entry.callback = (GtkItemFactoryCallback) NULL; - entry.callback_action = 0; - entry.item_type = (char *)""; - entry.accelerator = (gchar*) NULL; - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); // what is 2 ? - //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "
/tearoff" ); + GtkWidget *tearoff = gtk_tearoff_menu_item_new(); + + gtk_menu_append(GTK_MENU(m_menu), tearoff); } + m_prevRadio = NULL; + // append the title as the very first entry if we have it - if ( !!m_title ) + if ( !m_title.empty() ) { - Append(-2, m_title); + Append(wxGTK_TITLE_ID, m_title); AppendSeparator(); } } wxMenu::~wxMenu() { - m_items.Clear(); - - gtk_widget_destroy( m_menu ); - - gtk_object_unref( GTK_OBJECT(m_factory) ); + WX_CLEAR_LIST(wxMenuItemList, m_items); + + if ( GTK_IS_WIDGET( m_menu )) + { + // see wxMenu::Init + gtk_widget_unref( m_menu ); + // if the menu is inserted in another menu at this time, there was + // one more reference to it: + if ( m_owner ) + gtk_widget_destroy( m_menu ); + } } -bool wxMenu::GtkAppend(wxMenuItem *mitem) +bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos) { GtkWidget *menuItem; -#if defined(USE_MENU_BITMAPS) || !GTK_CHECK_VERSION(1, 2, 0) - bool appended = FALSE; + wxString text; +#ifndef __WXGTK20__ + GtkLabel* label; #endif - // does this item terminate the current radio group? - bool endOfRadioGroup = TRUE; - if ( mitem->IsSeparator() ) { - GtkItemFactoryEntry entry; - entry.path = (char *)"/sep"; - entry.callback = (GtkItemFactoryCallback) NULL; - entry.callback_action = 0; - entry.item_type = (char *)""; - entry.accelerator = (gchar*) NULL; - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); // what is 2 ? - - // this will be wrong for more than one separator. do we care? - menuItem = gtk_item_factory_get_widget( m_factory, "
/sep" ); - - // we might have a separator inside a radio group - endOfRadioGroup = FALSE; +#ifdef __WXGTK20__ + menuItem = gtk_separator_menu_item_new(); +#else + // TODO + menuItem = gtk_menu_item_new(); +#endif } - else if ( mitem->IsSubMenu() ) + else if (mitem->GetBitmap().Ok()) { - // text has "_" instead of "&" after mitem->SetText() - wxString text( mitem->GetText() ); - - // local buffer in multibyte form - char buf[200]; - strcpy( buf, "/" ); - strcat( buf, wxGTK_CONV( text ) ); - - GtkItemFactoryEntry entry; - entry.path = buf; - entry.callback = (GtkItemFactoryCallback) 0; - entry.callback_action = 0; - entry.item_type = (char *)""; - entry.accelerator = (gchar*) NULL; + text = mitem->GetText(); + const wxBitmap *bitmap = &mitem->GetBitmap(); - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); // what is 2 ? +#ifdef __WXGTK20__ + menuItem = gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text ) ); - wxString path( mitem->GetFactoryPath() ); - menuItem = gtk_item_factory_get_item( m_factory, wxGTK_CONV( path ) ); + GtkWidget *image; + if (bitmap->HasPixbuf()) + { + image = gtk_image_new_from_pixbuf(bitmap->GetPixbuf()); + } + else + { + GdkPixmap *gdk_pixmap = bitmap->GetPixmap(); + GdkBitmap *gdk_bitmap = bitmap->GetMask() ? + bitmap->GetMask()->GetBitmap() : + (GdkBitmap*) NULL; + image = gtk_image_new_from_pixmap( gdk_pixmap, gdk_bitmap ); + } + + gtk_widget_show(image); - gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), mitem->GetSubMenu()->m_menu ); + gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem), image ); - // 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); - } -#ifdef USE_MENU_BITMAPS - else if (mitem->GetBitmap().Ok()) // An item with bitmap - { - wxString text( mitem->GetText() ); - const wxBitmap *bitmap = &mitem->GetBitmap(); +#else + GdkPixmap *gdk_pixmap = bitmap->GetPixmap(); + GdkBitmap *gdk_bitmap = bitmap->GetMask() ? bitmap->GetMask()->GetBitmap() : (GdkBitmap*) NULL; menuItem = gtk_pixmap_menu_item_new (); - GtkWidget *label = gtk_accel_label_new ( wxGTK_CONV( text ) ); + label = GTK_LABEL(gtk_accel_label_new ( wxGTK_CONV( text ) )); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_container_add (GTK_CONTAINER (menuItem), label); - guint accel_key = gtk_label_parse_uline (GTK_LABEL(label), wxGTK_CONV( text ) ); + gtk_container_add (GTK_CONTAINER (menuItem), GTK_WIDGET(label)); + gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), menuItem); - if (accel_key != GDK_VoidSymbol) - { - gtk_widget_add_accelerator (menuItem, - "activate_item", - gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu)), - accel_key, 0, - GTK_ACCEL_LOCKED); - } - gtk_widget_show (label); - mitem->SetLabelWidget(label); + gtk_widget_show (GTK_WIDGET(label)); + + mitem->SetLabelWidget(GTK_WIDGET(label)); - GtkWidget* pixmap = gtk_pixmap_new( bitmap->GetPixmap(), bitmap->GetMask() ? bitmap->GetMask()->GetBitmap() : (GdkBitmap* )NULL); + GtkWidget* pixmap = gtk_pixmap_new( gdk_pixmap, gdk_bitmap ); gtk_widget_show(pixmap); gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem ), pixmap); - gtk_signal_connect( GTK_OBJECT(menuItem), "activate", - GTK_SIGNAL_FUNC(gtk_menu_clicked_callback), - (gpointer)this ); - - gtk_menu_append( GTK_MENU(m_menu), menuItem ); - gtk_widget_show( menuItem ); +#endif - appended = TRUE; // We've done this, don't do it again + m_prevRadio = NULL; } -#endif // USE_MENU_BITMAPS else // a normal item { // text has "_" instead of "&" after mitem->SetText() so don't use it - wxString text( mitem->GetText() ); - - // buffers containing the menu item path and type in multibyte form - char bufPath[256], - bufType[256]; - - strcpy( bufPath, "/" ); - strncat( bufPath, wxGTK_CONV(text), WXSIZEOF(bufPath) - 2 ); - bufPath[WXSIZEOF(bufPath) - 1] = '\0'; + text = mitem->GetText() ; - GtkItemFactoryEntry entry; - entry.path = bufPath; - entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback; - entry.callback_action = 0; - - wxString pathRadio; - const char *item_type; switch ( mitem->GetKind() ) { case wxITEM_CHECK: - item_type = ""; + { +#ifdef __WXGTK20__ + menuItem = gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text ) ); +#else + menuItem = gtk_check_menu_item_new_with_label( wxGTK_CONV( text ) ); + label = GTK_LABEL( GTK_BIN(menuItem)->child ); + // set new text + gtk_label_set_text( label, wxGTK_CONV( text ) ); +#endif + m_prevRadio = NULL; break; + } case wxITEM_RADIO: - if ( m_pathLastRadio.empty() ) + { + GSList *group = NULL; + if ( m_prevRadio == NULL ) { // start of a new radio group - item_type = ""; - wxString tmp( wxGTK_CONV_BACK( bufPath ) ); - tmp.Remove(0,1); - m_pathLastRadio = tmp; +#ifdef __WXGTK20__ + m_prevRadio = menuItem = gtk_radio_menu_item_new_with_mnemonic( group, wxGTK_CONV( text ) ); +#else + m_prevRadio = menuItem = gtk_radio_menu_item_new_with_label( group, wxGTK_CONV( text ) ); + label = GTK_LABEL( GTK_BIN(menuItem)->child ); + // set new text + gtk_label_set_text( label, wxGTK_CONV( text ) ); +#endif } else // continue the radio group { - pathRadio = m_pathLastRadio; - pathRadio.Replace(wxT("_"), wxT("")); - pathRadio.Prepend(wxT("
/")); - - strncpy(bufType, wxGTK_CONV(pathRadio), WXSIZEOF(bufType)); - bufType[WXSIZEOF(bufType) - 1] = '\0'; - item_type = bufType; +#ifdef __WXGTK20__ + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio)); + m_prevRadio = menuItem = gtk_radio_menu_item_new_with_mnemonic( group, wxGTK_CONV( text ) ); +#else + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio)); + m_prevRadio = menuItem = gtk_radio_menu_item_new_with_label( group, wxGTK_CONV( text ) ); + label = GTK_LABEL( GTK_BIN(menuItem)->child ); +#endif } - - // continue the existing radio group, if any - endOfRadioGroup = FALSE; break; + } default: wxFAIL_MSG( _T("unexpected menu item kind") ); // fall through case wxITEM_NORMAL: - item_type = ""; + { +#ifdef __WXGTK20__ + menuItem = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text ) ); +#else + menuItem = gtk_menu_item_new_with_label( wxGTK_CONV( text ) ); + label = GTK_LABEL( GTK_BIN(menuItem)->child ); +#endif + m_prevRadio = NULL; break; + } } - entry.item_type = (char *)item_type; // cast needed for GTK+ - entry.accelerator = (gchar*) NULL; + } + + guint accel_key; + GdkModifierType accel_mods; + wxCharBuffer buf = wxGTK_CONV( GetGtkHotKey(*mitem) ); -#if wxUSE_ACCEL - // due to an apparent bug in GTK+, we have to use a static buffer here - - // otherwise GTK+ 1.2.2 manages to override the memory we pass to it - // somehow! (VZ) - char s_accel[50]; // should be big enough, we check for overruns - wxString tmp( GetHotKey(*mitem) ); - strncpy(s_accel, wxGTK_CONV( tmp ), WXSIZEOF(s_accel)); - s_accel[WXSIZEOF(s_accel) - 1] = '\0'; - entry.accelerator = s_accel; -#else // !wxUSE_ACCEL - entry.accelerator = (char*) NULL; -#endif // wxUSE_ACCEL/!wxUSE_ACCEL - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - - wxString path( mitem->GetFactoryPath() ); - menuItem = gtk_item_factory_get_widget( m_factory, wxGTK_CONV( path ) ); - - if (!menuItem) - wxLogError( wxT("Wrong menu path: %s\n"), path.c_str() ); + // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetGtkHotKey(*mitem).c_str() ); + gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods); + if (accel_key != 0) + { + gtk_widget_add_accelerator (GTK_WIDGET(menuItem), + "activate", + m_accel, + accel_key, + accel_mods, + GTK_ACCEL_VISIBLE); } + if (pos == -1) + gtk_menu_shell_append(GTK_MENU_SHELL(m_menu), menuItem); + else + gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu), menuItem, pos); + + gtk_widget_show( menuItem ); + if ( !mitem->IsSeparator() ) { wxASSERT_MSG( menuItem, wxT("invalid menuitem") ); @@ -1315,46 +1190,68 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) gtk_signal_connect( GTK_OBJECT(menuItem), "deselect", GTK_SIGNAL_FUNC(gtk_menu_nolight_callback), (gpointer)this ); + + if ( mitem->IsSubMenu() && mitem->GetKind() != wxITEM_RADIO && mitem->GetKind() != wxITEM_CHECK ) + { + 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 + { + gtk_signal_connect( GTK_OBJECT(menuItem), "activate", + GTK_SIGNAL_FUNC(gtk_menu_clicked_callback), + (gpointer)this ); + } +#ifndef __WXGTK20__ + guint accel_key = gtk_label_parse_uline (GTK_LABEL(label), wxGTK_CONV( text ) ); + if (accel_key != GDK_VoidSymbol) + { + gtk_widget_add_accelerator (menuItem, + "activate_item", + gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu)), + accel_key, + GDK_MOD1_MASK, + GTK_ACCEL_LOCKED); + } +#endif } mitem->SetMenuItem(menuItem); - if ( endOfRadioGroup ) + if (ms_locked) { - m_pathLastRadio.clear(); + // This doesn't even exist! + // gtk_widget_lock_accelerators(mitem->GetMenuItem()); } return TRUE; } -bool wxMenu::DoAppend(wxMenuItem *mitem) +wxMenuItem* wxMenu::DoAppend(wxMenuItem *mitem) { - return GtkAppend(mitem) && wxMenuBase::DoAppend(mitem); + if (!GtkAppend(mitem)) + return NULL; + + return wxMenuBase::DoAppend(mitem); } -bool wxMenu::DoInsert(size_t pos, wxMenuItem *item) +wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item) { if ( !wxMenuBase::DoInsert(pos, item) ) - return FALSE; + return NULL; - // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as - // of version 1.2.6), so we first append the item and then change its - // index - if ( !GtkAppend(item) ) - return FALSE; + // TODO + if ( !GtkAppend(item, (int)pos) ) + return NULL; - if ( m_style & wxMENU_TEAROFF ) - { - // change the position as the first item is the tear-off marker - pos++; - } - - GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget); - gpointer data = g_list_last(menu_shell->children)->data; - menu_shell->children = g_list_remove(menu_shell->children, data); - menu_shell->children = g_list_insert(menu_shell->children, data, pos); - - return TRUE; + return item; } wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) @@ -1371,7 +1268,7 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const { - wxMenuItemList::Node *node = m_items.GetFirst(); + wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); while (node) { wxMenuItem *item = node->GetData(); @@ -1387,9 +1284,9 @@ int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const // helpers // ---------------------------------------------------------------------------- -#if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL +#if wxUSE_ACCEL -static wxString GetHotKey( const wxMenuItem& item ) +static wxString GetGtkHotKey( const wxMenuItem& item ) { wxString hotkey; @@ -1419,19 +1316,25 @@ static wxString GetHotKey( const wxMenuItem& item ) case WXK_F10: case WXK_F11: case WXK_F12: - hotkey << wxT('F') << code - WXK_F1 + 1; + case WXK_F13: + case WXK_F14: + case WXK_F15: + case WXK_F16: + case WXK_F17: + case WXK_F18: + case WXK_F19: + case WXK_F20: + case WXK_F21: + case WXK_F22: + case WXK_F23: + case WXK_F24: + hotkey += wxString::Format(wxT("F%d"), code - WXK_F1 + 1); break; // TODO: we should use gdk_keyval_name() (a.k.a. // XKeysymToString) here as well as hardcoding the keysym // names this might be not portable - case WXK_NUMPAD_INSERT: - hotkey << wxT("KP_Insert" ); - break; - case WXK_NUMPAD_DELETE: - hotkey << wxT("KP_Delete" ); - break; - case WXK_INSERT: + case WXK_INSERT: hotkey << wxT("Insert" ); break; case WXK_DELETE: @@ -1444,9 +1347,11 @@ static wxString GetHotKey( const wxMenuItem& item ) hotkey << wxT("Down" ); break; case WXK_PAGEUP: + case WXK_PRIOR: hotkey << wxT("Prior" ); break; case WXK_PAGEDOWN: + case WXK_NEXT: hotkey << wxT("Next" ); break; case WXK_LEFT: @@ -1464,7 +1369,165 @@ static wxString GetHotKey( const wxMenuItem& item ) case WXK_RETURN: hotkey << wxT("Return" ); break; - + case WXK_BACK: + hotkey << wxT("BackSpace" ); + break; + case WXK_TAB: + hotkey << wxT("Tab" ); + break; + case WXK_ESCAPE: + hotkey << wxT("Esc" ); + break; + case WXK_SPACE: + hotkey << wxT("space" ); + break; + case WXK_MULTIPLY: + hotkey << wxT("Multiply" ); + break; + case WXK_ADD: + hotkey << wxT("Add" ); + break; + case WXK_SEPARATOR: + hotkey << wxT("Separator" ); + break; + case WXK_SUBTRACT: + hotkey << wxT("Subtract" ); + break; + case WXK_DECIMAL: + hotkey << wxT("Decimal" ); + break; + case WXK_DIVIDE: + hotkey << wxT("Divide" ); + break; + case WXK_CANCEL: + hotkey << wxT("Cancel" ); + break; + case WXK_CLEAR: + hotkey << wxT("Clear" ); + break; + case WXK_MENU: + hotkey << wxT("Menu" ); + break; + case WXK_PAUSE: + hotkey << wxT("Pause" ); + break; + case WXK_CAPITAL: + hotkey << wxT("Capital" ); + break; + case WXK_SELECT: + hotkey << wxT("Select" ); + break; + case WXK_PRINT: + hotkey << wxT("Print" ); + break; + case WXK_EXECUTE: + hotkey << wxT("Execute" ); + break; + case WXK_SNAPSHOT: + hotkey << wxT("Snapshot" ); + break; + case WXK_HELP: + hotkey << wxT("Help" ); + break; + case WXK_NUMLOCK: + hotkey << wxT("Num_Lock" ); + break; + case WXK_SCROLL: + hotkey << wxT("Scroll_Lock" ); + break; + case WXK_NUMPAD_INSERT: + hotkey << wxT("KP_Insert" ); + break; + case WXK_NUMPAD_DELETE: + hotkey << wxT("KP_Delete" ); + break; + case WXK_NUMPAD_SPACE: + hotkey << wxT("KP_Space" ); + break; + case WXK_NUMPAD_TAB: + hotkey << wxT("KP_Tab" ); + break; + case WXK_NUMPAD_ENTER: + hotkey << wxT("KP_Enter" ); + break; + case WXK_NUMPAD_F1: case WXK_NUMPAD_F2: case WXK_NUMPAD_F3: + case WXK_NUMPAD_F4: + hotkey += wxString::Format(wxT("KP_F%d"), code - WXK_NUMPAD_F1 + 1); + break; + case WXK_NUMPAD_HOME: + hotkey << wxT("KP_Home" ); + break; + case WXK_NUMPAD_LEFT: + hotkey << wxT("KP_Left" ); + break; + case WXK_NUMPAD_UP: + hotkey << wxT("KP_Up" ); + break; + case WXK_NUMPAD_RIGHT: + hotkey << wxT("KP_Right" ); + break; + case WXK_NUMPAD_DOWN: + hotkey << wxT("KP_Down" ); + break; + case WXK_NUMPAD_PRIOR: case WXK_NUMPAD_PAGEUP: + hotkey << wxT("KP_Prior" ); + break; + case WXK_NUMPAD_NEXT: case WXK_NUMPAD_PAGEDOWN: + hotkey << wxT("KP_Next" ); + break; + case WXK_NUMPAD_END: + hotkey << wxT("KP_End" ); + break; + case WXK_NUMPAD_BEGIN: + hotkey << wxT("KP_Begin" ); + break; + case WXK_NUMPAD_EQUAL: + hotkey << wxT("KP_Equal" ); + break; + case WXK_NUMPAD_MULTIPLY: + hotkey << wxT("KP_Multiply" ); + break; + case WXK_NUMPAD_ADD: + hotkey << wxT("KP_Add" ); + break; + case WXK_NUMPAD_SEPARATOR: + hotkey << wxT("KP_Separator" ); + break; + case WXK_NUMPAD_SUBTRACT: + hotkey << wxT("KP_Subtract" ); + break; + case WXK_NUMPAD_DECIMAL: + hotkey << wxT("KP_Decimal" ); + break; + case WXK_NUMPAD_DIVIDE: + hotkey << wxT("KP_Divide" ); + break; + case WXK_NUMPAD0: case WXK_NUMPAD1: case WXK_NUMPAD2: + case WXK_NUMPAD3: case WXK_NUMPAD4: case WXK_NUMPAD5: + case WXK_NUMPAD6: case WXK_NUMPAD7: case WXK_NUMPAD8: case WXK_NUMPAD9: + hotkey += wxString::Format(wxT("KP_%d"), code - WXK_NUMPAD0); + break; + case WXK_WINDOWS_LEFT: + hotkey << wxT("Super_L" ); + break; + case WXK_WINDOWS_RIGHT: + hotkey << wxT("Super_R" ); + break; + case WXK_WINDOWS_MENU: + hotkey << wxT("Menu" ); + break; + case WXK_COMMAND: + hotkey << wxT("Command" ); + break; + /* These probably wouldn't work as there is no SpecialX in gdk/keynames.txt + case WXK_SPECIAL1: case WXK_SPECIAL2: case WXK_SPECIAL3: case WXK_SPECIAL4: + case WXK_SPECIAL5: case WXK_SPECIAL6: case WXK_SPECIAL7: case WXK_SPECIAL8: + case WXK_SPECIAL9: case WXK_SPECIAL10: case WXK_SPECIAL11: case WXK_SPECIAL12: + case WXK_SPECIAL13: case WXK_SPECIAL14: case WXK_SPECIAL15: case WXK_SPECIAL16: + case WXK_SPECIAL17: case WXK_SPECIAL18: case WXK_SPECIAL19: case WXK_SPECIAL20: + hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1); + break; + */ // if there are any other keys wxGetAccelFromString() may // return, we should process them here @@ -1495,7 +1558,7 @@ static wxString GetHotKey( const wxMenuItem& item ) // substitute for missing GtkPixmapMenuItem //----------------------------------------------------------------------------- -#ifdef USE_MENU_BITMAPS +#ifndef __WXGTK20__ /* * Copyright (C) 1998, 1999, 2000 Free Software Foundation @@ -1558,7 +1621,7 @@ static void changed_have_pixmap_status (GtkPixmapMenuItem *menu_item); static GtkMenuItemClass *parent_class = NULL; -} +} // extern "C" #define BORDER_SPACING 3 #define PMAP_WIDTH 20 @@ -1589,6 +1652,8 @@ gtk_pixmap_menu_item_get_type (void) return pixmap_menu_item_type; } +extern "C" { + /** * gtk_pixmap_menu_item_new * @@ -1867,5 +1932,7 @@ changed_have_pixmap_status (GtkPixmapMenuItem *menu_item) gtk_widget_queue_resize(GTK_WIDGET(menu_item)); } -#endif // USE_MENU_BITMAPS +} // extern "C" + +#endif // !__WXGTK20__