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