1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  11     #pragma implementation "menu.h" 
  12     #pragma implementation "menuitem.h" 
  15 // For compilers that support precompilation, includes "wx.h". 
  16 #include "wx/wxprec.h" 
  21 #include "wx/bitmap.h" 
  28 #include "wx/gtk/private.h" 
  30 #include <gdk/gdkkeysyms.h> 
  32 // FIXME: is this right? somehow I don't think so (VZ) 
  34     #include <glib-object.h> 
  36     #define gtk_accel_group_attach(g, o) _gtk_accel_group_attach((g), (o)) 
  37     #define gtk_accel_group_detach(g, o) _gtk_accel_group_detach((g), (o)) 
  38     #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m) 
  40     #define ACCEL_OBJECT        GObject 
  41     #define ACCEL_OBJECTS(a)    (a)->acceleratables 
  42     #define ACCEL_OBJ_CAST(obj) G_OBJECT(obj) 
  44     #define ACCEL_OBJECT        GtkObject 
  45     #define ACCEL_OBJECTS(a)    (a)->attach_objects 
  46     #define ACCEL_OBJ_CAST(obj) GTK_OBJECT(obj) 
  49 //----------------------------------------------------------------------------- 
  51 //----------------------------------------------------------------------------- 
  53 extern void wxapp_install_idle_handler(); 
  56 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL 
  57     static wxString 
GetHotKey( const wxMenuItem
& item 
); 
  60 //----------------------------------------------------------------------------- 
  61 // substitute for missing GtkPixmapMenuItem 
  62 //----------------------------------------------------------------------------- 
  66 #define GTK_TYPE_PIXMAP_MENU_ITEM            (gtk_pixmap_menu_item_get_type ()) 
  67 #define GTK_PIXMAP_MENU_ITEM(obj)            (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem)) 
  68 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass)) 
  69 #define GTK_IS_PIXMAP_MENU_ITEM(obj)         (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  70 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  71 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  72 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj)  (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj))) 
  74 #ifndef GTK_MENU_ITEM_GET_CLASS 
  75 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj))) 
  78 typedef struct _GtkPixmapMenuItem       GtkPixmapMenuItem
; 
  79 typedef struct _GtkPixmapMenuItemClass  GtkPixmapMenuItemClass
; 
  81 struct _GtkPixmapMenuItem
 
  83     GtkMenuItem menu_item
; 
  88 struct _GtkPixmapMenuItemClass
 
  90     GtkMenuItemClass parent_class
; 
  92     guint orig_toggle_size
; 
  93     guint have_pixmap_count
; 
  97 GtkType    
gtk_pixmap_menu_item_get_type       (void); 
  98 GtkWidget
* gtk_pixmap_menu_item_new            (void); 
  99 void       gtk_pixmap_menu_item_set_pixmap     (GtkPixmapMenuItem 
*menu_item
, 
 103 //----------------------------------------------------------------------------- 
 105 //----------------------------------------------------------------------------- 
 107 static wxString 
wxReplaceUnderscore( const wxString
& title 
) 
 111     /* GTK 1.2 wants to have "_" instead of "&" for accelerators */ 
 114     while (*pc 
!= wxT('\0')) 
 116         if ((*pc 
== wxT('&')) && (*(pc
+1) == wxT('&'))) 
 118             // "&" is doubled to indicate "&" instead of accelerator 
 122         else if (*pc 
== wxT('&')) 
 124 #if GTK_CHECK_VERSION(1, 2, 0) 
 128 #if GTK_CHECK_VERSION(2, 0, 0) 
 129         else if (*pc 
== wxT('/')) 
 133         else if (*pc 
== wxT('\\')) 
 137 #elif GTK_CHECK_VERSION(1, 2, 0) 
 138         else if (*pc 
== wxT('/')) 
 146             if ( *pc 
== wxT('_') ) 
 148                 // underscores must be doubled to prevent them from being 
 149                 // interpreted as accelerator character prefix by GTK 
 161 //----------------------------------------------------------------------------- 
 162 // activate message from GTK 
 163 //----------------------------------------------------------------------------- 
 165 static void gtk_menu_open_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 167     if (g_isIdle
) wxapp_install_idle_handler(); 
 169     wxMenuEvent 
event( wxEVT_MENU_OPEN
, -1, menu 
); 
 170     event
.SetEventObject( menu 
); 
 172     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 173     if (handler 
&& handler
->ProcessEvent(event
)) 
 176     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 177     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 180 //----------------------------------------------------------------------------- 
 182 //----------------------------------------------------------------------------- 
 184 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
) 
 186 wxMenuBar::wxMenuBar( long style 
) 
 188     /* the parent window is known after wxFrame::SetMenu() */ 
 189     m_needParent 
= FALSE
; 
 191     m_invokingWindow 
= (wxWindow
*) NULL
; 
 193     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 194         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") )) 
 196         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 200     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 201 #if GTK_CHECK_VERSION(1, 2, 1) 
 202     m_accel 
= gtk_accel_group_new(); 
 203     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 204     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 206     m_menubar 
= gtk_menu_bar_new(); 
 209     if (style 
& wxMB_DOCKABLE
) 
 211         m_widget 
= gtk_handle_box_new(); 
 212         gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) ); 
 213         gtk_widget_show( GTK_WIDGET(m_menubar
) ); 
 217         m_widget 
= GTK_WIDGET(m_menubar
); 
 225 wxMenuBar::wxMenuBar() 
 227     /* the parent window is known after wxFrame::SetMenu() */ 
 228     m_needParent 
= FALSE
; 
 230     m_invokingWindow 
= (wxWindow
*) NULL
; 
 232     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 233         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") )) 
 235         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 239     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 240 #if GTK_CHECK_VERSION(1, 2, 1) 
 241     m_accel 
= gtk_accel_group_new(); 
 242     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 243     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 245     m_menubar 
= gtk_menu_bar_new(); 
 248     m_widget 
= GTK_WIDGET(m_menubar
); 
 255 wxMenuBar::~wxMenuBar() 
 257 //    gtk_object_unref( GTK_OBJECT(m_factory) );  why not ? 
 260 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 262     menu
->SetInvokingWindow( (wxWindow
*) NULL 
); 
 264     wxWindow 
*top_frame 
= win
; 
 265     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 266         top_frame 
= top_frame
->GetParent(); 
 268     /* support for native hot keys */ 
 269     gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) ); 
 271     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 274         wxMenuItem 
*menuitem 
= node
->GetData(); 
 275         if (menuitem
->IsSubMenu()) 
 276             wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 277         node 
= node
->GetNext(); 
 281 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 283     menu
->SetInvokingWindow( win 
); 
 285 #if GTK_CHECK_VERSION(1, 2, 1) 
 286     wxWindow 
