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
->GetWindow(); 
  52     wxCHECK_RET( win
, "event for a menu without associated window?" ); 
  54     win
->HandleWindowEvent( event 
); 
  57 //----------------------------------------------------------------------------- 
  59 //----------------------------------------------------------------------------- 
  61 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
) 
  63 void wxMenuBar::Init(size_t n
, wxMenu 
*menus
[], const wxString titles
[], long style
) 
  65 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 
  66     // Hildon window uses a single menu instead of a menu bar, so wxMenuBar is 
  67     // the same as menu in this case 
  69     m_menubar 
= gtk_menu_new(); 
  70 #else // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 
  71     if (!PreCreation( NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
  72         !CreateBase( NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") )) 
  74         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
  78     m_menubar 
= gtk_menu_bar_new(); 
  80     if (style 
& wxMB_DOCKABLE
) 
  82         m_widget 
= gtk_handle_box_new(); 
  83         gtk_container_add(GTK_CONTAINER(m_widget
), m_menubar
); 
  84         gtk_widget_show(m_menubar
); 
  93     GTKApplyWidgetStyle(); 
  94 #endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2/!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 
  96     g_object_ref(m_widget
); 
  98     for (size_t i 
= 0; i 
< n
; ++i 
) 
  99         Append(menus
[i
], titles
[i
]); 
 102 wxMenuBar::wxMenuBar(size_t n
, wxMenu 
*menus
[], const wxString titles
[], long style
) 
 104     Init(n
, menus
, titles
, style
); 
 107 wxMenuBar::wxMenuBar(long style
) 
 109     Init(0, NULL
, NULL
, style
); 
 112 wxMenuBar::wxMenuBar() 
 114     Init(0, NULL
, NULL
, 0); 
 117 // recursive helpers for wxMenuBar::Attach() and Detach(): they are called to 
 118 // associate the menus with the frame they belong to or dissociate them from it 
 123 DetachFromFrame(wxMenu
* menu
, wxFrame
* frame
) 
 125     // support for native hot keys 
 128         // Note that wxGetTopLevelParent() is really needed because this frame 
 129         // can be an MDI child frame which is a fake frame and not a TLW at all 
 130         GtkWindow 
* const tlw 
= GTK_WINDOW(wxGetTopLevelParent(frame
)->m_widget
); 
 131         if (g_slist_find(menu
->m_accel
->acceleratables
, tlw
)) 
 132             gtk_window_remove_accel_group(tlw
, menu
->m_accel
); 
 135     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 138         wxMenuItem 
*menuitem 
= node
->GetData(); 
 139         if (menuitem
->IsSubMenu()) 
 140             DetachFromFrame(menuitem
->GetSubMenu(), frame
); 
 141         node 
= node
->GetNext(); 
 146 AttachToFrame(wxMenu
* menu
, wxFrame
* frame
) 
 148     // support for native hot keys 
 151         GtkWindow 
* const tlw 
= GTK_WINDOW(wxGetTopLevelParent(frame
)->m_widget
); 
 152         if (!g_slist_find(menu
->m_accel
->acceleratables
, tlw
)) 
 153             gtk_window_add_accel_group(tlw
, menu
->m_accel
); 
 156     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 159         wxMenuItem 
*menuitem 
= node
->GetData(); 
 160         if (menuitem
->IsSubMenu()) 
 161             AttachToFrame(menuitem
->GetSubMenu(), frame
); 
 162         node 
= node
->GetNext(); 
 166 } // anonymous namespace 
 168 void wxMenuBar::SetLayoutDirection(wxLayoutDirection dir
) 
 170     if ( dir 
== wxLayout_Default 
) 
 172         const wxWindow 
*const frame 
= GetFrame(); 
 175             // inherit layout from frame. 
 176             dir 
= frame
->GetLayoutDirection(); 
 178         else // use global layout 
 180             dir 
= wxTheApp
->GetLayoutDirection(); 
 184     if ( dir 
== wxLayout_Default 
) 
 187     GTKSetLayout(m_menubar
, dir
); 
 189     // also set the layout of all menus we already have (new ones will inherit 
 190     // the current layout) 
 191     for ( wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 193           node 
= node
->GetNext() ) 
 195         wxMenu 
*const menu 
= node
->GetData(); 
 196         menu
->SetLayoutDirection(dir
); 
 200 wxLayoutDirection 
wxMenuBar::GetLayoutDirection() const 
 202     return GTKGetLayout(m_menubar
); 
 205 void wxMenuBar::Attach(wxFrame 
*frame
) 
 207     wxMenuBarBase::Attach(frame
); 
 209     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 212         wxMenu 
*menu 
= node
->GetData(); 
 213         AttachToFrame( menu
, frame 
); 
 214         node 
= node
->GetNext(); 
 217     SetLayoutDirection(wxLayout_Default
); 
 220 void wxMenuBar::Detach() 
 222     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 225         wxMenu 
*menu 
= node
->GetData(); 
 226         DetachFromFrame( menu
, m_menuBarFrame 
); 
 227         node 
= node
->GetNext(); 
 230     wxMenuBarBase::Detach(); 
 233 bool wxMenuBar::Append( wxMenu 
*menu
, const wxString 
&title 
) 
 235     if ( !wxMenuBarBase::Append( menu
, title 
) ) 
 238     return GtkAppend(menu
, title
); 
 241 bool wxMenuBar::GtkAppend(wxMenu 
*menu
, const wxString
& title
, int pos
) 
 243     menu
->SetLayoutDirection(GetLayoutDirection()); 
 245 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2 
 246     // if the menu has only one item, append it directly to the top level menu 
 247     // instead of inserting a useless submenu 
 248     if ( menu
->GetMenuItemCount() == 1 ) 
 250         wxMenuItem 
* const item 
= menu
->FindItemByPosition(0); 
 252         // remove both mnemonics and accelerator: neither is useful under Maemo 
 253         const wxString 
str(wxStripMenuCodes(item
->GetItemLabel())); 
 255         if ( item
->IsSubMenu() ) 
 256             return GtkAppend(item
->GetSubMenu(), str
, pos
); 
 258         menu
->m_owner 
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str 
) ); 
 260         g_signal_connect(menu
->m_owner
, "activate", 
 261                          G_CALLBACK(menuitem_activate
), item
); 
 262         item
