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() */
1072 wxString
text( mitem
->GetText() );
1074 /* local buffer 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;
1087 const char *item_type
;
1088 switch ( mitem
->GetKind() )
1091 item_type
= "<CheckItem>";
1095 if ( m_pathLastRadio
.empty() )
1097 // start of a new radio group
1098 item_type
= "<RadioItem>";
1099 m_pathLastRadio
= buf
+ 1;
1101 else // continue the radio group
1103 pathRadio
= m_pathLastRadio
;
1104 pathRadio
.Replace(wxT("_"), wxT(""));
1105 pathRadio
.Prepend(wxT("<main>/"));
1106 strncat( buf2
, wxGTK_CONV(pathRadio
), WXSIZEOF(buf2
) - 2 );
1107 buf2
[WXSIZEOF(buf2
) - 1] = '\0';
1111 // continue the existing radio group, if any
1112 endOfRadioGroup
= FALSE
;
1116 wxFAIL_MSG( _T("unexpected menu item kind") );
1120 item_type
= "<Item>";
1124 entry
.item_type
= (char *)item_type
; // cast needed for GTK+
1125 entry
.accelerator
= (gchar
*) NULL
;
1128 // due to an apparent bug in GTK+, we have to use a static buffer here -
1129 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
1131 static char s_accel
[50]; // must be big enough
1132 wxString
tmp( GetHotKey(*mitem
) );
1133 strncpy(s_accel
, wxGTK_CONV( tmp
), WXSIZEOF(s_accel
));
1134 entry
.accelerator
= s_accel
;
1135 #else // !wxUSE_ACCEL
1136 entry
.accelerator
= (char*) NULL
;
1137 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
1139 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1141 wxString
path( mitem
->GetFactoryPath() );
1142 menuItem
= gtk_item_factory_get_widget( m_factory
, wxGTK_CONV( path
) );
1145 if ( !mitem
->IsSeparator() )
1147 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1148 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1151 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1152 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1156 mitem
->SetMenuItem(menuItem
);
1158 if ( endOfRadioGroup
)
1160 m_pathLastRadio
.clear();
1166 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
1168 return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
);
1171 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1173 if ( !wxMenuBase::DoInsert(pos
, item
) )
1177 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
1178 // of version 1.2.6), so we first append the item and then change its
1180 if ( !GtkAppend(item
) )
1183 if ( m_style
& wxMENU_TEAROFF
)
1185 // change the position as the first item is the tear-off marker
1189 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
1190 gpointer data
= g_list_last(menu_shell
->children
)->data
;
1191 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
1192 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
1196 // this should be easy to do...
1197 wxFAIL_MSG( wxT("not implemented") );
1200 #endif // GTK 1.2/1.0
1203 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1205 if ( !wxMenuBase::DoRemove(item
) )
1206 return (wxMenuItem
*)NULL
;
1208 // TODO: this code doesn't delete the item factory item and this seems
1209 // impossible as of GTK 1.2.6.
1210 gtk_widget_destroy( item
->GetMenuItem() );
1215 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1217 wxNode
*node
= m_items
.First();
1220 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1221 if (item
->GetMenuItem() == menuItem
)
1222 return item
->GetId();
1223 node
= node
->Next();
1229 // ----------------------------------------------------------------------------
1231 // ----------------------------------------------------------------------------
1233 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL
1235 static wxString
GetHotKey( const wxMenuItem
& item
)
1239 wxAcceleratorEntry
*accel
= item
.GetAccel();
1242 int flags
= accel
->GetFlags();
1243 if ( flags
& wxACCEL_ALT
)
1244 hotkey
+= wxT("<alt>");
1245 if ( flags
& wxACCEL_CTRL
)
1246 hotkey
+= wxT("<control>");
1247 if ( flags
& wxACCEL_SHIFT
)
1248 hotkey
+= wxT("<shift>");
1250 int code
= accel
->GetKeyCode();
1265 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1268 // TODO: we should use gdk_keyval_name() (a.k.a.
1269 // XKeysymToString) here as well as hardcoding the keysym
1270 // names this might be not portable
1271 case WXK_NUMPAD_INSERT
:
1272 hotkey
<< wxT("KP_Insert" );
1274 case WXK_NUMPAD_DELETE
:
1275 hotkey
<< wxT("KP_Delete" );
1278 hotkey
<< wxT("Insert" );
1281 hotkey
<< wxT("Delete" );
1284 // if there are any other keys wxGetAccelFromString() may
1285 // return, we should process them here
1290 gchar
*name
= gdk_keyval_name((guint
)code
);
1298 wxFAIL_MSG( wxT("unknown keyboard accel") );
1307 #endif // wxUSE_ACCEL
1310 //-----------------------------------------------------------------------------
1311 // substitute for missing GtkPixmapMenuItem
1312 //-----------------------------------------------------------------------------
1314 #ifdef USE_MENU_BITMAPS
1317 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1318 * All rights reserved.
1320 * This file is part of the Gnome Library.
1322 * The Gnome Library is free software; you can redistribute it and/or
1323 * modify it under the terms of the GNU Library General Public License as
1324 * published by the Free Software Foundation; either version 2 of the
1325 * License, or (at your option) any later version.
1327 * The Gnome Library is distributed in the hope that it will be useful,
1328 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1329 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1330 * Library General Public License for more details.
1332 * You should have received a copy of the GNU Library General Public
1333 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1334 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1335 * Boston, MA 02111-1307, USA.
1341 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1343 #include <gtk/gtkaccellabel.h>
1344 #include <gtk/gtksignal.h>
1345 #include <gtk/gtkmenuitem.h>
1346 #include <gtk/gtkmenu.h>
1347 #include <gtk/gtkcontainer.h>
1352 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1353 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1354 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1355 GdkRectangle
*area
);
1356 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1357 GdkEventExpose
*event
);
1359 /* we must override the following functions */
1361 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1362 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1363 GtkAllocation
*allocation
);
1364 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1365 gboolean include_internals
,
1366 GtkCallback callback
,
1367 gpointer callback_data
);
1368 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1369 GtkRequisition
*requisition
);
1370 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1373 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1375 static GtkMenuItemClass
*parent_class
= NULL
;
1379 #define BORDER_SPACING 3
1380 #define PMAP_WIDTH 20
1383 gtk_pixmap_menu_item_get_type (void)
1385 static GtkType pixmap_menu_item_type
= 0;
1387 if (!pixmap_menu_item_type
)
1389 GtkTypeInfo pixmap_menu_item_info
=
1391 (char *)"GtkPixmapMenuItem",
1392 sizeof (GtkPixmapMenuItem
),
1393 sizeof (GtkPixmapMenuItemClass
),
1394 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1395 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1396 /* reserved_1 */ NULL
,
1397 /* reserved_2 */ NULL
,
1398 (GtkClassInitFunc
) NULL
,
1401 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1402 &pixmap_menu_item_info
);
1405 return pixmap_menu_item_type
;
1409 * gtk_pixmap_menu_item_new
1411 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1412 * to set the pixmap wich is displayed at the left side.
1415 * &GtkWidget pointer to new menu item
1419 gtk_pixmap_menu_item_new (void)
1421 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1425 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1427 GtkObjectClass
*object_class
;
1428 GtkWidgetClass
*widget_class
;
1429 GtkMenuItemClass
*menu_item_class
;
1430 GtkContainerClass
*container_class
;
1432 object_class
= (GtkObjectClass
*) klass
;
1433 widget_class
= (GtkWidgetClass
*) klass
;
1434 menu_item_class
= (GtkMenuItemClass
*) klass
;
1435 container_class
= (GtkContainerClass
*) klass
;
1437 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1439 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1440 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1441 widget_class
->map
= gtk_pixmap_menu_item_map
;
1442 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1443 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1445 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1446 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1448 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1449 klass
->have_pixmap_count
= 0;
1453 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1457 mi
= GTK_MENU_ITEM (menu_item
);
1459 menu_item
->pixmap
= NULL
;
1463 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1466 g_return_if_fail (widget
!= NULL
);
1467 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1468 g_return_if_fail (area
!= NULL
);
1470 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1471 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1473 if (GTK_WIDGET_DRAWABLE (widget
) &&
1474 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1475 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1480 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1481 GdkEventExpose
*event
)
1483 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1484 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1485 g_return_val_if_fail (event
!= NULL
, FALSE
);
1487 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1488 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1490 if (GTK_WIDGET_DRAWABLE (widget
) &&
1491 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1492 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1499 * gtk_pixmap_menu_item_set_pixmap
1500 * @menu_item: Pointer to the pixmap menu item
1501 * @pixmap: Pointer to a pixmap widget
1503 * Set the pixmap of the menu item.
1508 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1511 g_return_if_fail (menu_item
!= NULL
);
1512 g_return_if_fail (pixmap
!= NULL
);
1513 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1514 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1515 g_return_if_fail (menu_item
->pixmap
== NULL
);
1517 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1518 menu_item
->pixmap
= pixmap
;
1520 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1521 !GTK_WIDGET_REALIZED (pixmap
))
1522 gtk_widget_realize (pixmap
);
1524 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1525 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1526 GTK_WIDGET_VISIBLE(pixmap
) &&
1527 !GTK_WIDGET_MAPPED (pixmap
))
1528 gtk_widget_map (pixmap
);
1531 changed_have_pixmap_status(menu_item
);
1533 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1534 gtk_widget_queue_resize (pixmap
);
1538 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1540 GtkPixmapMenuItem
*menu_item
;
1542 g_return_if_fail (widget
!= NULL
);
1543 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1545 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1547 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1549 if (menu_item
->pixmap
&&
1550 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1551 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1552 gtk_widget_map (menu_item
->pixmap
);
1556 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1557 GtkAllocation
*allocation
)
1559 GtkPixmapMenuItem
*pmenu_item
;
1561 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1563 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1565 GtkAllocation child_allocation
;
1568 border_width
= GTK_CONTAINER (widget
)->border_width
;
1570 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1571 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1572 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1573 child_allocation
.y
= (border_width
+ BORDER_SPACING
1574 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1575 / 2)); /* center pixmaps vertically */
1576 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1579 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1580 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1584 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1585 gboolean include_internals
,
1586 GtkCallback callback
,
1587 gpointer callback_data
)
1589 GtkPixmapMenuItem
*menu_item
;
1591 g_return_if_fail (container
!= NULL
);
1592 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1593 g_return_if_fail (callback
!= NULL
);
1595 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1597 if (menu_item
->pixmap
)
1598 (* callback
) (menu_item
->pixmap
, callback_data
);
1600 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1601 callback
,callback_data
);
1605 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1606 GtkRequisition
*requisition
)
1608 GtkPixmapMenuItem
*menu_item
;
1609 GtkRequisition req
= {0, 0};
1611 g_return_if_fail (widget
!= NULL
);
1612 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1613 g_return_if_fail (requisition
!= NULL
);
1615 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1617 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1619 if (menu_item
->pixmap
)
1620 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1622 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1623 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1627 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1631 gboolean widget_was_visible
;
1633 g_return_if_fail (container
!= NULL
);
1634 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1635 g_return_if_fail (child
!= NULL
);
1636 g_return_if_fail (GTK_IS_WIDGET (child
));
1638 bin
= GTK_BIN (container
);
1639 g_return_if_fail ((bin
->child
== child
||
1640 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1642 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1644 gtk_widget_unparent (child
);
1645 if (bin
->child
== child
)
1648 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1649 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1652 if (widget_was_visible
)
1653 gtk_widget_queue_resize (GTK_WIDGET (container
));
1657 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1659 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1661 if (menu_item
->pixmap
!= NULL
) {
1662 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1664 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1665 /* Install pixmap toggle size */
1666 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1669 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1671 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1672 /* Install normal toggle size */
1673 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1677 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1678 whenever the klass->toggle_size changes; but by doing it anytime
1679 this function is called, we get the same effect, just because of
1680 how the preferences option to show pixmaps works. Bogus, broken.
1682 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1683 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));
1686 #endif // USE_MENU_BITMAPS