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
)
582 wxapp_install_idle_handler();
584 int id
= menu
->FindMenuIdByMenuItem(widget
);
586 /* should find it for normal (not popup) menu */
587 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
588 _T("menu item not found in gtk_menu_clicked_callback") );
590 if (!menu
->IsEnabled(id
))
593 wxMenuItem
* item
= menu
->FindChildItem( id
);
594 wxCHECK_RET( item
, wxT("error in menu item callback") );
596 if (item
->IsCheckable())
598 bool isReallyChecked
= item
->IsChecked();
599 if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked
)
601 /* the menu item has been checked by calling wxMenuItem->Check() */
606 /* the user pressed on the menu item -> report and make consistent
608 item
->wxMenuItemBase::Check(isReallyChecked
);
612 menu
->SendEvent(item
->GetId(), item
->IsCheckable() ? item
->IsChecked() : -1);
615 //-----------------------------------------------------------------------------
617 //-----------------------------------------------------------------------------
619 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
621 if (g_isIdle
) wxapp_install_idle_handler();
623 int id
= menu
->FindMenuIdByMenuItem(widget
);
625 wxASSERT( id
!= -1 ); // should find it!
627 if (!menu
->IsEnabled(id
))
630 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
631 event
.SetEventObject( menu
);
633 if (menu
->GetEventHandler()->ProcessEvent(event
))
636 wxWindow
*win
= menu
->GetInvokingWindow();
637 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
640 //-----------------------------------------------------------------------------
642 //-----------------------------------------------------------------------------
644 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
646 if (g_isIdle
) wxapp_install_idle_handler();
648 int id
= menu
->FindMenuIdByMenuItem(widget
);
650 wxASSERT( id
!= -1 ); // should find it!
652 if (!menu
->IsEnabled(id
))
655 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
656 event
.SetEventObject( menu
);
658 if (menu
->GetEventHandler()->ProcessEvent(event
))
661 wxWindow
*win
= menu
->GetInvokingWindow();
663 win
->GetEventHandler()->ProcessEvent( event
);
666 //-----------------------------------------------------------------------------
668 //-----------------------------------------------------------------------------
670 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxMenuItemBase
)
672 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
674 const wxString
& name
,
675 const wxString
& help
,
679 return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
);
682 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
684 const wxString
& text
,
685 const wxString
& help
,
690 m_isCheckable
= isCheckable
;
694 m_parentMenu
= parentMenu
;
697 m_labelWidget
= (GtkWidget
*) NULL
;
698 m_menuItem
= (GtkWidget
*) NULL
;
703 wxMenuItem::~wxMenuItem()
705 // don't delete menu items, the menus take care of that
708 // return the menu item text without any menu accels
710 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
714 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
716 if ( *pc
== wxT('_') )
718 // wxGTK escapes "xxx_xxx" to "xxx__xxx"
724 if ( *pc
== wxT('&') )
736 void wxMenuItem::SetText( const wxString
& str
)
744 label
= (GtkLabel
*) m_labelWidget
;
746 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
749 gtk_label_set( label
, m_text
.mb_str());
751 /* reparse key accel */
752 (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() );
753 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
757 // it's valid for this function to be called even if m_menuItem == NULL
758 void wxMenuItem::DoSetText( const wxString
& str
)
760 /* '\t' is the deliminator indicating a hot key */
762 const wxChar
*pc
= str
;
763 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
767 #if (GTK_MINOR_VERSION > 0)
770 else if ( *pc
== wxT('_') ) // escape underscores
774 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
776 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
783 /* only GTK 1.2 knows about hot keys */
785 #if (GTK_MINOR_VERSION > 0)
796 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
801 return (wxAcceleratorEntry
*)NULL
;
804 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
806 label
<< wxT('\t') << GetHotKey();
808 return wxGetAccelFromString(label
);
811 #endif // wxUSE_ACCEL
813 void wxMenuItem::Check( bool check
)
815 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
817 wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") )
819 if (check
== m_isChecked
)
822 wxMenuItemBase::Check( check
);
823 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
826 void wxMenuItem::Enable( bool enable
)
828 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
830 gtk_widget_set_sensitive( m_menuItem
, enable
);
831 wxMenuItemBase::Enable( enable
);
834 bool wxMenuItem::IsChecked() const
836 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
838 wxCHECK_MSG( IsCheckable(), FALSE
,
839 wxT("can't get state of uncheckable item!") );
841 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
844 wxString
wxMenuItem::GetFactoryPath() const
846 /* in order to get the pointer to the item we need the item text
847 _without_ underscores */
848 wxString
path( wxT("<main>/") );
850 for ( const wxChar
*pc
= m_text
.c_str(); *pc
; pc
++ )
852 if ( *pc
== wxT('_') || *pc
== wxT('&') )
854 // remove '_' and '&' unconditionally
864 //-----------------------------------------------------------------------------
866 //-----------------------------------------------------------------------------
868 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
872 #if (GTK_MINOR_VERSION > 0)
873 m_accel
= gtk_accel_group_new();
874 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
875 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
877 m_menu
= gtk_menu_new(); // Do not show!
880 m_owner
= (GtkWidget
*) NULL
;
882 #if (GTK_MINOR_VERSION > 0)
883 /* Tearoffs are entries, just like separators. So if we want this
884 menu to be a tear-off one, we just append a tearoff entry
886 if(m_style
& wxMENU_TEAROFF
)
888 GtkItemFactoryEntry entry
;
889 entry
.path
= "/tearoff";
890 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
891 entry
.callback_action
= 0;
892 entry
.item_type
= "<Tearoff>";
893 entry
.accelerator
= (gchar
*) NULL
;
894 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
895 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
899 // append the title as the very first entry if we have it
911 gtk_widget_destroy( m_menu
);
913 gtk_object_unref( GTK_OBJECT(m_factory
) );
916 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
920 bool appended
= FALSE
;
922 if ( mitem
->IsSeparator() )
924 #if (GTK_MINOR_VERSION > 0)
925 GtkItemFactoryEntry entry
;
927 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
928 entry
.callback_action
= 0;
929 entry
.item_type
= "<Separator>";
930 entry
.accelerator
= (gchar
*) NULL
;
932 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
934 /* this will be wrong for more than one separator. do we care? */
935 menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
937 menuItem
= gtk_menu_item_new();
938 #endif // GTK 1.2/1.0
940 else if ( mitem
->IsSubMenu() )
942 #if (GTK_MINOR_VERSION > 0)
943 /* text has "_" instead of "&" after mitem->SetText() */
944 wxString
text( mitem
->GetText() );
946 /* local buffer in multibyte form */
949 strcat( buf
, text
.mb_str() );
951 GtkItemFactoryEntry entry
;
953 entry
.callback
= (GtkItemFactoryCallback
) 0;
954 entry
.callback_action
= 0;
955 entry
.item_type
= "<Branch>";
956 entry
.accelerator
= (gchar
*) NULL
;
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_item( m_factory
, path
.mb_str() );
963 menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
964 #endif // GTK 1.2/1.0
966 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
968 // if adding a submenu to a menu already existing in the menu bar, we
969 // must set invoking window to allow processing events from this
971 if ( m_invokingWindow
)
972 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
974 else if (mitem
->GetBitmap().Ok()) // An item with bitmap
976 wxString
text( mitem
->GetText() );
977 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
979 menuItem
= gtk_pixmap_menu_item_new ();
980 GtkWidget
*label
= gtk_accel_label_new (text
.mb_str());
981 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
982 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
983 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), text
.mb_str() );
984 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
985 if (accel_key
!= GDK_VoidSymbol
)
987 gtk_widget_add_accelerator (menuItem
,
989 gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)),
993 gtk_widget_show (label
);
995 mitem
->SetLabelWidget(label
);
997 GtkWidget
* pixmap
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
);
998 gtk_widget_show(pixmap
);
999 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1001 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1002 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1004 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1005 gtk_widget_show( menuItem
);
1007 appended
= TRUE
; // We've done this, don't do it again
1009 else // a normal item
1011 #if (GTK_MINOR_VERSION > 0)
1012 /* text has "_" instead of "&" after mitem->SetText() */
1013 wxString
text( mitem
->GetText() );
1015 /* local buffer in multibyte form */
1018 strcat( buf
, text
.mb_str() );
1020 GtkItemFactoryEntry entry
;
1022 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
1023 entry
.callback_action
= 0;
1024 if ( mitem
->IsCheckable() )
1025 entry
.item_type
= "<CheckItem>";
1027 entry
.item_type
= "<Item>";
1028 entry
.accelerator
= (gchar
*) NULL
;
1031 // due to an apparent bug in GTK+, we have to use a static buffer here -
1032 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
1034 static char s_accel
[50]; // must be big enougg
1035 wxString
tmp( GetHotKey(*mitem
) );
1036 strncpy(s_accel
, tmp
.mb_str(), WXSIZEOF(s_accel
));
1037 entry
.accelerator
= s_accel
;
1038 #else // !wxUSE_ACCEL
1039 entry
.accelerator
= (char*) NULL
;
1040 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
1042 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1044 wxString
path( mitem
->GetFactoryPath() );
1045 menuItem
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() );
1047 menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
1048 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
1050 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1051 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1053 #endif // GTK+ 1.2/1.0
1056 if ( !mitem
->IsSeparator() )
1058 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1059 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1062 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1063 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1067 #if GTK_MINOR_VERSION == 0
1070 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1071 gtk_widget_show( menuItem
);
1075 mitem
->SetMenuItem(menuItem
);
1080 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
1082 return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
);
1085 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1087 if ( !wxMenuBase::DoInsert(pos
, item
) )
1091 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
1092 // of version 1.2.6), so we first append the item and then change its
1094 if ( !GtkAppend(item
) )
1097 if ( m_style
& wxMENU_TEAROFF
)
1099 // change the position as the first item is the tear-off marker
1103 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
1104 gpointer data
= g_list_last(menu_shell
->children
)->data
;
1105 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
1106 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
1110 // this should be easy to do...
1111 wxFAIL_MSG( wxT("not implemented") );
1114 #endif // GTK 1.2/1.0
1117 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1119 if ( !wxMenuBase::DoRemove(item
) )
1120 return (wxMenuItem
*)NULL
;
1122 // TODO: this code doesn't delete the item factory item and this seems
1123 // impossible as of GTK 1.2.6.
1124 gtk_widget_destroy( item
->GetMenuItem() );
1129 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1131 wxNode
*node
= m_items
.First();
1134 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1135 if (item
->GetMenuItem() == menuItem
)
1136 return item
->GetId();
1137 node
= node
->Next();
1143 // ----------------------------------------------------------------------------
1145 // ----------------------------------------------------------------------------
1147 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL
1148 static wxString
GetHotKey( const wxMenuItem
& item
)
1152 wxAcceleratorEntry
*accel
= item
.GetAccel();
1155 int flags
= accel
->GetFlags();
1156 if ( flags
& wxACCEL_ALT
)
1157 hotkey
+= wxT("<alt>");
1158 if ( flags
& wxACCEL_CTRL
)
1159 hotkey
+= wxT("<control>");
1160 if ( flags
& wxACCEL_SHIFT
)
1161 hotkey
+= wxT("<shift>");
1163 int code
= accel
->GetKeyCode();
1178 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1181 // GTK seems to use XStringToKeySym here
1182 case WXK_NUMPAD_INSERT
:
1183 hotkey
<< wxT("KP_Insert" );
1185 case WXK_NUMPAD_DELETE
:
1186 hotkey
<< wxT("KP_Delete" );
1189 hotkey
<< wxT("Insert" );
1192 hotkey
<< wxT("Delete" );
1195 // if there are any other keys wxGetAccelFromString() may return,
1196 // we should process them here
1199 if ( wxIsalnum(code
) )
1201 hotkey
<< (wxChar
)code
;
1206 wxFAIL_MSG( wxT("unknown keyboard accel") );
1214 #endif // wxUSE_ACCEL
1217 //-----------------------------------------------------------------------------
1218 // substitute for missing GtkPixmapMenuItem
1219 //-----------------------------------------------------------------------------
1222 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1223 * All rights reserved.
1225 * This file is part of the Gnome Library.
1227 * The Gnome Library is free software; you can redistribute it and/or
1228 * modify it under the terms of the GNU Library General Public License as
1229 * published by the Free Software Foundation; either version 2 of the
1230 * License, or (at your option) any later version.
1232 * The Gnome Library is distributed in the hope that it will be useful,
1233 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1234 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1235 * Library General Public License for more details.
1237 * You should have received a copy of the GNU Library General Public
1238 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1239 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1240 * Boston, MA 02111-1307, USA.
1246 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1248 #include <gtk/gtkaccellabel.h>
1249 #include <gtk/gtksignal.h>
1250 #include <gtk/gtkmenuitem.h>
1251 #include <gtk/gtkmenu.h>
1252 #include <gtk/gtkcontainer.h>
1254 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1255 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1256 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1257 GdkRectangle
*area
);
1258 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1259 GdkEventExpose
*event
);
1261 /* we must override the following functions */
1263 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1264 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1265 GtkAllocation
*allocation
);
1266 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1267 gboolean include_internals
,
1268 GtkCallback callback
,
1269 gpointer callback_data
);
1270 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1271 GtkRequisition
*requisition
);
1272 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1275 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1277 static GtkMenuItemClass
*parent_class
= NULL
;
1279 #define BORDER_SPACING 3
1280 #define PMAP_WIDTH 20
1283 gtk_pixmap_menu_item_get_type (void)
1285 static GtkType pixmap_menu_item_type
= 0;
1287 if (!pixmap_menu_item_type
)
1289 GtkTypeInfo pixmap_menu_item_info
=
1291 "GtkPixmapMenuItem",
1292 sizeof (GtkPixmapMenuItem
),
1293 sizeof (GtkPixmapMenuItemClass
),
1294 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1295 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1296 /* reserved_1 */ NULL
,
1297 /* reserved_2 */ NULL
,
1298 (GtkClassInitFunc
) NULL
,
1301 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1302 &pixmap_menu_item_info
);
1305 return pixmap_menu_item_type
;
1309 * gtk_pixmap_menu_item_new
1311 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1312 * to set the pixmap wich is displayed at the left side.
1315 * &GtkWidget pointer to new menu item
1319 gtk_pixmap_menu_item_new (void)
1321 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1325 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1327 GtkObjectClass
*object_class
;
1328 GtkWidgetClass
*widget_class
;
1329 GtkMenuItemClass
*menu_item_class
;
1330 GtkContainerClass
*container_class
;
1332 object_class
= (GtkObjectClass
*) klass
;
1333 widget_class
= (GtkWidgetClass
*) klass
;
1334 menu_item_class
= (GtkMenuItemClass
*) klass
;
1335 container_class
= (GtkContainerClass
*) klass
;
1337 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1339 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1340 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1341 widget_class
->map
= gtk_pixmap_menu_item_map
;
1342 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1343 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1345 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1346 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1348 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1349 klass
->have_pixmap_count
= 0;
1353 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1357 mi
= GTK_MENU_ITEM (menu_item
);
1359 menu_item
->pixmap
= NULL
;
1363 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1366 g_return_if_fail (widget
!= NULL
);
1367 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1368 g_return_if_fail (area
!= NULL
);
1370 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1371 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1373 if (GTK_WIDGET_DRAWABLE (widget
) &&
1374 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1375 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1380 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1381 GdkEventExpose
*event
)
1383 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1384 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1385 g_return_val_if_fail (event
!= NULL
, FALSE
);
1387 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1388 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1390 if (GTK_WIDGET_DRAWABLE (widget
) &&
1391 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1392 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1399 * gtk_pixmap_menu_item_set_pixmap
1400 * @menu_item: Pointer to the pixmap menu item
1401 * @pixmap: Pointer to a pixmap widget
1403 * Set the pixmap of the menu item.
1408 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1411 g_return_if_fail (menu_item
!= NULL
);
1412 g_return_if_fail (pixmap
!= NULL
);
1413 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1414 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1415 g_return_if_fail (menu_item
->pixmap
== NULL
);
1417 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1418 menu_item
->pixmap
= pixmap
;
1420 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1421 !GTK_WIDGET_REALIZED (pixmap
))
1422 gtk_widget_realize (pixmap
);
1424 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1425 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1426 GTK_WIDGET_VISIBLE(pixmap
) &&
1427 !GTK_WIDGET_MAPPED (pixmap
))
1428 gtk_widget_map (pixmap
);
1431 changed_have_pixmap_status(menu_item
);
1433 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1434 gtk_widget_queue_resize (pixmap
);
1438 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1440 GtkPixmapMenuItem
*menu_item
;
1442 g_return_if_fail (widget
!= NULL
);
1443 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1445 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1447 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1449 if (menu_item
->pixmap
&&
1450 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1451 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1452 gtk_widget_map (menu_item
->pixmap
);
1456 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1457 GtkAllocation
*allocation
)
1459 GtkPixmapMenuItem
*pmenu_item
;
1461 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1463 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1465 GtkAllocation child_allocation
;
1468 border_width
= GTK_CONTAINER (widget
)->border_width
;
1470 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1471 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1472 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1473 child_allocation
.y
= (border_width
+ BORDER_SPACING
1474 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1475 / 2)); /* center pixmaps vertically */
1476 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1479 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1480 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1484 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1485 gboolean include_internals
,
1486 GtkCallback callback
,
1487 gpointer callback_data
)
1489 GtkPixmapMenuItem
*menu_item
;
1491 g_return_if_fail (container
!= NULL
);
1492 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1493 g_return_if_fail (callback
!= NULL
);
1495 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1497 if (menu_item
->pixmap
)
1498 (* callback
) (menu_item
->pixmap
, callback_data
);
1500 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1501 callback
,callback_data
);
1505 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1506 GtkRequisition
*requisition
)
1508 GtkPixmapMenuItem
*menu_item
;
1509 GtkRequisition req
= {0, 0};
1511 g_return_if_fail (widget
!= NULL
);
1512 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1513 g_return_if_fail (requisition
!= NULL
);
1515 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1517 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1519 if (menu_item
->pixmap
)
1520 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1522 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1523 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1527 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1531 gboolean widget_was_visible
;
1533 g_return_if_fail (container
!= NULL
);
1534 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1535 g_return_if_fail (child
!= NULL
);
1536 g_return_if_fail (GTK_IS_WIDGET (child
));
1538 bin
= GTK_BIN (container
);
1539 g_return_if_fail ((bin
->child
== child
||
1540 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1542 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1544 gtk_widget_unparent (child
);
1545 if (bin
->child
== child
)
1548 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1549 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1552 if (widget_was_visible
)
1553 gtk_widget_queue_resize (GTK_WIDGET (container
));
1557 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1559 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1561 if (menu_item
->pixmap
!= NULL
) {
1562 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1564 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1565 /* Install pixmap toggle size */
1566 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1569 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1571 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1572 /* Install normal toggle size */
1573 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1577 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1578 whenever the klass->toggle_size changes; but by doing it anytime
1579 this function is called, we get the same effect, just because of
1580 how the preferences option to show pixmaps works. Bogus, broken.
1582 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1583 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));