1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "menu.h" 
  12 #pragma implementation "menuitem.h" 
  18 #include "wx/bitmap.h" 
  25 #include "wx/gtk/private.h" 
  27 #include <gdk/gdkkeysyms.h> 
  29 // FIXME: is this right? somehow I don't think so (VZ) 
  31     #include <glib-object.h> 
  33     #define gtk_accel_group_attach(g, o) _gtk_accel_group_attach((g), (o)) 
  34     #define gtk_accel_group_detach(g, o) _gtk_accel_group_detach((g), (o)) 
  35     #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m) 
  37     #define ACCEL_OBJECT        GObject 
  38     #define ACCEL_OBJECTS(a)    (a)->acceleratables 
  39     #define ACCEL_OBJ_CAST(obj) G_OBJECT(obj) 
  41     #define ACCEL_OBJECT        GtkObject 
  42     #define ACCEL_OBJECTS(a)    (a)->attach_objects 
  43     #define ACCEL_OBJ_CAST(obj) GTK_OBJECT(obj) 
  46 //----------------------------------------------------------------------------- 
  48 //----------------------------------------------------------------------------- 
  50 extern void wxapp_install_idle_handler(); 
  53 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL 
  54     static wxString 
GetHotKey( const wxMenuItem
& item 
); 
  57 //----------------------------------------------------------------------------- 
  58 // substitute for missing GtkPixmapMenuItem 
  59 //----------------------------------------------------------------------------- 
  61 // FIXME: I can't make this compile with GTK+ 2.0, disabling for now (VZ) 
  63     #define USE_MENU_BITMAPS 
  66 #ifdef USE_MENU_BITMAPS 
  68 #define GTK_TYPE_PIXMAP_MENU_ITEM            (gtk_pixmap_menu_item_get_type ()) 
  69 #define GTK_PIXMAP_MENU_ITEM(obj)            (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem)) 
  70 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass)) 
  71 #define GTK_IS_PIXMAP_MENU_ITEM(obj)         (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  72 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  73 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  74 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj)  (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj))) 
  76 #ifndef GTK_MENU_ITEM_GET_CLASS 
  77 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj))) 
  80 typedef struct _GtkPixmapMenuItem       GtkPixmapMenuItem
; 
  81 typedef struct _GtkPixmapMenuItemClass  GtkPixmapMenuItemClass
; 
  83 struct _GtkPixmapMenuItem
 
  85     GtkMenuItem menu_item
; 
  90 struct _GtkPixmapMenuItemClass
 
  92     GtkMenuItemClass parent_class
; 
  94     guint orig_toggle_size
; 
  95     guint have_pixmap_count
; 
  99 GtkType           
gtk_pixmap_menu_item_get_type       (void); 
 100 GtkWidget
* gtk_pixmap_menu_item_new            (void); 
 101 void       gtk_pixmap_menu_item_set_pixmap     (GtkPixmapMenuItem 
*menu_item
, 
 104 #endif // USE_MENU_BITMAPS 
 106 //----------------------------------------------------------------------------- 
 108 //----------------------------------------------------------------------------- 
 110 static wxString 
wxReplaceUnderscore( const wxString
& title 
) 
 114     /* GTK 1.2 wants to have "_" instead of "&" for accelerators */ 
 117     while (*pc 
!= wxT('\0')) 
 119         if ((*pc 
== wxT('&')) && (*(pc
+1) == wxT('&'))) 
 121             // "&" is doubled to indicate "&" instead of accelerator 
 125         else if (*pc 
== wxT('&')) 
 127 #if GTK_CHECK_VERSION(1, 2, 0) 
 131 #if GTK_CHECK_VERSION(2, 0, 0) 
 132         else if (*pc 
== wxT('/')) 
 136         else if (*pc 
== wxT('\\')) 
 140 #elif GTK_CHECK_VERSION(1, 2, 0) 
 141         else if (*pc 
== wxT('/')) 
 149             if ( *pc 
== wxT('_') ) 
 151                 // underscores must be doubled to prevent them from being 
 152                 // interpreted as accelerator character prefix by GTK 
 164 //----------------------------------------------------------------------------- 
 165 // activate message from GTK 
 166 //----------------------------------------------------------------------------- 
 168 static void gtk_menu_open_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 170     if (g_isIdle
) wxapp_install_idle_handler(); 
 172     wxMenuEvent 
event( wxEVT_MENU_OPEN
, -1 ); 
 173     event
.SetEventObject( menu 
); 
 175     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 176     if (handler 
&& handler
->ProcessEvent(event
)) 
 179     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 180     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 183 //----------------------------------------------------------------------------- 
 185 //----------------------------------------------------------------------------- 
 187 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
) 
 189 wxMenuBar::wxMenuBar( long style 
) 
 191     /* the parent window is known after wxFrame::SetMenu() */ 
 192     m_needParent 
= FALSE
; 
 194     m_invokingWindow 
= (wxWindow
*) NULL
; 
 196     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 197         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") )) 
 199         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 203     m_menus
.DeleteContents( TRUE 
); 
 205     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 206 #if GTK_CHECK_VERSION(1, 2, 1) 
 207     m_accel 
= gtk_accel_group_new(); 
 208     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 209     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 211     m_menubar 
= gtk_menu_bar_new(); 
 214     if (style 
& wxMB_DOCKABLE
) 
 216         m_widget 
= gtk_handle_box_new(); 
 217         gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) ); 
 218         gtk_widget_show( GTK_WIDGET(m_menubar
) ); 
 222         m_widget 
= GTK_WIDGET(m_menubar
); 
 230 wxMenuBar::wxMenuBar() 
 232     /* the parent window is known after wxFrame::SetMenu() */ 
 233     m_needParent 
= FALSE
; 
 235     m_invokingWindow 
= (wxWindow
*) NULL
; 
 237     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 238         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") )) 
 240         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 244     m_menus
.DeleteContents( TRUE 
); 
 246     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 247 #if GTK_CHECK_VERSION(1, 2, 1) 
 248     m_accel 
= gtk_accel_group_new(); 
 249     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 250     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 252     m_menubar 
= gtk_menu_bar_new(); 
 255     m_widget 
= GTK_WIDGET(m_menubar
); 
 262 wxMenuBar::~wxMenuBar() 
 264 //    gtk_object_unref( GTK_OBJECT(m_factory) );  why not ? 
 267 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 269     menu