->SetMenuItem(menu
->m_owner
); 
 265 #endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2 /!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2 
 267         const wxString 
str(wxConvertMnemonicsToGTK(title
)); 
 269         // This doesn't have much effect right now. 
 270         menu
->SetTitle( str 
); 
 272         // The "m_owner" is the "menu item" 
 273         menu
->m_owner 
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str 
) ); 
 275         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 278     gtk_widget_show( menu
->m_owner 
); 
 281         gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner 
); 
 283         gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
, pos 
); 
 285     if ( m_menuBarFrame 
) 
 286         AttachToFrame( menu
, m_menuBarFrame 
); 
 291 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 293     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 298     if ( !GtkAppend(menu
, title
, (int)pos
) ) 
 304 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 306     // remove the old item and insert a new one 
 307     wxMenu 
*menuOld 
= Remove(pos
); 
 308     if ( menuOld 
&& !Insert(pos
, menu
, title
) ) 
 313     // either Insert() succeeded or Remove() failed and menuOld is NULL 
 317 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 319     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 323     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu
->m_owner
), NULL
); 
 324     gtk_container_remove(GTK_CONTAINER(m_menubar
), menu
->m_owner
); 
 326     gtk_widget_destroy( menu
->m_owner 
); 
 327     menu
->m_owner 
= NULL
; 
 329     DetachFromFrame( menu
, m_menuBarFrame 
); 
 334 static int FindMenuItemRecursive( const wxMenu 
*menu
, const wxString 
&menuString
, const wxString 
&itemString 
) 
 336     if (wxMenuItem::GetLabelText(wxConvertMnemonicsFromGTK(menu
->GetTitle())) == wxMenuItem::GetLabelText(menuString
)) 
 338         int res 
= menu
->FindItem( itemString 
); 
 339         if (res 
!= wxNOT_FOUND
) 
 343     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 346         wxMenuItem 
*item 
= node
->GetData(); 
 347         if (item
->IsSubMenu()) 
 348             return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
); 
 350         node 
= node
->GetNext(); 
 356 int wxMenuBar::FindMenuItem( const wxString 
&menuString
, const wxString 
&itemString 
) const 
 358     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 361         wxMenu 
*menu 
= node
->GetData(); 
 362         int res 
= FindMenuItemRecursive( menu
, menuString
, itemString
); 
 365         node 
= node
->GetNext(); 
 371 // Find a wxMenuItem using its id. Recurses down into sub-menus 
 372 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
) 
 374     wxMenuItem
* result 
= menu
->FindChildItem(id
); 
 376     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 377     while ( node 
&& result 
== NULL 
) 
 379         wxMenuItem 
*item 
= node
->GetData(); 
 380         if (item
->IsSubMenu()) 
 382             result 
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id 
); 
 384         node 
= node
->GetNext(); 
 390 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu 
**menuForItem 
) const 
 392     wxMenuItem
* result 
= 0; 
 393     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 394     while (node 
&& result 
== 0) 
 396         wxMenu 
*menu 
= node
->GetData(); 
 397         result 
= FindMenuItemByIdRecursive( menu
, id 
); 
 398         node 
= node
->GetNext(); 
 403         *menuForItem 
= result 
? result
->GetMenu() : NULL
; 
 409 void wxMenuBar::EnableTop( size_t pos
, bool flag 
) 
 411     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 413     wxCHECK_RET( node
, wxT("menu not found") ); 
 415     wxMenu
* menu 
= node
->GetData(); 
 418         gtk_widget_set_sensitive( menu
->m_owner
, flag 
); 
 421 wxString 
