1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/menu.cpp 
   3 // Purpose:     implementation of wxMenuBar and wxMenu classes for wxGTK 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  21     #include "wx/bitmap.h" 
  26 #include "wx/stockitem.h" 
  27 #include "wx/gtk/private.h" 
  28 #include "wx/gtk/private/mnemonics.h" 
  30 // we use normal item but with a special id for the menu title 
  31 static const int wxGTK_TITLE_ID 
= -3; 
  33 // forward declare it as it's used by wxMenuBar too when using Hildon 
  36     static void menuitem_activate(GtkWidget
*, wxMenuItem
* item
); 
  40 static void wxGetGtkAccel(const wxMenuItem
*, guint
*, GdkModifierType
*); 
  43 static void DoCommonMenuCallbackCode(wxMenu 
*menu
, wxMenuEvent
& event
) 
  45     event
.SetEventObject( menu 
); 
  47     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
  48     if (handler 
&& handler
->SafelyProcessEvent(event
)) 
  51     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
  53         win
->HandleWindowEvent( event 
); 
  56 //----------------------------------------------------------------------------- 
  58 //----------------------------------------------------------------------------- 
  60 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
) 
  62 void wxMenuBar::Init(size_t n
, wxMenu 
*menus
[], const wxString titles
[], long style
) 
  64     m_invokingWindow 
= NULL
; 
  66 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 
  67     // Hildon window uses a single menu instead of a menu bar, so wxMenuBar is 
  68     // the same as menu in this case 
  70     m_menubar 
= gtk_menu_new(); 
  71 #else // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 
  72     if (!PreCreation( NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
  73         !CreateBase( NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") )) 
  75         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
  79     m_menubar 
= gtk_menu_bar_new(); 
  81     if (style 
& wxMB_DOCKABLE
) 
  83         m_widget 
= gtk_handle_box_new(); 
  84         gtk_container_add(GTK_CONTAINER(m_widget
), m_menubar
); 
  85         gtk_widget_show(m_menubar
); 
  94     GTKApplyWidgetStyle(); 
  95 #endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2/!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 
  97     g_object_ref(m_widget
); 
  99     for (size_t i 
= 0; i 
< n
; ++i 
) 
 100         Append(menus
[i
], titles
[i
]); 
 103 wxMenuBar::wxMenuBar(size_t n
, wxMenu 
*menus
[], const wxString titles
[], long style
) 
 105     Init(n
, menus
, titles
, style
); 
 108 wxMenuBar::wxMenuBar(long style
) 
 110     Init(0, NULL
, NULL
, style
); 
 113 wxMenuBar::wxMenuBar() 
 115     Init(0, NULL
, NULL
, 0); 
 118 wxMenuBar::~wxMenuBar() 
 123 wxMenubarUnsetInvokingWindow(wxMenu
* menu
, wxWindow
* win
, GtkWindow
* tlw 
= NULL
) 
 125     menu
->SetInvokingWindow( NULL 
); 
 127     // support for native hot keys 
 131             tlw 
= GTK_WINDOW(wxGetTopLevelParent(win
)->m_widget
); 
 132         if (g_slist_find(menu
->m_accel
->acceleratables
, tlw
)) 
 133             gtk_window_remove_accel_group(tlw
, menu
->m_accel
); 
 136     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 139         wxMenuItem 
*menuitem 
= node
->GetData(); 
 140         if (menuitem
->IsSubMenu()) 
 141             wxMenubarUnsetInvokingWindow(menuitem
->GetSubMenu(), win
, tlw
); 
 142         node 
= node
->GetNext(); 
 147 wxMenubarSetInvokingWindow(wxMenu
* menu
, wxWindow
* win
, GtkWindow
* tlw 
= NULL
) 
 149     menu
->SetInvokingWindow( win 
); 
 151     // support for native hot keys 
 155             tlw 
= GTK_WINDOW(wxGetTopLevelParent(win
)->m_widget
); 
 156         if (!g_slist_find(menu
->m_accel
->acceleratables
, tlw
)) 
 157             gtk_window_add_accel_group(tlw
, menu
->m_accel
); 
 160     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 163         wxMenuItem 
*menuitem 
= node
->GetData(); 
 164         if (menuitem
->IsSubMenu()) 
 165             wxMenubarSetInvokingWindow(menuitem
->GetSubMenu(), win
, tlw
); 
 166         node 
= node
->GetNext(); 
 170 void wxMenuBar::SetInvokingWindow( wxWindow 
*win 
) 
 172     m_invokingWindow 
= win
; 
 174     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 177         wxMenu 
*menu 
= node
->GetData(); 
 178         wxMenubarSetInvokingWindow( menu
, win 
); 
 179         node 
= node
->GetNext(); 
 183 void wxMenuBar::SetLayoutDirection(wxLayoutDirection dir
) 
 185     if ( dir 
== wxLayout_Default 
) 
 187         const wxWindow 
*const frame 
= GetFrame(); 
 190             // inherit layout from frame. 
 191             dir 
= frame
->GetLayoutDirection(); 
 193         else // use global layout 
 195             dir 
= wxTheApp
->GetLayoutDirection(); 
 199     if ( dir 
== wxLayout_Default 
) 
 202     GTKSetLayout(m_menubar
, dir
); 
 204     // also set the layout of all menus we already have (new ones will inherit 
 205     // the current layout) 
 206     for ( wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 208           node 
= node
->GetNext() ) 
 210         wxMenu 
*const menu 
= node
->GetData(); 
 211         menu
->SetLayoutDirection(dir
); 
 215 wxLayoutDirection 
wxMenuBar::GetLayoutDirection() const 
 217     return GTKGetLayout(m_menubar
); 
 220 void wxMenuBar::Attach(wxFrame 
*frame
) 
 222     wxMenuBarBase::Attach(frame
); 
 224     SetLayoutDirection(wxLayout_Default
); 
 227 void wxMenuBar::UnsetInvokingWindow( wxWindow 
*win 
) 
 229     m_invokingWindow 
= NULL
; 
 231     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 234         wxMenu 
*menu 
= node
->GetData(); 
 235         wxMenubarUnsetInvokingWindow( menu
, win 
); 
 236         node 
= node
->GetNext(); 
 240 bool wxMenuBar::Append( wxMenu 
*menu
, const wxString 
&title 
) 
 242     if ( !wxMenuBarBase::Append( menu
, title 
) ) 
 245     return GtkAppend(menu
, title
); 
 248 bool wxMenuBar::GtkAppend(wxMenu 
*menu
, const wxString
& title
, int pos
) 
 250     menu
->SetLayoutDirection(GetLayoutDirection()); 
 252 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 
 253     // if the menu has only one item, append it directly to the top level menu 
 254     // instead of inserting a useless submenu 
 255     if ( menu
->GetMenuItemCount() == 1 ) 
 257         wxMenuItem 
* const item 
= menu
->FindItemByPosition(0); 
 259         // remove both mnemonics and accelerator: neither is useful under Maemo 
 260         const wxString 
str(wxStripMenuCodes(item
->GetItemLabel())); 
 262         if ( item
->IsSubMenu() ) 
 263             return GtkAppend(item
->GetSubMenu(), str
, pos
); 
 265         menu
->m_owner 
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str 
) ); 
 267         g_signal_connect(menu
->m_owner
, "activate", 
 268                          G_CALLBACK(menuitem_activate
), item
); 
 269         item
->SetMenuItem(menu
->m_owner
); 
 272 #endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2 /!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 
 274         const wxString 
str(wxConvertMnemonicsToGTK(title
)); 
 276         // This doesn't have much effect right now. 
 277         menu
->SetTitle( str 
); 
 279         // The "m_owner" is the "menu item" 
 280         menu
->m_owner 
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str 
) ); 
 282         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 285     gtk_widget_show( menu
->m_owner 
); 
 288         gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner 
); 
 290         gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
