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" 
  26 #include <gdk/gdkkeysyms.h> 
  29 //----------------------------------------------------------------------------- 
  31 //----------------------------------------------------------------------------- 
  33 extern void wxapp_install_idle_handler(); 
  36 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL 
  37 static wxString 
GetHotKey( const wxMenuItem
& item 
); 
  40 //----------------------------------------------------------------------------- 
  41 // substitute for missing GtkPixmapMenuItem 
  42 //----------------------------------------------------------------------------- 
  44 #define GTK_TYPE_PIXMAP_MENU_ITEM            (gtk_pixmap_menu_item_get_type ()) 
  45 #define GTK_PIXMAP_MENU_ITEM(obj)            (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem)) 
  46 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass)) 
  47 #define GTK_IS_PIXMAP_MENU_ITEM(obj)         (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  48 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  49 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM)) 
  50 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj)  (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj))) 
  52 #ifndef GTK_MENU_ITEM_GET_CLASS 
  53 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj))) 
  56 typedef struct _GtkPixmapMenuItem       GtkPixmapMenuItem
; 
  57 typedef struct _GtkPixmapMenuItemClass  GtkPixmapMenuItemClass
; 
  59 struct _GtkPixmapMenuItem
 
  61     GtkMenuItem menu_item
; 
  66 struct _GtkPixmapMenuItemClass
 
  68     GtkMenuItemClass parent_class
; 
  70     guint orig_toggle_size
; 
  71     guint have_pixmap_count
; 
  75 GtkType    
gtk_pixmap_menu_item_get_type       (void); 
  76 GtkWidget
* gtk_pixmap_menu_item_new            (void); 
  77 void       gtk_pixmap_menu_item_set_pixmap     (GtkPixmapMenuItem 
*menu_item
, 
  80 //----------------------------------------------------------------------------- 
  82 //----------------------------------------------------------------------------- 
  84 static wxString 
wxReplaceUnderscore( const wxString
& title 
) 
  88     /* GTK 1.2 wants to have "_" instead of "&" for accelerators */ 
  90     for ( pc 
= title
; *pc 
!= wxT('\0'); pc
++ ) 
  94 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
  97         else if (*pc 
== wxT('/')) 
 105             if ( *pc 
== wxT('_') ) 
 107                 // underscores must be doubled to prevent them from being 
 108                 // interpreted as accelerator character prefix by GTK 
 119 //----------------------------------------------------------------------------- 
 121 //----------------------------------------------------------------------------- 
 123 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
) 
 125 wxMenuBar::wxMenuBar( long style 
) 
 127     /* the parent window is known after wxFrame::SetMenu() */ 
 128     m_needParent 
= FALSE
; 
 130     m_invokingWindow 
= (wxWindow
*) NULL
; 
 132     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 133         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") )) 
 135         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 139     m_menus
.DeleteContents( TRUE 
); 
 141     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 142 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 143     m_accel 
= gtk_accel_group_new(); 
 144     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 145     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 147     m_menubar 
= gtk_menu_bar_new(); 
 150     if (style 
& wxMB_DOCKABLE
) 
 152         m_widget 
= gtk_handle_box_new(); 
 153         gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) ); 
 154         gtk_widget_show( GTK_WIDGET(m_menubar
) ); 
 158         m_widget 
= GTK_WIDGET(m_menubar
); 
 166 wxMenuBar::wxMenuBar() 
 168     /* the parent window is known after wxFrame::SetMenu() */ 
 169     m_needParent 
= FALSE
; 
 171     m_invokingWindow 
= (wxWindow
*) NULL
; 
 173     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 174         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") )) 
 176         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 180     m_menus
.DeleteContents( TRUE 
); 
 182     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 183 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 184     m_accel 
= gtk_accel_group_new(); 
 185     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 186     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 188     m_menubar 
= gtk_menu_bar_new(); 
 191     m_widget 
= GTK_WIDGET(m_menubar
); 
 198 wxMenuBar::~wxMenuBar() 
 200 //    gtk_object_unref( GTK_OBJECT(m_factory) );  why not ? 
 203 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 205     menu
->SetInvokingWindow( (wxWindow
*) NULL 
); 
 207 #if (GTK_MINOR_VERSION > 0) 
 208     wxWindow 
*top_frame 
= win
; 
 209     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 210         top_frame 
= top_frame
->GetParent(); 
 212     /* support for native hot keys  */ 
 213     gtk_accel_group_detach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) ); 
 216     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 219         wxMenuItem 
*menuitem 
= node
->GetData(); 
 220         if (menuitem
->IsSubMenu()) 
 221             wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 222         node 
= node
->GetNext(); 
 226 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 228     menu
->SetInvokingWindow( win 
); 
 230 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 231     wxWindow 
*top_frame 
= win
; 
 232     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 233         top_frame 
= top_frame
->GetParent(); 
 235     /* support for native hot keys  */ 
 236     GtkObject 
*obj 
= GTK_OBJECT(top_frame
->m_widget
); 
 237     if ( !g_slist_find( menu
->m_accel
->attach_objects
, obj 
) ) 
 238         gtk_accel_group_attach( menu
->m_accel
, obj 
); 
 241     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 244         wxMenuItem 
