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_window_add_accel_group((o), (g)) 
  37     #define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g)) 
  38     #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m) 
  40     #define ACCEL_OBJECT        GtkWindow 
  41     #define ACCEL_OBJECTS(a)    (a)->acceleratables 
  42     #define ACCEL_OBJ_CAST(obj) ((GtkWindow*) 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(); 
  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('&')) 
 128             if ( *pc 
== wxT('_') ) 
 130                 // underscores must be doubled to prevent them from being 
 131                 // interpreted as accelerator character prefix by GTK 
 140     // wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() ); 
 145 //----------------------------------------------------------------------------- 
 146 // activate message from GTK 
 147 //----------------------------------------------------------------------------- 
 149 static void gtk_menu_open_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 151     if (g_isIdle
) wxapp_install_idle_handler(); 
 153     wxMenuEvent 
event( wxEVT_MENU_OPEN
, -1, menu 
); 
 154     event
.SetEventObject( menu 
); 
 156     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 157     if (handler 
&& handler
->ProcessEvent(event
)) 
 160     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 161     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 164 //----------------------------------------------------------------------------- 
 166 //----------------------------------------------------------------------------- 
 168 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
) 
 170 wxMenuBar::wxMenuBar( long style 
) 
 172     // the parent window is known after wxFrame::SetMenu() 
 173     m_needParent 
= FALSE
; 
 175     m_invokingWindow 
= (wxWindow
*) NULL
; 
 177     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 178         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") )) 
 180         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 184     m_menubar 
= gtk_menu_bar_new(); 
 186     m_accel 
= gtk_accel_group_new(); 
 189     if (style 
& wxMB_DOCKABLE
) 
 191         m_widget 
= gtk_handle_box_new(); 
 192         gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) ); 
 193         gtk_widget_show( GTK_WIDGET(m_menubar
) ); 
 197         m_widget 
= GTK_WIDGET(m_menubar
); 
 205 wxMenuBar::wxMenuBar() 
 207     // the parent window is known after wxFrame::SetMenu() 
 208     m_needParent 
= FALSE
; 
 210     m_invokingWindow 
= (wxWindow
*) NULL
; 
 212     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 213         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") )) 
 215         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 219     m_menubar 
= gtk_menu_bar_new(); 
 221     m_accel 
= gtk_accel_group_new(); 
 224     m_widget 
= GTK_WIDGET(m_menubar
); 
 231 wxMenuBar::~wxMenuBar() 
 235 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 237     menu
->SetInvokingWindow( (wxWindow
*) NULL 
); 
 239     wxWindow 
*top_frame 
= win
; 
 240     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 241         top_frame 
= top_frame
->GetParent(); 
 244     // support for native hot keys 
 245     gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) ); 
 248     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 251         wxMenuItem 
*menuitem 
= node
->GetData(); 
 252         if (menuitem
->IsSubMenu()) 
 253             wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 254         node 
= node
->GetNext(); 
 258 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 260     menu
->SetInvokingWindow( win 
); 
 262     wxWindow 
*top_frame 
= win
; 
 263     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 264         top_frame 
= top_frame
->GetParent(); 
 266     // support for native hot keys 
 267     ACCEL_OBJECT 
*obj 
= ACCEL_OBJ_CAST(top_frame
->m_widget
); 
 268     if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj 
) ) 
 269         gtk_accel_group_attach( menu
->m_accel
, obj 
); 
 271     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 274         wxMenuItem 
*menuitem 
= node
->GetData(); 
 275         if (menuitem
->IsSubMenu()) 
 276             wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 277         node 
= node
->GetNext(); 
 281 void wxMenuBar::SetInvokingWindow( wxWindow 
*win 
) 
 283     m_invokingWindow 
= win
; 
 284     wxWindow 
*top_frame 
= win
; 
 285     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 286         top_frame 
= top_frame
->GetParent(); 
 289     // support for native key accelerators indicated by underscroes 
 290     ACCEL_OBJECT 
*obj 
= ACCEL_OBJ_CAST(top_frame
->m_widget
); 
 291     if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj 
) ) 
 292         gtk_accel_group_attach( m_accel
, obj 
); 
 295     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 298         wxMenu 
*menu 
= node
->GetData(); 
 299         wxMenubarSetInvokingWindow( menu
, win 
); 
 300         node 
= node
->GetNext(); 
 304 void wxMenuBar::UnsetInvokingWindow( wxWindow 
*win 
) 
 306     m_invokingWindow 
= (wxWindow
*) NULL
; 
 307     wxWindow 
*top_frame 
= win
; 
 308     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 309         top_frame 
= top_frame
->GetParent(); 
 312     // support for native key accelerators indicated by underscroes 
 313     gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) ); 
 316     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 319         wxMenu 
*menu 
= node
->GetData(); 
 320         wxMenubarUnsetInvokingWindow( menu
, win 
); 
 321         node 
= node
->GetNext(); 
 325 bool wxMenuBar::Append( wxMenu 
*menu
, const wxString 
&title 
) 
 327     if ( !wxMenuBarBase::Append( menu
, title 
) ) 
 330     return GtkAppend(menu
, title
); 
 333 bool wxMenuBar::GtkAppend(wxMenu 
*menu
, const wxString
& title
) 
 335     wxString 
str( wxReplaceUnderscore( title 
) ); 
 337     // This doesn't have much effect right now. 
 338     menu