, pos 
); 
 292     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
 293     // addings menu later on. 
 294     if (m_invokingWindow
) 
 295         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 300 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 302     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 307     if ( !GtkAppend(menu
, title
, (int)pos
) ) 
 313 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 315     // remove the old item and insert a new one 
 316     wxMenu 
*menuOld 
= Remove(pos
); 
 317     if ( menuOld 
&& !Insert(pos
, menu
, title
) ) 
 322     // either Insert() succeeded or Remove() failed and menuOld is NULL 
 326 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 328     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 332     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu
->m_owner
), NULL
); 
 333     gtk_container_remove(GTK_CONTAINER(m_menubar
), menu
->m_owner
); 
 335     gtk_widget_destroy( menu
->m_owner 
); 
 336     menu
->m_owner 
= NULL
; 
 338     if (m_invokingWindow
) 
 339         wxMenubarUnsetInvokingWindow( menu
, m_invokingWindow 
); 
 344 static int FindMenuItemRecursive( const wxMenu 
*menu
, const wxString 
&menuString
, const wxString 
&itemString 
) 
 346     if (wxMenuItem::GetLabelText(wxConvertMnemonicsFromGTK(menu
->GetTitle())) == wxMenuItem::GetLabelText(menuString
)) 
 348         int res 
= menu
->FindItem( itemString 
); 
 349         if (res 
!= wxNOT_FOUND
) 
 353     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 356         wxMenuItem 
*item 
= node
->GetData(); 
 357         if (item
->IsSubMenu()) 
 358             return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
); 
 360         node 
= node
->GetNext(); 
 366 int wxMenuBar::FindMenuItem( const wxString 
&menuString
, const wxString 
&itemString 
) const 
 368     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 371         wxMenu 
*menu 
= node
->GetData(); 
 372         int res 
= FindMenuItemRecursive( menu
, menuString
, itemString
); 
 375         node 
= node
->GetNext(); 
 381 // Find a wxMenuItem using its id. Recurses down into sub-menus 
 382 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
) 
 384     wxMenuItem
* result 
= menu
->FindChildItem(id
); 
 386     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 387     while ( node 
&& result 
== NULL 
) 
 389         wxMenuItem 
*item 
= node
->GetData(); 
 390         if (item
->IsSubMenu()) 
 392             result 
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id 
); 
 394         node 
= node
->GetNext(); 
 400 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu 