wxMenuBar::GetMenuLabel( size_t pos 
) const 
 423     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 425     wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") ); 
 427     wxMenu
* menu 
= node
->GetData(); 
 429     return wxConvertMnemonicsFromGTK(menu
->GetTitle()); 
 432 void wxMenuBar::SetMenuLabel( size_t pos
, const wxString
& label 
) 
 434     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 436     wxCHECK_RET( node
, wxT("menu not found") ); 
 438     wxMenu
* menu 
= node
->GetData(); 
 440     const wxString 
str(wxConvertMnemonicsToGTK(label
)); 
 442     menu
->SetTitle( str 
); 
 445         gtk_label_set_text_with_mnemonic( GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
), wxGTK_CONV(str
) ); 
 448 //----------------------------------------------------------------------------- 
 450 //----------------------------------------------------------------------------- 
 453 static void menuitem_activate(GtkWidget
*, wxMenuItem
* item
) 
 455     if (!item
->IsEnabled()) 
 458     int id 
= item
->GetId(); 
 459     if (id 
== wxGTK_TITLE_ID
) 
 461         // ignore events from the menu title 
 465     if (item
->IsCheckable()) 
 467         bool isReallyChecked 
= item
->IsChecked(), 
 468             isInternallyChecked 
= item
->wxMenuItemBase::IsChecked(); 
 470         // ensure that the internal state is always consistent with what is 
 471         // shown on the screen 
 472         item
->wxMenuItemBase::Check(isReallyChecked
); 
 474         // we must not report the events for the radio button going up nor the 
 475         // events resulting from the calls to wxMenuItem::Check() 
 476         if ( (item
->GetKind() == wxITEM_RADIO 
&& !isReallyChecked
) || 
 477              (isInternallyChecked 
== isReallyChecked
) ) 
 483     wxMenu
* menu 
= item
->GetMenu(); 
 484     menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1); 
 488 //----------------------------------------------------------------------------- 
 490 //----------------------------------------------------------------------------- 
 493 static void menuitem_select(GtkWidget
*, wxMenuItem
* item
) 
 495     if (!item
->IsEnabled()) 
 498     wxMenuEvent 
event(wxEVT_MENU_HIGHLIGHT
, item
->GetId()); 
 499     DoCommonMenuCallbackCode(item
->GetMenu(), event
); 
 503 //----------------------------------------------------------------------------- 
 505 //----------------------------------------------------------------------------- 
 508 static void menuitem_deselect(GtkWidget
*, wxMenuItem
* item
) 
 510     if (!item
->IsEnabled()) 
 513     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, -1 ); 
 514     DoCommonMenuCallbackCode(item
->GetMenu(), event
); 
 518 //----------------------------------------------------------------------------- 
 520 //----------------------------------------------------------------------------- 
 522 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
) 
 524 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 526                                 const wxString
& name
, 
 527                                 const wxString
& help
, 
 531     return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
); 
 534 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 536                        const wxString
& text
, 
 537                        const wxString
& help
, 
 540           : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
) 
 545 #if WXWIN_COMPATIBILITY_2_8 
 546 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 548                        const wxString
& text
, 
 549                        const wxString
& help
, 
 552           : wxMenuItemBase(parentMenu
, id
, text
, help
, 
 553                            isCheckable 
? wxITEM_CHECK 
: wxITEM_NORMAL
, subMenu
) 
 559 wxMenuItem::~wxMenuItem() 
 561    // don't delete menu items, the menus take care of that 
 564 void wxMenuItem::SetItemLabel( const wxString
& str 
) 
 569         // remove old accelerator 
 571         GdkModifierType accel_mods
; 
 572         wxGetGtkAccel(this, &accel_key
, &accel_mods
); 
 575             gtk_widget_remove_accelerator( 
 576                 m_menuItem
, m_parentMenu
->m_accel
, accel_key
, accel_mods
); 
 579 #endif // wxUSE_ACCEL 
 580     wxMenuItemBase::SetItemLabel(str
); 
 585 void wxMenuItem::SetGtkLabel() 
 587     const wxString text 
= wxConvertMnemonicsToGTK(m_text
.BeforeFirst('\t')); 
 588     GtkLabel
* label 
= GTK_LABEL(GTK_BIN(m_menuItem
)->child
); 
 589     gtk_label_set_text_with_mnemonic(label
, wxGTK_CONV_SYS(text
)); 
 592     GdkModifierType accel_mods