->SetTitle( str 
); 
 340     // The "m_owner" is the "menu item" 
 342     menu
->m_owner 
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str 
) ); 
 344     menu
->m_owner 
= gtk_menu_item_new_with_label( wxGTK_CONV( str 
) ); 
 345     GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child 
); 
 347     gtk_label_set_text( label
, wxGTK_CONV( str 
) ); 
 349     guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str 
) ); 
 350     if (accel_key 
!= GDK_VoidSymbol
) 
 352         gtk_widget_add_accelerator (menu
->m_owner
, 
 354                                         m_accel
,//gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)), 
 361     gtk_widget_show( menu
->m_owner 
); 
 363     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 365     gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner 
); 
 367     gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate", 
 368                         GTK_SIGNAL_FUNC(gtk_menu_open_callback
), 
 371     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
 372     // addings menu later on. 
 373     if (m_invokingWindow
) 
 375         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 377             // OPTIMISE ME:  we should probably cache this, or pass it 
 378             //               directly, but for now this is a minimal 
 379             //               change to validate the new dynamic sizing. 
 380             //               see (and refactor :) similar code in Remove 
 383         wxFrame 
*frame 
= wxDynamicCast( m_invokingWindow
, wxFrame 
); 
 386             frame
->UpdateMenuBarSize(); 
 392 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 394     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 399     if ( !GtkAppend(menu
, title
) ) 
 405 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 407     // remove the old item and insert a new one 
 408     wxMenu 
*menuOld 
= Remove(pos
); 
 409     if ( menuOld 
&& !Insert(pos
, menu
, title
) ) 
 411         return (wxMenu
*) NULL
; 
 414     // either Insert() succeeded or Remove() failed and menuOld is NULL 
 418 static wxMenu 
*CopyMenu (wxMenu 
*menu
) 
 420     wxMenu 
*menucopy 
= new wxMenu (); 
 421     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 424         wxMenuItem 
*item 
= node
->GetData(); 
 425         int itemid 
= item
->GetId(); 
 426         wxString text 
= item
->GetText(); 
 427         text
.Replace(wxT("_"), wxT("&")); 
 428         wxMenu 
*submenu 
= item
->GetSubMenu(); 
 431             wxMenuItem
* itemcopy 
= new wxMenuItem(menucopy
, 
 433                                         menu
->GetHelpString(itemid
)); 
 434             itemcopy
->SetBitmap(item
->GetBitmap()); 
 435             itemcopy
->SetCheckable(item
->IsCheckable()); 
 436             menucopy
->Append(itemcopy
); 
 439           menucopy
->Append (itemid
, text
, CopyMenu(submenu
), 
 440                             menu
->GetHelpString(itemid
)); 
 442         node 
= node
->GetNext(); 
 448 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 450     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 452         return (wxMenu
*) NULL
; 
 454     wxMenu 
*menucopy 
= CopyMenu( menu 
); 
 456     // unparent calls unref() and that would delete the widget so we raise 
 457     // the ref count to 2 artificially before invoking unparent. 
 458     gtk_widget_ref( menu
->m_menu 
); 
 459     gtk_widget_unparent( menu
->m_menu 
); 
 461     gtk_widget_destroy( menu
->m_owner 
); 
 466     if (m_invokingWindow
) 
 468         // OPTIMISE ME:  see comment in GtkAppend 
 469         wxFrame 
*frame 
= wxDynamicCast( m_invokingWindow
, wxFrame 
); 
 472             frame
->UpdateMenuBarSize(); 
 478 static int FindMenuItemRecursive( const wxMenu 
*menu
, const wxString 
&menuString
, const wxString 
&itemString 
) 
 480     if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
)) 
 482         int res 
= menu
->FindItem( itemString 
); 
 483         if (res 
!= wxNOT_FOUND
) 
 487     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 490         wxMenuItem 
*item 
= node
->GetData(); 
 491         if (item
->IsSubMenu()) 
 492             return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
); 
 494         node 
= node
->GetNext(); 
 500 int wxMenuBar::FindMenuItem( const wxString 
&menuString
, const wxString 
&itemString 
) const 
 502     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 505         wxMenu 
*menu 
= node
->GetData(); 
 506         int res 
= FindMenuItemRecursive( menu
, menuString
, itemString
); 
 509         node 
= node
->GetNext(); 
 515 // Find a wxMenuItem using its id. Recurses down into sub-menus 
 516 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
) 
 518     wxMenuItem
* result 
= menu
->FindChildItem(id
); 
 520     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
 521     while ( node 
&& result 
== NULL 
) 
 523         wxMenuItem 
*item 
= node
->GetData(); 
 524         if (item
->IsSubMenu()) 
 526             result 
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id 
); 
 528         node 
= node
->GetNext(); 
 534 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu 
**menuForItem 
) const 
 536     wxMenuItem
* result 
= 0; 
 537     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
 538     while (node 
&& result 
== 0) 
 540         wxMenu 
*menu 
= node
->GetData(); 
 541         result 
= FindMenuItemByIdRecursive( menu
, id 
); 
 542         node 
= node
->GetNext(); 
 547         *menuForItem 
= result 
? result
->GetMenu() : (wxMenu 
*)NULL
; 
 553 void wxMenuBar::EnableTop( size_t pos
, bool flag 
) 
 555     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 557     wxCHECK_RET( node
, wxT("menu not found") ); 
 559     wxMenu
