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" 
  27 //----------------------------------------------------------------------------- 
  29 //----------------------------------------------------------------------------- 
  31 extern void wxapp_install_idle_handler(); 
  34 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL 
  35 static wxString 
GetHotKey( const wxMenuItem
& item 
); 
  38 //----------------------------------------------------------------------------- 
  40 //----------------------------------------------------------------------------- 
  42 static wxString 
wxReplaceUnderscore( const wxString
& title 
) 
  46     /* GTK 1.2 wants to have "_" instead of "&" for accelerators */ 
  48     for ( pc 
= title
; *pc 
!= wxT('\0'); pc
++ ) 
  52 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
  55         else if (*pc 
== wxT('/')) 
  63             if ( *pc 
== wxT('_') ) 
  65                 // underscores must be doubled to prevent them from being 
  66                 // interpreted as accelerator character prefix by GTK 
  77 //----------------------------------------------------------------------------- 
  79 //----------------------------------------------------------------------------- 
  81 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
) 
  83 wxMenuBar::wxMenuBar( long style 
) 
  85     /* the parent window is known after wxFrame::SetMenu() */ 
  88     m_invokingWindow 
= (wxWindow
*) NULL
; 
  90     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
  91         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") )) 
  93         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
  97     m_menus
.DeleteContents( TRUE 
); 
  99     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 100 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 101     m_accel 
= gtk_accel_group_new(); 
 102     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 103     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 105     m_menubar 
= gtk_menu_bar_new(); 
 108     if (style 
& wxMB_DOCKABLE
) 
 110         m_widget 
= gtk_handle_box_new(); 
 111         gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) ); 
 112         gtk_widget_show( GTK_WIDGET(m_menubar
) ); 
 116         m_widget 
= GTK_WIDGET(m_menubar
); 
 124 wxMenuBar::wxMenuBar() 
 126     /* the parent window is known after wxFrame::SetMenu() */ 
 127     m_needParent 
= FALSE
; 
 129     m_invokingWindow 
= (wxWindow
*) NULL
; 
 131     if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize 
) || 
 132         !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") )) 
 134         wxFAIL_MSG( wxT("wxMenuBar creation failed") ); 
 138     m_menus
.DeleteContents( TRUE 
); 
 140     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 141 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 142     m_accel 
= gtk_accel_group_new(); 
 143     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel 
); 
 144     m_menubar 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 146     m_menubar 
= gtk_menu_bar_new(); 
 149     m_widget 
= GTK_WIDGET(m_menubar
); 
 156 wxMenuBar::~wxMenuBar() 
 158 //    gtk_object_unref( GTK_OBJECT(m_factory) );  why not ? 
 161 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 163     menu
->SetInvokingWindow( (wxWindow
*) NULL 
); 
 165 #if (GTK_MINOR_VERSION > 0) 
 166     wxWindow 
*top_frame 
= win
; 
 167     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 168         top_frame 
= top_frame
->GetParent(); 
 170     /* support for native hot keys  */ 
 171     gtk_accel_group_detach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) ); 
 174     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 177         wxMenuItem 
*menuitem 
= node
->GetData(); 
 178         if (menuitem
->IsSubMenu()) 
 179             wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 180         node 
= node
->GetNext(); 
 184 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
 186     menu
->SetInvokingWindow( win 
); 
 188 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 189     wxWindow 
*top_frame 
= win
; 
 190     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 191         top_frame 
= top_frame
->GetParent(); 
 193     /* support for native hot keys  */ 
 194     GtkObject 
*obj 
= GTK_OBJECT(top_frame
->m_widget
); 
 195     if ( !g_slist_find( menu
->m_accel
->attach_objects
, obj 
) ) 
 196         gtk_accel_group_attach( menu
->m_accel
, obj 
); 
 199     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 202         wxMenuItem 
*menuitem 
= node
->GetData(); 
 203         if (menuitem
->IsSubMenu()) 
 204             wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win 
); 
 205         node 
