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    gtk_widget_destroy( m_menu 
); 
1129    gtk_object_unref( GTK_OBJECT(m_factory
) ); 
1132 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
) 
1134     GtkWidget 
*menuItem
; 
1136 #if defined(USE_MENU_BITMAPS) || !GTK_CHECK_VERSION(1, 2, 0) 
1137     bool appended 
= FALSE
; 
1140     // does this item terminate the current radio group? 
1141     bool endOfRadioGroup 
= TRUE
; 
1143     if ( mitem
->IsSeparator() ) 
1145         GtkItemFactoryEntry entry
; 
1146         entry
.path 
= (char *)"/sep"; 
1147         entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
1148         entry
.callback_action 
= 0; 
1149         entry
.item_type 
= (char *)"<Separator>"; 
1150         entry
.accelerator 
= (gchar
*) NULL
; 
1152         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1154         // this will be wrong for more than one separator. do we care? 
1155         menuItem 
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" ); 
1157         // we might have a separator inside a radio group 
1158         endOfRadioGroup 
= FALSE
; 
1160     else if ( mitem
->IsSubMenu() ) 
1162         // text has "_" instead of "&" after mitem->SetText() 
1163         wxString 
text( mitem
->GetText() ); 
1165         // local buffer in multibyte form 
1168         strcat( buf
, wxGTK_CONV( text 
) ); 
1170         GtkItemFactoryEntry entry
; 
1172         entry
.callback 
= (GtkItemFactoryCallback
) 0; 
1173         entry
.callback_action 
= 0; 
1174         entry
.item_type 
= (char *)"<Branch>"; 
1175         entry
.accelerator 
= (gchar
*) NULL
; 
1177         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1179         wxString 
path( mitem
->GetFactoryPath() ); 
1180         menuItem 
= gtk_item_factory_get_item( m_factory
, wxGTK_CONV( path 
) ); 
1182         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
1184         // if adding a submenu to a menu already existing in the menu bar, we 
1185         // must set invoking window to allow processing events from this 
1187         if ( m_invokingWindow 
) 
1188             wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
); 
1190 #ifdef USE_MENU_BITMAPS 
1191     else if (mitem
->GetBitmap().Ok()) // An item with bitmap 
1193         wxString 
text( mitem
->GetText() ); 
1194         const wxBitmap 
*bitmap 
= &mitem
->GetBitmap(); 
1196         menuItem 
= gtk_pixmap_menu_item_new (); 
1197         GtkWidget 
*label 
= gtk_accel_label_new ( wxGTK_CONV( text 
) ); 
1198         gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5); 
1199         gtk_container_add (GTK_CONTAINER (menuItem
), label
); 
1200         guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1201         gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
); 
1202         if (accel_key 
!= GDK_VoidSymbol
) 
1204             gtk_widget_add_accelerator (menuItem
, 
1206                                         gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)), 
1210         gtk_widget_show (label
); 
1212         mitem
->SetLabelWidget(label
); 
1214         GtkWidget
* pixmap 
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
); 
1215         gtk_widget_show(pixmap
); 
1216         gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem 
), pixmap
); 
1218         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1219                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1222         gtk_menu_append( GTK_MENU(m_menu
), menuItem 
); 
1223         gtk_widget_show( menuItem 
); 
1225         appended 
= TRUE
; // We've done this, don't do it again 
1227 #endif // USE_MENU_BITMAPS 
1228     else // a normal item 
1230         // text has "_" instead of "&" after mitem->SetText() so don't use it 
1231         wxString 
text( mitem
->GetText() ); 
1233         // buffers containing the menu item path and type in multibyte form 
1237         strcpy( bufPath
, "/" ); 
1238         strncat( bufPath
, wxGTK_CONV(text
), WXSIZEOF(bufPath
) - 2 ); 
1239         bufPath
[WXSIZEOF(bufPath
) - 1] = '\0'; 
1241         GtkItemFactoryEntry entry
; 
1242         entry
.path 
= bufPath
; 
1243         entry
.callback 
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
; 
1244         entry
.callback_action 
= 0; 
1247         const char *item_type
; 
1248         switch ( mitem
->GetKind() ) 
1251                 item_type 
= "<CheckItem>"; 
1255                 if ( m_pathLastRadio
.empty() ) 
1257                     // start of a new radio group 
1258                     item_type 
= "<RadioItem>"; 
1259                     wxString 
tmp( wxGTK_CONV_BACK( bufPath 
) ); 
1261                     m_pathLastRadio 
= tmp
; 
1263                 else // continue the radio group 
1265                     pathRadio 
= m_pathLastRadio
; 
1266                     pathRadio
.Replace(wxT("_"), wxT("")); 
1267                     pathRadio
.Prepend(wxT("<main>/")); 
1269                     strncpy(bufType
, wxGTK_CONV(pathRadio
), WXSIZEOF(bufType
)); 
1270                     bufType
[WXSIZEOF(bufType
) - 1] = '\0'; 
1271                     item_type 
= bufType
; 
1274                 // continue the existing radio group, if any 
1275                 endOfRadioGroup 
= FALSE
; 
1279                 wxFAIL_MSG( _T("unexpected menu item kind") ); 
1283                 item_type 
= "<Item>"; 
1287         entry
.item_type 
= (char *)item_type
; // cast needed for GTK+ 
1288         entry
.accelerator 
= (gchar
*) NULL
; 
1291         // due to an apparent bug in GTK+, we have to use a static buffer here - 
1292         // otherwise GTK+ 1.2.2 manages to override the memory we pass to it 
1294         char s_accel
[50]; // should be big enough, we check for overruns 
1295         wxString 
tmp( GetHotKey(*mitem
) ); 
1296         strncpy(s_accel
, wxGTK_CONV( tmp 
), WXSIZEOF(s_accel
)); 
1297         s_accel
[WXSIZEOF(s_accel
) - 1] = '\0'; 
1298         entry
.accelerator 
= s_accel
; 
1299 #else // !wxUSE_ACCEL 
1300         entry
.accelerator 
= (char*) NULL
; 
1301 #endif // wxUSE_ACCEL/!wxUSE_ACCEL 
1303         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
1305         wxString 
path( mitem
->GetFactoryPath() ); 
1306         menuItem 
= gtk_item_factory_get_widget( m_factory
, wxGTK_CONV( path 
) ); 
1309             wxLogError( wxT("Wrong menu path: %s\n"), path
.c_str() ); 
1312     if ( !mitem
->IsSeparator() ) 
1314         wxASSERT_MSG( menuItem
, wxT("invalid menuitem") ); 
1316         gtk_signal_connect( GTK_OBJECT(menuItem
), "select", 
1317                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
), 
1320         gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect", 
1321                             GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
), 
1325     mitem
->SetMenuItem(menuItem
); 
1327     if ( endOfRadioGroup 
) 
1329         m_pathLastRadio
.clear(); 
1335 bool wxMenu::DoAppend(wxMenuItem 
*mitem
) 
1337     return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
); 
1340 bool wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
1342     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
1345     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
1346     // of version 1.2.6), so we first append the item and then change its 
1348     if ( !GtkAppend(item
) ) 
1351     if ( m_style 
& wxMENU_TEAROFF 
) 
1353         // change the position as the first item is the tear-off marker 
1357     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
1358     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
1359     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
1360     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
1365 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
1367     if ( !wxMenuBase::DoRemove(item
) ) 
1368         return (wxMenuItem 
*)NULL
; 
1370     // TODO: this code doesn't delete the item factory item and this seems 
1371     //       impossible as of GTK 1.2.6. 
1372     gtk_widget_destroy( item
->GetMenuItem() ); 
1377 int wxMenu::FindMenuIdByMenuItem( GtkWidget 
*menuItem 
) const 
1379     wxMenuItemList::Node    
*node 
= m_items
.GetFirst(); 
1382         wxMenuItem 
*item 
= node
->GetData(); 
1383         if (item
->GetMenuItem() == menuItem
) 
1384            return item
->GetId(); 
1385         node 
= node
->GetNext(); 
1391 // ---------------------------------------------------------------------------- 
1393 // ---------------------------------------------------------------------------- 
1395 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL 
1397 static wxString 
GetHotKey( const wxMenuItem
& item 
) 
1401     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
1404         int flags 
= accel
->GetFlags(); 
1405         if ( flags 
& wxACCEL_ALT 
) 
1406             hotkey 
+= wxT("<alt>"); 
1407         if ( flags 
& wxACCEL_CTRL 
) 
1408             hotkey 
+= wxT("<control>"); 
1409         if ( flags 
& wxACCEL_SHIFT 
) 
1410             hotkey 
+= wxT("<shift>"); 
1412         int code 
= accel
->GetKeyCode(); 
1427                 hotkey 
<< wxT('F') << code 
- WXK_F1 
+ 1; 
1430                 // TODO: we should use gdk_keyval_name() (a.k.a. 
1431                 //       XKeysymToString) here as well as hardcoding the keysym 
1432                 //       names this might be not portable 
1433             case WXK_NUMPAD_INSERT
: 
1434                 hotkey 
<< wxT("KP_Insert" ); 
1436             case WXK_NUMPAD_DELETE
: 
1437                 hotkey 
<< wxT("KP_Delete" ); 
1440                 hotkey 
<< wxT("Insert" ); 
1443                 hotkey 
<< wxT("Delete" ); 
1446                 hotkey 
<< wxT("Up" ); 
1449                 hotkey 
<< wxT("Down" ); 
1452                 hotkey 
<< wxT("Prior" ); 
1455                 hotkey 
<< wxT("Next" ); 
1458                 hotkey 
<< wxT("Left" ); 
1461                 hotkey 
<< wxT("Right" ); 
1464                 hotkey 
<< wxT("Home" ); 
1467                 hotkey 
<< wxT("End" ); 
1470                 hotkey 
<< wxT("Return" ); 
1473                 // if there are any other keys wxGetAccelFromString() may 
1474                 // return, we should process them here 
1479                     wxString name 
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) ); 
1487                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1496 #endif // wxUSE_ACCEL 
1499 //----------------------------------------------------------------------------- 
1500 // substitute for missing GtkPixmapMenuItem 
1501 //----------------------------------------------------------------------------- 
1503 #ifdef USE_MENU_BITMAPS 
1506  * Copyright (C) 1998, 1999, 2000 Free Software Foundation 
1507  * All rights reserved. 
1509  * This file is part of the Gnome Library. 
1511  * The Gnome Library is free software; you can redistribute it and/or 
1512  * modify it under the terms of the GNU Library General Public License as 
1513  * published by the Free Software Foundation; either version 2 of the 
1514  * License, or (at your option) any later version. 
1516  * The Gnome Library is distributed in the hope that it will be useful, 
1517  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
1518  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
1519  * Library General Public License for more details. 
1521  * You should have received a copy of the GNU Library General Public 
1522  * License along with the Gnome Library; see the file COPYING.LIB.  If not, 
1523  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
1524  * Boston, MA 02111-1307, USA. 
1530 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */ 
1532 #include <gtk/gtkaccellabel.h> 
1533 #include <gtk/gtksignal.h> 
1534 #include <gtk/gtkmenuitem.h> 
1535 #include <gtk/gtkmenu.h> 
1536 #include <gtk/gtkcontainer.h> 
1541 static void gtk_pixmap_menu_item_class_init    (GtkPixmapMenuItemClass 
*klass
); 
1542 static void gtk_pixmap_menu_item_init          (GtkPixmapMenuItem      
*menu_item
); 
1543 static void gtk_pixmap_menu_item_draw          (GtkWidget              
*widget
, 
1544                                                 GdkRectangle           
*area
); 
1545 static gint 
gtk_pixmap_menu_item_expose        (GtkWidget              
*widget
, 
1546                                                 GdkEventExpose         
*event
); 
1548 /* we must override the following functions */ 
1550 static void gtk_pixmap_menu_item_map           (GtkWidget        
*widget
); 
1551 static void gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1552                                                 GtkAllocation    
*allocation
); 
1553 static void gtk_pixmap_menu_item_forall        (GtkContainer    
*container
, 
1554                                                 gboolean         include_internals
, 
1555                                                 GtkCallback      callback
, 
1556                                                 gpointer         callback_data
); 
1557 static void gtk_pixmap_menu_item_size_request  (GtkWidget        
*widget
, 
1558                                                 GtkRequisition   
*requisition
); 
1559 static void gtk_pixmap_menu_item_remove        (GtkContainer 
*container
, 
1562 static void changed_have_pixmap_status         (GtkPixmapMenuItem 
*menu_item
); 
1564 static GtkMenuItemClass 
*parent_class 
= NULL
; 
1568 #define BORDER_SPACING  3 
1569 #define PMAP_WIDTH 20 
1572 gtk_pixmap_menu_item_get_type (void) 
1574   static GtkType pixmap_menu_item_type 
= 0; 
1576   if (!pixmap_menu_item_type
) 
1578       GtkTypeInfo pixmap_menu_item_info 
= 
1580         (char *)"GtkPixmapMenuItem", 
1581         sizeof (GtkPixmapMenuItem
), 
1582         sizeof (GtkPixmapMenuItemClass
), 
1583         (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
, 
1584         (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
, 
1585         /* reserved_1 */ NULL
, 
1586         /* reserved_2 */ NULL
, 
1587         (GtkClassInitFunc
) NULL
, 
1590       pixmap_menu_item_type 
= gtk_type_unique (gtk_menu_item_get_type (), 
1591                                                &pixmap_menu_item_info
); 
1594   return pixmap_menu_item_type
; 
1598  * gtk_pixmap_menu_item_new 
1600  * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap() 
1601  * to set the pixmap wich is displayed at the left side. 
1604  * &GtkWidget pointer to new menu item 
1608 gtk_pixmap_menu_item_new (void) 
1610   return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ())); 
1614 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass 
*klass
) 
1616   GtkObjectClass 
*object_class
; 
1617   GtkWidgetClass 
*widget_class
; 
1618   GtkMenuItemClass 
*menu_item_class
; 
1619   GtkContainerClass 
*container_class
; 
1621   object_class 
= (GtkObjectClass
*) klass
; 
1622   widget_class 
= (GtkWidgetClass
*) klass
; 
1623   menu_item_class 
= (GtkMenuItemClass
*) klass
; 
1624   container_class 
= (GtkContainerClass
*) klass
; 
1626   parent_class 
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ()); 
1628   widget_class
->draw 
= gtk_pixmap_menu_item_draw
; 
1629   widget_class
->expose_event 
= gtk_pixmap_menu_item_expose
; 
1630   widget_class
->map 
= gtk_pixmap_menu_item_map
; 
1631   widget_class
->size_allocate 
= gtk_pixmap_menu_item_size_allocate
; 
1632   widget_class
->size_request 
= gtk_pixmap_menu_item_size_request
; 
1634   container_class
->forall 
= gtk_pixmap_menu_item_forall
; 
1635   container_class
->remove 
= gtk_pixmap_menu_item_remove
; 
1637   klass
->orig_toggle_size 
= menu_item_class
->toggle_size
; 
1638   klass
->have_pixmap_count 
= 0; 
1642 gtk_pixmap_menu_item_init (GtkPixmapMenuItem 
*menu_item
) 
1646   mi 
= GTK_MENU_ITEM (menu_item
); 
1648   menu_item
->pixmap 
= NULL
; 
1652 gtk_pixmap_menu_item_draw (GtkWidget    
*widget
, 
1655   g_return_if_fail (widget 
!= NULL
); 
1656   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1657   g_return_if_fail (area 
!= NULL
); 
1659   if (GTK_WIDGET_CLASS (parent_class
)->draw
) 
1660     (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
); 
1662   if (GTK_WIDGET_DRAWABLE (widget
) && 
1663       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1664     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1669 gtk_pixmap_menu_item_expose (GtkWidget      
*widget
, 
1670                              GdkEventExpose 
*event
) 
1672   g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
1673   g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
); 
1674   g_return_val_if_fail (event 
!= NULL
, FALSE
); 
1676   if (GTK_WIDGET_CLASS (parent_class
)->expose_event
) 
1677     (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
); 
1679   if (GTK_WIDGET_DRAWABLE (widget
) && 
1680       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1681     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1688  * gtk_pixmap_menu_item_set_pixmap 
1689  * @menu_item: Pointer to the pixmap menu item 
1690  * @pixmap: Pointer to a pixmap widget 
1692  * Set the pixmap of the menu item. 
1697 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem 
*menu_item
, 
1700   g_return_if_fail (menu_item 
!= NULL
); 
1701   g_return_if_fail (pixmap 
!= NULL
); 
1702   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
)); 
1703   g_return_if_fail (GTK_IS_WIDGET (pixmap
)); 
1704   g_return_if_fail (menu_item
->pixmap 
== NULL
); 
1706   gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
)); 
1707   menu_item
->pixmap 
= pixmap
; 
1709   if (GTK_WIDGET_REALIZED (pixmap
->parent
) && 
1710       !GTK_WIDGET_REALIZED (pixmap
)) 
1711     gtk_widget_realize (pixmap
); 
1713   if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) { 
1714     if (GTK_WIDGET_MAPPED (pixmap
->parent
) && 
1715         GTK_WIDGET_VISIBLE(pixmap
) && 
1716         !GTK_WIDGET_MAPPED (pixmap
)) 
1717       gtk_widget_map (pixmap
); 
1720   changed_have_pixmap_status(menu_item
); 
1722   if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
)) 
1723     gtk_widget_queue_resize (pixmap
); 
1727 gtk_pixmap_menu_item_map (GtkWidget 
*widget
) 
1729   GtkPixmapMenuItem 
*menu_item
; 
1731   g_return_if_fail (widget 
!= NULL
); 
1732   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1734   menu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1736   GTK_WIDGET_CLASS(parent_class
)->map(widget
); 
1738   if (menu_item
->pixmap 
&& 
1739       GTK_WIDGET_VISIBLE (menu_item
->pixmap
) && 
1740       !GTK_WIDGET_MAPPED (menu_item
->pixmap
)) 
1741     gtk_widget_map (menu_item
->pixmap
); 
1745 gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1746                                     GtkAllocation    
*allocation
) 
1748   GtkPixmapMenuItem 
*pmenu_item
; 
1750   pmenu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1752   if (pmenu_item
->pixmap 
&& GTK_WIDGET_VISIBLE(pmenu_item
)) 
1754       GtkAllocation child_allocation
; 
1757       border_width 
= GTK_CONTAINER (widget
)->border_width
; 
1759       child_allocation
.width 
= pmenu_item
->pixmap
->requisition
.width
; 
1760       child_allocation
.height 
= pmenu_item
->pixmap
->requisition
.height
; 
1761       child_allocation
.x 
= border_width 
+ BORDER_SPACING
; 
1762       child_allocation
.y 
= (border_width 
+ BORDER_SPACING
 
1763                             + (((allocation
->height 
- child_allocation
.height
) - child_allocation
.x
) 
1764                                / 2)); /* center pixmaps vertically */ 
1765       gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
); 
1768   if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
) 
1769     GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
); 
1773 gtk_pixmap_menu_item_forall (GtkContainer    
*container
, 
1774                              gboolean         include_internals
, 
1775                              GtkCallback      callback
, 
1776                              gpointer         callback_data
) 
1778   GtkPixmapMenuItem 
*menu_item
; 
1780   g_return_if_fail (container 
!= NULL
); 
1781   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1782   g_return_if_fail (callback 
!= NULL
); 
1784   menu_item 
= GTK_PIXMAP_MENU_ITEM (container
); 
1786   if (menu_item
->pixmap
) 
1787     (* callback
) (menu_item
->pixmap
, callback_data
); 
1789   GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
, 
1790                                             callback
,callback_data
); 
1794 gtk_pixmap_menu_item_size_request (GtkWidget      
*widget
, 
1795                                    GtkRequisition 
*requisition
) 
1797   GtkPixmapMenuItem 
*menu_item
; 
1798   GtkRequisition req 
= {0, 0}; 
1800   g_return_if_fail (widget 
!= NULL
); 
1801   g_return_if_fail (GTK_IS_MENU_ITEM (widget
)); 
1802   g_return_if_fail (requisition 
!= NULL
); 
1804   GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
); 
1806   menu_item 
= GTK_PIXMAP_MENU_ITEM (widget
); 
1808   if (menu_item
->pixmap
) 
1809     gtk_widget_size_request(menu_item
->pixmap
, &req
); 
1811   requisition
->height 
= MAX(req
.height 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
, (unsigned int) requisition
->height
); 
1812   requisition
->width 
+= (req
.width 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
); 
1816 gtk_pixmap_menu_item_remove (GtkContainer 
*container
, 
1820   gboolean widget_was_visible
; 
1822   g_return_if_fail (container 
!= NULL
); 
1823   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1824   g_return_if_fail (child 
!= NULL
); 
1825   g_return_if_fail (GTK_IS_WIDGET (child
)); 
1827   bin 
= GTK_BIN (container
); 
1828   g_return_if_fail ((bin
->child 
== child 
|| 
1829                      (GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
== child
))); 
1831   widget_was_visible 
= GTK_WIDGET_VISIBLE (child
); 
1833   gtk_widget_unparent (child
); 
1834   if (bin
->child 
== child
) 
1837     GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
= NULL
; 
1838     changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
)); 
1841   if (widget_was_visible
) 
1842     gtk_widget_queue_resize (GTK_WIDGET (container
)); 
1846 /* important to only call this if there was actually a _change_ in pixmap == NULL */ 
1848 changed_have_pixmap_status (GtkPixmapMenuItem 
*menu_item
) 
1850   if (menu_item
->pixmap 
!= NULL
) { 
1851     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
+= 1; 
1853     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 1) { 
1854       /* Install pixmap toggle size */ 
1855       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
); 
1858     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
-= 1; 
1860     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 0) { 
1861       /* Install normal toggle size */ 
1862       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
; 
1866   /* Note that we actually need to do this for _all_ GtkPixmapMenuItem 
1867      whenever the klass->toggle_size changes; but by doing it anytime 
1868      this function is called, we get the same effect, just because of 
1869      how the preferences option to show pixmaps works. Bogus, broken. 
1871   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
))) 
1872     gtk_widget_queue_resize(GTK_WIDGET(menu_item
)); 
1875 #endif // USE_MENU_BITMAPS