* menu 
= node
->GetData(); 
 562         gtk_widget_set_sensitive( menu
->m_owner
, flag 
); 
 565 wxString 
wxMenuBar::GetLabelTop( size_t pos 
) const 
 567     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 569     wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") ); 
 571     wxMenu
* menu 
= node
->GetData(); 
 574     wxString 
text( menu
->GetTitle() ); 
 575     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 577         if ( *pc 
== wxT('_') ) 
 579             // '_' is the escape character for GTK+ 
 583         // don't remove ampersands '&' since if we have them in the menu title 
 584         // it means that they were doubled to indicate "&" instead of accelerator 
 592 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label 
) 
 594     wxMenuList::compatibility_iterator node 
= m_menus
.Item( pos 
); 
 596     wxCHECK_RET( node
, wxT("menu not found") ); 
 598     wxMenu
* menu 
= node
->GetData(); 
 600     wxString 
str( wxReplaceUnderscore( label 
) ); 
 602     menu
->SetTitle( str 
); 
 606         GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child 
); 
 609         gtk_label_set( label
, wxGTK_CONV( str 
) ); 
 611         /* reparse key accel */ 
 612         (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str 
) ); 
 613         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 618 //----------------------------------------------------------------------------- 
 620 //----------------------------------------------------------------------------- 
 622 static void gtk_menu_clicked_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 625         wxapp_install_idle_handler(); 
 627     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 629     /* should find it for normal (not popup) menu */ 
 630     wxASSERT_MSG( (id 
!= -1) || (menu
->GetInvokingWindow() != NULL
), 
 631                   _T("menu item not found in gtk_menu_clicked_callback") ); 
 633     if (!menu
->IsEnabled(id
)) 
 636     wxMenuItem
* item 
= menu
->FindChildItem( id 
); 
 637     wxCHECK_RET( item
, wxT("error in menu item callback") ); 
 639     if (item
->IsCheckable()) 
 641         bool isReallyChecked 
= item
->IsChecked(), 
 642             isInternallyChecked 
= item
->wxMenuItemBase::IsChecked(); 
 644         // ensure that the internal state is always consistent with what is 
 645         // shown on the screen 
 646         item
->wxMenuItemBase::Check(isReallyChecked
); 
 648         // we must not report the events for the radio button going up nor the 
 649         // events resulting from the calls to wxMenuItem::Check() 
 650         if ( (item
->GetKind() == wxITEM_RADIO 
&& !isReallyChecked
) || 
 651              (isInternallyChecked 
== isReallyChecked
) ) 
 658     // Is this menu on a menubar?  (possibly nested) 
 659     wxFrame
* frame 
= NULL
; 
 661     while ( pm 
&& !frame 
) 
 663         if ( pm
->IsAttached() ) 
 664             frame 
= pm
->GetMenuBar()->GetFrame(); 
 665         pm 
= pm
->GetParent(); 
 668     // FIXME: why do we have to call wxFrame::GetEventHandler() directly here? 
 669     //        normally wxMenu::SendEvent() should be enough, if it doesn't work 
 670     //        in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which 
 671     //        should be fixed instead of working around it here... 
 674         // If it is attached then let the frame send the event. 
 675         // Don't call frame->ProcessCommand(id) because it toggles 
 676         // checkable items and we've already done that above. 
 677         wxCommandEvent 
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
); 
 678         commandEvent
.SetEventObject(frame
); 
 679         if (item
->IsCheckable()) 
 680             commandEvent
.SetInt(item
->IsChecked()); 
 681         commandEvent
.SetEventObject(menu
); 
 683         frame
->GetEventHandler()->ProcessEvent(commandEvent
); 
 687         // otherwise let the menu have it 
 688         menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1); 
 692 //----------------------------------------------------------------------------- 
 694 //----------------------------------------------------------------------------- 
 696 static void gtk_menu_hilight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 698     if (g_isIdle
) wxapp_install_idle_handler(); 
 700     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 702     wxASSERT( id 
!= -1 ); // should find it! 
 704     if (!menu
->IsEnabled(id
)) 
 707     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, id 
); 
 708     event
.SetEventObject( menu 
); 
 710     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 711     if (handler 
&& handler
->ProcessEvent(event
)) 
 714     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 715     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 718 //----------------------------------------------------------------------------- 
 720 //----------------------------------------------------------------------------- 
 722 static void gtk_menu_nolight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 724     if (g_isIdle
) wxapp_install_idle_handler(); 
 726     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 728     wxASSERT( id 
!= -1 ); // should find it! 
 730     if (!menu
->IsEnabled(id
)) 
 733     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, -1 ); 
 734     event
.SetEventObject( menu 
); 
 736     wxEvtHandler
* handler 
= menu
->GetEventHandler(); 
 737     if (handler 
&& handler
->ProcessEvent(event
)) 
 740     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 742         win
->GetEventHandler()->ProcessEvent( event 
); 
 745 //----------------------------------------------------------------------------- 
 747 //----------------------------------------------------------------------------- 
 749 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
) 
 751 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 753                                 const wxString
& name
, 
 754                                 const wxString
& help
, 
 758     return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
); 
 761 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 763                        const wxString
& text
, 
 764                        const wxString
& help
, 
 767           : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
) 
 772 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 774                        const wxString
& text
, 
 775                        const wxString