->SetInvokingWindow( (wxWindow
*) NULL 
); 
 271     wxWindow 
*top_frame 
= win
; 
 272     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 273         top_frame 
= top_frame
->GetParent(); 
 275     /* support for native hot keys */ 
 276     gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) ); 
 278     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 281         wxMenuItem 
*menuitem 
= node
->GetData(); 
 282         if (menuitem
->IsSubMenu()) 
 283             wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 284         node 
= node
->GetNext(); 
 288 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 290     menu
->SetInvokingWindow( win 
); 
 292 #if GTK_CHECK_VERSION(1, 2, 1) 
 293     wxWindow 
*top_frame 
= win
; 
 294     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 295         top_frame 
= top_frame
->GetParent(); 
 297     /* support for native hot keys  */ 
 298     ACCEL_OBJECT 
*obj 
= ACCEL_OBJ_CAST(top_frame
->m_widget
); 
 299     if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj 
) ) 
 300         gtk_accel_group_attach( menu
->m_accel
, obj 
); 
 301 #endif // GTK+ 1.2.1+ 
 303     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 306         wxMenuItem 
*menuitem 
= node
->GetData(); 
 307         if (menuitem
->IsSubMenu()) 
 308             wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 309         node 
= node
->GetNext(); 
 313 void wxMenuBar::SetInvokingWindow( wxWindow 
*win 
) 
 315     m_invokingWindow 
= win
; 
 316 #if GTK_CHECK_VERSION(1, 2, 1) 
 317     wxWindow 
*top_frame 
= win
; 
 318     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 319         top_frame 
= top_frame
->GetParent(); 
 321     /* support for native key accelerators indicated by underscroes */ 
 322     ACCEL_OBJECT 
*obj 
= ACCEL_OBJ_CAST(top_frame
->m_widget
); 
 323     if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj 
) ) 
 324         gtk_accel_group_attach( m_accel
, obj 
); 
 325 #endif // GTK+ 1.2.1+ 
 327     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 330         wxMenu 
*menu 
= node
->GetData(); 
 331         wxMenubarSetInvokingWindow( menu
, win 
); 
 332         node 
= node
->GetNext(); 
 336 void wxMenuBar::UnsetInvokingWindow( wxWindow 
*win 
) 
 338     m_invokingWindow 
= (wxWindow
*) NULL
; 
 339 #if GTK_CHECK_VERSION(1, 2, 1) 
 340     wxWindow 
*top_frame 
= win
; 
 341     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 342         top_frame 
= top_frame
->GetParent(); 
 344     // support for native key accelerators indicated by underscroes 
 345     gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) ); 
 346 #endif // GTK+ 1.2.1+ 
 348     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 351         wxMenu 
*menu 
= node
->GetData(); 
 352         wxMenubarUnsetInvokingWindow( menu
, win 
); 
 353         node 
= node
->GetNext(); 
 357 bool wxMenuBar::Append( wxMenu 
*menu
, const wxString 
&title 
) 
 359     if ( !wxMenuBarBase::Append( menu
, title 
) ) 
 362     return GtkAppend(menu
, title
); 
 365 bool wxMenuBar::GtkAppend(wxMenu 
*menu
, const wxString
& title
) 
 367     wxString 
str( wxReplaceUnderscore( title 
) ); 
 369     // This doesn't have much effect right now. 
 370     menu
->SetTitle( str 
); 
 372     // GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. 
 373 #if GTK_CHECK_VERSION(1, 2, 1) 
 376     buf 
<< wxT('/') << str
.c_str(); 
 378     // local buffer in multibyte form 
 380     strcpy(cbuf
, wxGTK_CONV(buf
) ); 
 382     GtkItemFactoryEntry entry
; 
 383     entry
.path 
= (gchar 
*)cbuf
;  // const_cast 
 384     entry
.accelerator 
= (gchar
*) NULL
; 
 385     entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 386     entry
.callback_action 
= 0; 
 387     entry
.item_type 
= (char *)"<Branch>"; 
 389     gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
 390     // in order to get the pointer to the item we need the item text _without_ underscores 
 391     wxString tmp 
= wxT("<main>/"); 
 393     for ( pc 
= str
; *pc 
!= wxT('\0'); pc
++ ) 
 395        // contrary to the common sense, we must throw out _all_ underscores, 
 396        // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we 
 397        // might naively think). IMHO it's a bug in GTK+ (VZ) 
 398        while (*pc 
== wxT('_')) 
 402     menu
->m_owner 
= gtk_item_factory_get_item( m_factory
, wxGTK_CONV( tmp 
) ); 
 403     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 406     menu
->m_owner 
= gtk_menu_item_new_with_label( wxGTK_CONV( str 
) ); 
 407     gtk_widget_show( menu
->m_owner 
); 
 408     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 410     gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner 
); 
 414     gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate", 
 415                         GTK_SIGNAL_FUNC(gtk_menu_open_callback
), 
 418     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
 419     // addings menu later on. 
 420     if (m_invokingWindow
) 
 422         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 424             // OPTIMISE ME:  we should probably cache this, or pass it 
 425             //               directly, but for now this is a minimal 
 426             //               change to validate the new dynamic sizing. 
 427             //               see (and refactor :) similar code in Remove 
 430         wxFrame 
*frame 
= wxDynamicCast( m_invokingWindow
, wxFrame 
); 
 433             frame
->UpdateMenuBarSize(); 
 439 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 441     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 444     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
 445     // of version 1.2.6), so we first append the item and then change its 
 447     if ( !GtkAppend(menu
, title
) ) 
 450     if (pos
+1 >= m_menus
.GetCount()) 
 453     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
 454     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
 455     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
 456     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
 461 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 463     // remove the old item and insert a new one 
 464     wxMenu 
*menuOld 
= Remove(pos
); 
 465     if ( menuOld 
&& !Insert(pos
, menu
, title
) ) 
 467         return (wxMenu
*) NULL
; 
 470     // either Insert() succeeded or Remove() failed and menuOld is NULL 
 474 static wxMenu 
*CopyMenu (wxMenu 
*menu
) 
 476     wxMenu 
*menucopy 
= new wxMenu (); 
 477     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 480         wxMenuItem 