*top_frame 
= win
; 
 287     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 288         top_frame 
= top_frame
->GetParent(); 
 290     /* support for native hot keys  */ 
 291     ACCEL_OBJECT 
*obj 
= ACCEL_OBJ_CAST(top_frame
->m_widget
); 
 292     if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj 
) ) 
 293         gtk_accel_group_attach( menu
->m_accel
, obj 
); 
 294 #endif // GTK+ 1.2.1+ 
 296     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 299         wxMenuItem 
*menuitem 
= node
->GetData(); 
 300         if (menuitem
->IsSubMenu()) 
 301             wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 302         node 
= node
->GetNext(); 
 306 void wxMenuBar::SetInvokingWindow( wxWindow 
*win 
) 
 308     m_invokingWindow 
= win
; 
 309 #if GTK_CHECK_VERSION(1, 2, 1) 
 310     wxWindow 
*top_frame 
= win
; 
 311     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 312         top_frame 
= top_frame
->GetParent(); 
 314     /* support for native key accelerators indicated by underscroes */ 
 315     ACCEL_OBJECT 
*obj 
= ACCEL_OBJ_CAST(top_frame
->m_widget
); 
 316     if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj 
) ) 
 317         gtk_accel_group_attach( m_accel
, obj 
); 
 318 #endif // GTK+ 1.2.1+ 
 320     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 323         wxMenu 
*menu 
= node
->GetData(); 
 324         wxMenubarSetInvokingWindow( menu
, win 
); 
 325         node 
= node
->GetNext(); 
 329 void wxMenuBar::UnsetInvokingWindow( wxWindow 
*win 
) 
 331     m_invokingWindow 
= (wxWindow
*) NULL
; 
 332 #if GTK_CHECK_VERSION(1, 2, 1) 
 333     wxWindow 
*top_frame 
= win
; 
 334     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 335         top_frame 
= top_frame
->GetParent(); 
 337     // support for native key accelerators indicated by underscroes 
 338     gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) ); 
 339 #endif // GTK+ 1.2.1+ 
 341     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 344         wxMenu 
*menu 
= node
->GetData(); 
 345         wxMenubarUnsetInvokingWindow( menu
, win 
); 
 346         node 
= node
->GetNext(); 
 350 bool wxMenuBar::Append( wxMenu 
*menu
, const wxString 
&title 
) 
 352     if ( !wxMenuBarBase::Append( menu
, title 
) ) 
 355     return GtkAppend(menu
, title
); 
 358 bool wxMenuBar::GtkAppend(wxMenu 
*menu
, const wxString
& title
) 
 360     wxString 
str( wxReplaceUnderscore( title 
) ); 
 362     // This doesn't have much effect right now. 
 363     menu
->SetTitle( str 
); 
 365     // GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. 
 366 #if GTK_CHECK_VERSION(1, 2, 1) 
 369     buf 
<< wxT('/') << str
.c_str(); 
 371     // local buffer in multibyte form 
 373     strcpy(cbuf
, wxGTK_CONV(buf
) ); 
 375     GtkItemFactoryEntry entry
; 
 376     entry
.path 
= (gchar 
*)cbuf
;  // const_cast 
 377     entry
.accelerator 
= (gchar
*) NULL
; 
 378     entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 379     entry
.callback_action 
= 0; 
 380     entry
.item_type 
= (char *)"<Branch>"; 
 382     gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
 383     // in order to get the pointer to the item we need the item text _without_ underscores 
 384     wxString tmp 
= wxT("<main>/"); 
 386     for ( pc 
= str
; *pc 
!= wxT('\0'); pc
++ ) 
 388        // contrary to the common sense, we must throw out _all_ underscores, 
 389        // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we 
 390        // might naively think). IMHO it's a bug in GTK+ (VZ) 
 391        while (*pc 
== wxT('_')) 
 395     menu
->m_owner 
= gtk_item_factory_get_item( m_factory
, wxGTK_CONV( tmp 
) ); 
 396     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 399     menu
->m_owner 
= gtk_menu_item_new_with_label( wxGTK_CONV( str 
) ); 
 400     gtk_widget_show( menu
->m_owner 
); 
 401     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 403     gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner 
); 
 407     gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate", 
 408                         GTK_SIGNAL_FUNC(gtk_menu_open_callback
), 
 411     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
 412     // addings menu later on. 
 413     if (m_invokingWindow
) 
 415         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 417             // OPTIMISE ME:  we should probably cache this, or pass it 
 418             //               directly, but for now this is a minimal 
 419             //               change to validate the new dynamic sizing. 
 420             //               see (and refactor :) similar code in Remove 
 423         wxFrame 
*frame 
= wxDynamicCast( m_invokingWindow
, wxFrame 
); 
 426             frame
->UpdateMenuBarSize(); 
 432 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 434     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 437     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
 438     // of version 1.2.6), so we first append the item and then change its 
 440     if ( !GtkAppend(menu
, title
) ) 
 443     if (pos
+1 >= m_menus
.GetCount()) 
 446     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
 447     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
 448     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
 449     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
 454 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 456     // remove the old item and insert a new one 
 457     wxMenu 
*menuOld 
= Remove(pos
); 
 458     if ( menuOld 
&& !Insert(pos
, menu
, title
) ) 
 460         return (wxMenu
*) NULL
; 
 463     // either Insert() succeeded or Remove() failed and menuOld is NULL 
 467 static wxMenu 
*CopyMenu (wxMenu 
*menu
) 
 469     wxMenu 
*menucopy 
= new wxMenu (); 
 470     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 473         wxMenuItem 
*item 
= node
->GetData(); 
 474         int itemid 
= item
->GetId(); 
 475         wxString text 
= item
->GetText(); 
 476         text
.Replace(wxT("_"), wxT("&")); 
 477         wxMenu 
*submenu 
= item
->GetSubMenu(); 
 480             wxMenuItem
* itemcopy 
= new wxMenuItem(menucopy
, 
 482                                         menu
->GetHelpString(itemid
)); 
 483             itemcopy
->SetBitmap(item
->GetBitmap()); 
 484             itemcopy
->SetCheckable(item
->IsCheckable()); 
 485             menucopy
->Append(itemcopy
); 
 488           menucopy
->Append (itemid
, text
, CopyMenu(submenu
), 
 489                             menu
->GetHelpString(itemid
)); 
 491         node 
= node
->GetNext(); 
 497 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 499     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 501         return (wxMenu
*) NULL
; 
 504     GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget); 
 506     printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) ); 
 507     printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) ); 
 510     wxMenu 