*menuitem 
= node
->GetData(); 
 245         if (menuitem
->IsSubMenu()) 
 246             wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 247         node 
= node
->GetNext(); 
 251 void wxMenuBar::SetInvokingWindow( wxWindow 
*win 
) 
 253     m_invokingWindow 
= win
; 
 254 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 255     wxWindow 
*top_frame 
= win
; 
 256     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 257         top_frame 
= top_frame
->GetParent(); 
 259     /* support for native key accelerators indicated by underscroes */ 
 260     GtkObject 
*obj 
= GTK_OBJECT(top_frame
->m_widget
); 
 261     if ( !g_slist_find( m_accel
->attach_objects
, obj 
) ) 
 262         gtk_accel_group_attach( m_accel
, obj 
); 
 265     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 268         wxMenu 
*menu 
= node
->GetData(); 
 269         wxMenubarSetInvokingWindow( menu
, win 
); 
 270         node 
= node
->GetNext(); 
 274 void wxMenuBar::UnsetInvokingWindow( wxWindow 
*win 
) 
 276     m_invokingWindow 
= (wxWindow
*) NULL
; 
 277 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 278     wxWindow 
*top_frame 
= win
; 
 279     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 280         top_frame 
= top_frame
->GetParent(); 
 282     /* support for native key accelerators indicated by underscroes */ 
 283     gtk_accel_group_detach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) ); 
 286     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 289         wxMenu 
*menu 
= node
->GetData(); 
 290         wxMenubarUnsetInvokingWindow( menu
, win 
); 
 291         node 
= node
->GetNext(); 
 295 bool wxMenuBar::Append( wxMenu 
*menu
, const wxString 
&title 
) 
 297     if ( !wxMenuBarBase::Append( menu
, title 
) ) 
 300     return GtkAppend(menu
, title
); 
 303 bool wxMenuBar::GtkAppend(wxMenu 
*menu
, const wxString
& title
) 
 305     wxString 
str( wxReplaceUnderscore( title 
) ); 
 307     /* this doesn't have much effect right now */ 
 308     menu
->SetTitle( str 
); 
 310     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 311 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 313     /* local buffer in multibyte form */ 
 315     buf 
<< wxT('/') << str
.c_str(); 
 317     char *cbuf 
= new char[buf
.Length()+1]; 
 318     strcpy(cbuf
, buf
.mbc_str()); 
 320     GtkItemFactoryEntry entry
; 
 321     entry
.path 
= (gchar 
*)cbuf
;  // const_cast 
 322     entry
.accelerator 
= (gchar
*) NULL
; 
 323     entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 324     entry
.callback_action 
= 0; 
 325     entry
.item_type 
= "<Branch>"; 
 327     gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 328     /* in order to get the pointer to the item we need the item text _without_ underscores */ 
 329     wxString tmp 
= wxT("<main>/"); 
 331     for ( pc 
= str
; *pc 
!= wxT('\0'); pc
++ ) 
 333        // contrary to the common sense, we must throw out _all_ underscores, 
 334        // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we 
 335        // might naively think). IMHO it's a bug in GTK+ (VZ) 
 336        while (*pc 
== wxT('_')) 
 340     menu
->m_owner 
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() ); 
 341     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 345     menu
->m_owner 
= gtk_menu_item_new_with_label( str
.mb_str() ); 
 346     gtk_widget_show( menu
->m_owner 
); 
 347     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 349     gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner 
); 
 353     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
 354     // adding menu later on. 
 355     if (m_invokingWindow
) 
 356         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 361 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 363     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 367     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
 368     // of version 1.2.6), so we first append the item and then change its 
 370     if ( !GtkAppend(menu
, title
) ) 
 373     if (pos
+1 >= m_menus
.GetCount()) 
 376     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
 377     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
 378     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
 379     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
 383     // this should be easy to do with GTK 1.0 - can use standard functions for 
 384     // this and don't need any hacks like above, but as I don't have GTK 1.0 
 385     // any more I can't do it 
 386     wxFAIL_MSG( wxT("TODO") ); 
 389 #endif // GTK 1.2/1.0 
 392 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 394     // remove the old item and insert a new one 
 395     wxMenu 
*menuOld 
= Remove(pos
); 
 396     if ( menuOld 
&& !Insert(pos
, menu
, title
) ) 
 398         return (wxMenu
*) NULL
; 
 401     // either Insert() succeeded or Remove() failed and menuOld is NULL 
 405 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 407     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 409         return (wxMenu
*) NULL
; 
 412     GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget); 
 414     printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) ); 
 415     printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) ); 
 418     // unparent calls unref() and that would delete the widget so we raise 
 419     // the ref count to 2 artificially before invoking unparent. 
 420     gtk_widget_ref( menu
->m_menu 
); 
 421     gtk_widget_unparent( menu
->m_menu 
); 
 423     gtk_widget_destroy( menu
->m_owner 
); 
 426     printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) ); 
 427     printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) ); 
 433 static int FindMenuItemRecursive( const wxMenu 
*menu
, const wxString 
&menuString
, const wxString 
&itemString 
) 
 435     if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
)) 
 437         int res 