; 
 593     wxGetGtkAccel(this, &accel_key
, &accel_mods
); 
 596         gtk_widget_add_accelerator( 
 597             m_menuItem
, "activate", m_parentMenu
->m_accel
, 
 598             accel_key
, accel_mods
, GTK_ACCEL_VISIBLE
); 
 600 #endif // wxUSE_ACCEL 
 603 void wxMenuItem::SetBitmap(const wxBitmap
& bitmap
) 
 605     if (m_kind 
== wxITEM_NORMAL
) 
 608         wxFAIL_MSG("only normal menu items can have bitmaps"); 
 611 void wxMenuItem::Check( bool check 
) 
 613     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 615     if (check 
== m_isChecked
) 
 618     wxMenuItemBase::Check( check 
); 
 624             gtk_check_menu_item_set_active( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check 
); 
 628             wxFAIL_MSG( wxT("can't check this item") ); 
 632 void wxMenuItem::Enable( bool enable 
) 
 634     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 636     gtk_widget_set_sensitive( m_menuItem
, enable 
); 
 637     wxMenuItemBase::Enable( enable 
); 
 640 bool wxMenuItem::IsChecked() const 
 642     wxCHECK_MSG( m_menuItem
, false, wxT("invalid menu item") ); 
 644     wxCHECK_MSG( IsCheckable(), false, 
 645                  wxT("can't get state of uncheckable item!") ); 
 647     return ((GtkCheckMenuItem
*)m_menuItem
)->active 
!= 0; 
 650 //----------------------------------------------------------------------------- 
 652 //----------------------------------------------------------------------------- 
 656 static void menu_map(GtkWidget
*, wxMenu
* menu
) 
 658     wxMenuEvent 
event(wxEVT_MENU_OPEN
, menu
->m_popupShown 
? -1 : 0, menu
); 
 659     DoCommonMenuCallbackCode(menu
, event
); 
 662 // "hide" from m_menu 
 663 static void menu_hide(GtkWidget
*, wxMenu
* menu
) 
 665     wxMenuEvent 
event(wxEVT_MENU_CLOSE
, menu
->m_popupShown 
? -1 : 0, menu
); 
 666     menu
->m_popupShown 
= false; 
 667     DoCommonMenuCallbackCode(menu
, event
); 
 671 // "can_activate_accel" from menu item 
 673 static gboolean 
can_activate_accel(GtkWidget
*, guint
, wxMenu
* menu
) 
 676     // always allow our "activate" handler to be called 
 681 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
) 
 685     m_popupShown 
= false; 
 687     m_accel 
= gtk_accel_group_new(); 
 688     m_menu 
= gtk_menu_new(); 
 689     // NB: keep reference to the menu so that it is not destroyed behind 
 690     //     our back by GTK+ e.g. when it is removed from menubar: 
 691     g_object_ref(m_menu
); 
 692     gtk_object_sink(GTK_OBJECT(m_menu
)); 
 696     // Tearoffs are entries, just like separators. So if we want this 
 697     // menu to be a tear-off one, we just append a tearoff entry 
 699     if ( m_style 
& wxMENU_TEAROFF 
) 
 701         GtkWidget 
*tearoff 
= gtk_tearoff_menu_item_new(); 
 703         gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), tearoff
); 
 708     // append the title as the very first entry if we have it 
 709     if ( !m_title
.empty() ) 
 711         Append(wxGTK_TITLE_ID
, m_title
); 
 715     // "show" occurs for sub-menus which are not showing, so use "map" instead 
 716     g_signal_connect(m_menu
, "map", G_CALLBACK(menu_map
), this); 
 717     g_signal_connect(m_menu
, "hide", G_CALLBACK(menu_hide
), this); 
 723     g_object_unref(m_menu
); 
 725     // if the menu is inserted in another menu at this time, there was 
 726     // one more reference to it: 
 728        gtk_widget_destroy(m_menu
); 
 730     g_object_unref(m_accel
); 
 733 void wxMenu::SetLayoutDirection(const wxLayoutDirection dir
) 
 736         wxWindow::GTKSetLayout(m_owner
, dir
); 
 737     //else: will be called later by wxMenuBar again 
 740 wxLayoutDirection 
wxMenu::GetLayoutDirection() const 
 742     return wxWindow::GTKGetLayout(m_owner
); 
 745 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
, int pos
) 
 748     GtkWidget
* prevRadio 
= m_prevRadio
; 
 750     switch (mitem
->GetKind()) 
 752         case wxITEM_SEPARATOR
: 
 753             menuItem 
= gtk_separator_menu_item_new(); 
 756             menuItem 
= gtk_check_menu_item_new_with_label(""); 
 760                 GSList
* group 
= NULL
; 
 762                     group 
= gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(prevRadio
)); 
 763                 menuItem 
= gtk_radio_menu_item_new_with_label(group
, ""); 
 764                 m_prevRadio 
= menuItem
; 
 768             wxFAIL_MSG("unexpected menu item kind"); 
 771             const wxBitmap
& bitmap 
= mitem
->GetBitmap(); 
 775                 // always use pixbuf, because pixmap mask does not 
 776                 // work with disabled images in some themes 
 777                 GtkWidget
* image 
= gtk_image_new_from_pixbuf(bitmap
.GetPixbuf()); 
 778                 menuItem 