*menucopy 
= CopyMenu( menu 
); 
 512     // unparent calls unref() and that would delete the widget so we raise 
 513     // the ref count to 2 artificially before invoking unparent. 
 514     gtk_widget_ref( menu
->m_menu 
); 
 515     gtk_widget_unparent( menu
->m_menu 
); 
 517     gtk_widget_destroy( menu
->m_owner 
); 
 522     printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) ); 
 523     printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) ); 
 526     if (m_invokingWindow
) 
 528             // OPTIMISE ME:  see comment in GtkAppend 
 530     wxFrame 
*frame 
= wxDynamicCast( m_invokingWindow
, wxFrame 
); 
 533             frame
->UpdateMenuBarSize(); 
 539 static int FindMenuItemRecursive( const wxMenu 
*menu
, const wxString 
&menuString
, const wxString 
&itemString 
) 
 541     if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
)) 
 543         int res 
= menu
->FindItem( itemString 
); 
 544         if (res 
!= wxNOT_FOUND
) 
 548     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 551         wxMenuItem 
*item 
= node
->GetData(); 
 552         if (item
->IsSubMenu()) 
 553             return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
); 
 555         node 
= node
->GetNext(); 
 561 int wxMenuBar::FindMenuItem( const wxString 
&menuString
, const wxString 
&itemString 
) const 
 563     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 566         wxMenu 
*menu 
= node
->GetData(); 
 567         int res 
= FindMenuItemRecursive( menu
, menuString
, itemString
); 
 570         node 
= node
->GetNext(); 
 576 // Find a wxMenuItem using its id. Recurses down into sub-menus 
 577 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
) 
 579     wxMenuItem
* result 
= menu
->FindChildItem(id
); 
 581     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 582     while ( node 
&& result 
== NULL 
) 
 584         wxMenuItem 
*item 
= node
->GetData(); 
 585         if (item
->IsSubMenu()) 
 587             result 
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id 
); 
 589         node 
= node
->GetNext(); 
 595 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu 
**menuForItem 
) const 
 597     wxMenuItem
* result 
= 0; 
 598     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 599     while (node 
&& result 
== 0) 
 601         wxMenu 
*menu 
= node
->GetData(); 
 602         result 
= FindMenuItemByIdRecursive( menu
, id 
); 
 603         node 
= node
->GetNext(); 
 608         *menuForItem 
= result 
? result
->GetMenu() : (wxMenu 
*)NULL
; 
 614 void wxMenuBar::EnableTop( size_t pos
, bool flag 
) 
 616     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 618     wxCHECK_RET( node
, wxT("menu not found") ); 
 620     wxMenu
* menu 
= node
->GetData(); 
 623         gtk_widget_set_sensitive( menu
->m_owner
, flag 
); 
 626 wxString 
wxMenuBar::GetLabelTop( size_t pos 
) const 
 628     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 630     wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") ); 
 632     wxMenu
* menu 
= node
->GetData(); 
 635     wxString 
text( menu
->GetTitle() ); 
 636     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 638         if ( *pc 
== wxT('_') ) 
 640             // '_' is the escape character for GTK+ 
 644         // don't remove ampersands '&' since if we have them in the menu title 
 645         // it means that they were doubled to indicate "&" instead of accelerator 
 653 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label 
) 
 655     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 657     wxCHECK_RET( node
, wxT("menu not found") ); 
 659     wxMenu
* menu 
= node
->GetData(); 
 661     wxString 
str( wxReplaceUnderscore( label 
) ); 
 663     menu
->SetTitle( str 
); 
 667         GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child 
); 
 670         gtk_label_set( label
, wxGTK_CONV( str 
) ); 
 672         /* reparse key accel */ 
 673         (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str 
) ); 
 674         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 679 //----------------------------------------------------------------------------- 
 681 //----------------------------------------------------------------------------- 
 683 static void gtk_menu_clicked_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 686         wxapp_install_idle_handler(); 
 688     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 690     /* should find it for normal (not popup) menu */ 
 691     wxASSERT_MSG( (id 
!= -1) || (menu
->GetInvokingWindow() != NULL
), 
 692                   _T("menu item not found in gtk_menu_clicked_callback") ); 
 694     if (!menu
->IsEnabled(id
)) 
 697     wxMenuItem
* item 
= menu
->FindChildItem( id 
); 
 698     wxCHECK_RET( item
, wxT("error in menu item callback") ); 
 700     if (item
->IsCheckable()) 
 702         bool isReallyChecked 
= item
->IsChecked(), 
 703             isInternallyChecked 
= item
->wxMenuItemBase::IsChecked(); 
 705         // ensure that the internal state is always consistent with what is 
 706         // shown on the screen 
 707         item
->wxMenuItemBase::Check(isReallyChecked
); 
 709         // we must not report the events for the radio button going up nor the 
 710         // events resulting from the calls to wxMenuItem::Check() 
 711         if ( (item
->GetKind() == wxITEM_RADIO 
&& !isReallyChecked
) || 
 712              (isInternallyChecked 
== isReallyChecked
) ) 
 719     // Is this menu on a menubar?  (possibly nested) 
 720     wxFrame
* frame 
= NULL
; 
 722     while ( pm 
&& !frame 
) 
 724         if ( pm
->IsAttached() ) 
 725             frame 
= pm
->GetMenuBar()->GetFrame(); 
 726         pm 
= pm
->GetParent(); 
 729     // FIXME: why do we have to call wxFrame::GetEventHandler() directly here? 
 730     //        normally wxMenu::SendEvent() should be enough, if it doesn't work 
 731     //        in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which 
 732     //        should be fixed instead of working around it here... 
 735         // If it is attached then let the frame send the event. 
 736         // Don't call frame->ProcessCommand(id) because it toggles 
 737         // checkable items and we've already done that above. 
 738         wxCommandEvent 
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
); 
 739         commandEvent
.SetEventObject(frame
); 
 740         if (item
->IsCheckable()) 
 741             commandEvent
.SetInt(item
->IsChecked()); 
 742         commandEvent
.SetEventObject(menu
); 
 744         frame
->GetEventHandler()->ProcessEvent(commandEvent
); 
 748         // otherwise let the menu have it 
 749         menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1); 
 753 //----------------------------------------------------------------------------- 
 755 //----------------------------------------------------------------------------- 
 757 static void gtk_menu_hilight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 759     if (g_isIdle
) wxapp_install_idle_handler(); 
 761     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 763     wxASSERT( id 
!= -1 ); // should find it! 
 765     if (!menu
->IsEnabled(id
)) 
 768     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, id 
); 
 769     event