= node
->GetNext(); 
 209 void wxMenuBar::SetInvokingWindow( wxWindow 
*win 
) 
 211     m_invokingWindow 
= win
; 
 212 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 213     wxWindow 
*top_frame 
= win
; 
 214     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 215         top_frame 
= top_frame
->GetParent(); 
 217     /* support for native key accelerators indicated by underscroes */ 
 218     GtkObject 
*obj 
= GTK_OBJECT(top_frame
->m_widget
); 
 219     if ( !g_slist_find( m_accel
->attach_objects
, obj 
) ) 
 220         gtk_accel_group_attach( m_accel
, obj 
); 
 223     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 226         wxMenu 
*menu 
= node
->GetData(); 
 227         wxMenubarSetInvokingWindow( menu
, win 
); 
 228         node 
= node
->GetNext(); 
 232 void wxMenuBar::UnsetInvokingWindow( wxWindow 
*win 
) 
 234     m_invokingWindow 
= (wxWindow
*) NULL
; 
 235 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 236     wxWindow 
*top_frame 
= win
; 
 237     while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 238         top_frame 
= top_frame
->GetParent(); 
 240     /* support for native key accelerators indicated by underscroes */ 
 241     gtk_accel_group_detach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) ); 
 244     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 247         wxMenu 
*menu 
= node
->GetData(); 
 248         wxMenubarUnsetInvokingWindow( menu
, win 
); 
 249         node 
= node
->GetNext(); 
 253 bool wxMenuBar::Append( wxMenu 
*menu
, const wxString 
&title 
) 
 255     if ( !wxMenuBarBase::Append( menu
, title 
) ) 
 258     return GtkAppend(menu
, title
); 
 261 bool wxMenuBar::GtkAppend(wxMenu 
*menu
, const wxString
& title
) 
 263     wxString 
str( wxReplaceUnderscore( title 
) ); 
 265     /* this doesn't have much effect right now */ 
 266     menu
->SetTitle( str 
); 
 268     /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ 
 269 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) 
 271     /* local buffer in multibyte form */ 
 273     buf 
<< wxT('/') << str
.c_str(); 
 275     char *cbuf 
= new char[buf
.Length()+1]; 
 276     strcpy(cbuf
, buf
.mbc_str()); 
 278     GtkItemFactoryEntry entry
; 
 279     entry
.path 
= (gchar 
*)cbuf
;  // const_cast 
 280     entry
.accelerator 
= (gchar
*) NULL
; 
 281     entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 282     entry
.callback_action 
= 0; 
 283     entry
.item_type 
= "<Branch>"; 
 285     gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 286     /* in order to get the pointer to the item we need the item text _without_ underscores */ 
 287     wxString tmp 
= wxT("<main>/"); 
 289     for ( pc 
= str
; *pc 
!= wxT('\0'); pc
++ ) 
 291        // contrary to the common sense, we must throw out _all_ underscores, 
 292        // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we 
 293        // might naively think). IMHO it's a bug in GTK+ (VZ) 
 294        while (*pc 
== wxT('_')) 
 298     menu
->m_owner 
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() ); 
 299     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 303     menu
->m_owner 
= gtk_menu_item_new_with_label( str
.mb_str() ); 
 304     gtk_widget_show( menu
->m_owner 
); 
 305     gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu 
); 
 307     gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner 
); 
 311     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
 312     // adding menu later on. 
 313     if (m_invokingWindow
) 
 314         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 319 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 321     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 325     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
 326     // of version 1.2.6), so we first append the item and then change its 
 328     if ( !GtkAppend(menu
, title
) ) 
 331     if (pos
+1 >= m_menus
.GetCount()) 
 334     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
 335     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
 336     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
 337     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
 341     // this should be easy to do with GTK 1.0 - can use standard functions for 
 342     // this and don't need any hacks like above, but as I don't have GTK 1.0 
 343     // any more I can't do it 
 344     wxFAIL_MSG( wxT("TODO") ); 
 347 #endif // GTK 1.2/1.0 
 350 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 352     // remove the old item and insert a new one 
 353     wxMenu 