**menuForItem 
) const 
 402     wxMenuItem
* result 
= 0; 
 403     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 404     while (node 
&& result 
== 0) 
 406         wxMenu 
*menu 
= node
->GetData(); 
 407         result 
= FindMenuItemByIdRecursive( menu
, id 
); 
 408         node 
= node
->GetNext(); 
 413         *menuForItem 
= result 
? result
->GetMenu() : NULL
; 
 419 void wxMenuBar::EnableTop( size_t pos
, bool flag 
) 
 421     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 423     wxCHECK_RET( node
, wxT("menu not found") ); 
 425     wxMenu
* menu 
= node
->GetData(); 
 428         gtk_widget_set_sensitive( menu
->m_owner
, flag 
); 
 431 wxString 
wxMenuBar::GetMenuLabel( size_t pos 
) const 
 433     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 435     wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") ); 
 437     wxMenu
* menu 
= node
->GetData(); 
 439     return wxConvertMnemonicsFromGTK(menu
->GetTitle()); 
 442 void wxMenuBar::SetMenuLabel( size_t pos
, const wxString
& label 
) 
 444     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 446     wxCHECK_RET( node
, wxT("menu not found") ); 
 448     wxMenu
* menu 
= node
->GetData(); 
 450     const wxString 
str(wxConvertMnemonicsToGTK(label
)); 
 452     menu
->SetTitle( str 
); 
 455         gtk_label_set_text_with_mnemonic( GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
), wxGTK_CONV(str
) ); 
 458 //----------------------------------------------------------------------------- 
 460 //----------------------------------------------------------------------------- 
 463 static void menuitem_activate(GtkWidget
*, wxMenuItem
* item
) 
 465     if (!item
->IsEnabled()) 
 468     int id 
= item
->GetId(); 
 469     if (id 
== wxGTK_TITLE_ID
) 
 471         // ignore events from the menu title 
 475     if (item
->IsCheckable()) 
 477         bool isReallyChecked 
= item
->IsChecked(), 
 478             isInternallyChecked 
= item
->wxMenuItemBase::IsChecked(); 
 480         // ensure that the internal state is always consistent with what is 
 481         // shown on the screen 
 482         item
->wxMenuItemBase::Check(isReallyChecked
); 
 484         // we must not report the events for the radio button going up nor the 
 485         // events resulting from the calls to wxMenuItem::Check() 
 486         if ( (item
->GetKind() == wxITEM_RADIO 
&& !isReallyChecked
) || 
 487              (isInternallyChecked 
== isReallyChecked
) ) 
 493     wxMenu
* menu 
= item
->GetMenu(); 
 494     menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1); 
 498 //----------------------------------------------------------------------------- 
 500 //----------------------------------------------------------------------------- 
 503 static void menuitem_select(GtkWidget
*, wxMenuItem
* item
) 
 505     if (!item
->IsEnabled()) 
 508     wxMenu
* menu 
= item
->GetMenu(); 
 509     wxMenuEvent 
event(wxEVT_MENU_HIGHLIGHT
, item
->GetId()); 
 510     event
.SetEventObject( menu 
); 
 512     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 513     if (handler 
&& handler
->SafelyProcessEvent(event
)) 
 516     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 517     if (win
) win
->HandleWindowEvent( event 
); 
 521 //----------------------------------------------------------------------------- 
 523 //----------------------------------------------------------------------------- 
 526 static void menuitem_deselect(GtkWidget
*, wxMenuItem
* item
) 
 528     if (!item
->IsEnabled()) 
 531     wxMenu
* menu 
= item
->GetMenu(); 
 532     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, -1 ); 
 533     event
.SetEventObject( menu 
); 
 535     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 536     if (handler 
&& handler
->SafelyProcessEvent(event
)) 
 539     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 541         win
->HandleWindowEvent( event 
); 
 545 //----------------------------------------------------------------------------- 
 547 //----------------------------------------------------------------------------- 
 549 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
) 
 551 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 553                                 const wxString
& name
, 
 554                                 const wxString
& help
, 
 558     return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
); 
 561 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 563                        const wxString
& text
, 
 564                        const wxString
& help
, 
 567           : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
) 
 572 #if WXWIN_COMPATIBILITY_2_8 
 573 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 575                        const wxString
& text
, 
 576                        const wxString
& help
, 
 579           : wxMenuItemBase(parentMenu
, id
, text
, help
, 
 580                            isCheckable 
? wxITEM_CHECK 
: wxITEM_NORMAL
, subMenu
) 
 586 wxMenuItem::~wxMenuItem() 
 588    // don't delete menu items, the menus take care of that 
 591 void wxMenuItem::SetItemLabel( const wxString
& str 
) 
 596         // remove old accelerator 
 598         GdkModifierType accel_mods
; 
 599         wxGetGtkAccel(this, &accel_key
, &accel_mods
); 
 602             gtk_widget_remove_accelerator( 
 603                 m_menuItem
, m_parentMenu
->m_accel
, accel_key
, accel_mods
); 
 606 #endif // wxUSE_ACCEL 
 607     wxMenuItemBase::SetItemLabel(str
); 
 612 void wxMenuItem::SetGtkLabel() 
 614     const wxString text 
