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, 1)
123 else if (*pc
== wxT('/'))
131 if ( *pc
== wxT('_') )
133 // underscores must be doubled to prevent them from being
134 // interpreted as accelerator character prefix by GTK
145 //-----------------------------------------------------------------------------
147 //-----------------------------------------------------------------------------
149 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
151 wxMenuBar::wxMenuBar( long style
)
153 /* the parent window is known after wxFrame::SetMenu() */
154 m_needParent
= FALSE
;
156 m_invokingWindow
= (wxWindow
*) NULL
;
158 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
159 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
161 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
165 m_menus
.DeleteContents( TRUE
);
167 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
168 #if GTK_CHECK_VERSION(1, 2, 1)
169 m_accel
= gtk_accel_group_new();
170 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
171 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
173 m_menubar
= gtk_menu_bar_new();
176 if (style
& wxMB_DOCKABLE
)
178 m_widget
= gtk_handle_box_new();
179 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
180 gtk_widget_show( GTK_WIDGET(m_menubar
) );
184 m_widget
= GTK_WIDGET(m_menubar
);
192 wxMenuBar::wxMenuBar()
194 /* the parent window is known after wxFrame::SetMenu() */
195 m_needParent
= FALSE
;
197 m_invokingWindow
= (wxWindow
*) NULL
;
199 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
200 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
202 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
206 m_menus
.DeleteContents( TRUE
);
208 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
209 #if GTK_CHECK_VERSION(1, 2, 1)
210 m_accel
= gtk_accel_group_new();
211 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
212 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
214 m_menubar
= gtk_menu_bar_new();
217 m_widget
= GTK_WIDGET(m_menubar
);
224 wxMenuBar::~wxMenuBar()
226 // gtk_object_unref( GTK_OBJECT(m_factory) ); why not ?
229 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
231 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
233 #if GTK_CHECK_VERSION(1, 2, 0)
234 wxWindow
*top_frame
= win
;
235 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
236 top_frame
= top_frame
->GetParent();
238 /* support for native hot keys */
239 gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
242 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
245 wxMenuItem
*menuitem
= node
->GetData();
246 if (menuitem
->IsSubMenu())
247 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
248 node
= node
->GetNext();
252 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
254 menu
->SetInvokingWindow( win
);
256 #if GTK_CHECK_VERSION(1, 2, 1)
257 wxWindow
*top_frame
= win
;
258 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
259 top_frame
= top_frame
->GetParent();
261 /* support for native hot keys */
262 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
263 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
264 gtk_accel_group_attach( menu
->m_accel
, obj
);
265 #endif // GTK+ 1.2.1+
267 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
270 wxMenuItem
*menuitem
= node
->GetData();
271 if (menuitem
->IsSubMenu())
272 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
273 node
= node
->GetNext();
277 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
279 m_invokingWindow
= win
;
280 #if GTK_CHECK_VERSION(1, 2, 1)
281 wxWindow
*top_frame
= win
;
282 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
283 top_frame
= top_frame
->GetParent();
285 /* support for native key accelerators indicated by underscroes */
286 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
287 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
288 gtk_accel_group_attach( m_accel
, obj
);
289 #endif // GTK+ 1.2.1+
291 wxMenuList::Node
*node
= m_menus
.GetFirst();
294 wxMenu
*menu
= node
->GetData();
295 wxMenubarSetInvokingWindow( menu
, win
);
296 node
= node
->GetNext();
300 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
302 m_invokingWindow
= (wxWindow
*) NULL
;
303 #if GTK_CHECK_VERSION(1, 2, 1)
304 wxWindow
*top_frame
= win
;
305 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
306 top_frame
= top_frame
->GetParent();
308 /* support for native key accelerators indicated by underscroes */
309 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
310 #endif // GTK+ 1.2.1+
312 wxMenuList::Node
*node
= m_menus
.GetFirst();
315 wxMenu
*menu
= node
->GetData();
316 wxMenubarUnsetInvokingWindow( menu
, win
);
317 node
= node
->GetNext();
321 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
323 if ( !wxMenuBarBase::Append( menu
, title
) )
326 return GtkAppend(menu
, title
);
329 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
)
331 wxString
str( wxReplaceUnderscore( title
) );
333 /* this doesn't have much effect right now */
334 menu
->SetTitle( str
);
336 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
337 #if GTK_CHECK_VERSION(1, 2, 1)
339 /* local buffer in multibyte form */
341 buf
<< wxT('/') << str
.c_str();
343 char *cbuf
= new char[buf
.Length()+1];
344 strcpy(cbuf
, buf
.mbc_str());
346 GtkItemFactoryEntry entry
;
347 entry
.path
= (gchar
*)cbuf
; // const_cast
348 entry
.accelerator
= (gchar
*) NULL
;
349 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
350 entry
.callback_action
= 0;
351 entry
.item_type
= (char *)"<Branch>";
353 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
354 /* in order to get the pointer to the item we need the item text _without_ underscores */
355 wxString tmp
= wxT("<main>/");
357 for ( pc
= str
; *pc
!= wxT('\0'); pc
++ )
359 // contrary to the common sense, we must throw out _all_ underscores,
360 // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we
361 // might naively think). IMHO it's a bug in GTK+ (VZ)
362 while (*pc
== wxT('_'))
366 menu
->m_owner
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() );
367 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
371 menu
->m_owner
= gtk_menu_item_new_with_label( str
.mb_str() );
372 gtk_widget_show( menu
->m_owner
);
373 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
375 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
379 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
380 // adding menu later on.
381 if (m_invokingWindow
)
382 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
387 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
389 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
393 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
394 // of version 1.2.6), so we first append the item and then change its
396 if ( !GtkAppend(menu
, title
) )
399 if (pos
+1 >= m_menus
.GetCount())
402 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
403 gpointer data
= g_list_last(menu_shell
->children
)->data
;
404 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
405 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
409 // this should be easy to do with GTK 1.0 - can use standard functions for
410 // this and don't need any hacks like above, but as I don't have GTK 1.0
411 // any more I can't do it
412 wxFAIL_MSG( wxT("TODO") );
415 #endif // GTK 1.2/1.0
418 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
420 // remove the old item and insert a new one
421 wxMenu
*menuOld
= Remove(pos
);
422 if ( menuOld
&& !Insert(pos
, menu
, title
) )
424 return (wxMenu
*) NULL
;
427 // either Insert() succeeded or Remove() failed and menuOld is NULL
431 wxMenu
*wxMenuBar::Remove(size_t pos
)
433 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
435 return (wxMenu
*) NULL
;
438 GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget);
440 printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) );
441 printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) );
444 // unparent calls unref() and that would delete the widget so we raise
445 // the ref count to 2 artificially before invoking unparent.
446 gtk_widget_ref( menu
->m_menu
);
447 gtk_widget_unparent( menu
->m_menu
);
449 gtk_widget_destroy( menu
->m_owner
);
452 printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) );
453 printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) );
459 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
461 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
463 int res
= menu
->FindItem( itemString
);
464 if (res
!= wxNOT_FOUND
)
468 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
471 wxMenuItem
*item
= node
->GetData();
472 if (item
->IsSubMenu())
473 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
475 node
= node
->GetNext();
481 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
483 wxMenuList::Node
*node
= m_menus
.GetFirst();
486 wxMenu
*menu
= node
->GetData();
487 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
490 node
= node
->GetNext();
496 // Find a wxMenuItem using its id. Recurses down into sub-menus
497 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
499 wxMenuItem
* result
= menu
->FindChildItem(id
);
501 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
502 while ( node
&& result
== NULL
)
504 wxMenuItem
*item
= node
->GetData();
505 if (item
->IsSubMenu())
507 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
509 node
= node
->GetNext();
515 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
517 wxMenuItem
* result
= 0;
518 wxMenuList::Node
*node
= m_menus
.GetFirst();
519 while (node
&& result
== 0)
521 wxMenu
*menu
= node
->GetData();
522 result
= FindMenuItemByIdRecursive( menu
, id
);
523 node
= node
->GetNext();
528 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
534 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
536 wxMenuList::Node
*node
= m_menus
.Item( pos
);
538 wxCHECK_RET( node
, wxT("menu not found") );
540 wxMenu
* menu
= node
->GetData();
543 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
546 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
548 wxMenuList::Node
*node
= m_menus
.Item( pos
);
550 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
552 wxMenu
* menu
= node
->GetData();
555 wxString
text( menu
->GetTitle() );
556 #if GTK_CHECK_VERSION(1, 2, 0)
557 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
559 if ( *pc
== wxT('_') || *pc
== wxT('&') )
561 // '_' is the escape character for GTK+ and '&' is the one for
562 // wxWindows - skip both of them
570 #endif // GTK+ 1.2/1.0
575 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
577 wxMenuList::Node
*node
= m_menus
.Item( pos
);
579 wxCHECK_RET( node
, wxT("menu not found") );
581 wxMenu
* menu
= node
->GetData();
583 wxString
str( wxReplaceUnderscore( label
) );
585 menu
->SetTitle( str
);
589 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
592 gtk_label_set( label
, str
.mb_str());
594 /* reparse key accel */
595 (void)gtk_label_parse_uline (GTK_LABEL(label
), str
.mb_str() );
596 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
601 //-----------------------------------------------------------------------------
603 //-----------------------------------------------------------------------------
605 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
608 wxapp_install_idle_handler();
610 int id
= menu
->FindMenuIdByMenuItem(widget
);
612 /* should find it for normal (not popup) menu */
613 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
614 _T("menu item not found in gtk_menu_clicked_callback") );
616 if (!menu
->IsEnabled(id
))
619 wxMenuItem
* item
= menu
->FindChildItem( id
);
620 wxCHECK_RET( item
, wxT("error in menu item callback") );
622 if (item
->IsCheckable())
624 bool isReallyChecked
= item
->IsChecked(),
625 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
627 // ensure that the internal state is always consistent with what is
628 // shown on the screen
629 item
->wxMenuItemBase::Check(isReallyChecked
);
631 // we must not report the events for the radio button going up nor the
632 // events resulting from the calls to wxMenuItem::Check()
633 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
634 (isInternallyChecked
== isReallyChecked
) )
639 // the user pressed on the menu item: report the event below
642 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
645 //-----------------------------------------------------------------------------
647 //-----------------------------------------------------------------------------
649 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
651 if (g_isIdle
) wxapp_install_idle_handler();
653 int id
= menu
->FindMenuIdByMenuItem(widget
);
655 wxASSERT( id
!= -1 ); // should find it!
657 if (!menu
->IsEnabled(id
))
660 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
661 event
.SetEventObject( menu
);
663 if (menu
->GetEventHandler()->ProcessEvent(event
))
666 wxWindow
*win
= menu
->GetInvokingWindow();
667 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
670 //-----------------------------------------------------------------------------
672 //-----------------------------------------------------------------------------
674 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
676 if (g_isIdle
) wxapp_install_idle_handler();
678 int id
= menu
->FindMenuIdByMenuItem(widget
);
680 wxASSERT( id
!= -1 ); // should find it!
682 if (!menu
->IsEnabled(id
))
685 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
686 event
.SetEventObject( menu
);
688 if (menu
->GetEventHandler()->ProcessEvent(event
))
691 wxWindow
*win
= menu
->GetInvokingWindow();
693 win
->GetEventHandler()->ProcessEvent( event
);
696 //-----------------------------------------------------------------------------
698 //-----------------------------------------------------------------------------
700 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
702 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
704 const wxString
& name
,
705 const wxString
& help
,
709 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
712 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
714 const wxString
& text
,
715 const wxString
& help
,
718 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
723 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
725 const wxString
& text
,
726 const wxString
& help
,
729 : wxMenuItemBase(parentMenu
, id
, text
, help
,
730 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
735 void wxMenuItem::Init(const wxString
& text
)
737 m_labelWidget
= (GtkWidget
*) NULL
;
738 m_menuItem
= (GtkWidget
*) NULL
;
743 wxMenuItem::~wxMenuItem()
745 // don't delete menu items, the menus take care of that
748 // return the menu item text without any menu accels
750 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
754 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
756 if ( *pc
== wxT('_') )
758 // wxGTK escapes "xxx_xxx" to "xxx__xxx"
764 if ( *pc
== wxT('&') )
776 void wxMenuItem::SetText( const wxString
& str
)
778 // Some optimization to avoid flicker
779 wxString oldLabel
= m_text
;
780 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
781 oldLabel
.Replace(wxT("_"), wxT(""));
782 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
783 if (oldLabel
== label1
)
792 label
= (GtkLabel
*) m_labelWidget
;
794 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
797 gtk_label_set( label
, m_text
.mb_str());
799 /* reparse key accel */
800 (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() );
801 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
805 // it's valid for this function to be called even if m_menuItem == NULL
806 void wxMenuItem::DoSetText( const wxString
& str
)
808 /* '\t' is the deliminator indicating a hot key */
810 const wxChar
*pc
= str
;
811 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
815 #if GTK_CHECK_VERSION(1, 2, 0)
818 else if ( *pc
== wxT('_') ) // escape underscores
822 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
824 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
825 #endif // GTK+ 1.2.0+
831 /* only GTK 1.2 knows about hot keys */
834 #if GTK_CHECK_VERSION(1, 2, 0)
840 #endif // GTK+ 1.2.0+
845 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
850 return (wxAcceleratorEntry
*)NULL
;
853 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
855 label
<< wxT('\t') << GetHotKey();
857 return wxGetAccelFromString(label
);
860 #endif // wxUSE_ACCEL
862 void wxMenuItem::Check( bool check
)
864 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
866 if (check
== m_isChecked
)
869 wxMenuItemBase::Check( check
);
875 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
879 wxFAIL_MSG( _T("can't check this item") );
883 void wxMenuItem::Enable( bool enable
)
885 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
887 gtk_widget_set_sensitive( m_menuItem
, enable
);
888 wxMenuItemBase::Enable( enable
);
891 bool wxMenuItem::IsChecked() const
893 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
895 wxCHECK_MSG( IsCheckable(), FALSE
,
896 wxT("can't get state of uncheckable item!") );
898 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
901 wxString
wxMenuItem::GetFactoryPath() const
903 /* in order to get the pointer to the item we need the item text
904 _without_ underscores */
905 wxString
path( wxT("<main>/") );
907 for ( const wxChar
*pc
= m_text
.c_str(); *pc
; pc
++ )
909 if ( *pc
== wxT('_') || *pc
== wxT('&') )
911 // remove '_' and '&' unconditionally
921 //-----------------------------------------------------------------------------
923 //-----------------------------------------------------------------------------
925 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
929 #if GTK_CHECK_VERSION(1, 2, 0)
930 m_accel
= gtk_accel_group_new();
931 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
932 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
934 m_menu
= gtk_menu_new(); // Do not show!
937 m_owner
= (GtkWidget
*) NULL
;
939 #if GTK_CHECK_VERSION(1, 2, 0)
940 /* Tearoffs are entries, just like separators. So if we want this
941 menu to be a tear-off one, we just append a tearoff entry
943 if(m_style
& wxMENU_TEAROFF
)
945 GtkItemFactoryEntry entry
;
946 entry
.path
= (char *)"/tearoff";
947 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
948 entry
.callback_action
= 0;
949 entry
.item_type
= (char *)"<Tearoff>";
950 entry
.accelerator
= (gchar
*) NULL
;
951 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
952 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
954 #endif // GTK+ 1.2.0+
956 // append the title as the very first entry if we have it
968 gtk_widget_destroy( m_menu
);
970 gtk_object_unref( GTK_OBJECT(m_factory
) );
973 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
977 #if defined(USE_MENU_BITMAPS) || !GTK_CHECK_VERSION(1, 2, 0)
978 bool appended
= FALSE
;
981 #if GTK_CHECK_VERSION(1, 2, 0)
982 // does this item terminate the current radio group?
983 bool endOfRadioGroup
= TRUE
;
984 #endif // GTK+ >= 1.2
986 if ( mitem
->IsSeparator() )
988 #if GTK_CHECK_VERSION(1, 2, 0)
989 GtkItemFactoryEntry entry
;
990 entry
.path
= (char *)"/sep";
991 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
992 entry
.callback_action
= 0;
993 entry
.item_type
= (char *)"<Separator>";
994 entry
.accelerator
= (gchar
*) NULL
;
996 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
998 /* this will be wrong for more than one separator. do we care? */
999 menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
1001 // we might have a separator inside a radio group
1002 endOfRadioGroup
= FALSE
;
1004 menuItem
= gtk_menu_item_new();
1005 #endif // GTK 1.2/1.0
1007 else if ( mitem
->IsSubMenu() )
1009 #if GTK_CHECK_VERSION(1, 2, 0)
1010 /* text has "_" instead of "&" after mitem->SetText() */
1011 wxString
text( mitem
->GetText() );
1013 /* local buffer in multibyte form */
1016 strcat( buf
, text
.mb_str() );
1018 GtkItemFactoryEntry entry
;
1020 entry
.callback
= (GtkItemFactoryCallback
) 0;
1021 entry
.callback_action
= 0;
1022 entry
.item_type
= (char *)"<Branch>";
1023 entry
.accelerator
= (gchar
*) NULL
;
1025 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1027 wxString
path( mitem
->GetFactoryPath() );
1028 menuItem
= gtk_item_factory_get_item( m_factory
, path
.mb_str() );
1030 menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
1031 #endif // GTK 1.2/1.0
1033 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1035 // if adding a submenu to a menu already existing in the menu bar, we
1036 // must set invoking window to allow processing events from this
1038 if ( m_invokingWindow
)
1039 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1041 #ifdef USE_MENU_BITMAPS
1042 else if (mitem
->GetBitmap().Ok()) // An item with bitmap
1044 wxString
text( mitem
->GetText() );
1045 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1047 menuItem
= gtk_pixmap_menu_item_new ();
1048 GtkWidget
*label
= gtk_accel_label_new (text
.mb_str());
1049 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1050 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1051 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), text
.mb_str() );
1052 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1053 if (accel_key
!= GDK_VoidSymbol
)
1055 gtk_widget_add_accelerator (menuItem
,
1057 gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)),
1061 gtk_widget_show (label
);
1063 mitem
->SetLabelWidget(label
);
1065 GtkWidget
* pixmap
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
);
1066 gtk_widget_show(pixmap
);
1067 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1069 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1070 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1072 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1073 gtk_widget_show( menuItem
);
1075 appended
= TRUE
; // We've done this, don't do it again
1077 #endif // USE_MENU_BITMAPS
1078 else // a normal item
1080 #if GTK_CHECK_VERSION(1, 2, 0)
1081 /* text has "_" instead of "&" after mitem->SetText() */
1082 wxString
text( mitem
->GetText() );
1084 /* local buffer in multibyte form */
1087 strncat( buf
, text
.mb_str(), WXSIZEOF(buf
) - 2 );
1088 buf
[WXSIZEOF(buf
) - 1] = '\0';
1090 GtkItemFactoryEntry entry
;
1092 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
1093 entry
.callback_action
= 0;
1096 const char *item_type
;
1097 switch ( mitem
->GetKind() )
1100 item_type
= "<CheckItem>";
1104 if ( m_pathLastRadio
.empty() )
1106 // start of a new radio group
1107 item_type
= "<RadioItem>";
1108 m_pathLastRadio
= buf
+ 1;
1110 else // continue the radio group
1112 pathRadio
= m_pathLastRadio
;
1113 pathRadio
.Replace("_", "");
1114 pathRadio
.Prepend("<main>/");
1115 item_type
= pathRadio
;
1118 // continue the existing radio group, if any
1119 endOfRadioGroup
= FALSE
;
1123 wxFAIL_MSG( _T("unexpected menu item kind") );
1127 item_type
= "<Item>";
1131 entry
.item_type
= (char *)item_type
; // cast needed for GTK+
1132 entry
.accelerator
= (gchar
*) NULL
;
1135 // due to an apparent bug in GTK+, we have to use a static buffer here -
1136 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
1138 static char s_accel
[50]; // must be big enougg
1139 wxString
tmp( GetHotKey(*mitem
) );
1140 strncpy(s_accel
, tmp
.mb_str(), WXSIZEOF(s_accel
));
1141 entry
.accelerator
= s_accel
;
1142 #else // !wxUSE_ACCEL
1143 entry
.accelerator
= (char*) NULL
;
1144 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
1146 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1148 wxString
path( mitem
->GetFactoryPath() );
1149 menuItem
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() );
1151 menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
1152 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
1154 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1155 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1157 #endif // GTK+ 1.2/1.0
1160 if ( !mitem
->IsSeparator() )
1162 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1163 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1166 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1167 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1171 #if !GTK_CHECK_VERSION(1, 2, 0)
1174 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1175 gtk_widget_show( menuItem
);
1179 mitem
->SetMenuItem(menuItem
);
1181 #if GTK_CHECK_VERSION(1, 2, 0)
1182 if ( endOfRadioGroup
)
1184 m_pathLastRadio
.clear();
1186 #endif // GTK+ >= 1.2
1191 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
1193 return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
);
1196 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1198 if ( !wxMenuBase::DoInsert(pos
, item
) )
1202 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
1203 // of version 1.2.6), so we first append the item and then change its
1205 if ( !GtkAppend(item
) )
1208 if ( m_style
& wxMENU_TEAROFF
)
1210 // change the position as the first item is the tear-off marker
1214 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
1215 gpointer data
= g_list_last(menu_shell
->children
)->data
;
1216 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
1217 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
1221 // this should be easy to do...
1222 wxFAIL_MSG( wxT("not implemented") );
1225 #endif // GTK 1.2/1.0
1228 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1230 if ( !wxMenuBase::DoRemove(item
) )
1231 return (wxMenuItem
*)NULL
;
1233 // TODO: this code doesn't delete the item factory item and this seems
1234 // impossible as of GTK 1.2.6.
1235 gtk_widget_destroy( item
->GetMenuItem() );
1240 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1242 wxNode
*node
= m_items
.First();
1245 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1246 if (item
->GetMenuItem() == menuItem
)
1247 return item
->GetId();
1248 node
= node
->Next();
1254 // ----------------------------------------------------------------------------
1256 // ----------------------------------------------------------------------------
1258 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL
1260 static wxString
GetHotKey( const wxMenuItem
& item
)
1264 wxAcceleratorEntry
*accel
= item
.GetAccel();
1267 int flags
= accel
->GetFlags();
1268 if ( flags
& wxACCEL_ALT
)
1269 hotkey
+= wxT("<alt>");
1270 if ( flags
& wxACCEL_CTRL
)
1271 hotkey
+= wxT("<control>");
1272 if ( flags
& wxACCEL_SHIFT
)
1273 hotkey
+= wxT("<shift>");
1275 int code
= accel
->GetKeyCode();
1290 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1293 // TODO: we should use gdk_keyval_name() (a.k.a.
1294 // XKeysymToString) here as well as hardcoding the keysym
1295 // names this might be not portable
1296 case WXK_NUMPAD_INSERT
:
1297 hotkey
<< wxT("KP_Insert" );
1299 case WXK_NUMPAD_DELETE
:
1300 hotkey
<< wxT("KP_Delete" );
1303 hotkey
<< wxT("Insert" );
1306 hotkey
<< wxT("Delete" );
1309 // if there are any other keys wxGetAccelFromString() may
1310 // return, we should process them here
1315 gchar
*name
= gdk_keyval_name((guint
)code
);
1323 wxFAIL_MSG( wxT("unknown keyboard accel") );
1332 #endif // wxUSE_ACCEL
1335 //-----------------------------------------------------------------------------
1336 // substitute for missing GtkPixmapMenuItem
1337 //-----------------------------------------------------------------------------
1339 #ifdef USE_MENU_BITMAPS
1342 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1343 * All rights reserved.
1345 * This file is part of the Gnome Library.
1347 * The Gnome Library is free software; you can redistribute it and/or
1348 * modify it under the terms of the GNU Library General Public License as
1349 * published by the Free Software Foundation; either version 2 of the
1350 * License, or (at your option) any later version.
1352 * The Gnome Library is distributed in the hope that it will be useful,
1353 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1354 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1355 * Library General Public License for more details.
1357 * You should have received a copy of the GNU Library General Public
1358 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1359 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1360 * Boston, MA 02111-1307, USA.
1366 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1368 #include <gtk/gtkaccellabel.h>
1369 #include <gtk/gtksignal.h>
1370 #include <gtk/gtkmenuitem.h>
1371 #include <gtk/gtkmenu.h>
1372 #include <gtk/gtkcontainer.h>
1377 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1378 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1379 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1380 GdkRectangle
*area
);
1381 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1382 GdkEventExpose
*event
);
1384 /* we must override the following functions */
1386 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1387 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1388 GtkAllocation
*allocation
);
1389 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1390 gboolean include_internals
,
1391 GtkCallback callback
,
1392 gpointer callback_data
);
1393 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1394 GtkRequisition
*requisition
);
1395 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1398 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1400 static GtkMenuItemClass
*parent_class
= NULL
;
1404 #define BORDER_SPACING 3
1405 #define PMAP_WIDTH 20
1408 gtk_pixmap_menu_item_get_type (void)
1410 static GtkType pixmap_menu_item_type
= 0;
1412 if (!pixmap_menu_item_type
)
1414 GtkTypeInfo pixmap_menu_item_info
=
1416 (char *)"GtkPixmapMenuItem",
1417 sizeof (GtkPixmapMenuItem
),
1418 sizeof (GtkPixmapMenuItemClass
),
1419 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1420 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1421 /* reserved_1 */ NULL
,
1422 /* reserved_2 */ NULL
,
1423 (GtkClassInitFunc
) NULL
,
1426 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1427 &pixmap_menu_item_info
);
1430 return pixmap_menu_item_type
;
1434 * gtk_pixmap_menu_item_new
1436 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1437 * to set the pixmap wich is displayed at the left side.
1440 * &GtkWidget pointer to new menu item
1444 gtk_pixmap_menu_item_new (void)
1446 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1450 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1452 GtkObjectClass
*object_class
;
1453 GtkWidgetClass
*widget_class
;
1454 GtkMenuItemClass
*menu_item_class
;
1455 GtkContainerClass
*container_class
;
1457 object_class
= (GtkObjectClass
*) klass
;
1458 widget_class
= (GtkWidgetClass
*) klass
;
1459 menu_item_class
= (GtkMenuItemClass
*) klass
;
1460 container_class
= (GtkContainerClass
*) klass
;
1462 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1464 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1465 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1466 widget_class
->map
= gtk_pixmap_menu_item_map
;
1467 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1468 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1470 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1471 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1473 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1474 klass
->have_pixmap_count
= 0;
1478 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1482 mi
= GTK_MENU_ITEM (menu_item
);
1484 menu_item
->pixmap
= NULL
;
1488 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1491 g_return_if_fail (widget
!= NULL
);
1492 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1493 g_return_if_fail (area
!= NULL
);
1495 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1496 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1498 if (GTK_WIDGET_DRAWABLE (widget
) &&
1499 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1500 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1505 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1506 GdkEventExpose
*event
)
1508 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1509 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1510 g_return_val_if_fail (event
!= NULL
, FALSE
);
1512 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1513 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1515 if (GTK_WIDGET_DRAWABLE (widget
) &&
1516 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1517 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1524 * gtk_pixmap_menu_item_set_pixmap
1525 * @menu_item: Pointer to the pixmap menu item
1526 * @pixmap: Pointer to a pixmap widget
1528 * Set the pixmap of the menu item.
1533 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1536 g_return_if_fail (menu_item
!= NULL
);
1537 g_return_if_fail (pixmap
!= NULL
);
1538 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1539 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1540 g_return_if_fail (menu_item
->pixmap
== NULL
);
1542 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1543 menu_item
->pixmap
= pixmap
;
1545 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1546 !GTK_WIDGET_REALIZED (pixmap
))
1547 gtk_widget_realize (pixmap
);
1549 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1550 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1551 GTK_WIDGET_VISIBLE(pixmap
) &&
1552 !GTK_WIDGET_MAPPED (pixmap
))
1553 gtk_widget_map (pixmap
);
1556 changed_have_pixmap_status(menu_item
);
1558 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1559 gtk_widget_queue_resize (pixmap
);
1563 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1565 GtkPixmapMenuItem
*menu_item
;
1567 g_return_if_fail (widget
!= NULL
);
1568 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1570 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1572 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1574 if (menu_item
->pixmap
&&
1575 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1576 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1577 gtk_widget_map (menu_item
->pixmap
);
1581 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1582 GtkAllocation
*allocation
)
1584 GtkPixmapMenuItem
*pmenu_item
;
1586 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1588 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1590 GtkAllocation child_allocation
;
1593 border_width
= GTK_CONTAINER (widget
)->border_width
;
1595 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1596 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1597 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1598 child_allocation
.y
= (border_width
+ BORDER_SPACING
1599 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1600 / 2)); /* center pixmaps vertically */
1601 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1604 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1605 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1609 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1610 gboolean include_internals
,
1611 GtkCallback callback
,
1612 gpointer callback_data
)
1614 GtkPixmapMenuItem
*menu_item
;
1616 g_return_if_fail (container
!= NULL
);
1617 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1618 g_return_if_fail (callback
!= NULL
);
1620 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1622 if (menu_item
->pixmap
)
1623 (* callback
) (menu_item
->pixmap
, callback_data
);
1625 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1626 callback
,callback_data
);
1630 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1631 GtkRequisition
*requisition
)
1633 GtkPixmapMenuItem
*menu_item
;
1634 GtkRequisition req
= {0, 0};
1636 g_return_if_fail (widget
!= NULL
);
1637 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1638 g_return_if_fail (requisition
!= NULL
);
1640 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1642 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1644 if (menu_item
->pixmap
)
1645 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1647 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1648 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1652 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1656 gboolean widget_was_visible
;
1658 g_return_if_fail (container
!= NULL
);
1659 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1660 g_return_if_fail (child
!= NULL
);
1661 g_return_if_fail (GTK_IS_WIDGET (child
));
1663 bin
= GTK_BIN (container
);
1664 g_return_if_fail ((bin
->child
== child
||
1665 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1667 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1669 gtk_widget_unparent (child
);
1670 if (bin
->child
== child
)
1673 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1674 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1677 if (widget_was_visible
)
1678 gtk_widget_queue_resize (GTK_WIDGET (container
));
1682 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1684 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1686 if (menu_item
->pixmap
!= NULL
) {
1687 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1689 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1690 /* Install pixmap toggle size */
1691 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1694 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1696 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1697 /* Install normal toggle size */
1698 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1702 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1703 whenever the klass->toggle_size changes; but by doing it anytime
1704 this function is called, we get the same effect, just because of
1705 how the preferences option to show pixmaps works. Bogus, broken.
1707 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1708 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));
1711 #endif // USE_MENU_BITMAPS