.SetEventObject( menu 
); 
 771     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 772     if (handler 
&& handler
->ProcessEvent(event
)) 
 775     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 776     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 779 //----------------------------------------------------------------------------- 
 781 //----------------------------------------------------------------------------- 
 783 static void gtk_menu_nolight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 785     if (g_isIdle
) wxapp_install_idle_handler(); 
 787     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 789     wxASSERT( id 
!= -1 ); // should find it! 
 791     if (!menu
->IsEnabled(id
)) 
 794     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, -1 ); 
 795     event
.SetEventObject( menu 
); 
 797     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 798     if (handler 
&& handler
->ProcessEvent(event
)) 
 801     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 803         win
->GetEventHandler()->ProcessEvent( event 
); 
 806 //----------------------------------------------------------------------------- 
 808 //----------------------------------------------------------------------------- 
 810 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
) 
 812 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 814                                 const wxString
& name
, 
 815                                 const wxString
& help
, 
 819     return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
); 
 822 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 824                        const wxString
& text
, 
 825                        const wxString
& help
, 
 828           : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
) 
 833 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 835                        const wxString
& text
, 
 836                        const wxString
& help
, 
 839           : wxMenuItemBase(parentMenu
, id
, text
, help
, 
 840                            isCheckable 
? wxITEM_CHECK 
: wxITEM_NORMAL
, subMenu
) 
 845 void wxMenuItem::Init(const wxString
& text
) 
 847     m_labelWidget 
= (GtkWidget 
*) NULL
; 
 848     m_menuItem 
= (GtkWidget 
*) NULL
; 
 853 wxMenuItem::~wxMenuItem() 
 855    // don't delete menu items, the menus take care of that 
 858 // return the menu item text without any menu accels 
 860 wxString 
wxMenuItemBase::GetLabelFromText(const wxString
& text
) 
 864     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 866         if ( *pc 
== wxT('_') ) 
 868             // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx" 
 874 #if GTK_CHECK_VERSION(2, 0, 0) 
 875         if ( *pc 
== wxT('\\')  ) 
 877             // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx" 
 884         if ( (*pc 
== wxT('&')) && (*(pc
+1) != wxT('&')) ) 
 887             // "&" is doubled to indicate "&" instead of accelerator 
 894     // wxPrintf( L"text %s label %s\n", text.c_str(), label.c_str() ); 
 899 void wxMenuItem::SetText( const wxString
& str 
) 
 901     // Some optimization to avoid flicker 
 902     wxString oldLabel 
= m_text
; 
 903     oldLabel 
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t')); 
 904     oldLabel
.Replace(wxT("_"), wxT("")); 
 905     wxString label1 
= wxStripMenuCodes(str
.BeforeFirst('\t')); 
 906     if (oldLabel 
== label1
) 
 915             label 
= (GtkLabel
*) m_labelWidget
; 
 917             label 
= GTK_LABEL( GTK_BIN(m_menuItem
)->child 
); 
 919 #if GTK_CHECK_VERSION(2, 0, 0) 
 920         // We have to imitate item_factory_unescape_label here 
 922         for (size_t n 
= 0; n 
< m_text
.Len(); n
++) 
 924             if (m_text
[n
] != wxT('\\')) 
 928         gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(tmp
) ); 
 931         gtk_label_set( label
, wxGTK_CONV( m_text 
) ); 
 934         (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) ); 
 935         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 940 // it's valid for this function to be called even if m_menuItem == NULL 
 941 void wxMenuItem::DoSetText( const wxString
& str 
) 
 943     // '\t' is the deliminator indicating a hot key 
 945     const wxChar 
*pc 
= str
; 
 946     while ( (*pc 
!= wxT('\0')) && (*pc 
!= wxT('\t')) ) 
 948         if ((*pc 
== wxT('&')) && (*(pc
+1) == wxT('&'))) 
 950             // "&" is doubled to indicate "&" instead of accelerator 
 954         else if (*pc 
== wxT('&')) 
 958 #if GTK_CHECK_VERSION(2, 0, 0) 
 959         else if ( *pc 
== wxT('_') )    // escape underscores 
 961             // m_text << wxT("__");    doesn't work 
 964         else if (*pc 
== wxT('/'))      // we have to escape slashes 
 966             m_text 
<< wxT("\\/"); 
 968         else if (*pc 
== wxT('\\'))     // we have to double backslashes 
 970             m_text 
<< wxT("\\\\"); 
 973         else if ( *pc 
== wxT('_') )    // escape underscores 
 977         else if (*pc 
== wxT('/'))      /* we have to filter out slashes ... */ 
 979             m_text 
<< wxT('\\');  /* ... and replace them with back slashes */ 
 988     // wxPrintf( L"str %s m_text %s\n", str.c_str(), m_text.c_str() ); 