& help
, 
 778           : wxMenuItemBase(parentMenu
, id
, text
, help
, 
 779                            isCheckable 
? wxITEM_CHECK 
: wxITEM_NORMAL
, subMenu
) 
 784 void wxMenuItem::Init(const wxString
& text
) 
 786     m_labelWidget 
= (GtkWidget 
*) NULL
; 
 787     m_menuItem 
= (GtkWidget 
*) NULL
; 
 792 wxMenuItem::~wxMenuItem() 
 794    // don't delete menu items, the menus take care of that 
 797 // return the menu item text without any menu accels 
 799 wxString 
wxMenuItemBase::GetLabelFromText(const wxString
& text
) 
 803     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 805         if ( *pc 
== wxT('_') ) 
 807             // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx" 
 814         if ( *pc 
== wxT('\\')  ) 
 816             // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx" 
 823         if ( (*pc 
== wxT('&')) && (*(pc
+1) != wxT('&')) ) 
 826             // "&" is doubled to indicate "&" instead of accelerator 
 833     // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() ); 
 838 void wxMenuItem::SetText( const wxString
& str 
) 
 840     // Some optimization to avoid flicker 
 841     wxString oldLabel 
= m_text
; 
 842     oldLabel 
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t')); 
 843     oldLabel
.Replace(wxT("_"), wxT("")); 
 844     wxString label1 
= wxStripMenuCodes(str
.BeforeFirst('\t')); 
 845     if (oldLabel 
== label1
) 
 854             label 
= (GtkLabel
*) m_labelWidget
; 
 856             label 
= GTK_LABEL( GTK_BIN(m_menuItem
)->child 
); 
 859         gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) ); 
 862         gtk_label_set( label
, wxGTK_CONV( m_text 
) ); 
 865         (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) ); 
 866         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 871 // it's valid for this function to be called even if m_menuItem == NULL 
 872 void wxMenuItem::DoSetText( const wxString
& str 
) 
 874     // '\t' is the deliminator indicating a hot key 
 876     const wxChar 
*pc 
= str
; 
 877     while ( (*pc 
!= wxT('\0')) && (*pc 
!= wxT('\t')) ) 
 879         if ((*pc 
== wxT('&')) && (*(pc
+1) == wxT('&'))) 
 881             // "&" is doubled to indicate "&" instead of accelerator 
 885         else if (*pc 
== wxT('&')) 
 889         else if ( *pc 
== wxT('_') )    // escape underscores 
 900     // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() ); 
 913 wxAcceleratorEntry 
*wxMenuItem::GetAccel() const 
 918         return (wxAcceleratorEntry 
*)NULL
; 
 921     // as wxGetAccelFromString() looks for TAB, insert a dummy one here 
 923     label 
<< wxT('\t') << GetHotKey(); 
 925     return wxGetAccelFromString(label
); 
 928 #endif // wxUSE_ACCEL 
 930 void wxMenuItem::Check( bool check 
) 
 932     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 934     if (check 
== m_isChecked
) 
 937     wxMenuItemBase::Check( check 
); 
 943             gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check 
); 
 947             wxFAIL_MSG( _T("can't check this item") ); 
 951 void wxMenuItem::Enable( bool enable 
) 
 953     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 955     gtk_widget_set_sensitive( m_menuItem
, enable 
); 
 956     wxMenuItemBase::Enable( enable 
); 
 959 bool wxMenuItem::IsChecked() const 
 961     wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") ); 
 963     wxCHECK_MSG( IsCheckable(), FALSE
, 
 964                  wxT("can't get state of uncheckable item!") ); 
 966     return ((GtkCheckMenuItem
*)m_menuItem
)->active 
!= 0; 
 969 //----------------------------------------------------------------------------- 
 971 //----------------------------------------------------------------------------- 
 973 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
) 
 977     m_accel 
= gtk_accel_group_new(); 
 978     m_menu 
= gtk_menu_new(); 
 980     m_owner 
= (GtkWidget
*) NULL
; 
 982     // Tearoffs are entries, just like separators. So if we want this 
 983     // menu to be a tear-off one, we just append a tearoff entry 
 985     if(m_style 
& wxMENU_TEAROFF
) 
 987                 GtkWidget 
*tearoff 
= gtk_tearoff_menu_item_new(); 
 989                 gtk_menu_append(GTK_MENU(m_menu
), tearoff
); 
 994     // append the title as the very first entry if we have it 