*item 
= node
->GetData(); 
 481         int itemid 
= item
->GetId(); 
 482         wxString text 
= item
->GetText(); 
 483         text
.Replace(wxT("_"), wxT("&")); 
 484         wxMenu 
*submenu 
= item
->GetSubMenu(); 
 487             wxMenuItem
* itemcopy 
= new wxMenuItem(menucopy
, 
 489                                         menu
->GetHelpString(itemid
)); 
 490             itemcopy
->SetBitmap(item
->GetBitmap()); 
 491             itemcopy
->SetCheckable(item
->IsCheckable()); 
 492             menucopy
->Append(itemcopy
); 
 495           menucopy
->Append (itemid
, text
, CopyMenu(submenu
), 
 496                             menu
->GetHelpString(itemid
)); 
 498         node 
= node
->GetNext(); 
 504 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 506     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 508         return (wxMenu
*) NULL
; 
 511     GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget); 
 513     printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) ); 
 514     printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) ); 
 517     wxMenu 
*menucopy 
= CopyMenu( menu 
); 
 519     // unparent calls unref() and that would delete the widget so we raise 
 520     // the ref count to 2 artificially before invoking unparent. 
 521     gtk_widget_ref( menu
->m_menu 
); 
 522     gtk_widget_unparent( menu
->m_menu 
); 
 524     gtk_widget_destroy( menu
->m_owner 
); 
 529     printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) ); 
 530     printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) ); 
 533     if (m_invokingWindow
) 
 535             // OPTIMISE ME:  see comment in GtkAppend 
 537     wxFrame 
*frame 
= wxDynamicCast( m_invokingWindow
, wxFrame 
); 
 540             frame
->UpdateMenuBarSize(); 
 546 static int FindMenuItemRecursive( const wxMenu 
*menu
, const wxString 
&menuString
, const wxString 
&itemString 
) 
 548     if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
)) 
 550         int res 
= menu
->FindItem( itemString 
); 
 551         if (res 
!= wxNOT_FOUND
) 
 555     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 558         wxMenuItem 
*item 
= node
->GetData(); 
 559         if (item
->IsSubMenu()) 
 560             return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
); 
 562         node 
= node
->GetNext(); 
 568 int wxMenuBar::FindMenuItem( const wxString 
&menuString
, const wxString 
&itemString 
) const 
 570     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 573         wxMenu 
*menu 
= node
->GetData(); 
 574         int res 
= FindMenuItemRecursive( menu
, menuString
, itemString
); 
 577         node 
= node
->GetNext(); 
 583 // Find a wxMenuItem using its id. Recurses down into sub-menus 
 584 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
) 
 586     wxMenuItem
* result 
= menu
->FindChildItem(id
); 
 588     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 589     while ( node 
&& result 
== NULL 
) 
 591         wxMenuItem 
*item 
= node
->GetData(); 
 592         if (item
->IsSubMenu()) 
 594             result 
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id 
); 
 596         node 
= node
->GetNext(); 
 602 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu 
**menuForItem 
) const 
 604     wxMenuItem
* result 
= 0; 
 605     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 606     while (node 
&& result 
== 0) 
 608         wxMenu 
*menu 
= node
->GetData(); 
 609         result 
= FindMenuItemByIdRecursive( menu
, id 
); 
 610         node 
= node
->GetNext(); 
 615         *menuForItem 
= result 
? result
->GetMenu() : (wxMenu 
*)NULL
; 
 621 void wxMenuBar::EnableTop( size_t pos
, bool flag 
) 
 623     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 625     wxCHECK_RET( node
, wxT("menu not found") ); 
 627     wxMenu
* menu 
= node
->GetData(); 
 630         gtk_widget_set_sensitive( menu
->m_owner
, flag 
); 
 633 wxString 
wxMenuBar::GetLabelTop( size_t pos 
) const 
 635     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 637     wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") ); 
 639     wxMenu
* menu 
= node
->GetData(); 
 642     wxString 
text( menu
->GetTitle() ); 
 643     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 645         if ( *pc 
== wxT('_') ) 
 647             // '_' is the escape character for GTK+ 
 651         // don't remove ampersands '&' since if we have them in the menu title 
 652         // it means that they were doubled to indicate "&" instead of accelerator 
 660 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label 
) 
 662     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 664     wxCHECK_RET( node
, wxT("menu not found") ); 
 666     wxMenu
* menu 
= node
->GetData(); 
 668     wxString 
str( wxReplaceUnderscore( label 
) ); 
 670     menu
->SetTitle( str 
); 
 674         GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child 
); 
 677         gtk_label_set( label
, wxGTK_CONV( str 
) ); 
 679         /* reparse key accel */ 
 680         (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str 
) ); 
 681         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 686 //----------------------------------------------------------------------------- 
 688 //----------------------------------------------------------------------------- 
 690 static void gtk_menu_clicked_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 693         wxapp_install_idle_handler(); 
 695     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 697     /* should find it for normal (not popup) menu */ 
 698     wxASSERT_MSG( (id 
!= -1) || (menu
->GetInvokingWindow() != NULL
), 
 699                   _T("menu item not found in gtk_menu_clicked_callback") ); 
 701     if (!menu
->IsEnabled(id
)) 
 704     wxMenuItem
* item 
= menu
->FindChildItem( id 
); 
 705     wxCHECK_RET( item
, wxT("error in menu item callback") ); 
 707     if (item
->IsCheckable()) 
 709         bool isReallyChecked 
= item
->IsChecked(), 
 710             isInternallyChecked 
= item
->wxMenuItemBase::IsChecked(); 
 712         // ensure that the internal state is always consistent with what is 
 713         // shown on the screen 
 714         item
->wxMenuItemBase::Check(isReallyChecked
); 
 716         // we must not report the events for the radio button going up nor the 
 717         // events resulting from the calls to wxMenuItem::Check() 
 718         if ( (item
->GetKind() == wxITEM_RADIO 
&& !isReallyChecked
) || 
 719              (isInternallyChecked 
== isReallyChecked
) ) 
 726     // Is this menu on a menubar?  (possibly nested) 
 727     wxFrame
* frame 
= NULL
; 
 729     while ( pm 
&& !frame 
) 
 731         if ( pm
->IsAttached() ) 
 732             frame 