= menu
->FindItem( itemString 
); 
 438         if (res 
!= wxNOT_FOUND
) 
 442     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 445         wxMenuItem 
*item 
= node
->GetData(); 
 446         if (item
->IsSubMenu()) 
 447             return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
); 
 449         node 
= node
->GetNext(); 
 455 int wxMenuBar::FindMenuItem( const wxString 
&menuString
, const wxString 
&itemString 
) const 
 457     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 460         wxMenu 
*menu 
= node
->GetData(); 
 461         int res 
= FindMenuItemRecursive( menu
, menuString
, itemString
); 
 464         node 
= node
->GetNext(); 
 470 // Find a wxMenuItem using its id. Recurses down into sub-menus 
 471 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
) 
 473     wxMenuItem
* result 
= menu
->FindChildItem(id
); 
 475     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 476     while ( node 
&& result 
== NULL 
) 
 478         wxMenuItem 
*item 
= node
->GetData(); 
 479         if (item
->IsSubMenu()) 
 481             result 
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id 
); 
 483         node 
= node
->GetNext(); 
 489 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu 
**menuForItem 
) const 
 491     wxMenuItem
* result 
= 0; 
 492     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 493     while (node 
&& result 
== 0) 
 495         wxMenu 
*menu 
= node
->GetData(); 
 496         result 
= FindMenuItemByIdRecursive( menu
, id 
); 
 497         node 
= node
->GetNext(); 
 502         *menuForItem 
= result 
? result
->GetMenu() : (wxMenu 
*)NULL
; 
 508 void wxMenuBar::EnableTop( size_t pos
, bool flag 
) 
 510     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 512     wxCHECK_RET( node
, wxT("menu not found") ); 
 514     wxMenu
* menu 
= node
->GetData(); 
 517         gtk_widget_set_sensitive( menu
->m_owner
, flag 
); 
 520 wxString 
wxMenuBar::GetLabelTop( size_t pos 
) const 
 522     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 524     wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") ); 
 526     wxMenu
* menu 
= node
->GetData(); 
 529     wxString 
text( menu
->GetTitle() ); 
 530 #if (GTK_MINOR_VERSION > 0) 
 531     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 533         if ( *pc 
== wxT('_') || *pc 
== wxT('&') ) 
 535             // '_' is the escape character for GTK+ and '&' is the one for 
 536             // wxWindows - skip both of them 
 544 #endif // GTK+ 1.2/1.0 
 549 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label 
) 
 551     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 553     wxCHECK_RET( node
, wxT("menu not found") ); 
 555     wxMenu
* menu 
= node
->GetData(); 
 557     wxString 
str( wxReplaceUnderscore( label 
) ); 
 559     menu
->SetTitle( str 
); 
 563         GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child 
); 
 566         gtk_label_set( label
, str
.mb_str()); 
 568         /* reparse key accel */ 
 569         (void)gtk_label_parse_uline (GTK_LABEL(label
), str
.mb_str() ); 
 570         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 575 //----------------------------------------------------------------------------- 
 577 //----------------------------------------------------------------------------- 
 579 static void gtk_menu_clicked_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 581     if (g_isIdle
) wxapp_install_idle_handler(); 
 583     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 585     /* should find it for normal (not popup) menu */ 
 586     wxASSERT( (id 
!= -1) || (menu
->GetInvokingWindow() != NULL
) ); 
 588     if (!menu
->IsEnabled(id
)) 
 591     wxMenuItem
* item 
= menu
->FindChildItem( id 
); 
 592     wxCHECK_RET( item
, wxT("error in menu item callback") ); 
 594     if (item
->IsCheckable()) 
 596         bool isReallyChecked 