*menuOld 
= Remove(pos
); 
 354     if ( menuOld 
&& !Insert(pos
, menu
, title
) ) 
 356         return (wxMenu
*) NULL
; 
 359     // either Insert() succeeded or Remove() failed and menuOld is NULL 
 363 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 365     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 367         return (wxMenu
*) NULL
; 
 370     GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget); 
 372     printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) ); 
 373     printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) ); 
 376     // unparent calls unref() and that would delete the widget so we raise 
 377     // the ref count to 2 artificially before invoking unparent. 
 378     gtk_widget_ref( menu
->m_menu 
); 
 379     gtk_widget_unparent( menu
->m_menu 
); 
 381     gtk_widget_destroy( menu
->m_owner 
); 
 384     printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) ); 
 385     printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) ); 
 391 static int FindMenuItemRecursive( const wxMenu 
*menu
, const wxString 
&menuString
, const wxString 
&itemString 
) 
 393     if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
)) 
 395         int res 
= menu
->FindItem( itemString 
); 
 396         if (res 
!= wxNOT_FOUND
) 
 400     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 403         wxMenuItem 
*item 
= node
->GetData(); 
 404         if (item
->IsSubMenu()) 
 405             return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
); 
 407         node 
= node
->GetNext(); 
 413 int wxMenuBar::FindMenuItem( const wxString 
&menuString
, const wxString 
&itemString 
) const 
 415     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 418         wxMenu 
*menu 
= node
->GetData(); 
 419         int res 
= FindMenuItemRecursive( menu
, menuString
, itemString
); 
 422         node 
= node
->GetNext(); 
 428 // Find a wxMenuItem using its id. Recurses down into sub-menus 
 429 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
) 
 431     wxMenuItem
* result 
= menu
->FindChildItem(id
); 
 433     wxMenuItemList::Node 
*node 
= menu
->GetMenuItems().GetFirst(); 
 434     while ( node 
&& result 
== NULL 
) 
 436         wxMenuItem 
*item 
= node
->GetData(); 
 437         if (item
->IsSubMenu()) 
 439             result 
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id 
); 
 441         node 
= node
->GetNext(); 
 447 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu 
**menuForItem 
) const 
 449     wxMenuItem
* result 
= 0; 
 450     wxMenuList::Node 
*node 
= m_menus
.GetFirst(); 
 451     while (node 
&& result 
== 0) 
 453         wxMenu 
*menu 
= node
->GetData(); 
 454         result 
= FindMenuItemByIdRecursive( menu
, id 
); 
 455         node 
= node
->GetNext(); 
 460         *menuForItem 
= result 
? result
->GetMenu() : (wxMenu 
*)NULL
; 
 466 void wxMenuBar::EnableTop( size_t pos
, bool flag 
) 
 468     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 470     wxCHECK_RET( node
, wxT("menu not found") ); 
 472     wxMenu
* menu 
= node
->GetData(); 
 475         gtk_widget_set_sensitive( menu
->m_owner
, flag 
); 
 478 wxString 
wxMenuBar::GetLabelTop( size_t pos 
) const 
 480     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 482     wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") ); 
 484     wxMenu
* menu 
= node
->GetData(); 
 487     wxString 
text( menu
->GetTitle() ); 
 488 #if (GTK_MINOR_VERSION > 0) 
 489     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 491         if ( *pc 
== wxT('_') || *pc 
== wxT('&') ) 
 493             // '_' is the escape character for GTK+ and '&' is the one for 
 494             // wxWindows - skip both of them 
 502 #endif // GTK+ 1.2/1.0 
 507 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label 
) 
 509     wxMenuList::Node 
*node 
= m_menus
.Item( pos 
); 
 511     wxCHECK_RET( node
, wxT("menu not found") ); 
 513     wxMenu