= gtk_image_menu_item_new_with_label(""); 
 779                 gtk_widget_show(image
); 
 780                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuItem
), image
); 
 782             else if ((stockid 
= wxGetStockGtkID(mitem
->GetId())) != NULL
) 
 783                 // use stock bitmap for this item if available on the assumption 
 784                 // that it never hurts to follow GTK+ conventions more closely 
 785                 menuItem 
= gtk_image_menu_item_new_from_stock(stockid
, NULL
); 
 787                 menuItem 
= gtk_menu_item_new_with_label(""); 
 790     mitem
->SetMenuItem(menuItem
); 
 792     gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
); 
 794     gtk_widget_show( menuItem 
); 
 796     if ( !mitem
->IsSeparator() ) 
 798         mitem
->SetGtkLabel(); 
 799         g_signal_connect (menuItem
, "select", 
 800                           G_CALLBACK(menuitem_select
), mitem
); 
 801         g_signal_connect (menuItem
, "deselect", 
 802                           G_CALLBACK(menuitem_deselect
), mitem
); 
 804         if ( mitem
->IsSubMenu() && mitem
->GetKind() != wxITEM_RADIO 
&& mitem
->GetKind() != wxITEM_CHECK 
) 
 806             gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
 808             gtk_widget_show( mitem
->GetSubMenu()->m_menu 
); 
 812             g_signal_connect(menuItem
, "can_activate_accel", 
 813                 G_CALLBACK(can_activate_accel
), this); 
 814             g_signal_connect (menuItem
, "activate", 
 815                               G_CALLBACK(menuitem_activate
), 
 823 wxMenuItem
* wxMenu::DoAppend(wxMenuItem 
*mitem
) 
 825     if (!GtkAppend(mitem
)) 
 828     return wxMenuBase::DoAppend(mitem
); 
 831 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
 833     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
 837     if ( !GtkAppend(item
, (int)pos
) ) 
 843 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
 845     if ( !wxMenuBase::DoRemove(item
) ) 
 848     GtkWidget 
* const mitem 
= item
->GetMenuItem(); 
 849     if ( m_prevRadio 
== mitem 
) 
 851         // deleting an item starts a new radio group (has to as we shouldn't 
 852         // keep a deleted pointer anyhow) 
 856     gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem
), NULL
); 
 857     gtk_widget_destroy(mitem
); 
 858     item
->SetMenuItem(NULL
); 
 863 void wxMenu::Attach(wxMenuBarBase 
*menubar
) 
 865     wxMenuBase::Attach(menubar
); 
 867     // inherit layout direction from menubar. 
 868     SetLayoutDirection(menubar
->GetLayoutDirection()); 
 871 // ---------------------------------------------------------------------------- 
 873 // ---------------------------------------------------------------------------- 
 877 static wxString 
GetGtkHotKey( const wxMenuItem
& item 
) 
 881     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
 884         int flags 
= accel
->GetFlags(); 
 885         if ( flags 
& wxACCEL_ALT 
) 
 886             hotkey 
+= wxT("<alt>"); 
 887         if ( flags 
& wxACCEL_CTRL 
) 
 888             hotkey 
+= wxT("<control>"); 
 889         if ( flags 
& wxACCEL_SHIFT 
) 
 890             hotkey 
+= wxT("<shift>"); 
 892         int code 
= accel
->GetKeyCode(); 
 919                 hotkey 
+= wxString::Format(wxT("F%d"), code 
- WXK_F1 
+ 1); 
 922                 // TODO: we should use gdk_keyval_name() (a.k.a. 
 923                 //       XKeysymToString) here as well as hardcoding the keysym 
 924                 //       names this might be not portable 
 926                 hotkey 
<< wxT("Insert" ); 
 929                 hotkey 
<< wxT("Delete" ); 
 932                 hotkey 
<< wxT("Up" ); 
 935                 hotkey 
<< wxT("Down" ); 
 938                 hotkey 
<< wxT("Page_Up" ); 
 941                 hotkey 
<< wxT("Page_Down" ); 
 944                 hotkey 
<< wxT("Left" ); 
 947                 hotkey 
<< wxT("Right" ); 
 950                 hotkey 
<< wxT("Home" ); 
 953                 hotkey 
<< wxT("End" ); 
 956                 hotkey 
<< wxT("Return" ); 
 959                 hotkey 
<< wxT("BackSpace" ); 
 962                 hotkey 
<< wxT("Tab" ); 
 965                 hotkey 
<< wxT("Esc" ); 
 968                 hotkey 
<< wxT("space" ); 
 971                 hotkey 
<< wxT("Multiply" ); 
 974                 hotkey 
<< wxT("Add" ); 
 977                 hotkey 
<< wxT("Separator" ); 
 980                 hotkey 
<< wxT("Subtract" ); 
 983                 hotkey 
<< wxT("Decimal" ); 
 986                 hotkey 
<< wxT("Divide" ); 
 989                 hotkey 
<< wxT("Cancel" ); 
 992                 hotkey 
<< wxT("Clear" ); 
 995                 hotkey 
<< wxT("Menu" ); 
 998                 hotkey 
