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"
25 #include "wx/gtk/private.h"
27 #include <gdk/gdkkeysyms.h>
29 // FIXME: is this right? somehow I don't think so (VZ)
31 #include <glib-object.h>
33 #define gtk_accel_group_attach(g, o) _gtk_accel_group_attach((g), (o))
34 #define gtk_accel_group_detach(g, o) _gtk_accel_group_detach((g), (o))
35 #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m)
37 #define ACCEL_OBJECT GObject
38 #define ACCEL_OBJECTS(a) (a)->acceleratables
39 #define ACCEL_OBJ_CAST(obj) G_OBJECT(obj)
41 #define ACCEL_OBJECT GtkObject
42 #define ACCEL_OBJECTS(a) (a)->attach_objects
43 #define ACCEL_OBJ_CAST(obj) GTK_OBJECT(obj)
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
50 extern void wxapp_install_idle_handler();
53 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL
54 static wxString
GetHotKey( const wxMenuItem
& item
);
57 //-----------------------------------------------------------------------------
58 // substitute for missing GtkPixmapMenuItem
59 //-----------------------------------------------------------------------------
61 // FIXME: I can't make this compile with GTK+ 2.0, disabling for now (VZ)
63 #define USE_MENU_BITMAPS
66 #ifdef USE_MENU_BITMAPS
68 #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ())
69 #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem))
70 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass))
71 #define GTK_IS_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
72 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM))
73 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
74 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
76 #ifndef GTK_MENU_ITEM_GET_CLASS
77 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
80 typedef struct _GtkPixmapMenuItem GtkPixmapMenuItem
;
81 typedef struct _GtkPixmapMenuItemClass GtkPixmapMenuItemClass
;
83 struct _GtkPixmapMenuItem
85 GtkMenuItem menu_item
;
90 struct _GtkPixmapMenuItemClass
92 GtkMenuItemClass parent_class
;
94 guint orig_toggle_size
;
95 guint have_pixmap_count
;
99 GtkType
gtk_pixmap_menu_item_get_type (void);
100 GtkWidget
* gtk_pixmap_menu_item_new (void);
101 void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
104 #endif // USE_MENU_BITMAPS
106 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
110 static wxString
wxReplaceUnderscore( const wxString
& title
)
114 /* GTK 1.2 wants to have "_" instead of "&" for accelerators */
116 for ( pc
= title
; *pc
!= wxT('\0'); pc
++ )
120 #if GTK_CHECK_VERSION(1, 2, 0)
124 #if GTK_CHECK_VERSION(2, 0, 0)
125 else if (*pc
== wxT('/'))
129 else if (*pc
== wxT('\\'))
133 #elif GTK_CHECK_VERSION(1, 2, 0)
134 else if (*pc
== wxT('/'))
142 if ( *pc
== wxT('_') )
144 // underscores must be doubled to prevent them from being
145 // interpreted as accelerator character prefix by GTK
156 //-----------------------------------------------------------------------------
158 //-----------------------------------------------------------------------------
160 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
162 wxMenuBar::wxMenuBar( long style
)
164 /* the parent window is known after wxFrame::SetMenu() */
165 m_needParent
= FALSE
;
167 m_invokingWindow
= (wxWindow
*) NULL
;
169 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
170 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
172 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
176 m_menus
.DeleteContents( TRUE
);
178 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
179 #if GTK_CHECK_VERSION(1, 2, 1)
180 m_accel
= gtk_accel_group_new();
181 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
182 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
184 m_menubar
= gtk_menu_bar_new();
187 if (style
& wxMB_DOCKABLE
)
189 m_widget
= gtk_handle_box_new();
190 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
191 gtk_widget_show( GTK_WIDGET(m_menubar
) );
195 m_widget
= GTK_WIDGET(m_menubar
);
203 wxMenuBar::wxMenuBar()
205 /* the parent window is known after wxFrame::SetMenu() */
206 m_needParent
= FALSE
;
208 m_invokingWindow
= (wxWindow
*) NULL
;
210 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
211 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
213 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
217 m_menus
.DeleteContents( TRUE
);
219 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
220 #if GTK_CHECK_VERSION(1, 2, 1)
221 m_accel
= gtk_accel_group_new();
222 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
223 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
225 m_menubar
= gtk_menu_bar_new();
228 m_widget
= GTK_WIDGET(m_menubar
);
235 wxMenuBar::~wxMenuBar()
237 // gtk_object_unref( GTK_OBJECT(m_factory) ); why not ?
240 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
242 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
244 wxWindow
*top_frame
= win
;
245 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
246 top_frame
= top_frame
->GetParent();
248 /* support for native hot keys */
249 gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
251 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
254 wxMenuItem
*menuitem
= node
->GetData();
255 if (menuitem
->IsSubMenu())
256 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
257 node
= node
->GetNext();
261 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
263 menu
->SetInvokingWindow( win
);
265 #if GTK_CHECK_VERSION(1, 2, 1)
266 wxWindow
*top_frame
= win
;
267 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
268 top_frame
= top_frame
->GetParent();
270 /* support for native hot keys */
271 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
272 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
273 gtk_accel_group_attach( menu
->m_accel
, obj
);
274 #endif // GTK+ 1.2.1+
276 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
279 wxMenuItem
*menuitem
= node
->GetData();
280 if (menuitem
->IsSubMenu())
281 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
282 node
= node
->GetNext();
286 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
288 m_invokingWindow
= win
;
289 #if GTK_CHECK_VERSION(1, 2, 1)
290 wxWindow
*top_frame
= win
;
291 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
292 top_frame
= top_frame
->GetParent();
294 /* support for native key accelerators indicated by underscroes */
295 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
296 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
297 gtk_accel_group_attach( m_accel
, obj
);
298 #endif // GTK+ 1.2.1+
300 wxMenuList::Node
*node
= m_menus
.GetFirst();
303 wxMenu
*menu
= node
->GetData();
304 wxMenubarSetInvokingWindow( menu
, win
);
305 node
= node
->GetNext();
309 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
311 m_invokingWindow
= (wxWindow
*) NULL
;
312 #if GTK_CHECK_VERSION(1, 2, 1)
313 wxWindow
*top_frame
= win
;
314 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
315 top_frame
= top_frame
->GetParent();
317 /* support for native key accelerators indicated by underscroes */
318 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
319 #endif // GTK+ 1.2.1+
321 wxMenuList::Node
*node
= m_menus
.GetFirst();
324 wxMenu
*menu
= node
->GetData();
325 wxMenubarUnsetInvokingWindow( menu
, win
);
326 node
= node
->GetNext();
330 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
332 if ( !wxMenuBarBase::Append( menu
, title
) )
335 return GtkAppend(menu
, title
);
338 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
)
340 wxString
str( wxReplaceUnderscore( title
) );
342 /* this doesn't have much effect right now */
343 menu
->SetTitle( str
);
345 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
346 #if GTK_CHECK_VERSION(1, 2, 1)
349 buf
<< wxT('/') << str
.c_str();
351 /* local buffer in multibyte form */
353 strcpy(cbuf
, wxGTK_CONV(buf
) );
355 GtkItemFactoryEntry entry
;
356 entry
.path
= (gchar
*)cbuf
; // const_cast
357 entry
.accelerator
= (gchar
*) NULL
;
358 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
359 entry
.callback_action
= 0;
360 entry
.item_type
= (char *)"<Branch>";
362 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
363 /* in order to get the pointer to the item we need the item text _without_ underscores */
364 wxString tmp
= wxT("<main>/");
366 for ( pc
= str
; *pc
!= wxT('\0'); pc
++ )
368 // contrary to the common sense, we must throw out _all_ underscores,
369 // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we
370 // might naively think). IMHO it's a bug in GTK+ (VZ)
371 while (*pc
== wxT('_'))
375 menu
->m_owner
= gtk_item_factory_get_item( m_factory
, wxGTK_CONV( tmp
) );
376 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
379 menu
->m_owner
= gtk_menu_item_new_with_label( wxGTK_CONV( str
) );
380 gtk_widget_show( menu
->m_owner
);
381 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
383 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
387 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
388 // adding menu later on.
389 if (m_invokingWindow
)
390 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
395 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
397 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
400 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
401 // of version 1.2.6), so we first append the item and then change its
403 if ( !GtkAppend(menu
, title
) )
406 if (pos
+1 >= m_menus
.GetCount())
409 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
410 gpointer data
= g_list_last(menu_shell
->children
)->data
;
411 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
412 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
417 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
419 // remove the old item and insert a new one
420 wxMenu
*menuOld
= Remove(pos
);
421 if ( menuOld
&& !Insert(pos
, menu
, title
) )
423 return (wxMenu
*) NULL
;
426 // either Insert() succeeded or Remove() failed and menuOld is NULL
430 wxMenu
*wxMenuBar::Remove(size_t pos
)
432 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
434 return (wxMenu
*) NULL
;
437 GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget);
439 printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) );
440 printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) );
443 // unparent calls unref() and that would delete the widget so we raise
444 // the ref count to 2 artificially before invoking unparent.
445 gtk_widget_ref( menu
->m_menu
);
446 gtk_widget_unparent( menu
->m_menu
);
448 gtk_widget_destroy( menu
->m_owner
);
451 printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) );
452 printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) );
458 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
460 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
462 int res
= menu
->FindItem( itemString
);
463 if (res
!= wxNOT_FOUND
)
467 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
470 wxMenuItem
*item
= node
->GetData();
471 if (item
->IsSubMenu())
472 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
474 node
= node
->GetNext();
480 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
482 wxMenuList::Node
*node
= m_menus
.GetFirst();
485 wxMenu
*menu
= node
->GetData();
486 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
489 node
= node
->GetNext();
495 // Find a wxMenuItem using its id. Recurses down into sub-menus
496 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
498 wxMenuItem
* result
= menu
->FindChildItem(id
);
500 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
501 while ( node
&& result
== NULL
)
503 wxMenuItem
*item
= node
->GetData();
504 if (item
->IsSubMenu())
506 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
508 node
= node
->GetNext();
514 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
516 wxMenuItem
* result
= 0;
517 wxMenuList::Node
*node
= m_menus
.GetFirst();
518 while (node
&& result
== 0)
520 wxMenu
*menu
= node
->GetData();
521 result
= FindMenuItemByIdRecursive( menu
, id
);
522 node
= node
->GetNext();
527 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
533 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
535 wxMenuList::Node
*node
= m_menus
.Item( pos
);
537 wxCHECK_RET( node
, wxT("menu not found") );
539 wxMenu
* menu
= node
->GetData();
542 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
545 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
547 wxMenuList::Node
*node
= m_menus
.Item( pos
);
549 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
551 wxMenu
* menu
= node
->GetData();
554 wxString
text( menu
->GetTitle() );
555 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
557 if ( *pc
== wxT('_') || *pc
== wxT('&') )
559 // '_' is the escape character for GTK+ and '&' is the one for
560 // wxWindows - skip both of them
570 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
572 wxMenuList::Node
*node
= m_menus
.Item( pos
);
574 wxCHECK_RET( node
, wxT("menu not found") );
576 wxMenu
* menu
= node
->GetData();
578 wxString
str( wxReplaceUnderscore( label
) );
580 menu
->SetTitle( str
);
584 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
587 gtk_label_set( label
, wxGTK_CONV( str
) );
589 /* reparse key accel */
590 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
591 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
596 //-----------------------------------------------------------------------------
598 //-----------------------------------------------------------------------------
600 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
603 wxapp_install_idle_handler();
605 int id
= menu
->FindMenuIdByMenuItem(widget
);
607 /* should find it for normal (not popup) menu */
608 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
609 _T("menu item not found in gtk_menu_clicked_callback") );
611 if (!menu
->IsEnabled(id
))
614 wxMenuItem
* item
= menu
->FindChildItem( id
);
615 wxCHECK_RET( item
, wxT("error in menu item callback") );
617 if (item
->IsCheckable())
619 bool isReallyChecked
= item
->IsChecked(),
620 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
622 // ensure that the internal state is always consistent with what is
623 // shown on the screen
624 item
->wxMenuItemBase::Check(isReallyChecked
);
626 // we must not report the events for the radio button going up nor the
627 // events resulting from the calls to wxMenuItem::Check()
628 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
629 (isInternallyChecked
== isReallyChecked
) )
634 // the user pressed on the menu item: report the event below
637 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
640 //-----------------------------------------------------------------------------
642 //-----------------------------------------------------------------------------
644 static void gtk_menu_hilight_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
, id
);
656 event
.SetEventObject( menu
);
658 if (menu
->GetEventHandler()->ProcessEvent(event
))
661 wxWindow
*win
= menu
->GetInvokingWindow();
662 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
665 //-----------------------------------------------------------------------------
667 //-----------------------------------------------------------------------------
669 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
671 if (g_isIdle
) wxapp_install_idle_handler();
673 int id
= menu
->FindMenuIdByMenuItem(widget
);
675 wxASSERT( id
!= -1 ); // should find it!
677 if (!menu
->IsEnabled(id
))
680 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
681 event
.SetEventObject( menu
);
683 if (menu
->GetEventHandler()->ProcessEvent(event
))
686 wxWindow
*win
= menu
->GetInvokingWindow();
688 win
->GetEventHandler()->ProcessEvent( event
);
691 //-----------------------------------------------------------------------------
693 //-----------------------------------------------------------------------------
695 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
697 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
699 const wxString
& name
,
700 const wxString
& help
,
704 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
707 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
709 const wxString
& text
,
710 const wxString
& help
,
713 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
718 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
720 const wxString
& text
,
721 const wxString
& help
,
724 : wxMenuItemBase(parentMenu
, id
, text
, help
,
725 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
730 void wxMenuItem::Init(const wxString
& text
)
732 m_labelWidget
= (GtkWidget
*) NULL
;
733 m_menuItem
= (GtkWidget
*) NULL
;
738 wxMenuItem::~wxMenuItem()
740 // don't delete menu items, the menus take care of that
743 // return the menu item text without any menu accels
745 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
749 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
751 if ( *pc
== wxT('_') )
753 // wxGTK escapes "xxx_xxx" to "xxx__xxx"
759 if ( *pc
== wxT('&') )
771 void wxMenuItem::SetText( const wxString
& str
)
773 // Some optimization to avoid flicker
774 wxString oldLabel
= m_text
;
775 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
776 oldLabel
.Replace(wxT("_"), wxT(""));
777 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
778 if (oldLabel
== label1
)
787 label
= (GtkLabel
*) m_labelWidget
;
789 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
792 gtk_label_set( label
, wxGTK_CONV( m_text
) );
794 /* reparse key accel */
795 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( m_text
) );
796 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
800 // it's valid for this function to be called even if m_menuItem == NULL
801 void wxMenuItem::DoSetText( const wxString
& str
)
803 /* '\t' is the deliminator indicating a hot key */
805 const wxChar
*pc
= str
;
806 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
808 #if GTK_CHECK_VERSION(1, 2, 0)
813 else if ( *pc
== wxT('_') ) // escape underscores
817 #else // GTK+ < 1.2.0
822 #if GTK_CHECK_VERSION(2, 0, 0)
823 else if (*pc
== wxT('/')) // we have to escape slashes
825 m_text
<< wxT("\\/");
827 else if (*pc
== wxT('\\')) // we have to double backslashes
829 m_text
<< wxT("\\\\");
831 #elif GTK_CHECK_VERSION(1, 2, 0)
832 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
834 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
852 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
857 return (wxAcceleratorEntry
*)NULL
;
860 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
862 label
<< wxT('\t') << GetHotKey();
864 return wxGetAccelFromString(label
);
867 #endif // wxUSE_ACCEL
869 void wxMenuItem::Check( bool check
)
871 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
873 if (check
== m_isChecked
)
876 wxMenuItemBase::Check( check
);
882 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
886 wxFAIL_MSG( _T("can't check this item") );
890 void wxMenuItem::Enable( bool enable
)
892 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
894 gtk_widget_set_sensitive( m_menuItem
, enable
);
895 wxMenuItemBase::Enable( enable
);
898 bool wxMenuItem::IsChecked() const
900 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
902 wxCHECK_MSG( IsCheckable(), FALSE
,
903 wxT("can't get state of uncheckable item!") );
905 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
908 wxString
wxMenuItem::GetFactoryPath() const
910 /* in order to get the pointer to the item we need the item text
911 _without_ underscores */
912 wxString
path( wxT("<main>/") );
914 for ( const wxChar
*pc
= m_text
.c_str(); *pc
; pc
++ )
916 if ( *pc
== wxT('_') || *pc
== wxT('&') )
918 // remove '_' and '&' unconditionally
928 //-----------------------------------------------------------------------------
930 //-----------------------------------------------------------------------------
932 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
936 m_accel
= gtk_accel_group_new();
937 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
938 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
940 m_owner
= (GtkWidget
*) NULL
;
942 /* Tearoffs are entries, just like separators. So if we want this
943 menu to be a tear-off one, we just append a tearoff entry
945 if(m_style
& wxMENU_TEAROFF
)
947 GtkItemFactoryEntry entry
;
948 entry
.path
= (char *)"/tearoff";
949 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
950 entry
.callback_action
= 0;
951 entry
.item_type
= (char *)"<Tearoff>";
952 entry
.accelerator
= (gchar
*) NULL
;
953 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
954 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
957 // append the title as the very first entry if we have it
969 gtk_widget_destroy( m_menu
);
971 gtk_object_unref( GTK_OBJECT(m_factory
) );
974 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
978 #if defined(USE_MENU_BITMAPS) || !GTK_CHECK_VERSION(1, 2, 0)
979 bool appended
= FALSE
;
982 // does this item terminate the current radio group?
983 bool endOfRadioGroup
= TRUE
;
985 if ( mitem
->IsSeparator() )
987 GtkItemFactoryEntry entry
;
988 entry
.path
= (char *)"/sep";
989 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
990 entry
.callback_action
= 0;
991 entry
.item_type
= (char *)"<Separator>";
992 entry
.accelerator
= (gchar
*) NULL
;
994 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
996 /* this will be wrong for more than one separator. do we care? */
997 menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
999 // we might have a separator inside a radio group
1000 endOfRadioGroup
= FALSE
;
1002 else if ( mitem
->IsSubMenu() )
1004 /* text has "_" instead of "&" after mitem->SetText() */
1005 wxString
text( mitem
->GetText() );
1007 /* local buffer in multibyte form */
1010 strcat( buf
, wxGTK_CONV( text
) );
1012 GtkItemFactoryEntry entry
;
1014 entry
.callback
= (GtkItemFactoryCallback
) 0;
1015 entry
.callback_action
= 0;
1016 entry
.item_type
= (char *)"<Branch>";
1017 entry
.accelerator
= (gchar
*) NULL
;
1019 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1021 wxString
path( mitem
->GetFactoryPath() );
1022 menuItem
= gtk_item_factory_get_item( m_factory
, wxGTK_CONV( path
) );
1024 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1026 // if adding a submenu to a menu already existing in the menu bar, we
1027 // must set invoking window to allow processing events from this
1029 if ( m_invokingWindow
)
1030 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1032 #ifdef USE_MENU_BITMAPS
1033 else if (mitem
->GetBitmap().Ok()) // An item with bitmap
1035 wxString
text( mitem
->GetText() );
1036 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1038 menuItem
= gtk_pixmap_menu_item_new ();
1039 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1040 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1041 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1042 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1043 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1044 if (accel_key
!= GDK_VoidSymbol
)
1046 gtk_widget_add_accelerator (menuItem
,
1048 gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)),
1052 gtk_widget_show (label
);
1054 mitem
->SetLabelWidget(label
);
1056 GtkWidget
* pixmap
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
);
1057 gtk_widget_show(pixmap
);
1058 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1060 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1061 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1063 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1064 gtk_widget_show( menuItem
);
1066 appended
= TRUE
; // We've done this, don't do it again
1068 #endif // USE_MENU_BITMAPS
1069 else // a normal item
1071 // text has "_" instead of "&" after mitem->SetText() so don't use it
1072 wxString
text( mitem
->GetText() );
1074 // buffer containing the menu text in multibyte form
1077 strncat( buf
, wxGTK_CONV(text
), WXSIZEOF(buf
) - 2 );
1078 buf
[WXSIZEOF(buf
) - 1] = '\0';
1080 GtkItemFactoryEntry entry
;
1082 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
1083 entry
.callback_action
= 0;
1086 const char *item_type
;
1087 switch ( mitem
->GetKind() )
1090 item_type
= "<CheckItem>";
1094 if ( m_pathLastRadio
.empty() )
1096 // start of a new radio group
1097 item_type
= "<RadioItem>";
1098 m_pathLastRadio
= buf
+ 1;
1100 else // continue the radio group
1102 pathRadio
= m_pathLastRadio
;
1103 pathRadio
.Replace(wxT("_"), wxT(""));
1104 pathRadio
.Prepend(wxT("<main>/"));
1107 strncpy(buf2
, wxGTK_CONV(pathRadio
), WXSIZEOF(buf2
));
1108 buf2
[WXSIZEOF(buf2
) - 1] = '\0';
1112 // continue the existing radio group, if any
1113 endOfRadioGroup
= FALSE
;
1117 wxFAIL_MSG( _T("unexpected menu item kind") );
1121 item_type
= "<Item>";
1125 entry
.item_type
= (char *)item_type
; // cast needed for GTK+
1126 entry
.accelerator
= (gchar
*) NULL
;
1129 // due to an apparent bug in GTK+, we have to use a static buffer here -
1130 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
1132 char s_accel
[50]; // should be big enough, we check for overruns
1133 wxString
tmp( GetHotKey(*mitem
) );
1134 strncpy(s_accel
, wxGTK_CONV( tmp
), WXSIZEOF(s_accel
));
1135 s_accel
[WXSIZEOF(s_accel
) - 1] = '\0';
1136 entry
.accelerator
= s_accel
;
1137 #else // !wxUSE_ACCEL
1138 entry
.accelerator
= (char*) NULL
;
1139 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
1141 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1143 wxString
path( mitem
->GetFactoryPath() );
1144 menuItem
= gtk_item_factory_get_widget( m_factory
, wxGTK_CONV( path
) );
1147 if ( !mitem
->IsSeparator() )
1149 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1150 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1153 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1154 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1158 mitem
->SetMenuItem(menuItem
);
1160 if ( endOfRadioGroup
)
1162 m_pathLastRadio
.clear();
1168 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
1170 return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
);
1173 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1175 if ( !wxMenuBase::DoInsert(pos
, item
) )
1179 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
1180 // of version 1.2.6), so we first append the item and then change its
1182 if ( !GtkAppend(item
) )
1185 if ( m_style
& wxMENU_TEAROFF
)
1187 // change the position as the first item is the tear-off marker
1191 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
1192 gpointer data
= g_list_last(menu_shell
->children
)->data
;
1193 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
1194 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
1198 // this should be easy to do...
1199 wxFAIL_MSG( wxT("not implemented") );
1202 #endif // GTK 1.2/1.0
1205 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1207 if ( !wxMenuBase::DoRemove(item
) )
1208 return (wxMenuItem
*)NULL
;
1210 // TODO: this code doesn't delete the item factory item and this seems
1211 // impossible as of GTK 1.2.6.
1212 gtk_widget_destroy( item
->GetMenuItem() );
1217 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1219 wxNode
*node
= m_items
.First();
1222 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1223 if (item
->GetMenuItem() == menuItem
)
1224 return item
->GetId();
1225 node
= node
->Next();
1231 // ----------------------------------------------------------------------------
1233 // ----------------------------------------------------------------------------
1235 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL
1237 static wxString
GetHotKey( const wxMenuItem
& item
)
1241 wxAcceleratorEntry
*accel
= item
.GetAccel();
1244 int flags
= accel
->GetFlags();
1245 if ( flags
& wxACCEL_ALT
)
1246 hotkey
+= wxT("<alt>");
1247 if ( flags
& wxACCEL_CTRL
)
1248 hotkey
+= wxT("<control>");
1249 if ( flags
& wxACCEL_SHIFT
)
1250 hotkey
+= wxT("<shift>");
1252 int code
= accel
->GetKeyCode();
1267 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1270 // TODO: we should use gdk_keyval_name() (a.k.a.
1271 // XKeysymToString) here as well as hardcoding the keysym
1272 // names this might be not portable
1273 case WXK_NUMPAD_INSERT
:
1274 hotkey
<< wxT("KP_Insert" );
1276 case WXK_NUMPAD_DELETE
:
1277 hotkey
<< wxT("KP_Delete" );
1280 hotkey
<< wxT("Insert" );
1283 hotkey
<< wxT("Delete" );
1286 // if there are any other keys wxGetAccelFromString() may
1287 // return, we should process them here
1292 gchar
*name
= gdk_keyval_name((guint
)code
);
1300 wxFAIL_MSG( wxT("unknown keyboard accel") );
1309 #endif // wxUSE_ACCEL
1312 //-----------------------------------------------------------------------------
1313 // substitute for missing GtkPixmapMenuItem
1314 //-----------------------------------------------------------------------------
1316 #ifdef USE_MENU_BITMAPS
1319 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1320 * All rights reserved.
1322 * This file is part of the Gnome Library.
1324 * The Gnome Library is free software; you can redistribute it and/or
1325 * modify it under the terms of the GNU Library General Public License as
1326 * published by the Free Software Foundation; either version 2 of the
1327 * License, or (at your option) any later version.
1329 * The Gnome Library is distributed in the hope that it will be useful,
1330 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1331 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1332 * Library General Public License for more details.
1334 * You should have received a copy of the GNU Library General Public
1335 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1336 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1337 * Boston, MA 02111-1307, USA.
1343 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1345 #include <gtk/gtkaccellabel.h>
1346 #include <gtk/gtksignal.h>
1347 #include <gtk/gtkmenuitem.h>
1348 #include <gtk/gtkmenu.h>
1349 #include <gtk/gtkcontainer.h>
1354 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1355 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1356 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1357 GdkRectangle
*area
);
1358 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1359 GdkEventExpose
*event
);
1361 /* we must override the following functions */
1363 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1364 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1365 GtkAllocation
*allocation
);
1366 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1367 gboolean include_internals
,
1368 GtkCallback callback
,
1369 gpointer callback_data
);
1370 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1371 GtkRequisition
*requisition
);
1372 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1375 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1377 static GtkMenuItemClass
*parent_class
= NULL
;
1381 #define BORDER_SPACING 3
1382 #define PMAP_WIDTH 20
1385 gtk_pixmap_menu_item_get_type (void)
1387 static GtkType pixmap_menu_item_type
= 0;
1389 if (!pixmap_menu_item_type
)
1391 GtkTypeInfo pixmap_menu_item_info
=
1393 (char *)"GtkPixmapMenuItem",
1394 sizeof (GtkPixmapMenuItem
),
1395 sizeof (GtkPixmapMenuItemClass
),
1396 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1397 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1398 /* reserved_1 */ NULL
,
1399 /* reserved_2 */ NULL
,
1400 (GtkClassInitFunc
) NULL
,
1403 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1404 &pixmap_menu_item_info
);
1407 return pixmap_menu_item_type
;
1411 * gtk_pixmap_menu_item_new
1413 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1414 * to set the pixmap wich is displayed at the left side.
1417 * &GtkWidget pointer to new menu item
1421 gtk_pixmap_menu_item_new (void)
1423 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1427 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1429 GtkObjectClass
*object_class
;
1430 GtkWidgetClass
*widget_class
;
1431 GtkMenuItemClass
*menu_item_class
;
1432 GtkContainerClass
*container_class
;
1434 object_class
= (GtkObjectClass
*) klass
;
1435 widget_class
= (GtkWidgetClass
*) klass
;
1436 menu_item_class
= (GtkMenuItemClass
*) klass
;
1437 container_class
= (GtkContainerClass
*) klass
;
1439 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1441 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1442 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1443 widget_class
->map
= gtk_pixmap_menu_item_map
;
1444 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1445 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1447 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1448 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1450 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1451 klass
->have_pixmap_count
= 0;
1455 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1459 mi
= GTK_MENU_ITEM (menu_item
);
1461 menu_item
->pixmap
= NULL
;
1465 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1468 g_return_if_fail (widget
!= NULL
);
1469 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1470 g_return_if_fail (area
!= NULL
);
1472 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1473 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1475 if (GTK_WIDGET_DRAWABLE (widget
) &&
1476 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1477 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1482 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1483 GdkEventExpose
*event
)
1485 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1486 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1487 g_return_val_if_fail (event
!= NULL
, FALSE
);
1489 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1490 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1492 if (GTK_WIDGET_DRAWABLE (widget
) &&
1493 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1494 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1501 * gtk_pixmap_menu_item_set_pixmap
1502 * @menu_item: Pointer to the pixmap menu item
1503 * @pixmap: Pointer to a pixmap widget
1505 * Set the pixmap of the menu item.
1510 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1513 g_return_if_fail (menu_item
!= NULL
);
1514 g_return_if_fail (pixmap
!= NULL
);
1515 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1516 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1517 g_return_if_fail (menu_item
->pixmap
== NULL
);
1519 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1520 menu_item
->pixmap
= pixmap
;
1522 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1523 !GTK_WIDGET_REALIZED (pixmap
))
1524 gtk_widget_realize (pixmap
);
1526 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1527 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1528 GTK_WIDGET_VISIBLE(pixmap
) &&
1529 !GTK_WIDGET_MAPPED (pixmap
))
1530 gtk_widget_map (pixmap
);
1533 changed_have_pixmap_status(menu_item
);
1535 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1536 gtk_widget_queue_resize (pixmap
);
1540 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1542 GtkPixmapMenuItem
*menu_item
;
1544 g_return_if_fail (widget
!= NULL
);
1545 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1547 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1549 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1551 if (menu_item
->pixmap
&&
1552 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1553 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1554 gtk_widget_map (menu_item
->pixmap
);
1558 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1559 GtkAllocation
*allocation
)
1561 GtkPixmapMenuItem
*pmenu_item
;
1563 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1565 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1567 GtkAllocation child_allocation
;
1570 border_width
= GTK_CONTAINER (widget
)->border_width
;
1572 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1573 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1574 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1575 child_allocation
.y
= (border_width
+ BORDER_SPACING
1576 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1577 / 2)); /* center pixmaps vertically */
1578 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1581 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1582 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1586 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1587 gboolean include_internals
,
1588 GtkCallback callback
,
1589 gpointer callback_data
)
1591 GtkPixmapMenuItem
*menu_item
;
1593 g_return_if_fail (container
!= NULL
);
1594 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1595 g_return_if_fail (callback
!= NULL
);
1597 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1599 if (menu_item
->pixmap
)
1600 (* callback
) (menu_item
->pixmap
, callback_data
);
1602 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1603 callback
,callback_data
);
1607 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1608 GtkRequisition
*requisition
)
1610 GtkPixmapMenuItem
*menu_item
;
1611 GtkRequisition req
= {0, 0};
1613 g_return_if_fail (widget
!= NULL
);
1614 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1615 g_return_if_fail (requisition
!= NULL
);
1617 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1619 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1621 if (menu_item
->pixmap
)
1622 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1624 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1625 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1629 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1633 gboolean widget_was_visible
;
1635 g_return_if_fail (container
!= NULL
);
1636 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1637 g_return_if_fail (child
!= NULL
);
1638 g_return_if_fail (GTK_IS_WIDGET (child
));
1640 bin
= GTK_BIN (container
);
1641 g_return_if_fail ((bin
->child
== child
||
1642 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1644 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1646 gtk_widget_unparent (child
);
1647 if (bin
->child
== child
)
1650 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1651 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1654 if (widget_was_visible
)
1655 gtk_widget_queue_resize (GTK_WIDGET (container
));
1659 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1661 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1663 if (menu_item
->pixmap
!= NULL
) {
1664 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1666 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1667 /* Install pixmap toggle size */
1668 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1671 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1673 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1674 /* Install normal toggle size */
1675 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1679 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1680 whenever the klass->toggle_size changes; but by doing it anytime
1681 this function is called, we get the same effect, just because of
1682 how the preferences option to show pixmaps works. Bogus, broken.
1684 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1685 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));
1688 #endif // USE_MENU_BITMAPS