* menu 
= node
->GetData(); 
 515     wxString 
str( wxReplaceUnderscore( label 
) ); 
 517     menu
->SetTitle( str 
); 
 521         GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child 
); 
 524         gtk_label_set( label
, str
.mb_str()); 
 526         /* reparse key accel */ 
 527         (void)gtk_label_parse_uline (GTK_LABEL(label
), str
.mb_str() ); 
 528         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 533 //----------------------------------------------------------------------------- 
 535 //----------------------------------------------------------------------------- 
 537 static void gtk_menu_clicked_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 539     if (g_isIdle
) wxapp_install_idle_handler(); 
 541     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 543     /* should find it for normal (not popup) menu */ 
 544     wxASSERT( (id 
!= -1) || (menu
->GetInvokingWindow() != NULL
) ); 
 546     if (!menu
->IsEnabled(id
)) 
 549     wxMenuItem
* item 
= menu
->FindChildItem( id 
); 
 550     wxCHECK_RET( item
, wxT("error in menu item callback") ); 
 552     if (item
->IsCheckable()) 
 554         bool isReallyChecked 
= item
->IsChecked(); 
 555         if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked 
) 
 557             /* the menu item has been checked by calling wxMenuItem->Check() */ 
 562             /* the user pressed on the menu item -> report and make consistent 
 564             item
->wxMenuItemBase::Check(isReallyChecked
); 
 568     wxCommandEvent 
event( wxEVT_COMMAND_MENU_SELECTED
, id 
); 
 569     event
.SetEventObject( menu 
); 
 572 #if wxUSE_MENU_CALLBACK 
 573     if (menu
->GetCallback()) 
 575         (void) (*(menu
->GetCallback())) (*menu
, event
); 
 578 #endif // wxUSE_MENU_CALLBACK 
 580     if (menu
->GetEventHandler()->ProcessEvent(event
)) 
 583     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 585         win
->GetEventHandler()->ProcessEvent( event 
); 
 588 //----------------------------------------------------------------------------- 
 590 //----------------------------------------------------------------------------- 
 592 static void gtk_menu_hilight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 594     if (g_isIdle
) wxapp_install_idle_handler(); 
 596     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 598     wxASSERT( id 
!= -1 ); // should find it! 
 600     if (!menu
->IsEnabled(id
)) 
 603     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, id 
); 
 604     event
.SetEventObject( menu 
); 
 606     if (menu
->GetEventHandler()->ProcessEvent(event
)) 
 609     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 610     if (win
) win
->GetEventHandler()->ProcessEvent( event 
); 
 613 //----------------------------------------------------------------------------- 
 615 //----------------------------------------------------------------------------- 
 617 static void gtk_menu_nolight_callback( GtkWidget 
*widget
, wxMenu 
*menu 
) 
 619     if (g_isIdle
) wxapp_install_idle_handler(); 
 621     int id 
= menu
->FindMenuIdByMenuItem(widget
); 
 623     wxASSERT( id 
!= -1 ); // should find it! 
 625     if (!menu
->IsEnabled(id
)) 
 628     wxMenuEvent 
event( wxEVT_MENU_HIGHLIGHT
, -1 ); 
 629     event
.SetEventObject( menu 
); 
 631     if (menu
->GetEventHandler()->ProcessEvent(event
)) 
 634     wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 636         win
->GetEventHandler()->ProcessEvent( event 
); 
 639 //----------------------------------------------------------------------------- 
 641 //----------------------------------------------------------------------------- 
 643 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxMenuItemBase
) 
 645 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 647                                 const wxString
& name
, 
 648                                 const wxString
& help
, 
 652     return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
); 
 655 wxMenuItem::wxMenuItem(wxMenu 
*parentMenu
, 
 657                        const wxString
& text
, 
 658                        const wxString
& help
, 
 663     m_isCheckable 
= isCheckable
; 
 667     m_parentMenu 
= parentMenu
; 
 670     m_menuItem 
= (GtkWidget 
*) NULL
; 
 675 wxMenuItem::~wxMenuItem() 
 677    // don't delete menu items, the menus take care of that 
 680 // return the menu item text without any menu accels 
 682 wxString 
wxMenuItemBase::GetLabelFromText(const wxString
& text
) 
 685 #if (GTK_MINOR_VERSION > 0) 
 686     for ( const wxChar 
*pc 
= text
.c_str(); *pc
; pc
++ ) 
 688         if ( *pc 
== wxT('_') || *pc 
== wxT('&') ) 
 690             // '_' is the escape character for GTK+ and '&' is the one for 
 691             // wxWindows - skip both of them 
 699 #endif // GTK+ 1.2/1.0 
 704 void wxMenuItem::SetText( const wxString
& str 
) 
 710         GtkLabel 
*label 
= GTK_LABEL( GTK_BIN(m_menuItem
)->child 
); 
 713         gtk_label_set( label
, m_text
.mb_str()); 
 715         /* reparse key accel */ 
 716         (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() ); 
 717         gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) ); 
 721 // it's valid for this function to be called even if m_menuItem == NULL 
 722 void wxMenuItem::DoSetText( const wxString
& str 
) 
 724     /* '\t' is the deliminator indicating a hot key */ 
 726     const wxChar 
