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 if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked
)
627 /* the menu item has been checked by calling wxMenuItem->Check() */
632 /* the user pressed on the menu item -> report and make consistent
634 item
->wxMenuItemBase::Check(isReallyChecked
);
638 menu
->SendEvent(item
->GetId(), item
->IsCheckable() ? item
->IsChecked() : -1);
641 //-----------------------------------------------------------------------------
643 //-----------------------------------------------------------------------------
645 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
647 if (g_isIdle
) wxapp_install_idle_handler();
649 int id
= menu
->FindMenuIdByMenuItem(widget
);
651 wxASSERT( id
!= -1 ); // should find it!
653 if (!menu
->IsEnabled(id
))
656 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
657 event
.SetEventObject( menu
);
659 if (menu
->GetEventHandler()->ProcessEvent(event
))
662 wxWindow
*win
= menu
->GetInvokingWindow();
663 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
666 //-----------------------------------------------------------------------------
668 //-----------------------------------------------------------------------------
670 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
672 if (g_isIdle
) wxapp_install_idle_handler();
674 int id
= menu
->FindMenuIdByMenuItem(widget
);
676 wxASSERT( id
!= -1 ); // should find it!
678 if (!menu
->IsEnabled(id
))
681 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
682 event
.SetEventObject( menu
);
684 if (menu
->GetEventHandler()->ProcessEvent(event
))
687 wxWindow
*win
= menu
->GetInvokingWindow();
689 win
->GetEventHandler()->ProcessEvent( event
);
692 //-----------------------------------------------------------------------------
694 //-----------------------------------------------------------------------------
696 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
698 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
700 const wxString
& name
,
701 const wxString
& help
,
705 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
708 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
710 const wxString
& text
,
711 const wxString
& help
,
714 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
719 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
721 const wxString
& text
,
722 const wxString
& help
,
725 : wxMenuItemBase(parentMenu
, id
, text
, help
,
726 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
731 void wxMenuItem::Init(const wxString
& text
)
733 m_labelWidget
= (GtkWidget
*) NULL
;
734 m_menuItem
= (GtkWidget
*) NULL
;
739 wxMenuItem::~wxMenuItem()
741 // don't delete menu items, the menus take care of that
744 // return the menu item text without any menu accels
746 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
750 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
752 if ( *pc
== wxT('_') )
754 // wxGTK escapes "xxx_xxx" to "xxx__xxx"
760 if ( *pc
== wxT('&') )
772 void wxMenuItem::SetText( const wxString
& str
)
780 label
= (GtkLabel
*) m_labelWidget
;
782 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
785 gtk_label_set( label
, m_text
.mb_str());
787 /* reparse key accel */
788 (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() );
789 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
793 // it's valid for this function to be called even if m_menuItem == NULL
794 void wxMenuItem::DoSetText( const wxString
& str
)
796 /* '\t' is the deliminator indicating a hot key */
798 const wxChar
*pc
= str
;
799 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
803 #if GTK_CHECK_VERSION(1, 2, 0)
806 else if ( *pc
== wxT('_') ) // escape underscores
810 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
812 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
813 #endif // GTK+ 1.2.0+
819 /* only GTK 1.2 knows about hot keys */
822 #if GTK_CHECK_VERSION(1, 2, 0)
828 #endif // GTK+ 1.2.0+
833 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
838 return (wxAcceleratorEntry
*)NULL
;
841 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
843 label
<< wxT('\t') << GetHotKey();
845 return wxGetAccelFromString(label
);
848 #endif // wxUSE_ACCEL
850 void wxMenuItem::Check( bool check
)
852 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
854 if (check
== m_isChecked
)
857 wxMenuItemBase::Check( check
);
863 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
867 wxFAIL_MSG( _T("can't check this item") );
871 void wxMenuItem::Enable( bool enable
)
873 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
875 gtk_widget_set_sensitive( m_menuItem
, enable
);
876 wxMenuItemBase::Enable( enable
);
879 bool wxMenuItem::IsChecked() const
881 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
883 wxCHECK_MSG( IsCheckable(), FALSE
,
884 wxT("can't get state of uncheckable item!") );
886 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
889 wxString
wxMenuItem::GetFactoryPath() const
891 /* in order to get the pointer to the item we need the item text
892 _without_ underscores */
893 wxString
path( wxT("<main>/") );
895 for ( const wxChar
*pc
= m_text
.c_str(); *pc
; pc
++ )
897 if ( *pc
== wxT('_') || *pc
== wxT('&') )
899 // remove '_' and '&' unconditionally
909 //-----------------------------------------------------------------------------
911 //-----------------------------------------------------------------------------
913 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
917 #if GTK_CHECK_VERSION(1, 2, 0)
918 m_accel
= gtk_accel_group_new();
919 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
920 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
922 m_menu
= gtk_menu_new(); // Do not show!
925 m_owner
= (GtkWidget
*) NULL
;
927 #if GTK_CHECK_VERSION(1, 2, 0)
928 /* Tearoffs are entries, just like separators. So if we want this
929 menu to be a tear-off one, we just append a tearoff entry
931 if(m_style
& wxMENU_TEAROFF
)
933 GtkItemFactoryEntry entry
;
934 entry
.path
= (char *)"/tearoff";
935 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
936 entry
.callback_action
= 0;
937 entry
.item_type
= (char *)"<Tearoff>";
938 entry
.accelerator
= (gchar
*) NULL
;
939 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
940 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
942 #endif // GTK+ 1.2.0+
944 // append the title as the very first entry if we have it
956 gtk_widget_destroy( m_menu
);
958 gtk_object_unref( GTK_OBJECT(m_factory
) );
961 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
965 #if defined(USE_MENU_BITMAPS) || !GTK_CHECK_VERSION(1, 2, 0)
966 bool appended
= FALSE
;
969 #if GTK_CHECK_VERSION(1, 2, 0)
970 // does this item terminate the current radio group?
971 bool endOfRadioGroup
= TRUE
;
972 #endif // GTK+ >= 1.2
974 if ( mitem
->IsSeparator() )
976 #if GTK_CHECK_VERSION(1, 2, 0)
977 GtkItemFactoryEntry entry
;
978 entry
.path
= (char *)"/sep";
979 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
980 entry
.callback_action
= 0;
981 entry
.item_type
= (char *)"<Separator>";
982 entry
.accelerator
= (gchar
*) NULL
;
984 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
986 /* this will be wrong for more than one separator. do we care? */
987 menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
989 // we might have a separator inside a radio group
990 endOfRadioGroup
= FALSE
;
992 menuItem
= gtk_menu_item_new();
993 #endif // GTK 1.2/1.0
995 else if ( mitem
->IsSubMenu() )
997 #if GTK_CHECK_VERSION(1, 2, 0)
998 /* text has "_" instead of "&" after mitem->SetText() */
999 wxString
text( mitem
->GetText() );
1001 /* local buffer in multibyte form */
1004 strcat( buf
, text
.mb_str() );
1006 GtkItemFactoryEntry entry
;
1008 entry
.callback
= (GtkItemFactoryCallback
) 0;
1009 entry
.callback_action
= 0;
1010 entry
.item_type
= (char *)"<Branch>";
1011 entry
.accelerator
= (gchar
*) NULL
;
1013 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1015 wxString
path( mitem
->GetFactoryPath() );
1016 menuItem
= gtk_item_factory_get_item( m_factory
, path
.mb_str() );
1018 menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
1019 #endif // GTK 1.2/1.0
1021 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1023 // if adding a submenu to a menu already existing in the menu bar, we
1024 // must set invoking window to allow processing events from this
1026 if ( m_invokingWindow
)
1027 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1029 #ifdef USE_MENU_BITMAPS
1030 else if (mitem
->GetBitmap().Ok()) // An item with bitmap
1032 wxString
text( mitem
->GetText() );
1033 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1035 menuItem
= gtk_pixmap_menu_item_new ();
1036 GtkWidget
*label
= gtk_accel_label_new (text
.mb_str());
1037 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1038 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1039 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), text
.mb_str() );
1040 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1041 if (accel_key
!= GDK_VoidSymbol
)
1043 gtk_widget_add_accelerator (menuItem
,
1045 gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)),
1049 gtk_widget_show (label
);
1051 mitem
->SetLabelWidget(label
);
1053 GtkWidget
* pixmap
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
);
1054 gtk_widget_show(pixmap
);
1055 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1057 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1058 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1060 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1061 gtk_widget_show( menuItem
);
1063 appended
= TRUE
; // We've done this, don't do it again
1065 #endif // USE_MENU_BITMAPS
1066 else // a normal item
1068 #if GTK_CHECK_VERSION(1, 2, 0)
1069 /* text has "_" instead of "&" after mitem->SetText() */
1070 wxString
text( mitem
->GetText() );
1072 /* local buffer in multibyte form */
1075 strncat( buf
, text
.mb_str(), WXSIZEOF(buf
) - 2 );
1076 buf
[WXSIZEOF(buf
) - 1] = '\0';
1078 GtkItemFactoryEntry entry
;
1080 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
1081 entry
.callback_action
= 0;
1084 const char *item_type
;
1085 switch ( mitem
->GetKind() )
1088 item_type
= "<CheckItem>";
1092 if ( m_pathLastRadio
.empty() )
1094 // start of a new radio group
1095 item_type
= "<RadioItem>";
1096 m_pathLastRadio
= buf
+ 1;
1098 else // continue the radio group
1100 pathRadio
= m_pathLastRadio
;
1101 pathRadio
.Replace("_", "");
1102 pathRadio
.Prepend("<main>/");
1103 item_type
= pathRadio
;
1106 // continue the existing radio group, if any
1107 endOfRadioGroup
= FALSE
;
1111 wxFAIL_MSG( _T("unexpected menu item kind") );
1115 item_type
= "<Item>";
1119 entry
.item_type
= (char *)item_type
; // cast needed for GTK+
1120 entry
.accelerator
= (gchar
*) NULL
;
1123 // due to an apparent bug in GTK+, we have to use a static buffer here -
1124 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
1126 static char s_accel
[50]; // must be big enougg
1127 wxString
tmp( GetHotKey(*mitem
) );
1128 strncpy(s_accel
, tmp
.mb_str(), WXSIZEOF(s_accel
));
1129 entry
.accelerator
= s_accel
;
1130 #else // !wxUSE_ACCEL
1131 entry
.accelerator
= (char*) NULL
;
1132 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
1134 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1136 wxString
path( mitem
->GetFactoryPath() );
1137 menuItem
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() );
1139 menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
1140 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
1142 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1143 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1145 #endif // GTK+ 1.2/1.0
1148 if ( !mitem
->IsSeparator() )
1150 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1151 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1154 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1155 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1159 #if !GTK_CHECK_VERSION(1, 2, 0)
1162 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1163 gtk_widget_show( menuItem
);
1167 mitem
->SetMenuItem(menuItem
);
1169 #if GTK_CHECK_VERSION(1, 2, 0)
1170 if ( endOfRadioGroup
)
1172 m_pathLastRadio
.clear();
1174 #endif // GTK+ >= 1.2
1179 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
1181 return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
);
1184 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1186 if ( !wxMenuBase::DoInsert(pos
, item
) )
1190 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
1191 // of version 1.2.6), so we first append the item and then change its
1193 if ( !GtkAppend(item
) )
1196 if ( m_style
& wxMENU_TEAROFF
)
1198 // change the position as the first item is the tear-off marker
1202 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
1203 gpointer data
= g_list_last(menu_shell
->children
)->data
;
1204 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
1205 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
1209 // this should be easy to do...
1210 wxFAIL_MSG( wxT("not implemented") );
1213 #endif // GTK 1.2/1.0
1216 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1218 if ( !wxMenuBase::DoRemove(item
) )
1219 return (wxMenuItem
*)NULL
;
1221 // TODO: this code doesn't delete the item factory item and this seems
1222 // impossible as of GTK 1.2.6.
1223 gtk_widget_destroy( item
->GetMenuItem() );
1228 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1230 wxNode
*node
= m_items
.First();
1233 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1234 if (item
->GetMenuItem() == menuItem
)
1235 return item
->GetId();
1236 node
= node
->Next();
1242 // ----------------------------------------------------------------------------
1244 // ----------------------------------------------------------------------------
1246 #if GTK_CHECK_VERSION(1, 2, 0) && wxUSE_ACCEL
1248 static wxString
GetHotKey( const wxMenuItem
& item
)
1252 wxAcceleratorEntry
*accel
= item
.GetAccel();
1255 int flags
= accel
->GetFlags();
1256 if ( flags
& wxACCEL_ALT
)
1257 hotkey
+= wxT("<alt>");
1258 if ( flags
& wxACCEL_CTRL
)
1259 hotkey
+= wxT("<control>");
1260 if ( flags
& wxACCEL_SHIFT
)
1261 hotkey
+= wxT("<shift>");
1263 int code
= accel
->GetKeyCode();
1278 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1281 // TODO: we should use gdk_keyval_name() (a.k.a.
1282 // XKeysymToString) here as well as hardcoding the keysym
1283 // names this might be not portable
1284 case WXK_NUMPAD_INSERT
:
1285 hotkey
<< wxT("KP_Insert" );
1287 case WXK_NUMPAD_DELETE
:
1288 hotkey
<< wxT("KP_Delete" );
1291 hotkey
<< wxT("Insert" );
1294 hotkey
<< wxT("Delete" );
1297 // if there are any other keys wxGetAccelFromString() may
1298 // return, we should process them here
1303 gchar
*name
= gdk_keyval_name((guint
)code
);
1311 wxFAIL_MSG( wxT("unknown keyboard accel") );
1320 #endif // wxUSE_ACCEL
1323 //-----------------------------------------------------------------------------
1324 // substitute for missing GtkPixmapMenuItem
1325 //-----------------------------------------------------------------------------
1327 #ifdef USE_MENU_BITMAPS
1330 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1331 * All rights reserved.
1333 * This file is part of the Gnome Library.
1335 * The Gnome Library is free software; you can redistribute it and/or
1336 * modify it under the terms of the GNU Library General Public License as
1337 * published by the Free Software Foundation; either version 2 of the
1338 * License, or (at your option) any later version.
1340 * The Gnome Library is distributed in the hope that it will be useful,
1341 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1342 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1343 * Library General Public License for more details.
1345 * You should have received a copy of the GNU Library General Public
1346 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1347 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1348 * Boston, MA 02111-1307, USA.
1354 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1356 #include <gtk/gtkaccellabel.h>
1357 #include <gtk/gtksignal.h>
1358 #include <gtk/gtkmenuitem.h>
1359 #include <gtk/gtkmenu.h>
1360 #include <gtk/gtkcontainer.h>
1365 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1366 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1367 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1368 GdkRectangle
*area
);
1369 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1370 GdkEventExpose
*event
);
1372 /* we must override the following functions */
1374 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1375 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1376 GtkAllocation
*allocation
);
1377 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1378 gboolean include_internals
,
1379 GtkCallback callback
,
1380 gpointer callback_data
);
1381 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1382 GtkRequisition
*requisition
);
1383 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1386 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1388 static GtkMenuItemClass
*parent_class
= NULL
;
1392 #define BORDER_SPACING 3
1393 #define PMAP_WIDTH 20
1396 gtk_pixmap_menu_item_get_type (void)
1398 static GtkType pixmap_menu_item_type
= 0;
1400 if (!pixmap_menu_item_type
)
1402 GtkTypeInfo pixmap_menu_item_info
=
1404 (char *)"GtkPixmapMenuItem",
1405 sizeof (GtkPixmapMenuItem
),
1406 sizeof (GtkPixmapMenuItemClass
),
1407 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1408 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1409 /* reserved_1 */ NULL
,
1410 /* reserved_2 */ NULL
,
1411 (GtkClassInitFunc
) NULL
,
1414 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1415 &pixmap_menu_item_info
);
1418 return pixmap_menu_item_type
;
1422 * gtk_pixmap_menu_item_new
1424 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1425 * to set the pixmap wich is displayed at the left side.
1428 * &GtkWidget pointer to new menu item
1432 gtk_pixmap_menu_item_new (void)
1434 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1438 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1440 GtkObjectClass
*object_class
;
1441 GtkWidgetClass
*widget_class
;
1442 GtkMenuItemClass
*menu_item_class
;
1443 GtkContainerClass
*container_class
;
1445 object_class
= (GtkObjectClass
*) klass
;
1446 widget_class
= (GtkWidgetClass
*) klass
;
1447 menu_item_class
= (GtkMenuItemClass
*) klass
;
1448 container_class
= (GtkContainerClass
*) klass
;
1450 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1452 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1453 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1454 widget_class
->map
= gtk_pixmap_menu_item_map
;
1455 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1456 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1458 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1459 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1461 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1462 klass
->have_pixmap_count
= 0;
1466 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1470 mi
= GTK_MENU_ITEM (menu_item
);
1472 menu_item
->pixmap
= NULL
;
1476 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1479 g_return_if_fail (widget
!= NULL
);
1480 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1481 g_return_if_fail (area
!= NULL
);
1483 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1484 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1486 if (GTK_WIDGET_DRAWABLE (widget
) &&
1487 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1488 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1493 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1494 GdkEventExpose
*event
)
1496 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1497 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1498 g_return_val_if_fail (event
!= NULL
, FALSE
);
1500 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1501 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1503 if (GTK_WIDGET_DRAWABLE (widget
) &&
1504 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1505 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1512 * gtk_pixmap_menu_item_set_pixmap
1513 * @menu_item: Pointer to the pixmap menu item
1514 * @pixmap: Pointer to a pixmap widget
1516 * Set the pixmap of the menu item.
1521 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1524 g_return_if_fail (menu_item
!= NULL
);
1525 g_return_if_fail (pixmap
!= NULL
);
1526 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1527 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1528 g_return_if_fail (menu_item
->pixmap
== NULL
);
1530 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1531 menu_item
->pixmap
= pixmap
;
1533 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1534 !GTK_WIDGET_REALIZED (pixmap
))
1535 gtk_widget_realize (pixmap
);
1537 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1538 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1539 GTK_WIDGET_VISIBLE(pixmap
) &&
1540 !GTK_WIDGET_MAPPED (pixmap
))
1541 gtk_widget_map (pixmap
);
1544 changed_have_pixmap_status(menu_item
);
1546 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1547 gtk_widget_queue_resize (pixmap
);
1551 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1553 GtkPixmapMenuItem
*menu_item
;
1555 g_return_if_fail (widget
!= NULL
);
1556 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1558 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1560 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1562 if (menu_item
->pixmap
&&
1563 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1564 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1565 gtk_widget_map (menu_item
->pixmap
);
1569 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1570 GtkAllocation
*allocation
)
1572 GtkPixmapMenuItem
*pmenu_item
;
1574 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1576 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1578 GtkAllocation child_allocation
;
1581 border_width
= GTK_CONTAINER (widget
)->border_width
;
1583 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1584 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1585 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1586 child_allocation
.y
= (border_width
+ BORDER_SPACING
1587 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1588 / 2)); /* center pixmaps vertically */
1589 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1592 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1593 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1597 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1598 gboolean include_internals
,
1599 GtkCallback callback
,
1600 gpointer callback_data
)
1602 GtkPixmapMenuItem
*menu_item
;
1604 g_return_if_fail (container
!= NULL
);
1605 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1606 g_return_if_fail (callback
!= NULL
);
1608 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1610 if (menu_item
->pixmap
)
1611 (* callback
) (menu_item
->pixmap
, callback_data
);
1613 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1614 callback
,callback_data
);
1618 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1619 GtkRequisition
*requisition
)
1621 GtkPixmapMenuItem
*menu_item
;
1622 GtkRequisition req
= {0, 0};
1624 g_return_if_fail (widget
!= NULL
);
1625 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1626 g_return_if_fail (requisition
!= NULL
);
1628 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1630 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1632 if (menu_item
->pixmap
)
1633 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1635 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1636 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1640 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1644 gboolean widget_was_visible
;
1646 g_return_if_fail (container
!= NULL
);
1647 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1648 g_return_if_fail (child
!= NULL
);
1649 g_return_if_fail (GTK_IS_WIDGET (child
));
1651 bin
= GTK_BIN (container
);
1652 g_return_if_fail ((bin
->child
== child
||
1653 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1655 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1657 gtk_widget_unparent (child
);
1658 if (bin
->child
== child
)
1661 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1662 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1665 if (widget_was_visible
)
1666 gtk_widget_queue_resize (GTK_WIDGET (container
));
1670 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1672 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1674 if (menu_item
->pixmap
!= NULL
) {
1675 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1677 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1678 /* Install pixmap toggle size */
1679 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1682 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1684 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1685 /* Install normal toggle size */
1686 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1690 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1691 whenever the klass->toggle_size changes; but by doing it anytime
1692 this function is called, we get the same effect, just because of
1693 how the preferences option to show pixmaps works. Bogus, broken.
1695 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1696 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));
1699 #endif // USE_MENU_BITMAPS