= pm
->GetMenuBar()->GetFrame(); 
 733         pm 
= pm
->GetParent(); 
 738         // If it is attached then let the frame send the event. 
 739         // Don't call frame->ProcessCommand(id) because it toggles 
 740         // checkable items and we've already done that above. 
 741         wxCommandEvent 
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
); 
 742         commandEvent
.SetEventObject(frame
); 
 743         if (item
->IsCheckable()) 
 744             commandEvent
.SetInt(item
->IsChecked()); 
 746         frame
->GetEventHandler()->ProcessEvent(commandEvent
); 
 750         // otherwise let the menu have it 
 751         menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1); 
 755 //----------------------------------------------------------------------------- 
 757 //----------------------------------------------------------------------------- 
 759 static void gtk_menu_hilight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 761     if (g_isIdle
) wxapp_install_idle_handler(); 
 763     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 765     wxASSERT( id 
!= -1 ); // should find it! 
 767     if (!menu
->IsEnabled(id
)) 
 770     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, id 
); 
 771     event
.SetEventObject( menu 
); 
 773     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 774     if (handler 
&& handler
->ProcessEvent(event
)) 
 777     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 778     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 781 //----------------------------------------------------------------------------- 
 783 //----------------------------------------------------------------------------- 
 785 static void gtk_menu_nolight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 787     if (g_isIdle
) wxapp_install_idle_handler(); 
 789     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 791     wxASSERT( id 
!= -1 ); // should find it! 
 793     if (!menu
->IsEnabled(id
)) 
 796     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, -1 ); 
 797     event
.SetEventObject( menu 
); 
 799     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 800     if (handler 
&& handler
->ProcessEvent(event
)) 
 803     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 805         win
->GetEventHandler()->ProcessEvent( event 
); 
 808 //----------------------------------------------------------------------------- 
 810 //----------------------------------------------------------------------------- 
 812 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
) 
 814 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 816                                 const wxString
& name
, 
 817                                 const wxString
& help
, 
 821     return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
); 
 824 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 826                        const wxString
& text
, 
 827                        const wxString
& help
, 
 830           : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
) 
 835 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 837                        const wxString
& text
, 
 838                        const wxString
& help
, 
 841           : wxMenuItemBase(parentMenu
, id
, text
, help
, 
 842                            isCheckable 
? wxITEM_CHECK 
: wxITEM_NORMAL
, subMenu
) 
 847 void wxMenuItem::Init(const wxString
& text
) 
 849     m_labelWidget 
= (GtkWidget 
*) NULL
; 
 850     m_menuItem 
= (GtkWidget 
*) NULL
; 
 855 wxMenuItem::~wxMenuItem() 
 857    // don't delete menu items, the menus take care of that 
 860 // return the menu item text without any menu accels 
 862 wxString 
wxMenuItemBase::GetLabelFromText(const wxString
& text
) 
 866     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 868         if ( *pc 
== wxT('_') ) 
 870             // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx" 
 876 #if GTK_CHECK_VERSION(2, 0, 0) 
 877         if ( *pc 
== wxT('\\')  ) 
 879             // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx" 
 886         if ( (*pc 
== wxT('&')) && (*(pc
+1) != wxT('&')) ) 
 889             // "&" is doubled to indicate "&" instead of accelerator 
 896     // wxPrintf( L"text %s label %s\n", text.c_str(), label.c_str() ); 
 901 void wxMenuItem::SetText( const wxString
& str 
) 
 903     // Some optimization to avoid flicker 
 904     wxString oldLabel 
= m_text
; 
 905     oldLabel 
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t')); 
 906     oldLabel
.Replace(wxT("_"), wxT("")); 
 907     wxString label1 
= wxStripMenuCodes(str
.BeforeFirst('\t')); 
 908     if (oldLabel 
== label1
) 
 917             label 
= (GtkLabel
*) m_labelWidget
; 
 919             label 
= GTK_LABEL( GTK_BIN(m_menuItem
)->child 
); 
 921 #if GTK_CHECK_VERSION(2, 0, 0) 
 922         // We have to imitate item_factory_unescape_label here 
 924         for (size_t n 
= 0; n 
< m_text
.Len(); n
++) 
 926             if (m_text
[n
] != wxT('\\')) 
 930         gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(tmp
) ); 
 933         gtk_label_set( label
, wxGTK_CONV( m_text 
) ); 
 936         (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) ); 
 937         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 942 // it's valid for this function to be called even if m_menuItem == NULL 
 943 void wxMenuItem::DoSetText( const wxString
& str 
) 
 945     // '\t' is the deliminator indicating a hot key 
 947     const wxChar 
*pc 
= str
; 
 948     while ( (*pc 
!= wxT('\0')) && (*pc 
!= wxT('\t')) ) 
 950         if ((*pc 
== wxT('&')) && (*(pc
+1) == wxT('&'))) 
 952             // "&" is doubled to indicate "&" instead of accelerator 
 956         else if (*pc 
== wxT('&')) 
 960 #if GTK_CHECK_VERSION(2, 0, 0) 
 961         else if ( *pc 
== wxT('_') )    // escape underscores 
 963             // m_text << wxT("__");    doesn't work 
 966         else if (*pc 
== wxT('/'))      // we have to escape slashes 
 968             m_text 
<< wxT("\\/"); 
 970         else if (*pc 
== wxT('\\'))     // we have to double backslashes 
 972             m_text 
<< wxT("\\\\"); 
 975         else if ( *pc 
== wxT('_') )    // escape underscores 
 979         else if (*pc 
== wxT('/'))      /* we have to filter out slashes ... */ 
 981             m_text 
<< wxT('\\');  /* ... and replace them with back slashes */ 
 990     // wxPrintf( L"str %s m_text %s\n", str.c_str(), m_text.c_str() ); 