*pc 
= str
; 
 727     for (; (*pc 
!= wxT('\0')) && (*pc 
!= wxT('\t')); pc
++ ) 
 731 #if (GTK_MINOR_VERSION > 0) 
 734         else if ( *pc 
== wxT('_') )    // escape underscores 
 738         else if (*pc 
== wxT('/'))      /* we have to filter out slashes ... */ 
 740             m_text 
<< wxT('\\');  /* ... and replace them with back slashes */ 
 747     /* only GTK 1.2 knows about hot keys */ 
 749 #if (GTK_MINOR_VERSION > 0) 
 760 wxAcceleratorEntry 
*wxMenuItem::GetAccel() const 
 765         return (wxAcceleratorEntry 
*)NULL
; 
 768     // as wxGetAccelFromString() looks for TAB, insert a dummy one here 
 770     label 
<< wxT('\t') << GetHotKey(); 
 772     return wxGetAccelFromString(label
); 
 775 #endif // wxUSE_ACCEL 
 777 void wxMenuItem::Check( bool check 
) 
 779     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 781     wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") ) 
 783     if (check 
== m_isChecked
) 
 786     wxMenuItemBase::Check( check 
); 
 787     gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check 
); 
 790 void wxMenuItem::Enable( bool enable 
) 
 792     wxCHECK_RET( m_menuItem
, wxT("invalid menu item") ); 
 794     gtk_widget_set_sensitive( m_menuItem
, enable 
); 
 795     wxMenuItemBase::Enable( enable 
); 
 798 bool wxMenuItem::IsChecked() const 
 800     wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") ); 
 802     wxCHECK_MSG( IsCheckable(), FALSE
, 
 803                  wxT("can't get state of uncheckable item!") ); 
 805     return ((GtkCheckMenuItem
*)m_menuItem
)->active 
!= 0; 
 808 wxString 