= item
->IsChecked(); 
 597         if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked 
) 
 599             /* the menu item has been checked by calling wxMenuItem->Check() */ 
 604             /* the user pressed on the menu item -> report and make consistent 
 606             item
->wxMenuItemBase::Check(isReallyChecked
); 
 610     wxCommandEvent 
event( wxEVT_COMMAND_MENU_SELECTED
, id 
); 
 611     event
.SetEventObject( menu 
); 
 612     if (item
->IsCheckable()) 
 613         event
.SetInt( item
->IsChecked() ); 
 615 #if wxUSE_MENU_CALLBACK 
 616     if (menu
->GetCallback()) 
 618         (void) (*(menu
->GetCallback())) (*menu
, event
); 
 621 #endif // wxUSE_MENU_CALLBACK 
 623     if (menu
->GetEventHandler()->ProcessEvent(event
)) 
 626     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 628         win
->GetEventHandler()->ProcessEvent( event 
); 
 631 //----------------------------------------------------------------------------- 
 633 //----------------------------------------------------------------------------- 
 635 static void gtk_menu_hilight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 637     if (g_isIdle
) wxapp_install_idle_handler(); 
 639     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 641     wxASSERT( id 
!= -1 ); // should find it! 
 643     if (!menu
->IsEnabled(id
)) 
 646     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, id 
); 
 647     event
.SetEventObject( menu 
); 
 649     if (menu
->GetEventHandler()->ProcessEvent(event
)) 
 652     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 653     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 656 //----------------------------------------------------------------------------- 
 658 //----------------------------------------------------------------------------- 
 660 static void gtk_menu_nolight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 662     if (g_isIdle
) wxapp_install_idle_handler(); 
 664     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 666     wxASSERT( id 
!= -1 ); // should find it! 
 668     if (!menu
->IsEnabled(id
)) 
 671     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, -1 ); 
 672     event
.SetEventObject( menu 
); 
 674     if (menu
->GetEventHandler()->ProcessEvent(event
)) 
 677     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 679         win
->GetEventHandler()->ProcessEvent( event 
); 
 682 //----------------------------------------------------------------------------- 
 684 //----------------------------------------------------------------------------- 
 686 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxMenuItemBase
) 
 688 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 690                                 const wxString
& name
, 
 691                                 const wxString
& help
, 
 695     return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
); 
 698 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 700                        const wxString
& text
, 
 701                        const wxString
& help
, 
 706     m_isCheckable 
= isCheckable
; 
 710     m_parentMenu 
= parentMenu
; 
 713     m_labelWidget 
= (GtkWidget 
*) NULL
; 
 714     m_menuItem 
= (GtkWidget 
*) NULL
; 
 719 wxMenuItem::~wxMenuItem() 
 721    // don't delete menu items, the menus take care of that 
 724 // return the menu item text without any menu accels 
 726 wxString 
wxMenuItemBase::GetLabelFromText(const wxString
& text
) 
 730     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 732         if ( *pc 
== wxT('_')  ) 
 734             // wxGTK escapes "xxx_xxx" to "xxx__xxx" 
 740         if ( *pc 
== wxT('&') ) 
 752 void wxMenuItem::SetText( const wxString
& str 
) 
 760           label 
= (GtkLabel
*) m_labelWidget
; 
 762           label 
= GTK_LABEL( GTK_BIN(m_menuItem
)->child 
); 
 765         gtk_label_set( label
, m_text
.mb_str()); 
 767         /* reparse key accel */ 
 768         (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() ); 
 769         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 773 // it's valid for this function to be called even if m_menuItem == NULL 
 774 void wxMenuItem::DoSetText( const wxString
& str 
) 
 776     /* '\t' is the deliminator indicating a hot key */ 
 778     const wxChar 
*pc 
= str
; 
 779     for (; (*pc 
!= wxT('\0')) && (*pc 
!= wxT('\t')); pc
++ ) 
 783 #if (GTK_MINOR_VERSION > 0) 
 786         else if ( *pc 
== wxT('_') )    // escape underscores 
 790         else if (*pc 
== wxT('/'))      /* we have to filter out slashes ... */ 
 792             m_text 
<< wxT('\\');  /* ... and replace them with back slashes */ 
 799     /* only GTK 1.2 knows about hot keys */ 
 801 #if (GTK_MINOR_VERSION > 0) 
 812 wxAcceleratorEntry 
*wxMenuItem::GetAccel() const 
 817         return (wxAcceleratorEntry 
*)NULL
; 
 820     // as wxGetAccelFromString() looks for TAB, insert a dummy one here 
 822     label 
<< wxT('\t') << GetHotKey(); 
 824     return wxGetAccelFromString(label
); 
 827 #endif // wxUSE_ACCEL 
 829 void wxMenuItem::Check( bool check 
) 
 831     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 833     wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") ) 
 835     if (check 
== m_isChecked
) 
 838     wxMenuItemBase::Check( check 
); 
 839     gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check 
); 
 842 void wxMenuItem::Enable( bool enable 
) 
 844     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 846     gtk_widget_set_sensitive( m_menuItem
, enable 
); 
 847     wxMenuItemBase::Enable( enable 
); 
 850 bool wxMenuItem::IsChecked() const 
 852     wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") ); 
 854     wxCHECK_MSG( IsCheckable(), FALSE
, 
 855                  wxT("can't get state of uncheckable item!") ); 
 857     return ((GtkCheckMenuItem
*)m_menuItem
)->active 
!= 0; 
 860 wxString 
wxMenuItem::GetFactoryPath() const 
 862     /* in order to get the pointer to the item we need the item text 
 863        _without_ underscores */ 
 864     wxString 
path( wxT("<main>/") ); 
 866     for ( const wxChar 
*pc 
= m_text
.c_str(); *pc
; pc
++ ) 
 868         if ( *pc 
== wxT('_') || *pc 
== wxT('&') ) 
 870             // remove '_' and '&' unconditionally 
 880 //----------------------------------------------------------------------------- 
 882 //----------------------------------------------------------------------------- 
 884 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
) 
 888 #if (GTK_MINOR_VERSION > 0) 
 889     m_accel 
= gtk_accel_group_new(); 
 890     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel 
); 
 891     m_menu 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 893     m_menu 
= gtk_menu_new();  // Do not show! 
 896     m_owner 