= wxConvertMnemonicsToGTK(m_text
.BeforeFirst('\t')); 
 615     GtkLabel
* label 
= GTK_LABEL(GTK_BIN(m_menuItem
)->child
); 
 616     gtk_label_set_text_with_mnemonic(label
, wxGTK_CONV_SYS(text
)); 
 619     GdkModifierType accel_mods
; 
 620     wxGetGtkAccel(this, &accel_key
, &accel_mods
); 
 623         gtk_widget_add_accelerator( 
 624             m_menuItem
, "activate", m_parentMenu
->m_accel
, 
 625             accel_key
, accel_mods
, GTK_ACCEL_VISIBLE
); 
 627 #endif // wxUSE_ACCEL 
 630 void wxMenuItem::SetBitmap(const wxBitmap
& bitmap
) 
 632     if (m_kind 
== wxITEM_NORMAL
) 
 635         wxFAIL_MSG("only normal menu items can have bitmaps"); 
 638 void wxMenuItem::Check( bool check 
) 
 640     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 642     if (check 
== m_isChecked
) 
 645     wxMenuItemBase::Check( check 
); 
 651             gtk_check_menu_item_set_active( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check 
); 
 655             wxFAIL_MSG( wxT("can't check this item") ); 
 659 void wxMenuItem::Enable( bool enable 
) 
 661     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 663     gtk_widget_set_sensitive( m_menuItem
, enable 
); 
 664     wxMenuItemBase::Enable( enable 
); 
 667 bool wxMenuItem::IsChecked() const 
 669     wxCHECK_MSG( m_menuItem
, false, wxT("invalid menu item") ); 
 671     wxCHECK_MSG( IsCheckable(), false, 
 672                  wxT("can't get state of uncheckable item!") ); 
 674     return ((GtkCheckMenuItem
*)m_menuItem
)->active 
!= 0; 
 677 //----------------------------------------------------------------------------- 
 679 //----------------------------------------------------------------------------- 
 683 static void menu_map(GtkWidget
*, wxMenu
* menu
) 
 685     wxMenuEvent 
event(wxEVT_MENU_OPEN
, menu
->m_popupShown 
? -1 : 0, menu
); 
 686     DoCommonMenuCallbackCode(menu
, event
); 
 689 // "hide" from m_menu 
 690 static void menu_hide(GtkWidget
*, wxMenu
* menu
) 
 692     wxMenuEvent 
event(wxEVT_MENU_CLOSE
, menu
->m_popupShown 
? -1 : 0, menu
); 
 693     menu
->m_popupShown 
= false; 
 694     DoCommonMenuCallbackCode(menu
, event
); 
 698 // "can_activate_accel" from menu item 
 700 static gboolean 
can_activate_accel(GtkWidget
*, guint
, wxMenu
* menu
) 
 703     // always allow our "activate" handler to be called 
 708 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
) 
 712     m_popupShown 
= false; 
 714     m_accel 
= gtk_accel_group_new(); 
 715     m_menu 
= gtk_menu_new(); 
 716     // NB: keep reference to the menu so that it is not destroyed behind 
 717     //     our back by GTK+ e.g. when it is removed from menubar: 
 718     g_object_ref(m_menu
); 
 719     gtk_object_sink(GTK_OBJECT(m_menu
)); 
 723     // Tearoffs are entries, just like separators. So if we want this 
 724     // menu to be a tear-off one, we just append a tearoff entry 
 726     if ( m_style 
& wxMENU_TEAROFF 
) 
 728         GtkWidget 
*tearoff 
= gtk_tearoff_menu_item_new(); 
 730         gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), tearoff
); 
 735     // append the title as the very first entry if we have it 
 736     if ( !m_title
.empty() ) 
 738         Append(wxGTK_TITLE_ID
, m_title
); 
 742     // "show" occurs for sub-menus which are not showing, so use "map" instead 
 743     g_signal_connect(m_menu
, "map", G_CALLBACK(menu_map
), this); 
 744     g_signal_connect(m_menu
, "hide", G_CALLBACK(menu_hide
), this); 
 750     g_object_unref(m_menu
); 
 752     // if the menu is inserted in another menu at this time, there was 
 753     // one more reference to it: 
 755        gtk_widget_destroy(m_menu
); 
 757     g_object_unref(m_accel
); 
 760 void wxMenu::SetLayoutDirection(const wxLayoutDirection dir
) 
 763         wxWindow::GTKSetLayout(m_owner
, dir
); 
 764     //else: will be called later by wxMenuBar again 
 767 wxLayoutDirection 
wxMenu::GetLayoutDirection() const 
 769     return wxWindow::GTKGetLayout(m_owner
); 
 772 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
, int pos
) 
 775     GtkWidget
* prevRadio 
= m_prevRadio
; 
 777     switch (mitem
->GetKind()) 
 779         case wxITEM_SEPARATOR
: 
 780             menuItem 
= gtk_separator_menu_item_new(); 
 783             menuItem 
= gtk_check_menu_item_new_with_label(""); 
 787                 GSList
* group 
= NULL
; 
 789                     group 
= gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(prevRadio
)); 
 790                 menuItem 