<< wxT("Pause" ); 
1001                 hotkey 
<< wxT("Capital" ); 
1004                 hotkey 
<< wxT("Select" ); 
1007                 hotkey 
<< wxT("Print" ); 
1010                 hotkey 
<< wxT("Execute" ); 
1013                 hotkey 
<< wxT("Snapshot" ); 
1016                 hotkey 
<< wxT("Help" ); 
1019                 hotkey 
<< wxT("Num_Lock" ); 
1022                 hotkey 
<< wxT("Scroll_Lock" ); 
1024             case WXK_NUMPAD_INSERT
: 
1025                 hotkey 
<< wxT("KP_Insert" ); 
1027             case WXK_NUMPAD_DELETE
: 
1028                 hotkey 
<< wxT("KP_Delete" ); 
1030              case WXK_NUMPAD_SPACE
: 
1031                 hotkey 
<< wxT("KP_Space" ); 
1033             case WXK_NUMPAD_TAB
: 
1034                 hotkey 
<< wxT("KP_Tab" ); 
1036             case WXK_NUMPAD_ENTER
: 
1037                 hotkey 
<< wxT("KP_Enter" ); 
1039             case WXK_NUMPAD_F1
: case WXK_NUMPAD_F2
: case WXK_NUMPAD_F3
: 
1041                 hotkey 
+= wxString::Format(wxT("KP_F%d"), code 
- WXK_NUMPAD_F1 
+ 1); 
1043             case WXK_NUMPAD_HOME
: 
1044                 hotkey 
<< wxT("KP_Home" ); 
1046             case WXK_NUMPAD_LEFT
: 
1047                 hotkey 
<< wxT("KP_Left" ); 
1050                 hotkey 
<< wxT("KP_Up" ); 
1052             case WXK_NUMPAD_RIGHT
: 
1053                 hotkey 
<< wxT("KP_Right" ); 
1055             case WXK_NUMPAD_DOWN
: 
1056                 hotkey 
<< wxT("KP_Down" ); 
1058             case WXK_NUMPAD_PAGEUP
: 
1059                 hotkey 
<< wxT("KP_Page_Up" ); 
1061             case WXK_NUMPAD_PAGEDOWN
: 
1062                 hotkey 
<< wxT("KP_Page_Down" ); 
1064             case WXK_NUMPAD_END
: 
1065                 hotkey 
<< wxT("KP_End" ); 
1067             case WXK_NUMPAD_BEGIN
: 
1068                 hotkey 
<< wxT("KP_Begin" ); 
1070             case WXK_NUMPAD_EQUAL
: 
1071                 hotkey 
<< wxT("KP_Equal" ); 
1073             case WXK_NUMPAD_MULTIPLY
: 
1074                 hotkey 
<< wxT("KP_Multiply" ); 
1076             case WXK_NUMPAD_ADD
: 
1077                 hotkey 
<< wxT("KP_Add" ); 
1079             case WXK_NUMPAD_SEPARATOR
: 
1080                 hotkey 
<< wxT("KP_Separator" ); 
1082             case WXK_NUMPAD_SUBTRACT
: 
1083                 hotkey 
<< wxT("KP_Subtract" ); 
1085             case WXK_NUMPAD_DECIMAL
: 
1086                 hotkey 
<< wxT("KP_Decimal" ); 
1088             case WXK_NUMPAD_DIVIDE
: 
1089                 hotkey 
<< wxT("KP_Divide" ); 
1091            case WXK_NUMPAD0
: case WXK_NUMPAD1
: case WXK_NUMPAD2
: 
1092            case WXK_NUMPAD3
: case WXK_NUMPAD4
: case WXK_NUMPAD5
: 
1093            case WXK_NUMPAD6
: case WXK_NUMPAD7
: case WXK_NUMPAD8
: case WXK_NUMPAD9
: 
1094                 hotkey 
+= wxString::Format(wxT("KP_%d"), code 
- WXK_NUMPAD0
); 
1096             case WXK_WINDOWS_LEFT
: 
1097                 hotkey 
<< wxT("Super_L" ); 
1099             case WXK_WINDOWS_RIGHT
: 
1100                 hotkey 
<< wxT("Super_R" ); 
1102             case WXK_WINDOWS_MENU
: 
1103                 hotkey 
<< wxT("Menu" ); 
1106                 hotkey 
<< wxT("Command" ); 
1108           /* These probably wouldn't work as there is no SpecialX in gdk/keynames.txt 
1109             case WXK_SPECIAL1: case WXK_SPECIAL2: case WXK_SPECIAL3: case WXK_SPECIAL4: 
1110             case WXK_SPECIAL5: case WXK_SPECIAL6: case WXK_SPECIAL7: case WXK_SPECIAL8: 
1111             case WXK_SPECIAL9:  case WXK_SPECIAL10:  case WXK_SPECIAL11: case WXK_SPECIAL12: 
1112             case WXK_SPECIAL13: case WXK_SPECIAL14: case WXK_SPECIAL15: case WXK_SPECIAL16: 
1113             case WXK_SPECIAL17: case WXK_SPECIAL18: case WXK_SPECIAL19:  case WXK_SPECIAL20: 
1114                 hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1); 
1117                 // if there are any other keys wxAcceleratorEntry::Create() may 
1118                 // return, we should process them here 
1124                         name 
= wxGTK_CONV_BACK_SYS(gdk_keyval_name((guint
)code
)); 
1125                     if ( !name
.empty() ) 
1132                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1142 wxGetGtkAccel(const wxMenuItem
* item
, guint
* accel_key
, GdkModifierType
* accel_mods
) 
1145     const wxString string 
= GetGtkHotKey(*item
); 
1146     if (!string
.empty()) 
1147         gtk_accelerator_parse(wxGTK_CONV_SYS(string
), accel_key
, accel_mods
); 
1150         GtkStockItem stock_item
; 
1151         const char* stockid 
= wxGetStockGtkID(item
->GetId()); 
1152         if (stockid 
&& gtk_stock_lookup(stockid
, &stock_item
)) 
1154             *accel_key 
= stock_item
.keyval
; 
1155             *accel_mods 
= stock_item
.modifier
; 
1159 #endif // wxUSE_ACCEL 
1161 const char *wxGetStockGtkID(wxWindowID id
) 
1163     #define STOCKITEM(wx,gtk)      \ 
1167     #if GTK_CHECK_VERSION(2,6,0) 
1168         #define STOCKITEM_26(wx,gtk) STOCKITEM(wx,gtk) 
1170         #define STOCKITEM_26(wx,gtk) 
1173     #if GTK_CHECK_VERSION(2,8,0) 
1174         #define STOCKITEM_28(wx,gtk) STOCKITEM(wx,gtk) 
1176         #define STOCKITEM_28(wx,gtk) 
1179     #if GTK_CHECK_VERSION(2,10,0) 
1180         #define STOCKITEM_210(wx,gtk) STOCKITEM(wx,gtk) 
1182         #define STOCKITEM_210(wx,gtk) 
1188         STOCKITEM_26(wxID_ABOUT
,         GTK_STOCK_ABOUT
) 
1189         STOCKITEM(wxID_ADD
,              GTK_STOCK_ADD
) 
1190         STOCKITEM(wxID_APPLY
,            GTK_STOCK_APPLY
) 
1191         STOCKITEM(wxID_BACKWARD
,         GTK_STOCK_GO_BACK
) 
1192         STOCKITEM(wxID_BOLD
,             GTK_STOCK_BOLD
) 
1193         STOCKITEM(wxID_BOTTOM
,           GTK_STOCK_GOTO_BOTTOM
) 
1194         STOCKITEM(wxID_CANCEL
,           GTK_STOCK_CANCEL
) 
1195         STOCKITEM(wxID_CDROM
,            GTK_STOCK_CDROM
) 
1196         STOCKITEM(wxID_CLEAR
,            GTK_STOCK_CLEAR
) 
1197         STOCKITEM(wxID_CLOSE
,            GTK_STOCK_CLOSE
) 
1198         STOCKITEM(wxID_CONVERT
,          GTK_STOCK_CONVERT
) 
1199         STOCKITEM(wxID_COPY
,             GTK_STOCK_COPY
) 
1200         STOCKITEM(wxID_CUT
,              GTK_STOCK_CUT
) 
1201         STOCKITEM(wxID_DELETE
,           GTK_STOCK_DELETE
) 
1202         STOCKITEM(wxID_DOWN
,             GTK_STOCK_GO_DOWN
) 
1203         STOCKITEM_26(wxID_EDIT
,          GTK_STOCK_EDIT
) 
1204         STOCKITEM(wxID_EXECUTE
,          GTK_STOCK_EXECUTE
) 
1205         STOCKITEM(wxID_EXIT
,             GTK_STOCK_QUIT
) 
1206         STOCKITEM_26(wxID_FILE
,          GTK_STOCK_FILE
) 
1207         STOCKITEM(wxID_FIND
,             GTK_STOCK_FIND
) 
1208         STOCKITEM(wxID_FIRST
,            GTK_STOCK_GOTO_FIRST
) 
1209         STOCKITEM(wxID_FLOPPY
,           GTK_STOCK_FLOPPY
) 
1210         STOCKITEM(wxID_FORWARD
,          GTK_STOCK_GO_FORWARD
) 
1211         STOCKITEM(wxID_HARDDISK
,         GTK_STOCK_HARDDISK
) 
1212         STOCKITEM(wxID_HELP
,             GTK_STOCK_HELP
) 
1213         STOCKITEM(wxID_HOME
,             GTK_STOCK_HOME
) 
1214         STOCKITEM(wxID_INDENT
,           GTK_STOCK_INDENT
) 
1215         STOCKITEM(wxID_INDEX
,            GTK_STOCK_INDEX
) 
1216         STOCKITEM_28(wxID_INFO
,           GTK_STOCK_INFO
) 
1217         STOCKITEM(wxID_ITALIC
,           GTK_STOCK_ITALIC
) 
1218         STOCKITEM(wxID_JUMP_TO
,          GTK_STOCK_JUMP_TO
) 
1219         STOCKITEM(wxID_JUSTIFY_CENTER
,   GTK_STOCK_JUSTIFY_CENTER
) 
1220         STOCKITEM(wxID_JUSTIFY_FILL
,     GTK_STOCK_JUSTIFY_FILL
) 
1221         STOCKITEM(wxID_JUSTIFY_LEFT
,     GTK_STOCK_JUSTIFY_LEFT
) 
1222         STOCKITEM(wxID_JUSTIFY_RIGHT
,    GTK_STOCK_JUSTIFY_RIGHT
) 
1223         STOCKITEM(wxID_LAST
,             GTK_STOCK_GOTO_LAST
) 
1224         STOCKITEM(wxID_NETWORK
,          GTK_STOCK_NETWORK
) 
1225         STOCKITEM(wxID_NEW
,              GTK_STOCK_NEW
) 
1226         STOCKITEM(wxID_NO
,               GTK_STOCK_NO
) 
1227         STOCKITEM(wxID_OK
,               GTK_STOCK_OK
) 
1228         STOCKITEM(wxID_OPEN
,             GTK_STOCK_OPEN
) 
1229         STOCKITEM(wxID_PASTE
,            GTK_STOCK_PASTE
) 
1230         STOCKITEM(wxID_PREFERENCES
,      GTK_STOCK_PREFERENCES
) 
1231         STOCKITEM(wxID_PREVIEW
,          GTK_STOCK_PRINT_PREVIEW
) 
1232         STOCKITEM(wxID_PRINT
,            GTK_STOCK_PRINT
) 
1233         STOCKITEM(wxID_PROPERTIES
,       GTK_STOCK_PROPERTIES
) 
1234         STOCKITEM(wxID_REDO
,             GTK_STOCK_REDO
) 
1235         STOCKITEM(wxID_REFRESH
,          GTK_STOCK_REFRESH
) 
1236         STOCKITEM(wxID_REMOVE
,           GTK_STOCK_REMOVE
) 
1237         STOCKITEM(wxID_REPLACE
,          GTK_STOCK_FIND_AND_REPLACE
) 
1238         STOCKITEM(wxID_REVERT_TO_SAVED
,  GTK_STOCK_REVERT_TO_SAVED
) 
1239         STOCKITEM(wxID_SAVE
,             GTK_STOCK_SAVE
) 
1240         STOCKITEM(wxID_SAVEAS
,           GTK_STOCK_SAVE_AS
) 
1241         STOCKITEM_210(wxID_SELECTALL
,    GTK_STOCK_SELECT_ALL
) 
1242         STOCKITEM(wxID_SELECT_COLOR
,     GTK_STOCK_SELECT_COLOR
) 
1243         STOCKITEM(wxID_SELECT_FONT
,      GTK_STOCK_SELECT_FONT
) 
1244         STOCKITEM(wxID_SORT_ASCENDING
,   GTK_STOCK_SORT_ASCENDING
) 
1245         STOCKITEM(wxID_SORT_DESCENDING
,  GTK_STOCK_SORT_DESCENDING
) 
1246         STOCKITEM(wxID_SPELL_CHECK
,      GTK_STOCK_SPELL_CHECK
) 
1247         STOCKITEM(wxID_STOP
,             GTK_STOCK_STOP
) 
1248         STOCKITEM(wxID_STRIKETHROUGH
,    GTK_STOCK_STRIKETHROUGH
) 
1249         STOCKITEM(wxID_TOP
,              GTK_STOCK_GOTO_TOP
) 
1250         STOCKITEM(wxID_UNDELETE
,         GTK_STOCK_UNDELETE
) 
1251         STOCKITEM(wxID_UNDERLINE
,        GTK_STOCK_UNDERLINE
) 
1252         STOCKITEM(wxID_UNDO
,             GTK_STOCK_UNDO
) 
1253         STOCKITEM(wxID_UNINDENT
,         GTK_STOCK_UNINDENT
) 
1254         STOCKITEM(wxID_UP
,               GTK_STOCK_GO_UP
) 
1255         STOCKITEM(wxID_YES
,              GTK_STOCK_YES
) 
1256         STOCKITEM(wxID_ZOOM_100
,         GTK_STOCK_ZOOM_100
) 
1257         STOCKITEM(wxID_ZOOM_FIT
,         GTK_STOCK_ZOOM_FIT
) 
1258         STOCKITEM(wxID_ZOOM_IN
,          GTK_STOCK_ZOOM_IN
) 
1259         STOCKITEM(wxID_ZOOM_OUT
,         GTK_STOCK_ZOOM_OUT
) 
1270 #endif // wxUSE_MENUS