wxMenuItem::GetFactoryPath() const 
 810     /* in order to get the pointer to the item we need the item text _without_ 
 812     wxString 
path( wxT("<main>/") ); 
 818 //----------------------------------------------------------------------------- 
 820 //----------------------------------------------------------------------------- 
 822 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
) 
 826 #if (GTK_MINOR_VERSION > 0) 
 827     m_accel 
= gtk_accel_group_new(); 
 828     m_factory 
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel 
); 
 829     m_menu 
= gtk_item_factory_get_widget( m_factory
, "<main>" ); 
 831     m_menu 
= gtk_menu_new();  // Do not show! 
 834     m_owner 
= (GtkWidget
*) NULL
; 
 836 #if (GTK_MINOR_VERSION > 0) 
 837     /* Tearoffs are entries, just like separators. So if we want this 
 838        menu to be a tear-off one, we just append a tearoff entry 
 840     if(m_style 
& wxMENU_TEAROFF
) 
 842        GtkItemFactoryEntry entry
; 
 843        entry
.path 
= "/tearoff"; 
 844        entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 845        entry
.callback_action 
= 0; 
 846        entry
.item_type 
= "<Tearoff>"; 
 847        entry
.accelerator 
= (gchar
*) NULL
; 
 848        gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 849        //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" ); 
 853     // append the title as the very first entry if we have it 
 865    gtk_widget_destroy( m_menu 
); 
 867    gtk_object_unref( GTK_OBJECT(m_factory
) ); 
 870 bool wxMenu::GtkAppend(wxMenuItem 
*mitem
) 
 874     if ( mitem
->IsSeparator() ) 
 876 #if (GTK_MINOR_VERSION > 0) 
 877         GtkItemFactoryEntry entry
; 
 879         entry
.callback 
= (GtkItemFactoryCallback
) NULL
; 
 880         entry
.callback_action 
= 0; 
 881         entry
.item_type 
= "<Separator>"; 
 882         entry
.accelerator 
= (gchar
*) NULL
; 
 884         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 886         /* this will be wrong for more than one separator. do we care? */ 
 887         menuItem 
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" ); 
 889         menuItem 
= gtk_menu_item_new(); 
 890 #endif // GTK 1.2/1.0 
 892     else if ( mitem
->IsSubMenu() ) 
 894 #if (GTK_MINOR_VERSION > 0) 
 895         /* text has "_" instead of "&" after mitem->SetText() */ 
 896         wxString 
text( mitem
->GetText() ); 
 898         /* local buffer in multibyte form */ 
 901         strcat( buf
, text
.mb_str() ); 
 903         GtkItemFactoryEntry entry
; 
 905         entry
.callback 
= (GtkItemFactoryCallback
) 0; 
 906         entry
.callback_action 
= 0; 
 907         entry
.item_type 
= "<Branch>"; 
 908         entry
.accelerator 
= (gchar
*) NULL
; 
 910         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 912         wxString 
path( mitem
->GetFactoryPath() ); 
 913         menuItem 
= gtk_item_factory_get_item( m_factory
, path
.mb_str() ); 
 915         menuItem 
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str()); 
 916 #endif // GTK 1.2/1.0 
 918         gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu 
); 
 920         // if adding a submenu to a menu already existing in the menu bar, we 
 921         // must set invoking window to allow processing events from this 
 923         if ( m_invokingWindow 
) 
 924             wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
); 
 926     else // a normal item 
 928 #if (GTK_MINOR_VERSION > 0) 
 929         /* text has "_" instead of "&" after mitem->SetText() */ 
 930         wxString 
text( mitem
->GetText() ); 
 932         /* local buffer in multibyte form */ 
 935         strcat( buf
, text
.mb_str() ); 
 937         GtkItemFactoryEntry entry
; 
 939         entry
.callback 
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
; 
 940         entry
.callback_action 
= 0; 
 941         if ( mitem
->IsCheckable() ) 
 942             entry
.item_type 
= "<CheckItem>"; 
 944             entry
.item_type 
= "<Item>"; 
 945         entry
.accelerator 
= (gchar
*) NULL
; 
 948         // due to an apparent bug in GTK+, we have to use a static buffer here - 
 949         // otherwise GTK+ 1.2.2 manages to override the memory we pass to it 
 951         static char s_accel
[32]; // must be big enough for <control><alt><shift>F12 
 952         strncpy(s_accel
, GetHotKey(*mitem
).mb_str(), WXSIZEOF(s_accel
)); 
 953         entry
.accelerator 
= s_accel
; 
 954 #else // !wxUSE_ACCEL 
 955         entry