= gtk_radio_menu_item_new_with_label(group
, ""); 
 791                 m_prevRadio 
= menuItem
; 
 795             wxFAIL_MSG("unexpected menu item kind"); 
 798             const wxBitmap
& bitmap 
= mitem
->GetBitmap(); 
 802                 // always use pixbuf, because pixmap mask does not 
 803                 // work with disabled images in some themes 
 804                 GtkWidget
* image 
= gtk_image_new_from_pixbuf(bitmap
.GetPixbuf()); 
 805                 menuItem 
= gtk_image_menu_item_new_with_label(""); 
 806                 gtk_widget_show(image
); 
 807                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuItem
), image
); 
 809             else if ((stockid 
= wxGetStockGtkID(mitem
->GetId())) != NULL
) 
 810                 // use stock bitmap for this item if available on the assumption 
 811                 // that it never hurts to follow GTK+ conventions more closely 
 812                 menuItem 
= gtk_image_menu_item_new_from_stock(stockid
, NULL
); 
 814                 menuItem 
= gtk_menu_item_new_with_label(""); 
 817     mitem
->SetMenuItem(menuItem
); 
 819     gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
); 
 821     gtk_widget_show( menuItem 
); 
 823     if ( !mitem
->IsSeparator() ) 
 825         mitem
->SetGtkLabel(); 
 826         g_signal_connect (menuItem
, "select", 
 827                           G_CALLBACK(menuitem_select
), mitem
); 
 828         g_signal_connect (menuItem
, "deselect", 
 829                           G_CALLBACK(menuitem_deselect
), mitem
); 
 831         if ( mitem
->IsSubMenu() && mitem
->GetKind() != wxITEM_RADIO 
&& mitem
->GetKind() != wxITEM_CHECK 
) 
 833             gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
 835             gtk_widget_show( mitem
->GetSubMenu()->m_menu 
); 
 837             // if adding a submenu to a menu already existing in the menu bar, we 
 838             // must set invoking window to allow processing events from this 
 840             if ( m_invokingWindow 
) 
 841                 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
); 
 845             g_signal_connect(menuItem
, "can_activate_accel", 
 846                 G_CALLBACK(can_activate_accel
), this); 
 847             g_signal_connect (menuItem
, "activate", 
 848                               G_CALLBACK(menuitem_activate
), 
 856 wxMenuItem
* wxMenu::DoAppend(wxMenuItem 
*mitem
) 
 858     if (!GtkAppend(mitem
)) 
 861     return wxMenuBase::DoAppend(mitem
); 
 864 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
 866     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
 870     if ( !GtkAppend(item
, (int)pos
) ) 
 876 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
 878     if ( !wxMenuBase::DoRemove(item
) ) 
 881     GtkWidget 
* const mitem 
= item
->GetMenuItem(); 
 882     if ( m_prevRadio 
== mitem 
) 
 884         // deleting an item starts a new radio group (has to as we shouldn't 
 885         // keep a deleted pointer anyhow) 
 889     gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem
), NULL
); 
 890     gtk_widget_destroy(mitem
); 
 891     item
->SetMenuItem(NULL
); 
 896 void wxMenu::Attach(wxMenuBarBase 
*menubar
) 
 898     wxMenuBase::Attach(menubar
); 
 900     // inherit layout direction from menubar. 
 901     SetLayoutDirection(menubar
->GetLayoutDirection()); 
 904 // ---------------------------------------------------------------------------- 
 906 // ---------------------------------------------------------------------------- 
 910 static wxString 
GetGtkHotKey( const wxMenuItem
& item 
) 
 914     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
 917         int flags 
= accel
->GetFlags(); 
 918         if ( flags 
& wxACCEL_ALT 
) 
 919             hotkey 
+= wxT("<alt>"); 
 920         if ( flags 
& wxACCEL_CTRL 
) 
 921             hotkey 
+= wxT("<control>"); 
 922         if ( flags 
& wxACCEL_SHIFT 
) 
 923             hotkey 
+= wxT("<shift>"); 
 925         int code 
= accel
->GetKeyCode(); 
 952                 hotkey 
+= wxString::Format(wxT("F%d"), code 
- WXK_F1 
+ 1); 
 955                 // TODO: we should use gdk_keyval_name() (a.k.a. 
 956                 //       XKeysymToString) here as well as hardcoding the keysym 
 957                 //       names this might be not portable 
 959                 hotkey 
<< wxT("Insert" ); 
 962                 hotkey 
<< wxT("Delete" ); 
 965                 hotkey 
<< wxT("Up" ); 
 968                 hotkey 
<< wxT("Down" ); 
 971                 hotkey 
<< wxT("Page_Up" ); 
 974                 hotkey 
<< wxT("Page_Down" ); 
 977                 hotkey 
<< wxT("Left" ); 
 980                 hotkey 
<< wxT("Right" ); 
 983                 hotkey 
<< wxT("Home" ); 
 986                 hotkey 
<< wxT("End" ); 
 989                 hotkey 
<< wxT("Return" ); 
 992                 hotkey 
<< wxT("BackSpace" ); 
 995                 hotkey 
<< wxT("Tab" ); 
 998                 hotkey 
