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
= (char *)"<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
, wxObject
)
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
= (char *)"/tearoff";
890 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
891 entry
.callback_action
= 0;
892 entry
.item_type
= (char *)"<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
;
926 entry
.path
= (char *)"/sep";
927 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
928 entry
.callback_action
= 0;
929 entry
.item_type
= (char *)"<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
= (char *)"<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
= (char *)"<CheckItem>";
1027 entry
.item_type
= (char *)"<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>
1257 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1258 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1259 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1260 GdkRectangle
*area
);
1261 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1262 GdkEventExpose
*event
);
1264 /* we must override the following functions */
1266 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1267 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1268 GtkAllocation
*allocation
);
1269 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1270 gboolean include_internals
,
1271 GtkCallback callback
,
1272 gpointer callback_data
);
1273 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1274 GtkRequisition
*requisition
);
1275 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1278 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1280 static GtkMenuItemClass
*parent_class
= NULL
;
1284 #define BORDER_SPACING 3
1285 #define PMAP_WIDTH 20
1288 gtk_pixmap_menu_item_get_type (void)
1290 static GtkType pixmap_menu_item_type
= 0;
1292 if (!pixmap_menu_item_type
)
1294 GtkTypeInfo pixmap_menu_item_info
=
1296 (char *)"GtkPixmapMenuItem",
1297 sizeof (GtkPixmapMenuItem
),
1298 sizeof (GtkPixmapMenuItemClass
),
1299 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1300 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1301 /* reserved_1 */ NULL
,
1302 /* reserved_2 */ NULL
,
1303 (GtkClassInitFunc
) NULL
,
1306 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1307 &pixmap_menu_item_info
);
1310 return pixmap_menu_item_type
;
1314 * gtk_pixmap_menu_item_new
1316 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1317 * to set the pixmap wich is displayed at the left side.
1320 * &GtkWidget pointer to new menu item
1324 gtk_pixmap_menu_item_new (void)
1326 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1330 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1332 GtkObjectClass
*object_class
;
1333 GtkWidgetClass
*widget_class
;
1334 GtkMenuItemClass
*menu_item_class
;
1335 GtkContainerClass
*container_class
;
1337 object_class
= (GtkObjectClass
*) klass
;
1338 widget_class
= (GtkWidgetClass
*) klass
;
1339 menu_item_class
= (GtkMenuItemClass
*) klass
;
1340 container_class
= (GtkContainerClass
*) klass
;
1342 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1344 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1345 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1346 widget_class
->map
= gtk_pixmap_menu_item_map
;
1347 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1348 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1350 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1351 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1353 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1354 klass
->have_pixmap_count
= 0;
1358 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1362 mi
= GTK_MENU_ITEM (menu_item
);
1364 menu_item
->pixmap
= NULL
;
1368 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1371 g_return_if_fail (widget
!= NULL
);
1372 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1373 g_return_if_fail (area
!= NULL
);
1375 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1376 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1378 if (GTK_WIDGET_DRAWABLE (widget
) &&
1379 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1380 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1385 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1386 GdkEventExpose
*event
)
1388 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1389 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1390 g_return_val_if_fail (event
!= NULL
, FALSE
);
1392 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1393 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1395 if (GTK_WIDGET_DRAWABLE (widget
) &&
1396 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1397 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1404 * gtk_pixmap_menu_item_set_pixmap
1405 * @menu_item: Pointer to the pixmap menu item
1406 * @pixmap: Pointer to a pixmap widget
1408 * Set the pixmap of the menu item.
1413 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1416 g_return_if_fail (menu_item
!= NULL
);
1417 g_return_if_fail (pixmap
!= NULL
);
1418 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1419 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1420 g_return_if_fail (menu_item
->pixmap
== NULL
);
1422 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1423 menu_item
->pixmap
= pixmap
;
1425 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1426 !GTK_WIDGET_REALIZED (pixmap
))
1427 gtk_widget_realize (pixmap
);
1429 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1430 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1431 GTK_WIDGET_VISIBLE(pixmap
) &&
1432 !GTK_WIDGET_MAPPED (pixmap
))
1433 gtk_widget_map (pixmap
);
1436 changed_have_pixmap_status(menu_item
);
1438 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1439 gtk_widget_queue_resize (pixmap
);
1443 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1445 GtkPixmapMenuItem
*menu_item
;
1447 g_return_if_fail (widget
!= NULL
);
1448 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1450 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1452 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1454 if (menu_item
->pixmap
&&
1455 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1456 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1457 gtk_widget_map (menu_item
->pixmap
);
1461 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1462 GtkAllocation
*allocation
)
1464 GtkPixmapMenuItem
*pmenu_item
;
1466 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1468 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1470 GtkAllocation child_allocation
;
1473 border_width
= GTK_CONTAINER (widget
)->border_width
;
1475 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1476 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1477 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1478 child_allocation
.y
= (border_width
+ BORDER_SPACING
1479 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1480 / 2)); /* center pixmaps vertically */
1481 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1484 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1485 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1489 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1490 gboolean include_internals
,
1491 GtkCallback callback
,
1492 gpointer callback_data
)
1494 GtkPixmapMenuItem
*menu_item
;
1496 g_return_if_fail (container
!= NULL
);
1497 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1498 g_return_if_fail (callback
!= NULL
);
1500 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1502 if (menu_item
->pixmap
)
1503 (* callback
) (menu_item
->pixmap
, callback_data
);
1505 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1506 callback
,callback_data
);
1510 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1511 GtkRequisition
*requisition
)
1513 GtkPixmapMenuItem
*menu_item
;
1514 GtkRequisition req
= {0, 0};
1516 g_return_if_fail (widget
!= NULL
);
1517 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1518 g_return_if_fail (requisition
!= NULL
);
1520 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1522 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1524 if (menu_item
->pixmap
)
1525 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1527 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1528 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1532 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1536 gboolean widget_was_visible
;
1538 g_return_if_fail (container
!= NULL
);
1539 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1540 g_return_if_fail (child
!= NULL
);
1541 g_return_if_fail (GTK_IS_WIDGET (child
));
1543 bin
= GTK_BIN (container
);
1544 g_return_if_fail ((bin
->child
== child
||
1545 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1547 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1549 gtk_widget_unparent (child
);
1550 if (bin
->child
== child
)
1553 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1554 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1557 if (widget_was_visible
)
1558 gtk_widget_queue_resize (GTK_WIDGET (container
));
1562 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1564 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1566 if (menu_item
->pixmap
!= NULL
) {
1567 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1569 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1570 /* Install pixmap toggle size */
1571 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1574 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1576 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1577 /* Install normal toggle size */
1578 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1582 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1583 whenever the klass->toggle_size changes; but by doing it anytime
1584 this function is called, we get the same effect, just because of
1585 how the preferences option to show pixmaps works. Bogus, broken.
1587 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1588 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));