= (GtkWidget
*) NULL
; 
 898 #if (GTK_MINOR_VERSION > 0) 
 899     /* Tearoffs are entries, just like separators. So if we want this 
 900        menu to be a tear-off one, we just append a tearoff entry 
 902     if(m_style 
& wxMENU_TEAROFF
) 
 904        GtkItemFactoryEntry entry
; 
 905        entry
.path 
= "/tearoff"; 
 906        entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 907        entry
.callback_action 
= 0; 
 908        entry
.item_type 
= "<Tearoff>"; 
 909        entry
.accelerator 
= (gchar
*) NULL
; 
 910        gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 911        //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" ); 
 915     // append the title as the very first entry if we have it 
 927    gtk_widget_destroy( m_menu 
); 
 929    gtk_object_unref( GTK_OBJECT(m_factory
) ); 
 932 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
) 
 936     bool appended 
= FALSE
; 
 938     if ( mitem
->IsSeparator() ) 
 940 #if (GTK_MINOR_VERSION > 0) 
 941         GtkItemFactoryEntry entry
; 
 943         entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 944         entry
.callback_action 
= 0; 
 945         entry
.item_type 
= "<Separator>"; 
 946         entry
.accelerator 
= (gchar
*) NULL
; 
 948         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 950         /* this will be wrong for more than one separator. do we care? */ 
 951         menuItem 
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" ); 
 953         menuItem 
= gtk_menu_item_new(); 
 954 #endif // GTK 1.2/1.0 
 956     else if ( mitem
->IsSubMenu() ) 
 958 #if (GTK_MINOR_VERSION > 0) 
 959         /* text has "_" instead of "&" after mitem->SetText() */ 
 960         wxString 
text( mitem
->GetText() ); 
 962         /* local buffer in multibyte form */ 
 965         strcat( buf
, text
.mb_str() ); 
 967         GtkItemFactoryEntry entry
; 
 969         entry
.callback 
= (GtkItemFactoryCallback
) 0; 
 970         entry
.callback_action 
= 0; 
 971         entry
.item_type 
= "<Branch>"; 
 972         entry
.accelerator 
= (gchar
*) NULL
; 
 974         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 976         wxString 
path( mitem
->GetFactoryPath() ); 
 977         menuItem 
= gtk_item_factory_get_item( m_factory
, path
.mb_str() ); 
 979         menuItem 
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str()); 
 980 #endif // GTK 1.2/1.0 
 982         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
 984         // if adding a submenu to a menu already existing in the menu bar, we 
 985         // must set invoking window to allow processing events from this 
 987         if ( m_invokingWindow 
) 
 988             wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
); 
 990     else if (mitem
->GetBitmap().Ok()) // An item with bitmap 
 992         wxString 
text( mitem
->GetText() ); 
 993         const wxBitmap 
*bitmap 
= &mitem
->GetBitmap(); 
 995         menuItem 
= gtk_pixmap_menu_item_new (); 
 996         GtkWidget 
*label 
= gtk_accel_label_new (text
.mb_str()); 
 997         gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5); 
 998         gtk_container_add (GTK_CONTAINER (menuItem
), label
); 
 999         guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), text