.accelerator 
= (char*) NULL
; 
 956 #endif // wxUSE_ACCEL/!wxUSE_ACCEL 
 958         gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 );  /* what is 2 ? */ 
 960         wxString 
path( mitem
->GetFactoryPath() ); 
 961         menuItem 
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() ); 
 963         menuItem 
= checkable 
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() ) 
 964                              : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() ); 
 966         gtk_signal_connect( GTK_OBJECT(menuItem
), "activate", 
 967                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
), 
 969 #endif // GTK+ 1.2/1.0 
 972     if ( !mitem
->IsSeparator() ) 
 974         gtk_signal_connect( GTK_OBJECT(menuItem
), "select", 
 975                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
), 
 978         gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect", 
 979                             GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
), 
 983 #if GTK_MINOR_VERSION == 0 
 984     gtk_menu_append( GTK_MENU(m_menu
), menuItem 
); 
 985     gtk_widget_show( menuItem 
); 
 988     mitem
->SetMenuItem(menuItem
); 
 993 bool wxMenu::DoAppend(wxMenuItem 
*mitem
) 
 995     return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
); 
 998 bool wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
1000     if ( !wxMenuBase::DoInsert(pos
, item
) ) 
1004     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as 
1005     // of version 1.2.6), so we first append the item and then change its 
1007     if ( !GtkAppend(item
) ) 
1010     if ( m_style 
& wxMENU_TEAROFF 
) 
1012         // change the position as the first item is the tear-off marker 
1016     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL(m_factory
->widget
); 
1017     gpointer data 
= g_list_last(menu_shell
->children
)->data
; 
1018     menu_shell
->children 
= g_list_remove(menu_shell
->children
, data
); 
1019     menu_shell
->children 
= g_list_insert(menu_shell
->children
, data
, pos
); 
1023     // this should be easy to do... 
1024     wxFAIL_MSG( wxT("not implemented") ); 
1027 #endif // GTK 1.2/1.0 
1030 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
1032     if ( !wxMenuBase::DoRemove(item
) ) 
1033         return (wxMenuItem 
*)NULL
; 
1035     // TODO: this code doesn't delete the item factory item and this seems 
1036     //       impossible as of GTK 1.2.6. 
1037     gtk_widget_destroy( item
->GetMenuItem() ); 
1042 int wxMenu::FindMenuIdByMenuItem( GtkWidget 
*menuItem 
) const 
1044     wxNode 
*node 
= m_items
.First(); 
1047         wxMenuItem 
*item 
= (wxMenuItem
*)node
->Data(); 
1048         if (item
->GetMenuItem() == menuItem
) 
1049            return item
->GetId(); 
1050         node 
= node
->Next(); 
1056 // ---------------------------------------------------------------------------- 
1058 // ---------------------------------------------------------------------------- 
1060 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL 
1061 static wxString 
GetHotKey( const wxMenuItem
& item 
) 
1065     wxAcceleratorEntry 
*accel 
= item
.GetAccel(); 
1068         int flags 
= accel
->GetFlags(); 
1069         if ( flags 
& wxACCEL_ALT 
) 
1070             hotkey 
+= wxT("<alt>"); 
1071         if ( flags 
& wxACCEL_CTRL 
) 
1072             hotkey 
+= wxT("<control>"); 
1073         if ( flags 
& wxACCEL_SHIFT 
) 
1074             hotkey 
+= wxT("<shift>"); 
1076         int code 
= accel
->GetKeyCode(); 
1091                 hotkey 
<< wxT('F') << code 
- WXK_F1 
+ 1; 
1094                 // if there are any other keys wxGetAccelFromString() may return, 
1095                 // we should process them here 
1098                 if ( wxIsalnum(code
) ) 
1100                     hotkey 
<< (wxChar
)code
; 
1105                 wxFAIL_MSG( wxT("unknown keyboard accel") ); 
1113 #endif // wxUSE_ACCEL