1004    WX_CLEAR_LIST(wxMenuItemList
, m_items
); 
1006    if ( GTK_IS_WIDGET( m_menu 
)) 
1007        gtk_widget_destroy( m_menu 
); 
1010 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
) 
1012     GtkWidget 
*menuItem
; 
1014     if ( mitem
->IsSeparator() ) 
1017         menuItem 
= gtk_separator_menu_item_new(); 
1020         menuItem 
= gtk_menu_item_new(); 
1022         gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
); 
1025     else if ( mitem
->IsSubMenu() ) 
1027         // text has "_" instead of "&" after mitem->SetText() 
1028         wxString 
text( mitem
->GetText() ); 
1031         menuItem 
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text 
) ); 
1033         menuItem 
= gtk_menu_item_new_with_label( wxGTK_CONV( text 
) ); 
1034         GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menuItem
)->child 
); 
1036         gtk_label_set_text( label
, wxGTK_CONV( text 
) ); 
1037         // reparse key accel 
1038         guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1039         if (accel_key 
!= GDK_VoidSymbol
) 
1041             gtk_widget_add_accelerator (menuItem
, 
1043                                         gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)), 
1050         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
1051         gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
); 
1053         gtk_widget_show( mitem
->GetSubMenu()->m_menu 
); 
1055         // if adding a submenu to a menu already existing in the menu bar, we 
1056         // must set invoking window to allow processing events from this 
1058         if ( m_invokingWindow 
) 
1059             wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
); 
1063     else if (mitem
->GetBitmap().Ok()) 
1065         wxString text 
= mitem
->GetText(); 
1066         const wxBitmap 
*bitmap 
= &mitem
->GetBitmap(); 
1067         GdkPixmap 
*gdk_pixmap 
= bitmap
->GetPixmap(); 
1068         GdkBitmap 
*gdk_bitmap 
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
; 
1071         menuItem 
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text 
) ); 
1073         GtkWidget 
*image 
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap 
); 
1074         gtk_widget_show(image
); 
1076         gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image 
); 
1078         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1079                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1082         gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
); 
1085         menuItem 
= gtk_pixmap_menu_item_new (); 
1086         GtkWidget 
*label 
= gtk_accel_label_new ( wxGTK_CONV( text 
) ); 
1087         gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5); 
1088         gtk_container_add (GTK_CONTAINER (menuItem
), label
); 
1090         gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
); 
1092         GdkModifierType accel_mods
; 
1094         // accelerator for the item, as specified by its label 
1095         // (ex. Ctrl+O for open) 
1096         gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
, 
1098         if (accel_key 
!= GDK_VoidSymbol
) 
1100             gtk_widget_add_accelerator (menuItem
, 
1103                                         accel_key
, accel_mods
, 
1107         // accelerator for the underlined char (ex ALT+F for the File menu) 
1108         accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1109         if (accel_key 
!= GDK_VoidSymbol
) 
1111             gtk_widget_add_accelerator (menuItem
, 
1113                                         gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)), 
1119         gtk_widget_show (label
); 
1121         mitem
->SetLabelWidget(label
); 
1123         GtkWidget
* pixmap 
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap 
); 
1124         gtk_widget_show(pixmap
); 
1125         gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem 
), pixmap
); 
1127         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1128                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1131         gtk_menu_append( GTK_MENU(m_menu
), menuItem 
); 
1132         gtk_widget_show( menuItem 
); 
1137     else // a normal item 
1139         // text has "_" instead of "&" after mitem->SetText() so don't use it 
1140         wxString 
text( mitem
->GetText() ); 
1142         switch ( mitem
->GetKind() ) 
1147                 menuItem 
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text 
) ); 
1149                 menuItem 
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text 
) ); 
1150                 GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menuItem
)->child 
); 
1152                 gtk_label_set_text( label
, wxGTK_CONV( text 
) ); 
1153                 // reparse key accel 
1154                 guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1155                 if (accel_key 
!= GDK_VoidSymbol
) 
1157                     gtk_widget_add_accelerator (menuItem
, 
1159                                                 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)), 
1171                 GSList 
*group 
= NULL
; 
1172                 if ( m_prevRadio 
== NULL 
) 
1174                     // start of a new radio group 
1176                     m_prevRadio 
= menuItem 
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text 
) ); 
1178                     m_prevRadio 
= menuItem 
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text 
) ); 
1179                     GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menuItem
)->child 
); 
1181                     gtk_label_set_text( label
, wxGTK_CONV( text 
) ); 
1182                     // reparse key accel 
1183                     guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1184                     if (accel_key 
!= GDK_VoidSymbol
) 
1186                         gtk_widget_add_accelerator (menuItem
, 
1188                                                     gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)), 
1195                 else // continue the radio group 
1198                     group 
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
)); 
1199                     m_prevRadio 
= menuItem 
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text 
) ); 
1201                     group 
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
)); 
1202                     m_prevRadio 
= menuItem 
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text 
) ); 
1203                     GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menuItem
)->child 
); 
1205                     gtk_label_set_text( label
, wxGTK_CONV( text 
) ); 
1206                     // reparse key accel 
1207                     guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1208                     if (accel_key 
!= GDK_VoidSymbol
) 
1210                         gtk_widget_add_accelerator (menuItem
, 
1212                                                     gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)), 
1222                 wxFAIL_MSG( _T("unexpected menu item kind") ); 
1228                 menuItem 
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text 
) ); 
1230                 menuItem 
= gtk_menu_item_new_with_label( wxGTK_CONV( text 
) ); 
1231                 GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menuItem
)->child 
); 
1233                 gtk_label_set_text( label
, wxGTK_CONV( text 
) ); 
1234                 // reparse key accel 
1235                 guint accel_key 
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text 
) ); 
1236                 if (accel_key 
!= GDK_VoidSymbol
) 
1238                     gtk_widget_add_accelerator (menuItem
, 
1240                                                     gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)), 
1251         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
1252                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
1255         gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
); 
1259     GdkModifierType accel_mods
; 
1260     wxCharBuffer buf 
= wxGTK_CONV( GetHotKey(*mitem
) ); 
1262     // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );  
1264     gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
); 
1267         gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),  
1275     gtk_widget_show( menuItem 
); 
1277     if ( !mitem
->IsSeparator() ) 
1279         wxASSERT_MSG( menuItem
, wxT("invalid menuitem") ); 
1281         gtk_signal_connect( GTK_OBJECT(menuItem
), "select", 
1282                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
), 
1285         gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect", 
1286                             GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
), 
1290     mitem
->SetMenuItem(menuItem
); 
1294         // This doesn't even exist! 
1295         // gtk_widget_lock_accelerators(mitem->GetMenuItem()); 
1301 wxMenuItem
* wxMenu::DoAppend(wxMenuItem 
*mitem
) 
1303     if (!GtkAppend(mitem
)) 
1306     return wxMenuBase::DoAppend(mitem
); 
1309 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
1311     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
1315     if ( !GtkAppend(item
) ) 
1321 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
1323     if ( !wxMenuBase::DoRemove(item
) ) 
1324         return (wxMenuItem 
*)NULL
; 
1326     // TODO: this code doesn't delete the item factory item and this seems 
1327     //       impossible as of GTK 1.2.6. 
1328     gtk_widget_destroy( item
->GetMenuItem() ); 
1333 int wxMenu::FindMenuIdByMenuItem( GtkWidget 
*menuItem 
) const 
1335     wxMenuItemList::compatibility_iterator node 
= m_items
.GetFirst(); 
1338         wxMenuItem 
*item 
= node
->GetData(); 
1339         if (item
->GetMenuItem() == menuItem
) 
1340            return item
->GetId(); 
1341         node 
= node
->GetNext(); 
1347 // ---------------------------------------------------------------------------- 
1349 // ---------------------------------------------------------------------------- 
1353 static wxString 
GetHotKey( const wxMenuItem
& item 
) 
1357     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
1360         int flags 
= accel
->GetFlags(); 
1361         if ( flags 
& wxACCEL_ALT 
) 
1362             hotkey 
+= wxT("<alt>"); 
1363         if ( flags 
& wxACCEL_CTRL 
) 
1364             hotkey 
+= wxT("<control>"); 
1365         if ( flags 
& wxACCEL_SHIFT 
) 
1366             hotkey 
+= wxT("<shift>"); 
1368         int code 
= accel
->GetKeyCode(); 
1383                 hotkey 
<< wxT('F') << code 
- WXK_F1 
+ 1; 
1386                 // TODO: we should use gdk_keyval_name() (a.k.a. 
1387                 //       XKeysymToString) here as well as hardcoding the keysym 
1388                 //       names this might be not portable 
1389             case WXK_NUMPAD_INSERT
: 
1390                 hotkey 
<< wxT("KP_Insert" ); 
1392             case WXK_NUMPAD_DELETE
: 
1393                 hotkey 
<< wxT("KP_Delete" ); 
1396                 hotkey 
<< wxT("Insert" ); 
1399                 hotkey 
<< wxT("Delete" ); 
1402                 hotkey 
<< wxT("Up" ); 
1405                 hotkey 
<< wxT("Down" ); 
1409                 hotkey 
<< wxT("Prior" ); 
1413                 hotkey 
<< wxT("Next" ); 
1416                 hotkey 
<< wxT("Left" ); 
1419                 hotkey 
<< wxT("Right" ); 
1422                 hotkey 
<< wxT("Home" ); 
1425                 hotkey 
<< wxT("End" ); 
1428                 hotkey 
<< wxT("Return" ); 
1431                 // if there are any other keys wxGetAccelFromString() may 
1432                 // return, we should process them here 
1437                     wxString name 
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) ); 
1445                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1454 #endif // wxUSE_ACCEL 
1457 //----------------------------------------------------------------------------- 
1458 // substitute for missing GtkPixmapMenuItem 
1459 //----------------------------------------------------------------------------- 
1464  * Copyright (C) 1998, 1999, 2000 Free Software Foundation 
1465  * All rights reserved. 
1467  * This file is part of the Gnome Library. 
1469  * The Gnome Library is free software; you can redistribute it and/or 
1470  * modify it under the terms of the GNU Library General Public License as 
1471  * published by the Free Software Foundation; either version 2 of the 
1472  * License, or (at your option) any later version. 
1474  * The Gnome Library is distributed in the hope that it will be useful, 
1475  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
1476  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
1477  * Library General Public License for more details. 
1479  * You should have received a copy of the GNU Library General Public 
1480  * License along with the Gnome Library; see the file COPYING.LIB.  If not, 
1481  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
1482  * Boston, MA 02111-1307, USA. 
1488 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */ 
1490 #include <gtk/gtkaccellabel.h> 
1491 #include <gtk/gtksignal.h> 
1492 #include <gtk/gtkmenuitem.h> 
1493 #include <gtk/gtkmenu.h> 
1494 #include <gtk/gtkcontainer.h> 
1499 static void gtk_pixmap_menu_item_class_init    (GtkPixmapMenuItemClass 
*klass
); 
1500 static void gtk_pixmap_menu_item_init          (GtkPixmapMenuItem      
*menu_item
); 
1501 static void gtk_pixmap_menu_item_draw          (GtkWidget              
*widget
, 
1502                                                 GdkRectangle           
*area
); 
1503 static gint 
gtk_pixmap_menu_item_expose        (GtkWidget              
*widget
, 
1504                                                 GdkEventExpose         
*event
); 
1506 /* we must override the following functions */ 
1508 static void gtk_pixmap_menu_item_map           (GtkWidget        
*widget
); 
1509 static void gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1510                                                 GtkAllocation    
*allocation
); 
1511 static void gtk_pixmap_menu_item_forall        (GtkContainer    
*container
, 
1512                                                 gboolean         include_internals
, 
1513                                                 GtkCallback      callback
, 
1514                                                 gpointer         callback_data
); 
1515 static void gtk_pixmap_menu_item_size_request  (GtkWidget        
*widget
, 
1516                                                 GtkRequisition   
*requisition
); 
1517 static void gtk_pixmap_menu_item_remove        (GtkContainer 
*container
, 
1520 static void changed_have_pixmap_status         (GtkPixmapMenuItem 
*menu_item
); 
1522 static GtkMenuItemClass 
*parent_class 
= NULL
; 
1526 #define BORDER_SPACING  3 
1527 #define PMAP_WIDTH 20 
1530 gtk_pixmap_menu_item_get_type (void) 
1532   static GtkType pixmap_menu_item_type 
= 0; 
1534   if (!pixmap_menu_item_type
) 
1536       GtkTypeInfo pixmap_menu_item_info 
= 
1538         (char *)"GtkPixmapMenuItem", 
1539         sizeof (GtkPixmapMenuItem
), 
1540         sizeof (GtkPixmapMenuItemClass
), 
1541         (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
, 
1542         (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
, 
1543         /* reserved_1 */ NULL
, 
1544         /* reserved_2 */ NULL
, 
1545         (GtkClassInitFunc
) NULL
, 
1548       pixmap_menu_item_type 
= gtk_type_unique (gtk_menu_item_get_type (), 
1549                                                &pixmap_menu_item_info
); 
1552   return pixmap_menu_item_type
; 
1556  * gtk_pixmap_menu_item_new 
1558  * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap() 
1559  * to set the pixmap wich is displayed at the left side. 
1562  * &GtkWidget pointer to new menu item 
1566 gtk_pixmap_menu_item_new (void) 
1568   return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ())); 
1572 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass 
*klass
) 
1574   GtkObjectClass 
*object_class
; 
1575   GtkWidgetClass 
*widget_class
; 
1576   GtkMenuItemClass 
*menu_item_class
; 
1577   GtkContainerClass 
*container_class
; 
1579   object_class 
= (GtkObjectClass
*) klass
; 
1580   widget_class 
= (GtkWidgetClass
*) klass
; 
1581   menu_item_class 
= (GtkMenuItemClass
*) klass
; 
1582   container_class 
= (GtkContainerClass
*) klass
; 
1584   parent_class 
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ()); 
1586   widget_class
->draw 
= gtk_pixmap_menu_item_draw
; 
1587   widget_class
->expose_event 
= gtk_pixmap_menu_item_expose
; 
1588   widget_class
->map 
= gtk_pixmap_menu_item_map
; 
1589   widget_class
->size_allocate 
= gtk_pixmap_menu_item_size_allocate
; 
1590   widget_class
->size_request 
= gtk_pixmap_menu_item_size_request
; 
1592   container_class
->forall 
= gtk_pixmap_menu_item_forall
; 
1593   container_class
->remove 
= gtk_pixmap_menu_item_remove
; 
1595   klass
->orig_toggle_size 
= menu_item_class
->toggle_size
; 
1596   klass
->have_pixmap_count 
= 0; 
1600 gtk_pixmap_menu_item_init (GtkPixmapMenuItem 
*menu_item
) 
1604   mi 
= GTK_MENU_ITEM (menu_item
); 
1606   menu_item
->pixmap 
= NULL
; 
1610 gtk_pixmap_menu_item_draw (GtkWidget    
*widget
, 
1613   g_return_if_fail (widget 
!= NULL
); 
1614   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1615   g_return_if_fail (area 
!= NULL
); 
1617   if (GTK_WIDGET_CLASS (parent_class
)->draw
) 
1618     (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
); 
1620   if (GTK_WIDGET_DRAWABLE (widget
) && 
1621       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1622     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1627 gtk_pixmap_menu_item_expose (GtkWidget      
*widget
, 
1628                              GdkEventExpose 
*event
) 
1630   g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
1631   g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
); 
1632   g_return_val_if_fail (event 
!= NULL
, FALSE
); 
1634   if (GTK_WIDGET_CLASS (parent_class
)->expose_event
) 
1635     (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
); 
1637   if (GTK_WIDGET_DRAWABLE (widget
) && 
1638       GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) { 
1639     gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
); 
1646  * gtk_pixmap_menu_item_set_pixmap 
1647  * @menu_item: Pointer to the pixmap menu item 
1648  * @pixmap: Pointer to a pixmap widget 
1650  * Set the pixmap of the menu item. 
1655 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem 
*menu_item
, 
1658   g_return_if_fail (menu_item 
!= NULL
); 
1659   g_return_if_fail (pixmap 
!= NULL
); 
1660   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
)); 
1661   g_return_if_fail (GTK_IS_WIDGET (pixmap
)); 
1662   g_return_if_fail (menu_item
->pixmap 
== NULL
); 
1664   gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
)); 
1665   menu_item
->pixmap 
= pixmap
; 
1667   if (GTK_WIDGET_REALIZED (pixmap
->parent
) && 
1668       !GTK_WIDGET_REALIZED (pixmap
)) 
1669     gtk_widget_realize (pixmap
); 
1671   if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) { 
1672     if (GTK_WIDGET_MAPPED (pixmap
->parent
) && 
1673         GTK_WIDGET_VISIBLE(pixmap
) && 
1674         !GTK_WIDGET_MAPPED (pixmap
)) 
1675       gtk_widget_map (pixmap
); 
1678   changed_have_pixmap_status(menu_item
); 
1680   if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
)) 
1681     gtk_widget_queue_resize (pixmap
); 
1685 gtk_pixmap_menu_item_map (GtkWidget 
*widget
) 
1687   GtkPixmapMenuItem 
*menu_item
; 
1689   g_return_if_fail (widget 
!= NULL
); 
1690   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
)); 
1692   menu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1694   GTK_WIDGET_CLASS(parent_class
)->map(widget
); 
1696   if (menu_item
->pixmap 
&& 
1697       GTK_WIDGET_VISIBLE (menu_item
->pixmap
) && 
1698       !GTK_WIDGET_MAPPED (menu_item
->pixmap
)) 
1699     gtk_widget_map (menu_item
->pixmap
); 
1703 gtk_pixmap_menu_item_size_allocate (GtkWidget        
*widget
, 
1704                                     GtkAllocation    
*allocation
) 
1706   GtkPixmapMenuItem 
*pmenu_item
; 
1708   pmenu_item 
= GTK_PIXMAP_MENU_ITEM(widget
); 
1710   if (pmenu_item
->pixmap 
&& GTK_WIDGET_VISIBLE(pmenu_item
)) 
1712       GtkAllocation child_allocation
; 
1715       border_width 
= GTK_CONTAINER (widget
)->border_width
; 
1717       child_allocation
.width 
= pmenu_item
->pixmap
->requisition
.width
; 
1718       child_allocation
.height 
= pmenu_item
->pixmap
->requisition
.height
; 
1719       child_allocation
.x 
= border_width 
+ BORDER_SPACING
; 
1720       child_allocation
.y 
= (border_width 
+ BORDER_SPACING
 
1721                             + (((allocation
->height 
- child_allocation
.height
) - child_allocation
.x
) 
1722                                / 2)); /* center pixmaps vertically */ 
1723       gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
); 
1726   if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
) 
1727     GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
); 
1731 gtk_pixmap_menu_item_forall (GtkContainer    
*container
, 
1732                              gboolean         include_internals
, 
1733                              GtkCallback      callback
, 
1734                              gpointer         callback_data
) 
1736   GtkPixmapMenuItem 
*menu_item
; 
1738   g_return_if_fail (container 
!= NULL
); 
1739   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1740   g_return_if_fail (callback 
!= NULL
); 
1742   menu_item 
= GTK_PIXMAP_MENU_ITEM (container
); 
1744   if (menu_item
->pixmap
) 
1745     (* callback
) (menu_item
->pixmap
, callback_data
); 
1747   GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
, 
1748                                             callback
,callback_data
); 
1752 gtk_pixmap_menu_item_size_request (GtkWidget      
*widget
, 
1753                                    GtkRequisition 
*requisition
) 
1755   GtkPixmapMenuItem 
*menu_item
; 
1756   GtkRequisition req 
= {0, 0}; 
1758   g_return_if_fail (widget 
!= NULL
); 
1759   g_return_if_fail (GTK_IS_MENU_ITEM (widget
)); 
1760   g_return_if_fail (requisition 
!= NULL
); 
1762   GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
); 
1764   menu_item 
= GTK_PIXMAP_MENU_ITEM (widget
); 
1766   if (menu_item
->pixmap
) 
1767     gtk_widget_size_request(menu_item
->pixmap
, &req
); 
1769   requisition
->height 
= MAX(req
.height 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
, (unsigned int) requisition
->height
); 
1770   requisition
->width 
+= (req
.width 
+ GTK_CONTAINER(widget
)->border_width 
+ BORDER_SPACING
); 
1774 gtk_pixmap_menu_item_remove (GtkContainer 
*container
, 
1778   gboolean widget_was_visible
; 
1780   g_return_if_fail (container 
!= NULL
); 
1781   g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
)); 
1782   g_return_if_fail (child 
!= NULL
); 
1783   g_return_if_fail (GTK_IS_WIDGET (child
)); 
1785   bin 
= GTK_BIN (container
); 
1786   g_return_if_fail ((bin
->child 
== child 
|| 
1787                      (GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
== child
))); 
1789   widget_was_visible 
= GTK_WIDGET_VISIBLE (child
); 
1791   gtk_widget_unparent (child
); 
1792   if (bin
->child 
== child
) 
1795     GTK_PIXMAP_MENU_ITEM(container
)->pixmap 
= NULL
; 
1796     changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
)); 
1799   if (widget_was_visible
) 
1800     gtk_widget_queue_resize (GTK_WIDGET (container
)); 
1804 /* important to only call this if there was actually a _change_ in pixmap == NULL */ 
1806 changed_have_pixmap_status (GtkPixmapMenuItem 
*menu_item
) 
1808   if (menu_item
->pixmap 
!= NULL
) { 
1809     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
+= 1; 
1811     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 1) { 
1812       /* Install pixmap toggle size */ 
1813       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
); 
1816     GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
-= 1; 
1818     if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count 
== 0) { 
1819       /* Install normal toggle size */ 
1820       GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size 
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
; 
1824   /* Note that we actually need to do this for _all_ GtkPixmapMenuItem 
1825      whenever the klass->toggle_size changes; but by doing it anytime 
1826      this function is called, we get the same effect, just because of 
1827      how the preferences option to show pixmaps works. Bogus, broken. 
1829   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
))) 
1830     gtk_widget_queue_resize(GTK_WIDGET(menu_item
));