<< wxT("Esc" ); 
1001                 hotkey 
<< wxT("space" ); 
1004                 hotkey 
<< wxT("Multiply" ); 
1007                 hotkey 
<< wxT("Add" ); 
1010                 hotkey 
<< wxT("Separator" ); 
1013                 hotkey 
<< wxT("Subtract" ); 
1016                 hotkey 
<< wxT("Decimal" ); 
1019                 hotkey 
<< wxT("Divide" ); 
1022                 hotkey 
<< wxT("Cancel" ); 
1025                 hotkey 
<< wxT("Clear" ); 
1028                 hotkey 
<< wxT("Menu" ); 
1031                 hotkey 
<< wxT("Pause" ); 
1034                 hotkey 
<< wxT("Capital" ); 
1037                 hotkey 
<< wxT("Select" ); 
1040                 hotkey 
<< wxT("Print" ); 
1043                 hotkey 
<< wxT("Execute" ); 
1046                 hotkey 
<< wxT("Snapshot" ); 
1049                 hotkey 
<< wxT("Help" ); 
1052                 hotkey 
<< wxT("Num_Lock" ); 
1055                 hotkey 
<< wxT("Scroll_Lock" ); 
1057             case WXK_NUMPAD_INSERT
: 
1058                 hotkey 
<< wxT("KP_Insert" ); 
1060             case WXK_NUMPAD_DELETE
: 
1061                 hotkey 
<< wxT("KP_Delete" ); 
1063              case WXK_NUMPAD_SPACE
: 
1064                 hotkey 
<< wxT("KP_Space" ); 
1066             case WXK_NUMPAD_TAB
: 
1067                 hotkey 
<< wxT("KP_Tab" ); 
1069             case WXK_NUMPAD_ENTER
: 
1070                 hotkey 
<< wxT("KP_Enter" ); 
1072             case WXK_NUMPAD_F1
: case WXK_NUMPAD_F2
: case WXK_NUMPAD_F3
: 
1074                 hotkey 
+= wxString::Format(wxT("KP_F%d"), code 
- WXK_NUMPAD_F1 
+ 1); 
1076             case WXK_NUMPAD_HOME
: 
1077                 hotkey 
<< wxT("KP_Home" ); 
1079             case WXK_NUMPAD_LEFT
: 
1080                 hotkey 
<< wxT("KP_Left" ); 
1083                 hotkey 
<< wxT("KP_Up" ); 
1085             case WXK_NUMPAD_RIGHT
: 
1086                 hotkey 
<< wxT("KP_Right" ); 
1088             case WXK_NUMPAD_DOWN
: 
1089                 hotkey 
<< wxT("KP_Down" ); 
1091             case WXK_NUMPAD_PAGEUP
: 
1092                 hotkey 
<< wxT("KP_Page_Up" ); 
1094             case WXK_NUMPAD_PAGEDOWN
: 
1095                 hotkey 
<< wxT("KP_Page_Down" ); 
1097             case WXK_NUMPAD_END
: 
1098                 hotkey 
<< wxT("KP_End" ); 
1100             case WXK_NUMPAD_BEGIN
: 
1101                 hotkey 
<< wxT("KP_Begin" ); 
1103             case WXK_NUMPAD_EQUAL
: 
1104                 hotkey 
<< wxT("KP_Equal" ); 
1106             case WXK_NUMPAD_MULTIPLY
: 
1107                 hotkey 
<< wxT("KP_Multiply" ); 
1109             case WXK_NUMPAD_ADD
: 
1110                 hotkey 
<< wxT("KP_Add" ); 
1112             case WXK_NUMPAD_SEPARATOR
: 
1113                 hotkey 
<< wxT("KP_Separator" ); 
1115             case WXK_NUMPAD_SUBTRACT
: 
1116                 hotkey 
<< wxT("KP_Subtract" ); 
1118             case WXK_NUMPAD_DECIMAL
: 
1119                 hotkey 
<< wxT("KP_Decimal" ); 
1121             case WXK_NUMPAD_DIVIDE
: 
1122                 hotkey 
<< wxT("KP_Divide" ); 
1124            case WXK_NUMPAD0
: case WXK_NUMPAD1
: case WXK_NUMPAD2
: 
1125            case WXK_NUMPAD3
: case WXK_NUMPAD4
: case WXK_NUMPAD5
: 
1126            case WXK_NUMPAD6
: case WXK_NUMPAD7
: case WXK_NUMPAD8
: case WXK_NUMPAD9
: 
1127                 hotkey 
+= wxString::Format(wxT("KP_%d"), code 
- WXK_NUMPAD0
); 
1129             case WXK_WINDOWS_LEFT
: 
1130                 hotkey 
<< wxT("Super_L" ); 
1132             case WXK_WINDOWS_RIGHT
: 
1133                 hotkey 
<< wxT("Super_R" ); 
1135             case WXK_WINDOWS_MENU
: 
1136                 hotkey 
<< wxT("Menu" ); 
1139                 hotkey 
<< wxT("Command" ); 
1141           /* These probably wouldn't work as there is no SpecialX in gdk/keynames.txt 
1142             case WXK_SPECIAL1: case WXK_SPECIAL2: case WXK_SPECIAL3: case WXK_SPECIAL4: 
1143             case WXK_SPECIAL5: case WXK_SPECIAL6: case WXK_SPECIAL7: case WXK_SPECIAL8: 
1144             case WXK_SPECIAL9:  case WXK_SPECIAL10:  case WXK_SPECIAL11: case WXK_SPECIAL12: 
1145             case WXK_SPECIAL13: case WXK_SPECIAL14: case WXK_SPECIAL15: case WXK_SPECIAL16: 
1146             case WXK_SPECIAL17: case WXK_SPECIAL18: case WXK_SPECIAL19:  case WXK_SPECIAL20: 
1147                 hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1); 
1150                 // if there are any other keys wxAcceleratorEntry::Create() may 
1151                 // return, we should process them here 
1157                         name 
= wxGTK_CONV_BACK_SYS(gdk_keyval_name((guint
)code
)); 
1158                     if ( !name
.empty() ) 
1165                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1175 wxGetGtkAccel(const wxMenuItem
* item
, guint
* accel_key
, GdkModifierType
* accel_mods
) 
1178     const wxString string 
= GetGtkHotKey(*item
); 
1179     if (!string
.empty()) 
1180         gtk_accelerator_parse(wxGTK_CONV_SYS(string
), accel_key
, accel_mods
); 
1183         GtkStockItem stock_item
; 
1184         const char* stockid 
= wxGetStockGtkID(item
->GetId()); 
1185         if (stockid 
&& gtk_stock_lookup(stockid
, &stock_item
)) 
1187             *accel_key 
= stock_item
.keyval
; 
1188             *accel_mods 
= stock_item
.modifier
; 
1192 #endif // wxUSE_ACCEL 
1194 const char *wxGetStockGtkID(wxWindowID id
) 
1196     #define STOCKITEM(wx,gtk)      \ 
1200     #if GTK_CHECK_VERSION(2,6,0) 
1201         #define STOCKITEM_26(wx,gtk) STOCKITEM(wx,gtk) 
1203         #define STOCKITEM_26(wx,gtk) 
1206     #if GTK_CHECK_VERSION(2,8,0) 
1207         #define STOCKITEM_28(wx,gtk) STOCKITEM(wx,gtk) 
1209         #define STOCKITEM_28(wx,gtk) 
1212     #if GTK_CHECK_VERSION(2,10,0) 
1213         #define STOCKITEM_210(wx,gtk) STOCKITEM(wx,gtk) 
1215         #define STOCKITEM_210(wx,gtk) 
1221         STOCKITEM_26(wxID_ABOUT
,         GTK_STOCK_ABOUT
) 
1222         STOCKITEM(wxID_ADD
,              GTK_STOCK_ADD
) 
1223         STOCKITEM(wxID_APPLY
,            GTK_STOCK_APPLY
) 
1224         STOCKITEM(wxID_BACKWARD
,         GTK_STOCK_GO_BACK
) 
1225         STOCKITEM(wxID_BOLD
,             GTK_STOCK_BOLD
) 
1226         STOCKITEM(wxID_BOTTOM
,           GTK_STOCK_GOTO_BOTTOM
) 
1227         STOCKITEM(wxID_CANCEL
,           GTK_STOCK_CANCEL
) 
1228         STOCKITEM(wxID_CDROM
,            GTK_STOCK_CDROM
) 
1229         STOCKITEM(wxID_CLEAR
,            GTK_STOCK_CLEAR
) 
1230         STOCKITEM(wxID_CLOSE
,            GTK_STOCK_CLOSE
) 
1231         STOCKITEM(wxID_CONVERT
,          GTK_STOCK_CONVERT
) 
1232         STOCKITEM(wxID_COPY
,             GTK_STOCK_COPY
) 
1233         STOCKITEM(wxID_CUT
,              GTK_STOCK_CUT
) 
1234         STOCKITEM(wxID_DELETE
,           GTK_STOCK_DELETE
) 
1235         STOCKITEM(wxID_DOWN
,             GTK_STOCK_GO_DOWN
) 
1236         STOCKITEM_26(wxID_EDIT
,          GTK_STOCK_EDIT
) 
1237         STOCKITEM(wxID_EXECUTE
,          GTK_STOCK_EXECUTE
) 
1238         STOCKITEM(wxID_EXIT
,             GTK_STOCK_QUIT
) 
1239         STOCKITEM_26(wxID_FILE
,          GTK_STOCK_FILE
) 
1240         STOCKITEM(wxID_FIND
,             GTK_STOCK_FIND
) 
1241         STOCKITEM(wxID_FIRST
,            GTK_STOCK_GOTO_FIRST
) 
1242         STOCKITEM(wxID_FLOPPY
,           GTK_STOCK_FLOPPY
) 
1243         STOCKITEM(wxID_FORWARD
,          GTK_STOCK_GO_FORWARD
) 
1244         STOCKITEM(wxID_HARDDISK
,         GTK_STOCK_HARDDISK
) 
1245         STOCKITEM(wxID_HELP
,             GTK_STOCK_HELP
) 
1246         STOCKITEM(wxID_HOME
,             GTK_STOCK_HOME
) 
1247         STOCKITEM(wxID_INDENT
,           GTK_STOCK_INDENT
) 
1248         STOCKITEM(wxID_INDEX
,            GTK_STOCK_INDEX
) 
1249         STOCKITEM_28(wxID_INFO
,           GTK_STOCK_INFO
) 
1250         STOCKITEM(wxID_ITALIC
,           GTK_STOCK_ITALIC
) 
1251         STOCKITEM(wxID_JUMP_TO
,          GTK_STOCK_JUMP_TO
) 
1252         STOCKITEM(wxID_JUSTIFY_CENTER
,   GTK_STOCK_JUSTIFY_CENTER
) 
1253         STOCKITEM(wxID_JUSTIFY_FILL
,     GTK_STOCK_JUSTIFY_FILL
) 
1254         STOCKITEM(wxID_JUSTIFY_LEFT
,     GTK_STOCK_JUSTIFY_LEFT
) 
1255         STOCKITEM(wxID_JUSTIFY_RIGHT
,    GTK_STOCK_JUSTIFY_RIGHT
) 
1256         STOCKITEM(wxID_LAST
,             GTK_STOCK_GOTO_LAST
) 
1257         STOCKITEM(wxID_NETWORK
,          GTK_STOCK_NETWORK
) 
1258         STOCKITEM(wxID_NEW
,              GTK_STOCK_NEW
) 
1259         STOCKITEM(wxID_NO
,               GTK_STOCK_NO
) 
1260         STOCKITEM(wxID_OK
,               GTK_STOCK_OK
) 
1261         STOCKITEM(wxID_OPEN
,             GTK_STOCK_OPEN
) 
1262         STOCKITEM(wxID_PASTE
,            GTK_STOCK_PASTE
) 
1263         STOCKITEM(wxID_PREFERENCES
,      GTK_STOCK_PREFERENCES
) 
1264         STOCKITEM(wxID_PREVIEW
,          GTK_STOCK_PRINT_PREVIEW
) 
1265         STOCKITEM(wxID_PRINT
,            GTK_STOCK_PRINT
) 
1266         STOCKITEM(wxID_PROPERTIES
,       GTK_STOCK_PROPERTIES
) 
1267         STOCKITEM(wxID_REDO
,             GTK_STOCK_REDO
) 
1268         STOCKITEM(wxID_REFRESH
,          GTK_STOCK_REFRESH
) 
1269         STOCKITEM(wxID_REMOVE
,           GTK_STOCK_REMOVE
) 
1270         STOCKITEM(wxID_REPLACE
,          GTK_STOCK_FIND_AND_REPLACE
) 
1271         STOCKITEM(wxID_REVERT_TO_SAVED
,  GTK_STOCK_REVERT_TO_SAVED
) 
1272         STOCKITEM(wxID_SAVE
,             GTK_STOCK_SAVE
) 
1273         STOCKITEM(wxID_SAVEAS
,           GTK_STOCK_SAVE_AS
) 
1274         STOCKITEM_210(wxID_SELECTALL
,    GTK_STOCK_SELECT_ALL
) 
1275         STOCKITEM(wxID_SELECT_COLOR
,     GTK_STOCK_SELECT_COLOR
) 
1276         STOCKITEM(wxID_SELECT_FONT
,      GTK_STOCK_SELECT_FONT
) 
1277         STOCKITEM(wxID_SORT_ASCENDING
,   GTK_STOCK_SORT_ASCENDING
) 
1278         STOCKITEM(wxID_SORT_DESCENDING
,  GTK_STOCK_SORT_DESCENDING
) 
1279         STOCKITEM(wxID_SPELL_CHECK
,      GTK_STOCK_SPELL_CHECK
) 
1280         STOCKITEM(wxID_STOP
,             GTK_STOCK_STOP
) 
1281         STOCKITEM(wxID_STRIKETHROUGH
,    GTK_STOCK_STRIKETHROUGH
) 
1282         STOCKITEM(wxID_TOP
,              GTK_STOCK_GOTO_TOP
) 
1283         STOCKITEM(wxID_UNDELETE
,         GTK_STOCK_UNDELETE
) 
1284         STOCKITEM(wxID_UNDERLINE
,        GTK_STOCK_UNDERLINE
) 
1285         STOCKITEM(wxID_UNDO
,             GTK_STOCK_UNDO
) 
1286         STOCKITEM(wxID_UNINDENT
,         GTK_STOCK_UNINDENT
) 
1287         STOCKITEM(wxID_UP
,               GTK_STOCK_GO_UP
) 
1288         STOCKITEM(wxID_YES
,              GTK_STOCK_YES
) 
1289         STOCKITEM(wxID_ZOOM_100
,         GTK_STOCK_ZOOM_100
) 
1290         STOCKITEM(wxID_ZOOM_FIT
,         GTK_STOCK_ZOOM_FIT
) 
1291         STOCKITEM(wxID_ZOOM_IN
,          GTK_STOCK_ZOOM_IN
) 
1292         STOCKITEM(wxID_ZOOM_OUT
,         GTK_STOCK_ZOOM_OUT
) 
1303 #endif // wxUSE_MENUS