.mb_str() ); 
1000         gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
); 
1001         if (accel_key 
!= GDK_VoidSymbol
) 
1003             gtk_widget_add_accelerator (menuItem
, 
1005                                         gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)), 
1009         gtk_widget_show (label
); 
1011         mitem
->SetLabelWidget(label
); 
1013         GtkWidget
* pixmap 
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
); 
1014         gtk_widget_show(pixmap
); 
1015         gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem 
), pixmap
); 
1017         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1018                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1020         gtk_menu_append( GTK_MENU(m_menu
), menuItem 
); 
1021         gtk_widget_show( menuItem 
); 
1023         appended 
= TRUE
; // We've done this, don't do it again 
1025     else // a normal item 
1027 #if (GTK_MINOR_VERSION > 0) 
1028         /* text has "_" instead of "&" after mitem->SetText() */ 
1029         wxString 
text( mitem
->GetText() ); 
1031         /* local buffer in multibyte form */ 
1034         strcat( buf
, text
.mb_str() ); 
1036         GtkItemFactoryEntry entry
; 
1038         entry
.callback 
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
; 
1039         entry
.callback_action 
= 0; 
1040         if ( mitem
->IsCheckable() ) 
1041             entry
.item_type 
= "<CheckItem>"; 
1043             entry
.item_type 
= "<Item>"; 
1044         entry
.accelerator 
= (gchar
*) NULL
; 
1047         // due to an apparent bug in GTK+, we have to use a static buffer here - 
1048         // otherwise GTK+ 1.2.2 manages to override the memory we pass to it 
1050         static char s_accel
[50]; // must be big enougg 
1051         wxString 
tmp( GetHotKey(*mitem
) ); 
1052         strncpy(s_accel
, tmp
.mb_str(), WXSIZEOF(s_accel
)); 
1053         entry
.accelerator 
= s_accel
; 
1054 #else // !wxUSE_ACCEL 
1055         entry
.accelerator 
= (char*) NULL
; 
1056 #endif // wxUSE_ACCEL/!wxUSE_ACCEL 
1058         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
1060         wxString 
path( mitem
->GetFactoryPath() ); 
1061         menuItem 
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() ); 
1063         menuItem 
= checkable 
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() ) 
1064                              : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() ); 
1066         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1067                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1069 #endif // GTK+ 1.2/1.0 
1072     if ( !mitem
->IsSeparator() ) 
1074         gtk_signal_connect( GTK_OBJECT(menuItem
), "select", 
1075                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
), 
1078         gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect", 
1079                             GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
), 
1083 #if GTK_MINOR_VERSION == 0 
1086         gtk_menu_append( GTK_MENU(m_menu
), menuItem 
); 
1087         gtk_widget_show( menuItem 
); 
1091     mitem
->SetMenuItem(menuItem
); 
1096 bool wxMenu::DoAppend(wxMenuItem 
*mitem
) 
1098     return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
); 
1101 bool wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
1103     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
1107     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
1108     // of version 1.2.6), so we first append the item and then change its 
1110     if ( !GtkAppend(item
) ) 
1113     if ( m_style 
& wxMENU_TEAROFF 
) 
1115         // change the position as the first item is the tear-off marker 
1119     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
1120     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
1121     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
1122     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
1126     // this should be easy to do... 
1127     wxFAIL_MSG( wxT("not implemented") ); 
1130 #endif // GTK 1.2/1.0 
1133 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
1135     if ( !wxMenuBase::DoRemove(item
) ) 
1136         return (wxMenuItem 
*)NULL
; 
1138     // TODO: this code doesn't delete the item factory item and this seems 
1139     //       impossible as of GTK 1.2.6. 
1140     gtk_widget_destroy( item
->GetMenuItem() ); 
1145 int wxMenu::FindMenuIdByMenuItem( GtkWidget 
*menuItem 
) const 
1147     wxNode 
*node 
= m_items
.First(); 
1150         wxMenuItem 
*item 
= (wxMenuItem
*)node
->Data(); 
1151         if (item
->GetMenuItem() == menuItem
) 
1152            return item
->GetId(); 
1153         node 
= node
->Next(); 
1159 // ---------------------------------------------------------------------------- 
1161 // ---------------------------------------------------------------------------- 
1163 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL 
1164 static wxString 
GetHotKey( const wxMenuItem
& item 
) 
1168     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
1171         int flags 
= accel
->GetFlags(); 
1172         if ( flags 
& wxACCEL_ALT 
) 
1173             hotkey 
+= wxT("<alt>"); 
1174         if ( flags 
& wxACCEL_CTRL 
) 
1175             hotkey 
+= wxT("<control>"); 
1176         if ( flags 
& wxACCEL_SHIFT 
) 
1177             hotkey 
+= wxT("<shift>"); 
1179         int code 
= accel
->GetKeyCode(); 
1194                 hotkey 
<< wxT('F') << code 
- WXK_F1 
+ 1; 
1197                 // GTK seems to use XStringToKeySym here 
1198             case WXK_NUMPAD_INSERT
: 
1199                 hotkey 
<< wxT("KP_Insert" ); 
1201             case WXK_NUMPAD_DELETE
: 
1202                 hotkey 
<< wxT("KP_Delete" ); 
1205                 hotkey 
<< wxT("Insert" ); 
1208                 hotkey 
<< wxT("Delete" ); 
1211                 // if there are any other keys wxGetAccelFromString() may return, 
1212                 // we should process them here 
1215                 if ( wxIsalnum(code
) ) 
1217                     hotkey 
<< (wxChar
)code
; 
1222                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1230 #endif // wxUSE_ACCEL 
1233 //----------------------------------------------------------------------------- 
1234 // substitute for missing GtkPixmapMenuItem 
1235 //----------------------------------------------------------------------------- 
1238  * Copyright (C) 1998, 1999, 2000 Free Software Foundation 
1239  * All rights reserved. 
1241  * This file is part of the Gnome Library. 
1243  * The Gnome Library is free software; you can redistribute it and/or 
1244  * modify it under the terms of the GNU Library General Public License as 
1245  * published by the Free Software Foundation; either version 2 of the 
1246  * License, or (at your option) any later version. 
1248  * The Gnome Library is distributed in the hope that it will be useful, 
1249  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
1250  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
1251  * Library General Public License for more details. 
1253  * You should have received a copy of the GNU Library General Public 
1254  * License along with the Gnome Library; see the file COPYING.LIB.  If not, 
1255  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
1256  * Boston, MA 02111-1307, USA. 
1262 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */ 
1264 #include <gtk/gtkaccellabel.h> 
1265 #include <gtk/gtksignal.h> 
1266 #include <gtk/gtkmenuitem.h> 
1267 #include <gtk/gtkmenu.h> 
1268 #include <gtk/gtkcontainer.h> 
1270 static void gtk_pixmap_menu_item_class_init    (GtkPixmapMenuItemClass 
*klass
); 
1271 static void gtk_pixmap_menu_item_init          (GtkPixmapMenuItem      
*menu_item
); 
1272 static void gtk_pixmap_menu_item_draw          (GtkWidget              
*widget
, 
1273                                                 GdkRectangle           
*area
); 
1274 static gint 
gtk_pixmap_menu_item_expose        (GtkWidget              
*widget
, 
1275                                                 GdkEventExpose         
*event
); 
1277 /* we must override the following functions */ 
1279 static void gtk_pixmap_menu_item_map           (GtkWidget        
*widget
); 
1280 static void gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1281                                                 GtkAllocation    
*allocation
); 
1282 static void gtk_pixmap_menu_item_forall        (GtkContainer    
*container
, 
1283                                                 gboolean         include_internals
, 
1284                                                 GtkCallback      callback
, 
1285                                                 gpointer         callback_data
); 
1286 static void gtk_pixmap_menu_item_size_request  (GtkWidget        
*widget
, 
1287                                                 GtkRequisition   
*requisition
); 
1288 static void gtk_pixmap_menu_item_remove        (GtkContainer 
*container
, 
1291 static void changed_have_pixmap_status         (GtkPixmapMenuItem 
*menu_item
); 
1293 static GtkMenuItemClass 
*parent_class 
= NULL
; 
1295 #define BORDER_SPACING  3 
1296 #define PMAP_WIDTH 20 
1299 gtk_pixmap_menu_item_get_type (void) 
1301   static GtkType pixmap_menu_item_type 
= 0; 
1303   if (!pixmap_menu_item_type
) 
1305       GtkTypeInfo pixmap_menu_item_info 
= 
1307         "GtkPixmapMenuItem", 
1308         sizeof (GtkPixmapMenuItem
), 
1309         sizeof (GtkPixmapMenuItemClass
), 
1310         (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
, 
1311         (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
, 
1312         /* reserved_1 */ NULL
, 
1313         /* reserved_2 */ NULL
, 
1314         (GtkClassInitFunc
) NULL
, 
1317       pixmap_menu_item_type 
= gtk_type_unique (gtk_menu_item_get_type (),  
1318                                                &pixmap_menu_item_info
); 
1321   return pixmap_menu_item_type
; 
1325  * gtk_pixmap_menu_item_new 
1327  * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()  
1328  * to set the pixmap wich is displayed at the left side. 
1331  * &GtkWidget pointer to new menu item 
1335 gtk_pixmap_menu_item_new (void) 
1337   return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ())); 
1341 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass 
*klass
) 
1343   GtkObjectClass 
*object_class
; 
1344   GtkWidgetClass 
*widget_class
; 
1345   GtkMenuItemClass 
*menu_item_class
; 
1346   GtkContainerClass 
*container_class
; 
1348   object_class 
= (GtkObjectClass
*) klass
; 
1349   widget_class 
= (GtkWidgetClass
*) klass
; 
1350   menu_item_class 
= (GtkMenuItemClass
*) klass
; 
1351   container_class 
= (GtkContainerClass
*) klass
; 
1353   parent_class 
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ()); 
1355   widget_class
->draw 
= gtk_pixmap_menu_item_draw
; 
1356   widget_class
->expose_event 
= gtk_pixmap_menu_item_expose
; 
1357   widget_class
->map 
= gtk_pixmap_menu_item_map
; 
1358   widget_class
->size_allocate 
= gtk_pixmap_menu_item_size_allocate
; 
1359   widget_class
->size_request 
= gtk_pixmap_menu_item_size_request
; 
1361   container_class
->forall 
= gtk_pixmap_menu_item_forall
; 
1362   container_class
->remove 
= gtk_pixmap_menu_item_remove
; 
1364   klass
->orig_toggle_size 
= menu_item_class
->toggle_size
; 
1365   klass
->have_pixmap_count 
= 0; 
1369 gtk_pixmap_menu_item_init (GtkPixmapMenuItem 
*menu_item
) 
1373   mi 
= GTK_MENU_ITEM (menu_item
); 
1375   menu_item
->pixmap 
= NULL
; 
1379 gtk_pixmap_menu_item_draw (GtkWidget    
*widget
, 
1382   g_return_if_fail (widget 
!= NULL
); 
1383   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1384   g_return_if_fail (area 
!= NULL
); 
1386   if (GTK_WIDGET_CLASS (parent_class
)->draw
) 
1387     (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
); 
1389   if (GTK_WIDGET_DRAWABLE (widget
) &&  
1390       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1391     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1396 gtk_pixmap_menu_item_expose (GtkWidget      
*widget
, 
1397                              GdkEventExpose 
*event
) 
1399   g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
1400   g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
); 
1401   g_return_val_if_fail (event 
!= NULL
, FALSE
); 
1403   if (GTK_WIDGET_CLASS (parent_class
)->expose_event
) 
1404     (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
); 
1406   if (GTK_WIDGET_DRAWABLE (widget
) &&  
1407       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1408     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1415  * gtk_pixmap_menu_item_set_pixmap 
1416  * @menu_item: Pointer to the pixmap menu item 
1417  * @pixmap: Pointer to a pixmap widget 
1419  * Set the pixmap of the menu item. 
1424 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem 
*menu_item
, 
1427   g_return_if_fail (menu_item 
!= NULL
); 
1428   g_return_if_fail (pixmap 
!= NULL
); 
1429   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
)); 
1430   g_return_if_fail (GTK_IS_WIDGET (pixmap
)); 
1431   g_return_if_fail (menu_item
->pixmap 
== NULL
); 
1433   gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
)); 
1434   menu_item
->pixmap 
= pixmap
; 
1436   if (GTK_WIDGET_REALIZED (pixmap
->parent
) && 
1437       !GTK_WIDGET_REALIZED (pixmap
)) 
1438     gtk_widget_realize (pixmap
); 
1440   if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {       
1441     if (GTK_WIDGET_MAPPED (pixmap
->parent
) && 
1442         GTK_WIDGET_VISIBLE(pixmap
) && 
1443         !GTK_WIDGET_MAPPED (pixmap
)) 
1444       gtk_widget_map (pixmap
); 
1447   changed_have_pixmap_status(menu_item
); 
1449   if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
)) 
1450     gtk_widget_queue_resize (pixmap
); 
1454 gtk_pixmap_menu_item_map (GtkWidget 
*widget
) 
1456   GtkPixmapMenuItem 
*menu_item
; 
1458   g_return_if_fail (widget 
!= NULL
); 
1459   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1461   menu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1463   GTK_WIDGET_CLASS(parent_class
)->map(widget
); 
1465   if (menu_item
->pixmap 
&& 
1466       GTK_WIDGET_VISIBLE (menu_item
->pixmap
) && 
1467       !GTK_WIDGET_MAPPED (menu_item
->pixmap
)) 
1468     gtk_widget_map (menu_item
->pixmap
); 
1472 gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1473                                     GtkAllocation    
*allocation
) 
1475   GtkPixmapMenuItem 
*pmenu_item
; 
1477   pmenu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1479   if (pmenu_item
->pixmap 
&& GTK_WIDGET_VISIBLE(pmenu_item
)) 
1481       GtkAllocation child_allocation
; 
1484       border_width 
= GTK_CONTAINER (widget
)->border_width
; 
1486       child_allocation
.width 
= pmenu_item
->pixmap
->requisition
.width
; 
1487       child_allocation
.height 
= pmenu_item
->pixmap
->requisition
.height
; 
1488       child_allocation
.x 
= border_width 
+ BORDER_SPACING
; 
1489       child_allocation
.y 
= (border_width 
+ BORDER_SPACING
 
1490                             + (((allocation
->height 
- child_allocation
.height
) - child_allocation
.x
) 
1491                                / 2)); /* center pixmaps vertically */ 
1492       gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
); 
1495   if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
) 
1496     GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
); 
1500 gtk_pixmap_menu_item_forall (GtkContainer    
*container
, 
1501                              gboolean         include_internals
, 
1502                              GtkCallback      callback
, 
1503                              gpointer         callback_data
) 
1505   GtkPixmapMenuItem 
*menu_item
; 
1507   g_return_if_fail (container 
!= NULL
); 
1508   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1509   g_return_if_fail (callback 
!= NULL
); 
1511   menu_item 
= GTK_PIXMAP_MENU_ITEM (container
); 
1513   if (menu_item
->pixmap
) 
1514     (* callback
) (menu_item
->pixmap
, callback_data
); 
1516   GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
, 
1517                                             callback
,callback_data
); 
1521 gtk_pixmap_menu_item_size_request (GtkWidget      
*widget
, 
1522                                    GtkRequisition 
*requisition
) 
1524   GtkPixmapMenuItem 
*menu_item
; 
1525   GtkRequisition req 
= {0, 0}; 
1527   g_return_if_fail (widget 
!= NULL
); 
1528   g_return_if_fail (GTK_IS_MENU_ITEM (widget
)); 
1529   g_return_if_fail (requisition 
!= NULL
); 
1531   GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
); 
1533   menu_item 
= GTK_PIXMAP_MENU_ITEM (widget
); 
1535   if (menu_item
->pixmap
) 
1536     gtk_widget_size_request(menu_item
->pixmap
, &req
); 
1538   requisition
->height 
= MAX(req
.height 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
, (unsigned int) requisition
->height
); 
1539   requisition
->width 
+= (req
.width 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
); 
1543 gtk_pixmap_menu_item_remove (GtkContainer 
*container
, 
1547   gboolean widget_was_visible
; 
1549   g_return_if_fail (container 
!= NULL
); 
1550   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1551   g_return_if_fail (child 
!= NULL
); 
1552   g_return_if_fail (GTK_IS_WIDGET (child
)); 
1554   bin 
= GTK_BIN (container
); 
1555   g_return_if_fail ((bin
->child 
== child 
||  
1556                      (GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
== child
))); 
1558   widget_was_visible 
= GTK_WIDGET_VISIBLE (child
); 
1560   gtk_widget_unparent (child
); 
1561   if (bin
->child 
== child
) 
1564     GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
= NULL
; 
1565     changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
)); 
1568   if (widget_was_visible
) 
1569     gtk_widget_queue_resize (GTK_WIDGET (container
)); 
1573 /* important to only call this if there was actually a _change_ in pixmap == NULL */ 
1575 changed_have_pixmap_status (GtkPixmapMenuItem 
*menu_item
) 
1577   if (menu_item
->pixmap 
!= NULL
) { 
1578     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
+= 1; 
1580     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 1) { 
1581       /* Install pixmap toggle size */ 
1582       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
); 
1585     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
-= 1; 
1587     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 0) { 
1588       /* Install normal toggle size */ 
1589       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;     
1593   /* Note that we actually need to do this for _all_ GtkPixmapMenuItem 
1594      whenever the klass->toggle_size changes; but by doing it anytime 
1595      this function is called, we get the same effect, just because of 
1596      how the preferences option to show pixmaps works. Bogus, broken. 
1598   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))  
1599     gtk_widget_queue_resize(GTK_WIDGET(menu_item
));