1003 wxAcceleratorEntry 
*wxMenuItem::GetAccel() const 
1008         return (wxAcceleratorEntry 
*)NULL
; 
1011     // as wxGetAccelFromString() looks for TAB, insert a dummy one here 
1013     label 
<< wxT('\t') << GetHotKey(); 
1015     return wxGetAccelFromString(label
); 
1018 #endif // wxUSE_ACCEL 
1020 void wxMenuItem::Check( bool check 
) 
1022     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
1024     if (check 
== m_isChecked
) 
1027     wxMenuItemBase::Check( check 
); 
1029     switch ( GetKind() ) 
1033             gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check 
); 
1037             wxFAIL_MSG( _T("can't check this item") ); 
1041 void wxMenuItem::Enable( bool enable 
) 
1043     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
1045     gtk_widget_set_sensitive( m_menuItem
, enable 
); 
1046     wxMenuItemBase::Enable( enable 
); 
1049 bool wxMenuItem::IsChecked() const 
1051     wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") ); 
1053     wxCHECK_MSG( IsCheckable(), FALSE
, 
1054                  wxT("can't get state of uncheckable item!") ); 
1056     return ((GtkCheckMenuItem
*)m_menuItem
)->active 
!= 0; 
1059 wxString 
wxMenuItem::GetFactoryPath() const 
1061     // In order to get the pointer to the item we need the item 
1062     // text _without_ underscores in GTK 1.2 
1063     wxString 
path( wxT("<main>/") ); 
1065     for ( const wxChar 
*pc 
= m_text
.c_str(); *pc
; pc
++ ) 
1067         if ( *pc 
== wxT('_') ) 
1072             // remove '_' unconditionally 
1077         // don't remove ampersands '&' since if we have them in the menu item title 
1078         // it means that they were doubled to indicate "&" instead of accelerator 
1086 //----------------------------------------------------------------------------- 
1088 //----------------------------------------------------------------------------- 
1090 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
) 
1094     m_accel 
= gtk_accel_group_new(); 
1095     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel 
); 
1096     m_menu 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
1098     m_owner 
= (GtkWidget
*) NULL
; 
1100     // Tearoffs are entries, just like separators. So if we want this 
1101     // menu to be a tear-off one, we just append a tearoff entry 
1103     if(m_style 
& wxMENU_TEAROFF
) 
1105        GtkItemFactoryEntry entry
; 
1106        entry
.path 
= (char *)"/tearoff"; 
1107        entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
1108        entry
.callback_action 
= 0; 
1109        entry
.item_type 
= (char *)"<Tearoff>"; 
1110        entry
.accelerator 
= (gchar
*) NULL
; 
1111        gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1112        //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" ); 
1115     // append the title as the very first entry if we have it 
1118         Append(-2, m_title
); 
1127    if ( GTK_IS_WIDGET( m_menu 
)) 
1128        gtk_widget_destroy( m_menu 
); 
1130    gtk_object_unref( GTK_OBJECT(m_factory
) ); 
1133 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
) 
1135     GtkWidget 
*menuItem
; 
1137 #if defined(USE_MENU_BITMAPS) || !GTK_CHECK_VERSION(1, 2, 0) 
1138     bool appended 
= FALSE
; 
1141     // does this item terminate the current radio group? 
1142     bool endOfRadioGroup 
= TRUE
; 
1144     if ( mitem
->IsSeparator() ) 
1146         GtkItemFactoryEntry entry
; 
1147         entry
.path 
= (char *)"/sep"; 
1148         entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
1149         entry
.callback_action 
= 0; 
1150         entry
.item_type 
= (char *)"<Separator>"; 
1151         entry
.accelerator 
= (gchar
*) NULL
; 
1153         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1155         // this will be wrong for more than one separator. do we care? 
1156         menuItem 
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" ); 
1158         // we might have a separator inside a radio group 
1159         endOfRadioGroup 
= FALSE
; 
1161     else if ( mitem
->IsSubMenu() ) 
1163         // text has "_" instead of "&" after mitem->SetText() 
1164         wxString 
text( mitem
->GetText() ); 
1166         // local buffer in multibyte form 
1169         strcat( buf
, wxGTK_CONV( text 
) ); 
1171         GtkItemFactoryEntry entry
; 
1173         entry
.callback 
= (GtkItemFactoryCallback
) 0; 
1174         entry
.callback_action 
= 0; 
1175         entry
.item_type 
= (char *)"<Branch>"; 
1176         entry
.accelerator 
= (gchar
*) NULL
; 
1178         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1180         wxString 
path( mitem
->GetFactoryPath() ); 
1181         menuItem 
= gtk_item_factory_get_item( m_factory
, wxGTK_CONV( path 
) ); 
1183         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
1185         // if adding a submenu to a menu already existing in the menu bar, we 
1186         // must set invoking window to allow processing events from this 
1188         if ( m_invokingWindow 
) 
1189             wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
); 
1191 #ifdef USE_MENU_BITMAPS 
1192     else if (mitem
->GetBitmap().Ok()) // An item with bitmap 
1194         wxString 
text( mitem
->GetText() ); 
1195         const wxBitmap 
*bitmap 
= &mitem
->GetBitmap(); 
1197         menuItem 
= gtk_pixmap_menu_item_new (); 
1198         GtkWidget 
*label 
= gtk_accel_label_new ( wxGTK_CONV( text 
) ); 
1199         gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5); 
1200         gtk_container_add (GTK_CONTAINER (menuItem
), label
); 
1201         guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1202         gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
); 
1203         if (accel_key 
!= GDK_VoidSymbol
) 
1205             gtk_widget_add_accelerator (menuItem
, 
1207                                         gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)), 
1211         gtk_widget_show (label
); 
1213         mitem
->SetLabelWidget(label
); 
1215         GtkWidget
* pixmap 
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
); 
1216         gtk_widget_show(pixmap
); 
1217         gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem 
), pixmap
); 
1219         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1220                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1223         gtk_menu_append( GTK_MENU(m_menu
), menuItem 
); 
1224         gtk_widget_show( menuItem 
); 
1226         appended 
= TRUE
; // We've done this, don't do it again 
1228 #endif // USE_MENU_BITMAPS 
1229     else // a normal item 
1231         // text has "_" instead of "&" after mitem->SetText() so don't use it 
1232         wxString 
text( mitem
->GetText() ); 
1234         // buffers containing the menu item path and type in multibyte form 
1238         strcpy( bufPath
, "/" ); 
1239         strncat( bufPath
, wxGTK_CONV(text
), WXSIZEOF(bufPath
) - 2 ); 
1240         bufPath
[WXSIZEOF(bufPath
) - 1] = '\0'; 
1242         GtkItemFactoryEntry entry
; 
1243         entry
.path 
= bufPath
; 
1244         entry
.callback 
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
; 
1245         entry
.callback_action 
= 0; 
1248         const char *item_type
; 
1249         switch ( mitem
->GetKind() ) 
1252                 item_type 
= "<CheckItem>"; 
1256                 if ( m_pathLastRadio
.empty() ) 
1258                     // start of a new radio group 
1259                     item_type 
= "<RadioItem>"; 
1260                     wxString 
tmp( wxGTK_CONV_BACK( bufPath 
) ); 
1262                     m_pathLastRadio 
= tmp
; 
1264                 else // continue the radio group 
1266                     pathRadio 
= m_pathLastRadio
; 
1267                     pathRadio
.Replace(wxT("_"), wxT("")); 
1268                     pathRadio
.Prepend(wxT("<main>/")); 
1270                     strncpy(bufType
, wxGTK_CONV(pathRadio
), WXSIZEOF(bufType
)); 
1271                     bufType
[WXSIZEOF(bufType
) - 1] = '\0'; 
1272                     item_type 
= bufType
; 
1275                 // continue the existing radio group, if any 
1276                 endOfRadioGroup 
= FALSE
; 
1280                 wxFAIL_MSG( _T("unexpected menu item kind") ); 
1284                 item_type 
= "<Item>"; 
1288         entry
.item_type 
= (char *)item_type
; // cast needed for GTK+ 
1289         entry
.accelerator 
= (gchar
*) NULL
; 
1292         // due to an apparent bug in GTK+, we have to use a static buffer here - 
1293         // otherwise GTK+ 1.2.2 manages to override the memory we pass to it 
1295         char s_accel
[50]; // should be big enough, we check for overruns 
1296         wxString 
tmp( GetHotKey(*mitem
) ); 
1297         strncpy(s_accel
, wxGTK_CONV( tmp 
), WXSIZEOF(s_accel
)); 
1298         s_accel
[WXSIZEOF(s_accel
) - 1] = '\0'; 
1299         entry
.accelerator 
= s_accel
; 
1300 #else // !wxUSE_ACCEL 
1301         entry
.accelerator 
= (char*) NULL
; 
1302 #endif // wxUSE_ACCEL/!wxUSE_ACCEL 
1304         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
1306         wxString 
path( mitem
->GetFactoryPath() ); 
1307         menuItem 
= gtk_item_factory_get_widget( m_factory
, wxGTK_CONV( path 
) ); 
1310             wxLogError( wxT("Wrong menu path: %s\n"), path
.c_str() ); 
1313     if ( !mitem
->IsSeparator() ) 
1315         wxASSERT_MSG( menuItem
, wxT("invalid menuitem") ); 
1317         gtk_signal_connect( GTK_OBJECT(menuItem
), "select", 
1318                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
), 
1321         gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect", 
1322                             GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
), 
1326     mitem
->SetMenuItem(menuItem
); 
1328     if ( endOfRadioGroup 
) 
1330         m_pathLastRadio
.clear(); 
1336 bool wxMenu::DoAppend(wxMenuItem 
*mitem
) 
1338     return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
); 
1341 bool wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
1343     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
1346     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
1347     // of version 1.2.6), so we first append the item and then change its 
1349     if ( !GtkAppend(item
) ) 
1352     if ( m_style 
& wxMENU_TEAROFF 
) 
1354         // change the position as the first item is the tear-off marker 
1358     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
1359     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
1360     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
1361     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
1366 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
1368     if ( !wxMenuBase::DoRemove(item
) ) 
1369         return (wxMenuItem 
*)NULL
; 
1371     // TODO: this code doesn't delete the item factory item and this seems 
1372     //       impossible as of GTK 1.2.6. 
1373     gtk_widget_destroy( item
->GetMenuItem() ); 
1378 int wxMenu::FindMenuIdByMenuItem( GtkWidget 
*menuItem 
) const 
1380     wxMenuItemList::Node    
*node 
= m_items
.GetFirst(); 
1383         wxMenuItem 
*item 
= node
->GetData(); 
1384         if (item
->GetMenuItem() == menuItem
) 
1385            return item
->GetId(); 
1386         node 
= node
->GetNext(); 
1392 // ---------------------------------------------------------------------------- 
1394 // ---------------------------------------------------------------------------- 
1396 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL 
1398 static wxString 
GetHotKey( const wxMenuItem
& item 
) 
1402     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
1405         int flags 
= accel
->GetFlags(); 
1406         if ( flags 
& wxACCEL_ALT 
) 
1407             hotkey 
+= wxT("<alt>"); 
1408         if ( flags 
& wxACCEL_CTRL 
) 
1409             hotkey 
+= wxT("<control>"); 
1410         if ( flags 
& wxACCEL_SHIFT 
) 
1411             hotkey 
+= wxT("<shift>"); 
1413         int code 
= accel
->GetKeyCode(); 
1428                 hotkey 
<< wxT('F') << code 
- WXK_F1 
+ 1; 
1431                 // TODO: we should use gdk_keyval_name() (a.k.a. 
1432                 //       XKeysymToString) here as well as hardcoding the keysym 
1433                 //       names this might be not portable 
1434             case WXK_NUMPAD_INSERT
: 
1435                 hotkey 
<< wxT("KP_Insert" ); 
1437             case WXK_NUMPAD_DELETE
: 
1438                 hotkey 
<< wxT("KP_Delete" ); 
1441                 hotkey 
<< wxT("Insert" ); 
1444                 hotkey 
<< wxT("Delete" ); 
1447                 hotkey 
<< wxT("Up" ); 
1450                 hotkey 
<< wxT("Down" ); 
1453                 hotkey 
<< wxT("Prior" ); 
1456                 hotkey 
<< wxT("Next" ); 
1459                 hotkey 
<< wxT("Left" ); 
1462                 hotkey 
<< wxT("Right" ); 
1465                 hotkey 
<< wxT("Home" ); 
1468                 hotkey 
<< wxT("End" ); 
1471                 hotkey 
<< wxT("Return" ); 
1474                 // if there are any other keys wxGetAccelFromString() may 
1475                 // return, we should process them here 
1480                     wxString name 
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) ); 
1488                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1497 #endif // wxUSE_ACCEL 
1500 //----------------------------------------------------------------------------- 
1501 // substitute for missing GtkPixmapMenuItem 
1502 //----------------------------------------------------------------------------- 
1504 #ifdef USE_MENU_BITMAPS 
1507  * Copyright (C) 1998, 1999, 2000 Free Software Foundation 
1508  * All rights reserved. 
1510  * This file is part of the Gnome Library. 
1512  * The Gnome Library is free software; you can redistribute it and/or 
1513  * modify it under the terms of the GNU Library General Public License as 
1514  * published by the Free Software Foundation; either version 2 of the 
1515  * License, or (at your option) any later version. 
1517  * The Gnome Library is distributed in the hope that it will be useful, 
1518  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
1519  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
1520  * Library General Public License for more details. 
1522  * You should have received a copy of the GNU Library General Public 
1523  * License along with the Gnome Library; see the file COPYING.LIB.  If not, 
1524  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
1525  * Boston, MA 02111-1307, USA. 
1531 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */ 
1533 #include <gtk/gtkaccellabel.h> 
1534 #include <gtk/gtksignal.h> 
1535 #include <gtk/gtkmenuitem.h> 
1536 #include <gtk/gtkmenu.h> 
1537 #include <gtk/gtkcontainer.h> 
1542 static void gtk_pixmap_menu_item_class_init    (GtkPixmapMenuItemClass 
*klass
); 
1543 static void gtk_pixmap_menu_item_init          (GtkPixmapMenuItem      
*menu_item
); 
1544 static void gtk_pixmap_menu_item_draw          (GtkWidget              
*widget
, 
1545                                                 GdkRectangle           
*area
); 
1546 static gint 
gtk_pixmap_menu_item_expose        (GtkWidget              
*widget
, 
1547                                                 GdkEventExpose         
*event
); 
1549 /* we must override the following functions */ 
1551 static void gtk_pixmap_menu_item_map           (GtkWidget        
*widget
); 
1552 static void gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1553                                                 GtkAllocation    
*allocation
); 
1554 static void gtk_pixmap_menu_item_forall        (GtkContainer    
*container
, 
1555                                                 gboolean         include_internals
, 
1556                                                 GtkCallback      callback
, 
1557                                                 gpointer         callback_data
); 
1558 static void gtk_pixmap_menu_item_size_request  (GtkWidget        
*widget
, 
1559                                                 GtkRequisition   
*requisition
); 
1560 static void gtk_pixmap_menu_item_remove        (GtkContainer 
*container
, 
1563 static void changed_have_pixmap_status         (GtkPixmapMenuItem 
*menu_item
); 
1565 static GtkMenuItemClass 
*parent_class 
= NULL
; 
1569 #define BORDER_SPACING  3 
1570 #define PMAP_WIDTH 20 
1573 gtk_pixmap_menu_item_get_type (void) 
1575   static GtkType pixmap_menu_item_type 
= 0; 
1577   if (!pixmap_menu_item_type
) 
1579       GtkTypeInfo pixmap_menu_item_info 
= 
1581         (char *)"GtkPixmapMenuItem", 
1582         sizeof (GtkPixmapMenuItem
), 
1583         sizeof (GtkPixmapMenuItemClass
), 
1584         (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
, 
1585         (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
, 
1586         /* reserved_1 */ NULL
, 
1587         /* reserved_2 */ NULL
, 
1588         (GtkClassInitFunc
) NULL
, 
1591       pixmap_menu_item_type 
= gtk_type_unique (gtk_menu_item_get_type (), 
1592                                                &pixmap_menu_item_info
); 
1595   return pixmap_menu_item_type
; 
1599  * gtk_pixmap_menu_item_new 
1601  * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap() 
1602  * to set the pixmap wich is displayed at the left side. 
1605  * &GtkWidget pointer to new menu item 
1609 gtk_pixmap_menu_item_new (void) 
1611   return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ())); 
1615 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass 
*klass
) 
1617   GtkObjectClass 
*object_class
; 
1618   GtkWidgetClass 
*widget_class
; 
1619   GtkMenuItemClass 
*menu_item_class
; 
1620   GtkContainerClass 
*container_class
; 
1622   object_class 
= (GtkObjectClass
*) klass
; 
1623   widget_class 
= (GtkWidgetClass
*) klass
; 
1624   menu_item_class 
= (GtkMenuItemClass
*) klass
; 
1625   container_class 
= (GtkContainerClass
*) klass
; 
1627   parent_class 
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ()); 
1629   widget_class
->draw 
= gtk_pixmap_menu_item_draw
; 
1630   widget_class
->expose_event 
= gtk_pixmap_menu_item_expose
; 
1631   widget_class
->map 
= gtk_pixmap_menu_item_map
; 
1632   widget_class
->size_allocate 
= gtk_pixmap_menu_item_size_allocate
; 
1633   widget_class
->size_request 
= gtk_pixmap_menu_item_size_request
; 
1635   container_class
->forall 
= gtk_pixmap_menu_item_forall
; 
1636   container_class
->remove 
= gtk_pixmap_menu_item_remove
; 
1638   klass
->orig_toggle_size 
= menu_item_class
->toggle_size
; 
1639   klass
->have_pixmap_count 
= 0; 
1643 gtk_pixmap_menu_item_init (GtkPixmapMenuItem 
*menu_item
) 
1647   mi 
= GTK_MENU_ITEM (menu_item
); 
1649   menu_item
->pixmap 
= NULL
; 
1653 gtk_pixmap_menu_item_draw (GtkWidget    
*widget
, 
1656   g_return_if_fail (widget 
!= NULL
); 
1657   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1658   g_return_if_fail (area 
!= NULL
); 
1660   if (GTK_WIDGET_CLASS (parent_class
)->draw
) 
1661     (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
); 
1663   if (GTK_WIDGET_DRAWABLE (widget
) && 
1664       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1665     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1670 gtk_pixmap_menu_item_expose (GtkWidget      
*widget
, 
1671                              GdkEventExpose 
*event
) 
1673   g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
1674   g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
); 
1675   g_return_val_if_fail (event 
!= NULL
, FALSE
); 
1677   if (GTK_WIDGET_CLASS (parent_class
)->expose_event
) 
1678     (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
); 
1680   if (GTK_WIDGET_DRAWABLE (widget
) && 
1681       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1682     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1689  * gtk_pixmap_menu_item_set_pixmap 
1690  * @menu_item: Pointer to the pixmap menu item 
1691  * @pixmap: Pointer to a pixmap widget 
1693  * Set the pixmap of the menu item. 
1698 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem 
*menu_item
, 
1701   g_return_if_fail (menu_item 
!= NULL
); 
1702   g_return_if_fail (pixmap 
!= NULL
); 
1703   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
)); 
1704   g_return_if_fail (GTK_IS_WIDGET (pixmap
)); 
1705   g_return_if_fail (menu_item
->pixmap 
== NULL
); 
1707   gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
)); 
1708   menu_item
->pixmap 
= pixmap
; 
1710   if (GTK_WIDGET_REALIZED (pixmap
->parent
) && 
1711       !GTK_WIDGET_REALIZED (pixmap
)) 
1712     gtk_widget_realize (pixmap
); 
1714   if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) { 
1715     if (GTK_WIDGET_MAPPED (pixmap
->parent
) && 
1716         GTK_WIDGET_VISIBLE(pixmap
) && 
1717         !GTK_WIDGET_MAPPED (pixmap
)) 
1718       gtk_widget_map (pixmap
); 
1721   changed_have_pixmap_status(menu_item
); 
1723   if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
)) 
1724     gtk_widget_queue_resize (pixmap
); 
1728 gtk_pixmap_menu_item_map (GtkWidget 
*widget
) 
1730   GtkPixmapMenuItem 
*menu_item
; 
1732   g_return_if_fail (widget 
!= NULL
); 
1733   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1735   menu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1737   GTK_WIDGET_CLASS(parent_class
)->map(widget
); 
1739   if (menu_item
->pixmap 
&& 
1740       GTK_WIDGET_VISIBLE (menu_item
->pixmap
) && 
1741       !GTK_WIDGET_MAPPED (menu_item
->pixmap
)) 
1742     gtk_widget_map (menu_item
->pixmap
); 
1746 gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1747                                     GtkAllocation    
*allocation
) 
1749   GtkPixmapMenuItem 
*pmenu_item
; 
1751   pmenu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1753   if (pmenu_item
->pixmap 
&& GTK_WIDGET_VISIBLE(pmenu_item
)) 
1755       GtkAllocation child_allocation
; 
1758       border_width 
= GTK_CONTAINER (widget
)->border_width
; 
1760       child_allocation
.width 
= pmenu_item
->pixmap
->requisition
.width
; 
1761       child_allocation
.height 
= pmenu_item
->pixmap
->requisition
.height
; 
1762       child_allocation
.x 
= border_width 
+ BORDER_SPACING
; 
1763       child_allocation
.y 
= (border_width 
+ BORDER_SPACING
 
1764                             + (((allocation
->height 
- child_allocation
.height
) - child_allocation
.x
) 
1765                                / 2)); /* center pixmaps vertically */ 
1766       gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
); 
1769   if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
) 
1770     GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
); 
1774 gtk_pixmap_menu_item_forall (GtkContainer    
*container
, 
1775                              gboolean         include_internals
, 
1776                              GtkCallback      callback
, 
1777                              gpointer         callback_data
) 
1779   GtkPixmapMenuItem 
*menu_item
; 
1781   g_return_if_fail (container 
!= NULL
); 
1782   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1783   g_return_if_fail (callback 
!= NULL
); 
1785   menu_item 
= GTK_PIXMAP_MENU_ITEM (container
); 
1787   if (menu_item
->pixmap
) 
1788     (* callback
) (menu_item
->pixmap
, callback_data
); 
1790   GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
, 
1791                                             callback
,callback_data
); 
1795 gtk_pixmap_menu_item_size_request (GtkWidget      
*widget
, 
1796                                    GtkRequisition 
*requisition
) 
1798   GtkPixmapMenuItem 
*menu_item
; 
1799   GtkRequisition req 
= {0, 0}; 
1801   g_return_if_fail (widget 
!= NULL
); 
1802   g_return_if_fail (GTK_IS_MENU_ITEM (widget
)); 
1803   g_return_if_fail (requisition 
!= NULL
); 
1805   GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
); 
1807   menu_item 
= GTK_PIXMAP_MENU_ITEM (widget
); 
1809   if (menu_item
->pixmap
) 
1810     gtk_widget_size_request(menu_item
->pixmap
, &req
); 
1812   requisition
->height 
= MAX(req
.height 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
, (unsigned int) requisition
->height
); 
1813   requisition
->width 
+= (req
.width 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
); 
1817 gtk_pixmap_menu_item_remove (GtkContainer 
*container
, 
1821   gboolean widget_was_visible
; 
1823   g_return_if_fail (container 
!= NULL
); 
1824   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1825   g_return_if_fail (child 
!= NULL
); 
1826   g_return_if_fail (GTK_IS_WIDGET (child
)); 
1828   bin 
= GTK_BIN (container
); 
1829   g_return_if_fail ((bin
->child 
== child 
|| 
1830                      (GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
== child
))); 
1832   widget_was_visible 
= GTK_WIDGET_VISIBLE (child
); 
1834   gtk_widget_unparent (child
); 
1835   if (bin
->child 
== child
) 
1838     GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
= NULL
; 
1839     changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
)); 
1842   if (widget_was_visible
) 
1843     gtk_widget_queue_resize (GTK_WIDGET (container
)); 
1847 /* important to only call this if there was actually a _change_ in pixmap == NULL */ 
1849 changed_have_pixmap_status (GtkPixmapMenuItem 
*menu_item
) 
1851   if (menu_item
->pixmap 
!= NULL
) { 
1852     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
+= 1; 
1854     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 1) { 
1855       /* Install pixmap toggle size */ 
1856       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
); 
1859     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
-= 1; 
1861     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 0) { 
1862       /* Install normal toggle size */ 
1863       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
; 
1867   /* Note that we actually need to do this for _all_ GtkPixmapMenuItem 
1868      whenever the klass->toggle_size changes; but by doing it anytime 
1869      this function is called, we get the same effect, just because of 
1870      how the preferences option to show pixmaps works. Bogus, broken. 
1872   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
))) 
1873     gtk_widget_queue_resize(GTK_WIDGET(menu_item
)); 
1876 #endif // USE_MENU_BITMAPS