1001 wxAcceleratorEntry 
*wxMenuItem::GetAccel() const 
1006         return (wxAcceleratorEntry 
*)NULL
; 
1009     // as wxGetAccelFromString() looks for TAB, insert a dummy one here 
1011     label 
<< wxT('\t') << GetHotKey(); 
1013     return wxGetAccelFromString(label
); 
1016 #endif // wxUSE_ACCEL 
1018 void wxMenuItem::Check( bool check 
) 
1020     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
1022     if (check 
== m_isChecked
) 
1025     wxMenuItemBase::Check( check 
); 
1027     switch ( GetKind() ) 
1031             gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check 
); 
1035             wxFAIL_MSG( _T("can't check this item") ); 
1039 void wxMenuItem::Enable( bool enable 
) 
1041     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
1043     gtk_widget_set_sensitive( m_menuItem
, enable 
); 
1044     wxMenuItemBase::Enable( enable 
); 
1047 bool wxMenuItem::IsChecked() const 
1049     wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") ); 
1051     wxCHECK_MSG( IsCheckable(), FALSE
, 
1052                  wxT("can't get state of uncheckable item!") ); 
1054     return ((GtkCheckMenuItem
*)m_menuItem
)->active 
!= 0; 
1057 wxString 
wxMenuItem::GetFactoryPath() const 
1059     // In order to get the pointer to the item we need the item 
1060     // text _without_ underscores in GTK 1.2 
1061     wxString 
path( wxT("<main>/") ); 
1063     for ( const wxChar 
*pc 
= m_text
.c_str(); *pc
; pc
++ ) 
1065         if ( *pc 
== wxT('_') ) 
1070             // remove '_' unconditionally 
1075         // don't remove ampersands '&' since if we have them in the menu item title 
1076         // it means that they were doubled to indicate "&" instead of accelerator 
1084 //----------------------------------------------------------------------------- 
1086 //----------------------------------------------------------------------------- 
1088 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
) 
1092     m_accel 
= gtk_accel_group_new(); 
1093     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel 
); 
1094     m_menu 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
1096     m_owner 
= (GtkWidget
*) NULL
; 
1098     // Tearoffs are entries, just like separators. So if we want this 
1099     // menu to be a tear-off one, we just append a tearoff entry 
1101     if(m_style 
& wxMENU_TEAROFF
) 
1103        GtkItemFactoryEntry entry
; 
1104        entry
.path 
= (char *)"/tearoff"; 
1105        entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
1106        entry
.callback_action 
= 0; 
1107        entry
.item_type 
= (char *)"<Tearoff>"; 
1108        entry
.accelerator 
= (gchar
*) NULL
; 
1109        gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1110        //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" ); 
1113     // append the title as the very first entry if we have it 
1116         Append(-2, m_title
); 
1123    WX_CLEAR_LIST(wxMenuItemList
, m_items
); 
1125    if ( GTK_IS_WIDGET( m_menu 
)) 
1126        gtk_widget_destroy( m_menu 
); 
1128    gtk_object_unref( GTK_OBJECT(m_factory
) ); 
1131 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
) 
1133     GtkWidget 
*menuItem
; 
1135     // does this item terminate the current radio group? 
1136     bool endOfRadioGroup 
= TRUE
; 
1138     if ( mitem
->IsSeparator() ) 
1140         GtkItemFactoryEntry entry
; 
1141         entry
.path 
= (char *)"/sep"; 
1142         entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
1143         entry
.callback_action 
= 0; 
1144         entry
.item_type 
= (char *)"<Separator>"; 
1145         entry
.accelerator 
= (gchar
*) NULL
; 
1147         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1149         // this will be wrong for more than one separator. do we care? 
1150         menuItem 
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" ); 
1152         // we might have a separator inside a radio group 
1153         endOfRadioGroup 
= FALSE
; 
1155     else if ( mitem
->IsSubMenu() ) 
1157         // text has "_" instead of "&" after mitem->SetText() 
1158         wxString 
text( mitem
->GetText() ); 
1160         // local buffer in multibyte form 
1163         strcat( buf
, wxGTK_CONV( text 
) ); 
1165         GtkItemFactoryEntry entry
; 
1167         entry
.callback 
= (GtkItemFactoryCallback
) 0; 
1168         entry
.callback_action 
= 0; 
1169         entry
.item_type 
= (char *)"<Branch>"; 
1170         entry
.accelerator 
= (gchar
*) NULL
; 
1172         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  // what is 2 ? 
1174         wxString 
path( mitem
->GetFactoryPath() ); 
1175         menuItem 
= gtk_item_factory_get_item( m_factory
, wxGTK_CONV( path 
) ); 
1177         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
1179         // if adding a submenu to a menu already existing in the menu bar, we 
1180         // must set invoking window to allow processing events from this 
1182         if ( m_invokingWindow 
) 
1183             wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
); 
1186     else if (mitem
->GetBitmap().Ok()) 
1188         // Our extra code for Bitmaps in GTK 1.2 
1189         wxString 
text( mitem
->GetText() ); 
1190         const wxBitmap 
*bitmap 
= &mitem
->GetBitmap(); 
1192         menuItem 
= gtk_pixmap_menu_item_new (); 
1193         GtkWidget 
*label 
= gtk_accel_label_new ( wxGTK_CONV( text 
) ); 
1194         gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5); 
1195         gtk_container_add (GTK_CONTAINER (menuItem
), label
); 
1197         gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
); 
1199         GdkModifierType accel_mods
; 
1201         // accelerator for the item, as specified by its label 
1202         // (ex. Ctrl+O for open) 
1203         gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
, 
1205         if (accel_key 
!= GDK_VoidSymbol
) 
1207             gtk_widget_add_accelerator (menuItem
, 
1209                                         gtk_menu_get_accel_group( 
1211                                         accel_key
, accel_mods
, 
1215         // accelerator for the underlined char (ex ALT+F for the File menu) 
1216         accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1217         if (accel_key 
!= GDK_VoidSymbol
) 
1219             gtk_widget_add_accelerator (menuItem
, 
1221                                         gtk_menu_ensure_uline_accel_group ( 
1223                                         accel_key
, (GdkModifierType
) 0, 
1227         gtk_widget_show (label
); 
1229         mitem
->SetLabelWidget(label
); 
1231         GtkWidget
* pixmap 
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
); 
1232         gtk_widget_show(pixmap
); 
1233         gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem 
), pixmap
); 
1235         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1236                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1239         gtk_menu_append( GTK_MENU(m_menu
), menuItem 
); 
1240         gtk_widget_show( menuItem 
); 
1243     else // a normal item 
1245         // text has "_" instead of "&" after mitem->SetText() so don't use it 
1246         wxString 
text( mitem
->GetText() ); 
1248         // buffers containing the menu item path and type in multibyte form 
1252         strcpy( bufPath
, "/" ); 
1253         strncat( bufPath
, wxGTK_CONV(text
), WXSIZEOF(bufPath
) - 2 ); 
1254         bufPath
[WXSIZEOF(bufPath
) - 1] = '\0'; 
1256         GtkItemFactoryEntry entry
; 
1257         entry
.path 
= bufPath
; 
1258         entry
.callback 
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
; 
1259         entry
.callback_action 
= 0; 
1262         const char *item_type
; 
1263         switch ( mitem
->GetKind() ) 
1266                 item_type 
= "<CheckItem>"; 
1270                 if ( m_pathLastRadio
.empty() ) 
1272                     // start of a new radio group 
1273                     item_type 
= "<RadioItem>"; 
1274                     wxString 
tmp( wxGTK_CONV_BACK( bufPath 
) ); 
1276                     m_pathLastRadio 
= tmp
; 
1278                 else // continue the radio group 
1280                     pathRadio 
= m_pathLastRadio
; 
1281                     pathRadio
.Replace(wxT("_"), wxT("")); 
1282                     pathRadio
.Prepend(wxT("<main>/")); 
1284                     strncpy(bufType
, wxGTK_CONV(pathRadio
), WXSIZEOF(bufType
)); 
1285                     bufType
[WXSIZEOF(bufType
) - 1] = '\0'; 
1286                     item_type 
= bufType
; 
1289                 // continue the existing radio group, if any 
1290                 endOfRadioGroup 
= FALSE
; 
1294                 wxFAIL_MSG( _T("unexpected menu item kind") ); 
1298                 item_type 
= "<Item>"; 
1299 #if defined(__WXGTK20__) && wxUSE_IMAGE 
1300                 if (mitem
->GetBitmap().Ok()) 
1302                     item_type 
= "<ImageItem>"; 
1303                     // GTK2's image factory know about image items, but they need to 
1304                     // get a GdkPixbuf structure, which we need to create on the fly. 
1305                     // This Pixbuf structure needs to be static so we create it and 
1306                     // just make it a memory leak... 
1307                     wxImage 
image( mitem
->GetBitmap().ConvertToImage() ); 
1308                     size_t size 
= 4 +   // magic 
1310                                   image
.GetHeight() * image
.GetWidth() * 4; // RGBA 
1312                     unsigned char *dest 
= new unsigned char[size
]; 
1313                     entry
.extra_data 
= dest
; 
1315                     unsigned char *source 
= image
.GetData(); 
1316                     bool has_mask 
= image
.HasMask(); 
1317                     unsigned char mask_r 
= image
.GetMaskRed(); 
1318                     unsigned char mask_b 
= image
.GetMaskBlue(); 
1319                     unsigned char mask_g 
= image
.GetMaskGreen(); 
1323                     *dest 
= 'G'; dest
++; *dest 
= 'd'; dest
++; *dest 
= 'k'; dest
++; *dest 
= 'P'; dest
++; 
1326                     *dest 
= tmp 
>> 24; dest
++; *dest 
= tmp 
>> 16; dest
++; *dest 
= tmp 
>> 8; dest
++; *dest 
= tmp
; dest
++; 
1328                     *dest 
= 1; dest
++; *dest 
= 1; dest
++; *dest 
= 0; dest
++; *dest 
= 2; dest
++; 
1330                     tmp 
= image
.GetWidth()*4; 
1331                     *dest 
= tmp 
>> 24; dest
++; *dest 
= tmp 
>> 16; dest
++; *dest 
= tmp 
>> 8; dest
++; *dest 
= tmp
; dest
++; 
1333                     tmp 
= image
.GetWidth(); 
1334                     *dest 
= tmp 
>> 24; dest
++; *dest 
= tmp 
>> 16; dest
++; *dest 
= tmp 
>> 8; dest
++; *dest 
= tmp
; dest
++; 
1336                     tmp 
= image
.GetHeight(); 
1337                     *dest 
= tmp 
>> 24; dest
++; *dest 
= tmp 
>> 16; dest
++; *dest 
= tmp 
>> 8; dest
++; *dest 
= tmp
; dest
++; 
1339                     for (int i 
= 0; i 
< image
.GetWidth()*image
.GetHeight(); i
++) 
1341                         unsigned char r 
= *source
; source
++; 
1342                         unsigned char g 
= *source
; source
++; 
1343                         unsigned char b 
= *source
; source
++; 
1347                         if (has_mask 
&& (r 
== mask_r
)  && (g 
== mask_g
)  && (b 
== mask_b
)) 
1359         entry
.item_type 
= (char *)item_type
; // cast needed for GTK+ 
1360         entry
.accelerator 
= (gchar
*) NULL
; 
1363         // due to an apparent bug in GTK+, we have to use a static buffer here - 
1364         // otherwise GTK+ 1.2.2 manages to override the memory we pass to it 
1366         char s_accel
[50]; // should be big enough, we check for overruns 
1367         wxString 
tmp( GetHotKey(*mitem
) ); 
1368         strncpy(s_accel
, wxGTK_CONV( tmp 
), WXSIZEOF(s_accel
)); 
1369         s_accel
[WXSIZEOF(s_accel
) - 1] = '\0'; 
1370         entry
.accelerator 
= s_accel
; 
1371 #else // !wxUSE_ACCEL 
1372         entry
.accelerator 
= (char*) NULL
; 
1373 #endif // wxUSE_ACCEL/!wxUSE_ACCEL 
1375         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
1377         wxString 
path( mitem
->GetFactoryPath() ); 
1378         menuItem 
= gtk_item_factory_get_widget( m_factory
, wxGTK_CONV( path 
) ); 
1381             wxLogError( wxT("Wrong menu path: %s\n"), path
.c_str() ); 
1384     if ( !mitem
->IsSeparator() ) 
1386         wxASSERT_MSG( menuItem
, wxT("invalid menuitem") ); 
1388         gtk_signal_connect( GTK_OBJECT(menuItem
), "select", 
1389                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
), 
1392         gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect", 
1393                             GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
), 
1397     mitem
->SetMenuItem(menuItem
); 
1399     if ( endOfRadioGroup 
) 
1401         m_pathLastRadio
.clear(); 
1407 wxMenuItem
* wxMenu::DoAppend(wxMenuItem 
*mitem
) 
1409     if (!GtkAppend(mitem
)) 
1411     return wxMenuBase::DoAppend(mitem
); 
1414 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
1416     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
1419     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
1420     // of version 1.2.6), so we first append the item and then change its 
1422     if ( !GtkAppend(item
) ) 
1425     if ( m_style 
& wxMENU_TEAROFF 
) 
1427         // change the position as the first item is the tear-off marker 
1431     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
1432     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
1433     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
1434     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
1439 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
1441     if ( !wxMenuBase::DoRemove(item
) ) 
1442         return (wxMenuItem 
*)NULL
; 
1444     // TODO: this code doesn't delete the item factory item and this seems 
1445     //       impossible as of GTK 1.2.6. 
1446     gtk_widget_destroy( item
->GetMenuItem() ); 
1451 int wxMenu::FindMenuIdByMenuItem( GtkWidget 
*menuItem 
) const 
1453     wxMenuItemList::compatibility_iterator node 
= m_items
.GetFirst(); 
1456         wxMenuItem 
*item 
= node
->GetData(); 
1457         if (item
->GetMenuItem() == menuItem
) 
1458            return item
->GetId(); 
1459         node 
= node
->GetNext(); 
1465 // ---------------------------------------------------------------------------- 
1467 // ---------------------------------------------------------------------------- 
1469 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL 
1471 static wxString 
GetHotKey( const wxMenuItem
& item 
) 
1475     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
1478         int flags 
= accel
->GetFlags(); 
1479         if ( flags 
& wxACCEL_ALT 
) 
1480             hotkey 
+= wxT("<alt>"); 
1481         if ( flags 
& wxACCEL_CTRL 
) 
1482             hotkey 
+= wxT("<control>"); 
1483         if ( flags 
& wxACCEL_SHIFT 
) 
1484             hotkey 
+= wxT("<shift>"); 
1486         int code 
= accel
->GetKeyCode(); 
1501                 hotkey 
<< wxT('F') << code 
- WXK_F1 
+ 1; 
1504                 // TODO: we should use gdk_keyval_name() (a.k.a. 
1505                 //       XKeysymToString) here as well as hardcoding the keysym 
1506                 //       names this might be not portable 
1507             case WXK_NUMPAD_INSERT
: 
1508                 hotkey 
<< wxT("KP_Insert" ); 
1510             case WXK_NUMPAD_DELETE
: 
1511                 hotkey 
<< wxT("KP_Delete" ); 
1514                 hotkey 
<< wxT("Insert" ); 
1517                 hotkey 
<< wxT("Delete" ); 
1520                 hotkey 
<< wxT("Up" ); 
1523                 hotkey 
<< wxT("Down" ); 
1527                 hotkey 
<< wxT("Prior" ); 
1531                 hotkey 
<< wxT("Next" ); 
1534                 hotkey 
<< wxT("Left" ); 
1537                 hotkey 
<< wxT("Right" ); 
1540                 hotkey 
<< wxT("Home" ); 
1543                 hotkey 
<< wxT("End" ); 
1546                 hotkey 
<< wxT("Return" ); 
1549                 // if there are any other keys wxGetAccelFromString() may 
1550                 // return, we should process them here 
1555                     wxString name 
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) ); 
1563                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1572 #endif // wxUSE_ACCEL 
1575 //----------------------------------------------------------------------------- 
1576 // substitute for missing GtkPixmapMenuItem 
1577 //----------------------------------------------------------------------------- 
1582  * Copyright (C) 1998, 1999, 2000 Free Software Foundation 
1583  * All rights reserved. 
1585  * This file is part of the Gnome Library. 
1587  * The Gnome Library is free software; you can redistribute it and/or 
1588  * modify it under the terms of the GNU Library General Public License as 
1589  * published by the Free Software Foundation; either version 2 of the 
1590  * License, or (at your option) any later version. 
1592  * The Gnome Library is distributed in the hope that it will be useful, 
1593  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
1594  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
1595  * Library General Public License for more details. 
1597  * You should have received a copy of the GNU Library General Public 
1598  * License along with the Gnome Library; see the file COPYING.LIB.  If not, 
1599  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
1600  * Boston, MA 02111-1307, USA. 
1606 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */ 
1608 #include <gtk/gtkaccellabel.h> 
1609 #include <gtk/gtksignal.h> 
1610 #include <gtk/gtkmenuitem.h> 
1611 #include <gtk/gtkmenu.h> 
1612 #include <gtk/gtkcontainer.h> 
1617 static void gtk_pixmap_menu_item_class_init    (GtkPixmapMenuItemClass 
*klass
); 
1618 static void gtk_pixmap_menu_item_init          (GtkPixmapMenuItem      
*menu_item
); 
1619 static void gtk_pixmap_menu_item_draw          (GtkWidget              
*widget
, 
1620                                                 GdkRectangle           
*area
); 
1621 static gint 
gtk_pixmap_menu_item_expose        (GtkWidget              
*widget
, 
1622                                                 GdkEventExpose         
*event
); 
1624 /* we must override the following functions */ 
1626 static void gtk_pixmap_menu_item_map           (GtkWidget        
*widget
); 
1627 static void gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1628                                                 GtkAllocation    
*allocation
); 
1629 static void gtk_pixmap_menu_item_forall        (GtkContainer    
*container
, 
1630                                                 gboolean         include_internals
, 
1631                                                 GtkCallback      callback
, 
1632                                                 gpointer         callback_data
); 
1633 static void gtk_pixmap_menu_item_size_request  (GtkWidget        
*widget
, 
1634                                                 GtkRequisition   
*requisition
); 
1635 static void gtk_pixmap_menu_item_remove        (GtkContainer 
*container
, 
1638 static void changed_have_pixmap_status         (GtkPixmapMenuItem 
*menu_item
); 
1640 static GtkMenuItemClass 
*parent_class 
= NULL
; 
1644 #define BORDER_SPACING  3 
1645 #define PMAP_WIDTH 20 
1648 gtk_pixmap_menu_item_get_type (void) 
1650   static GtkType pixmap_menu_item_type 
= 0; 
1652   if (!pixmap_menu_item_type
) 
1654       GtkTypeInfo pixmap_menu_item_info 
= 
1656         (char *)"GtkPixmapMenuItem", 
1657         sizeof (GtkPixmapMenuItem
), 
1658         sizeof (GtkPixmapMenuItemClass
), 
1659         (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
, 
1660         (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
, 
1661         /* reserved_1 */ NULL
, 
1662         /* reserved_2 */ NULL
, 
1663         (GtkClassInitFunc
) NULL
, 
1666       pixmap_menu_item_type 
= gtk_type_unique (gtk_menu_item_get_type (), 
1667                                                &pixmap_menu_item_info
); 
1670   return pixmap_menu_item_type
; 
1674  * gtk_pixmap_menu_item_new 
1676  * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap() 
1677  * to set the pixmap wich is displayed at the left side. 
1680  * &GtkWidget pointer to new menu item 
1684 gtk_pixmap_menu_item_new (void) 
1686   return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ())); 
1690 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass 
*klass
) 
1692   GtkObjectClass 
*object_class
; 
1693   GtkWidgetClass 
*widget_class
; 
1694   GtkMenuItemClass 
*menu_item_class
; 
1695   GtkContainerClass 
*container_class
; 
1697   object_class 
= (GtkObjectClass
*) klass
; 
1698   widget_class 
= (GtkWidgetClass
*) klass
; 
1699   menu_item_class 
= (GtkMenuItemClass
*) klass
; 
1700   container_class 
= (GtkContainerClass
*) klass
; 
1702   parent_class 
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ()); 
1704   widget_class
->draw 
= gtk_pixmap_menu_item_draw
; 
1705   widget_class
->expose_event 
= gtk_pixmap_menu_item_expose
; 
1706   widget_class
->map 
= gtk_pixmap_menu_item_map
; 
1707   widget_class
->size_allocate 
= gtk_pixmap_menu_item_size_allocate
; 
1708   widget_class
->size_request 
= gtk_pixmap_menu_item_size_request
; 
1710   container_class
->forall 
= gtk_pixmap_menu_item_forall
; 
1711   container_class
->remove 
= gtk_pixmap_menu_item_remove
; 
1713   klass
->orig_toggle_size 
= menu_item_class
->toggle_size
; 
1714   klass
->have_pixmap_count 
= 0; 
1718 gtk_pixmap_menu_item_init (GtkPixmapMenuItem 
*menu_item
) 
1722   mi 
= GTK_MENU_ITEM (menu_item
); 
1724   menu_item
->pixmap 
= NULL
; 
1728 gtk_pixmap_menu_item_draw (GtkWidget    
*widget
, 
1731   g_return_if_fail (widget 
!= NULL
); 
1732   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1733   g_return_if_fail (area 
!= NULL
); 
1735   if (GTK_WIDGET_CLASS (parent_class
)->draw
) 
1736     (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
); 
1738   if (GTK_WIDGET_DRAWABLE (widget
) && 
1739       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1740     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1745 gtk_pixmap_menu_item_expose (GtkWidget      
*widget
, 
1746                              GdkEventExpose 
*event
) 
1748   g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
1749   g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
); 
1750   g_return_val_if_fail (event 
!= NULL
, FALSE
); 
1752   if (GTK_WIDGET_CLASS (parent_class
)->expose_event
) 
1753     (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
); 
1755   if (GTK_WIDGET_DRAWABLE (widget
) && 
1756       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1757     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1764  * gtk_pixmap_menu_item_set_pixmap 
1765  * @menu_item: Pointer to the pixmap menu item 
1766  * @pixmap: Pointer to a pixmap widget 
1768  * Set the pixmap of the menu item. 
1773 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem 
*menu_item
, 
1776   g_return_if_fail (menu_item 
!= NULL
); 
1777   g_return_if_fail (pixmap 
!= NULL
); 
1778   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
)); 
1779   g_return_if_fail (GTK_IS_WIDGET (pixmap
)); 
1780   g_return_if_fail (menu_item
->pixmap 
== NULL
); 
1782   gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
)); 
1783   menu_item
->pixmap 
= pixmap
; 
1785   if (GTK_WIDGET_REALIZED (pixmap
->parent
) && 
1786       !GTK_WIDGET_REALIZED (pixmap
)) 
1787     gtk_widget_realize (pixmap
); 
1789   if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) { 
1790     if (GTK_WIDGET_MAPPED (pixmap
->parent
) && 
1791         GTK_WIDGET_VISIBLE(pixmap
) && 
1792         !GTK_WIDGET_MAPPED (pixmap
)) 
1793       gtk_widget_map (pixmap
); 
1796   changed_have_pixmap_status(menu_item
); 
1798   if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
)) 
1799     gtk_widget_queue_resize (pixmap
); 
1803 gtk_pixmap_menu_item_map (GtkWidget 
*widget
) 
1805   GtkPixmapMenuItem 
*menu_item
; 
1807   g_return_if_fail (widget 
!= NULL
); 
1808   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1810   menu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1812   GTK_WIDGET_CLASS(parent_class
)->map(widget
); 
1814   if (menu_item
->pixmap 
&& 
1815       GTK_WIDGET_VISIBLE (menu_item
->pixmap
) && 
1816       !GTK_WIDGET_MAPPED (menu_item
->pixmap
)) 
1817     gtk_widget_map (menu_item
->pixmap
); 
1821 gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1822                                     GtkAllocation    
*allocation
) 
1824   GtkPixmapMenuItem 
*pmenu_item
; 
1826   pmenu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1828   if (pmenu_item
->pixmap 
&& GTK_WIDGET_VISIBLE(pmenu_item
)) 
1830       GtkAllocation child_allocation
; 
1833       border_width 
= GTK_CONTAINER (widget
)->border_width
; 
1835       child_allocation
.width 
= pmenu_item
->pixmap
->requisition
.width
; 
1836       child_allocation
.height 
= pmenu_item
->pixmap
->requisition
.height
; 
1837       child_allocation
.x 
= border_width 
+ BORDER_SPACING
; 
1838       child_allocation
.y 
= (border_width 
+ BORDER_SPACING
 
1839                             + (((allocation
->height 
- child_allocation
.height
) - child_allocation
.x
) 
1840                                / 2)); /* center pixmaps vertically */ 
1841       gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
); 
1844   if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
) 
1845     GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
); 
1849 gtk_pixmap_menu_item_forall (GtkContainer    
*container
, 
1850                              gboolean         include_internals
, 
1851                              GtkCallback      callback
, 
1852                              gpointer         callback_data
) 
1854   GtkPixmapMenuItem 
*menu_item
; 
1856   g_return_if_fail (container 
!= NULL
); 
1857   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1858   g_return_if_fail (callback 
!= NULL
); 
1860   menu_item 
= GTK_PIXMAP_MENU_ITEM (container
); 
1862   if (menu_item
->pixmap
) 
1863     (* callback
) (menu_item
->pixmap
, callback_data
); 
1865   GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
, 
1866                                             callback
,callback_data
); 
1870 gtk_pixmap_menu_item_size_request (GtkWidget      
*widget
, 
1871                                    GtkRequisition 
*requisition
) 
1873   GtkPixmapMenuItem 
*menu_item
; 
1874   GtkRequisition req 
= {0, 0}; 
1876   g_return_if_fail (widget 
!= NULL
); 
1877   g_return_if_fail (GTK_IS_MENU_ITEM (widget
)); 
1878   g_return_if_fail (requisition 
!= NULL
); 
1880   GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
); 
1882   menu_item 
= GTK_PIXMAP_MENU_ITEM (widget
); 
1884   if (menu_item
->pixmap
) 
1885     gtk_widget_size_request(menu_item
->pixmap
, &req
); 
1887   requisition
->height 
= MAX(req
.height 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
, (unsigned int) requisition
->height
); 
1888   requisition
->width 
+= (req
.width 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
); 
1892 gtk_pixmap_menu_item_remove (GtkContainer 
*container
, 
1896   gboolean widget_was_visible
; 
1898   g_return_if_fail (container 
!= NULL
); 
1899   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1900   g_return_if_fail (child 
!= NULL
); 
1901   g_return_if_fail (GTK_IS_WIDGET (child
)); 
1903   bin 
= GTK_BIN (container
); 
1904   g_return_if_fail ((bin
->child 
== child 
|| 
1905                      (GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
== child
))); 
1907   widget_was_visible 
= GTK_WIDGET_VISIBLE (child
); 
1909   gtk_widget_unparent (child
); 
1910   if (bin
->child 
== child
) 
1913     GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
= NULL
; 
1914     changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
)); 
1917   if (widget_was_visible
) 
1918     gtk_widget_queue_resize (GTK_WIDGET (container
)); 
1922 /* important to only call this if there was actually a _change_ in pixmap == NULL */ 
1924 changed_have_pixmap_status (GtkPixmapMenuItem 
*menu_item
) 
1926   if (menu_item
->pixmap 
!= NULL
) { 
1927     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
+= 1; 
1929     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 1) { 
1930       /* Install pixmap toggle size */ 
1931       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
); 
1934     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
-= 1; 
1936     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 0) { 
1937       /* Install normal toggle size */ 
1938       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
; 
1942   /* Note that we actually need to do this for _all_ GtkPixmapMenuItem 
1943      whenever the klass->toggle_size changes; but by doing it anytime 
1944      this function is called, we get the same effect, just because of 
1945      how the preferences option to show pixmaps works. Bogus, broken. 
1947   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
))) 
1948     gtk_widget_queue_resize(GTK_WIDGET(menu_item
));