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
));