1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "menu.h"
12 #pragma implementation "menuitem.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
21 #include "wx/bitmap.h"
28 #include "wx/gtk/private.h"
30 #include <gdk/gdkkeysyms.h>
32 // FIXME: is this right? somehow I don't think so (VZ)
34 #include <glib-object.h>
36 #define gtk_accel_group_attach(g, o) gtk_window_add_accel_group((o), (g))
37 #define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g))
38 #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m)
40 #define ACCEL_OBJECT GtkWindow
41 #define ACCEL_OBJECTS(a) (a)->acceleratables
42 #define ACCEL_OBJ_CAST(obj) ((GtkWindow*) obj)
44 #define ACCEL_OBJECT GtkObject
45 #define ACCEL_OBJECTS(a) (a)->attach_objects
46 #define ACCEL_OBJ_CAST(obj) GTK_OBJECT(obj)
49 // we use normal item but with a special id for the menu title
50 static const int wxGTK_TITLE_ID
= -3;
52 //-----------------------------------------------------------------------------
54 //-----------------------------------------------------------------------------
56 extern void wxapp_install_idle_handler();
60 static wxString
GetHotKey( const wxMenuItem
& item
);
63 //-----------------------------------------------------------------------------
64 // substitute for missing GtkPixmapMenuItem
65 //-----------------------------------------------------------------------------
69 #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ())
70 #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem))
71 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass))
72 #define GTK_IS_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
73 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM))
74 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
75 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
77 #ifndef GTK_MENU_ITEM_GET_CLASS
78 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
81 typedef struct _GtkPixmapMenuItem GtkPixmapMenuItem
;
82 typedef struct _GtkPixmapMenuItemClass GtkPixmapMenuItemClass
;
84 struct _GtkPixmapMenuItem
86 GtkMenuItem menu_item
;
91 struct _GtkPixmapMenuItemClass
93 GtkMenuItemClass parent_class
;
95 guint orig_toggle_size
;
96 guint have_pixmap_count
;
100 GtkType
gtk_pixmap_menu_item_get_type (void);
101 GtkWidget
* gtk_pixmap_menu_item_new (void);
102 void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
106 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
110 static wxString
wxReplaceUnderscore( const wxString
& title
)
114 // GTK 1.2 wants to have "_" instead of "&" for accelerators
117 while (*pc
!= wxT('\0'))
119 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
121 // "&" is doubled to indicate "&" instead of accelerator
125 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
143 // wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() );
148 //-----------------------------------------------------------------------------
149 // activate message from GTK
150 //-----------------------------------------------------------------------------
152 static void gtk_menu_open_callback( GtkWidget
*widget
, wxMenu
*menu
)
154 if (g_isIdle
) wxapp_install_idle_handler();
156 wxMenuEvent
event( wxEVT_MENU_OPEN
, -1, menu
);
157 event
.SetEventObject( menu
);
159 wxEvtHandler
* handler
= menu
->GetEventHandler();
160 if (handler
&& handler
->ProcessEvent(event
))
163 wxWindow
*win
= menu
->GetInvokingWindow();
164 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
167 //-----------------------------------------------------------------------------
169 //-----------------------------------------------------------------------------
171 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
173 wxMenuBar::wxMenuBar( long style
)
175 // the parent window is known after wxFrame::SetMenu()
176 m_needParent
= FALSE
;
178 m_invokingWindow
= (wxWindow
*) NULL
;
180 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
181 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
183 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
187 m_menubar
= gtk_menu_bar_new();
189 m_accel
= gtk_accel_group_new();
192 if (style
& wxMB_DOCKABLE
)
194 m_widget
= gtk_handle_box_new();
195 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
196 gtk_widget_show( GTK_WIDGET(m_menubar
) );
200 m_widget
= GTK_WIDGET(m_menubar
);
208 wxMenuBar::wxMenuBar()
210 // the parent window is known after wxFrame::SetMenu()
211 m_needParent
= FALSE
;
213 m_invokingWindow
= (wxWindow
*) NULL
;
215 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
216 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
218 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
222 m_menubar
= gtk_menu_bar_new();
224 m_accel
= gtk_accel_group_new();
227 m_widget
= GTK_WIDGET(m_menubar
);
234 wxMenuBar::~wxMenuBar()
238 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
240 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
242 wxWindow
*top_frame
= win
;
243 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
244 top_frame
= top_frame
->GetParent();
247 // support for native hot keys
248 gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
251 wxMenuItemList::compatibility_iterator 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 wxWindow
*top_frame
= win
;
266 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
267 top_frame
= top_frame
->GetParent();
269 // support for native hot keys
270 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
271 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
272 gtk_accel_group_attach( menu
->m_accel
, obj
);
274 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
277 wxMenuItem
*menuitem
= node
->GetData();
278 if (menuitem
->IsSubMenu())
279 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
280 node
= node
->GetNext();
284 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
286 m_invokingWindow
= win
;
287 wxWindow
*top_frame
= win
;
288 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
289 top_frame
= top_frame
->GetParent();
292 // support for native key accelerators indicated by underscroes
293 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
294 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
295 gtk_accel_group_attach( m_accel
, obj
);
298 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
301 wxMenu
*menu
= node
->GetData();
302 wxMenubarSetInvokingWindow( menu
, win
);
303 node
= node
->GetNext();
307 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
309 m_invokingWindow
= (wxWindow
*) NULL
;
310 wxWindow
*top_frame
= win
;
311 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
312 top_frame
= top_frame
->GetParent();
315 // support for native key accelerators indicated by underscroes
316 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
319 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
322 wxMenu
*menu
= node
->GetData();
323 wxMenubarUnsetInvokingWindow( menu
, win
);
324 node
= node
->GetNext();
328 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
330 if ( !wxMenuBarBase::Append( menu
, title
) )
333 return GtkAppend(menu
, title
);
336 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
, int pos
)
338 wxString
str( wxReplaceUnderscore( title
) );
340 // This doesn't have much effect right now.
341 menu
->SetTitle( str
);
343 // The "m_owner" is the "menu item"
345 menu
->m_owner
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str
) );
347 menu
->m_owner
= gtk_menu_item_new_with_label( wxGTK_CONV( str
) );
348 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
350 gtk_label_set_text( label
, wxGTK_CONV( str
) );
352 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
353 if (accel_key
!= GDK_VoidSymbol
)
355 gtk_widget_add_accelerator (menu
->m_owner
,
357 m_accel
,//gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)),
364 gtk_widget_show( menu
->m_owner
);
366 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
369 gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
);
371 gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
, pos
);
373 gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate",
374 GTK_SIGNAL_FUNC(gtk_menu_open_callback
),
377 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
378 // addings menu later on.
379 if (m_invokingWindow
)
381 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
383 // OPTIMISE ME: we should probably cache this, or pass it
384 // directly, but for now this is a minimal
385 // change to validate the new dynamic sizing.
386 // see (and refactor :) similar code in Remove
389 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
392 frame
->UpdateMenuBarSize();
398 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
400 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
405 if ( !GtkAppend(menu
, title
, (int)pos
) )
411 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
413 // remove the old item and insert a new one
414 wxMenu
*menuOld
= Remove(pos
);
415 if ( menuOld
&& !Insert(pos
, menu
, title
) )
417 return (wxMenu
*) NULL
;
420 // either Insert() succeeded or Remove() failed and menuOld is NULL
424 wxMenu
*wxMenuBar::Remove(size_t pos
)
426 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
428 return (wxMenu
*) NULL
;
430 gtk_menu_item_remove_submenu( GTK_MENU_ITEM(menu
->m_owner
) );
431 gtk_container_remove(GTK_CONTAINER(m_menubar
), menu
->m_owner
);
433 gtk_widget_destroy( menu
->m_owner
);
434 menu
->m_owner
= NULL
;
436 if (m_invokingWindow
)
438 // OPTIMISE ME: see comment in GtkAppend
439 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
442 frame
->UpdateMenuBarSize();
448 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
450 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
452 int res
= menu
->FindItem( itemString
);
453 if (res
!= wxNOT_FOUND
)
457 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
460 wxMenuItem
*item
= node
->GetData();
461 if (item
->IsSubMenu())
462 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
464 node
= node
->GetNext();
470 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
472 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
475 wxMenu
*menu
= node
->GetData();
476 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
479 node
= node
->GetNext();
485 // Find a wxMenuItem using its id. Recurses down into sub-menus
486 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
488 wxMenuItem
* result
= menu
->FindChildItem(id
);
490 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
491 while ( node
&& result
== NULL
)
493 wxMenuItem
*item
= node
->GetData();
494 if (item
->IsSubMenu())
496 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
498 node
= node
->GetNext();
504 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
506 wxMenuItem
* result
= 0;
507 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
508 while (node
&& result
== 0)
510 wxMenu
*menu
= node
->GetData();
511 result
= FindMenuItemByIdRecursive( menu
, id
);
512 node
= node
->GetNext();
517 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
523 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
525 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
527 wxCHECK_RET( node
, wxT("menu not found") );
529 wxMenu
* menu
= node
->GetData();
532 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
535 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
537 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
539 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
541 wxMenu
* menu
= node
->GetData();
544 wxString
text( menu
->GetTitle() );
545 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
547 if ( *pc
== wxT('_') )
549 // '_' is the escape character for GTK+
553 // don't remove ampersands '&' since if we have them in the menu title
554 // it means that they were doubled to indicate "&" instead of accelerator
562 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
564 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
566 wxCHECK_RET( node
, wxT("menu not found") );
568 wxMenu
* menu
= node
->GetData();
570 wxString
str( wxReplaceUnderscore( label
) );
572 menu
->SetTitle( str
);
576 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
579 gtk_label_set( label
, wxGTK_CONV( str
) );
581 /* reparse key accel */
582 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
583 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
588 //-----------------------------------------------------------------------------
590 //-----------------------------------------------------------------------------
592 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
595 wxapp_install_idle_handler();
597 int id
= menu
->FindMenuIdByMenuItem(widget
);
599 /* should find it for normal (not popup) menu */
600 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
601 _T("menu item not found in gtk_menu_clicked_callback") );
603 if (!menu
->IsEnabled(id
))
606 wxMenuItem
* item
= menu
->FindChildItem( id
);
607 wxCHECK_RET( item
, wxT("error in menu item callback") );
609 if ( item
->GetId() == wxGTK_TITLE_ID
)
611 // ignore events from the menu title
615 if (item
->IsCheckable())
617 bool isReallyChecked
= item
->IsChecked(),
618 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
620 // ensure that the internal state is always consistent with what is
621 // shown on the screen
622 item
->wxMenuItemBase::Check(isReallyChecked
);
624 // we must not report the events for the radio button going up nor the
625 // events resulting from the calls to wxMenuItem::Check()
626 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
627 (isInternallyChecked
== isReallyChecked
) )
634 // Is this menu on a menubar? (possibly nested)
635 wxFrame
* frame
= NULL
;
636 if(menu
->IsAttached())
637 frame
= menu
->GetMenuBar()->GetFrame();
639 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
640 // normally wxMenu::SendEvent() should be enough, if it doesn't work
641 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
642 // should be fixed instead of working around it here...
645 // If it is attached then let the frame send the event.
646 // Don't call frame->ProcessCommand(id) because it toggles
647 // checkable items and we've already done that above.
648 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
649 commandEvent
.SetEventObject(frame
);
650 if (item
->IsCheckable())
651 commandEvent
.SetInt(item
->IsChecked());
652 commandEvent
.SetEventObject(menu
);
654 frame
->GetEventHandler()->ProcessEvent(commandEvent
);
658 // otherwise let the menu have it
659 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
663 //-----------------------------------------------------------------------------
665 //-----------------------------------------------------------------------------
667 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
669 if (g_isIdle
) wxapp_install_idle_handler();
671 int id
= menu
->FindMenuIdByMenuItem(widget
);
673 wxASSERT( id
!= -1 ); // should find it!
675 if (!menu
->IsEnabled(id
))
678 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
679 event
.SetEventObject( menu
);
681 wxEvtHandler
* handler
= menu
->GetEventHandler();
682 if (handler
&& handler
->ProcessEvent(event
))
685 wxWindow
*win
= menu
->GetInvokingWindow();
686 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
689 //-----------------------------------------------------------------------------
691 //-----------------------------------------------------------------------------
693 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
695 if (g_isIdle
) wxapp_install_idle_handler();
697 int id
= menu
->FindMenuIdByMenuItem(widget
);
699 wxASSERT( id
!= -1 ); // should find it!
701 if (!menu
->IsEnabled(id
))
704 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
705 event
.SetEventObject( menu
);
707 wxEvtHandler
* handler
= menu
->GetEventHandler();
708 if (handler
&& handler
->ProcessEvent(event
))
711 wxWindow
*win
= menu
->GetInvokingWindow();
713 win
->GetEventHandler()->ProcessEvent( event
);
716 //-----------------------------------------------------------------------------
718 //-----------------------------------------------------------------------------
720 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
722 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
724 const wxString
& name
,
725 const wxString
& help
,
729 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
732 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
734 const wxString
& text
,
735 const wxString
& help
,
738 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
743 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
745 const wxString
& text
,
746 const wxString
& help
,
749 : wxMenuItemBase(parentMenu
, id
, text
, help
,
750 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
755 void wxMenuItem::Init(const wxString
& text
)
757 m_labelWidget
= (GtkWidget
*) NULL
;
758 m_menuItem
= (GtkWidget
*) NULL
;
763 wxMenuItem::~wxMenuItem()
765 // don't delete menu items, the menus take care of that
768 // return the menu item text without any menu accels
770 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
774 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
776 if ( *pc
== wxT('\t'))
779 if ( *pc
== wxT('_') )
781 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
788 if ( *pc
== wxT('\\') )
790 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
797 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
800 // "&" is doubled to indicate "&" instead of accelerator
807 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
812 void wxMenuItem::SetText( const wxString
& str
)
814 // Some optimization to avoid flicker
815 wxString oldLabel
= m_text
;
816 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
817 oldLabel
.Replace(wxT("_"), wxT(""));
818 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
819 if (oldLabel
== label1
)
828 label
= (GtkLabel
*) m_labelWidget
;
830 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
833 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
836 gtk_label_set( label
, wxGTK_CONV( m_text
) );
839 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
840 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
845 // it's valid for this function to be called even if m_menuItem == NULL
846 void wxMenuItem::DoSetText( const wxString
& str
)
848 // '\t' is the deliminator indicating a hot key
850 const wxChar
*pc
= str
;
851 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
853 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
855 // "&" is doubled to indicate "&" instead of accelerator
859 else if (*pc
== wxT('&'))
863 else if ( *pc
== wxT('_') ) // escape underscores
874 // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() );
887 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
892 return (wxAcceleratorEntry
*)NULL
;
895 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
897 label
<< wxT('\t') << GetHotKey();
899 return wxGetAccelFromString(label
);
902 #endif // wxUSE_ACCEL
904 void wxMenuItem::Check( bool check
)
906 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
908 if (check
== m_isChecked
)
911 wxMenuItemBase::Check( check
);
917 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
921 wxFAIL_MSG( _T("can't check this item") );
925 void wxMenuItem::Enable( bool enable
)
927 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
929 gtk_widget_set_sensitive( m_menuItem
, enable
);
930 wxMenuItemBase::Enable( enable
);
933 bool wxMenuItem::IsChecked() const
935 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
937 wxCHECK_MSG( IsCheckable(), FALSE
,
938 wxT("can't get state of uncheckable item!") );
940 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
943 //-----------------------------------------------------------------------------
945 //-----------------------------------------------------------------------------
947 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
951 m_accel
= gtk_accel_group_new();
952 m_menu
= gtk_menu_new();
953 // NB: keep reference to the menu so that it is not destroyed behind
954 // our back by GTK+ e.g. when it is removed from menubar:
955 gtk_widget_ref(m_menu
);
957 m_owner
= (GtkWidget
*) NULL
;
959 // Tearoffs are entries, just like separators. So if we want this
960 // menu to be a tear-off one, we just append a tearoff entry
962 if ( m_style
& wxMENU_TEAROFF
)
964 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
966 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
971 // append the title as the very first entry if we have it
972 if ( !m_title
.empty() )
974 Append(wxGTK_TITLE_ID
, m_title
);
981 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
983 if ( GTK_IS_WIDGET( m_menu
))
985 gtk_widget_unref( m_menu
); // see wxMenu::Init
986 gtk_widget_destroy( m_menu
);
990 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
994 if ( mitem
->IsSeparator() )
997 menuItem
= gtk_separator_menu_item_new();
1000 menuItem
= gtk_menu_item_new();
1003 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1005 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1007 else if ( mitem
->IsSubMenu() )
1009 // text has "_" instead of "&" after mitem->SetText()
1010 wxString
text( mitem
->GetText() );
1013 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1015 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1016 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1018 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1019 // reparse key accel
1020 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1021 if (accel_key
!= GDK_VoidSymbol
)
1023 gtk_widget_add_accelerator (menuItem
,
1025 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1032 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1034 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1036 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1038 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1040 // if adding a submenu to a menu already existing in the menu bar, we
1041 // must set invoking window to allow processing events from this
1043 if ( m_invokingWindow
)
1044 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1048 else if (mitem
->GetBitmap().Ok())
1050 wxString text
= mitem
->GetText();
1051 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1052 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1053 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1056 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1058 GtkWidget
*image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1059 gtk_widget_show(image
);
1061 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1063 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1064 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1068 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1070 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1073 menuItem
= gtk_pixmap_menu_item_new ();
1074 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1075 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1076 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1078 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1080 GdkModifierType accel_mods
;
1082 // accelerator for the item, as specified by its label
1083 // (ex. Ctrl+O for open)
1084 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1086 if (accel_key
!= GDK_VoidSymbol
)
1088 gtk_widget_add_accelerator (menuItem
,
1091 accel_key
, accel_mods
,
1095 // accelerator for the underlined char (ex ALT+F for the File menu)
1096 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1097 if (accel_key
!= GDK_VoidSymbol
)
1099 gtk_widget_add_accelerator (menuItem
,
1101 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1107 gtk_widget_show (label
);
1109 mitem
->SetLabelWidget(label
);
1111 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1112 gtk_widget_show(pixmap
);
1113 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1115 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1116 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1120 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1122 gtk_menu_insert( GTK_MENU(m_menu
), menuItem
, pos
);
1123 gtk_widget_show( menuItem
);
1128 else // a normal item
1130 // text has "_" instead of "&" after mitem->SetText() so don't use it
1131 wxString
text( mitem
->GetText() );
1133 switch ( mitem
->GetKind() )
1138 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1140 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1141 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1143 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1144 // reparse key accel
1145 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1146 if (accel_key
!= GDK_VoidSymbol
)
1148 gtk_widget_add_accelerator (menuItem
,
1150 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1162 GSList
*group
= NULL
;
1163 if ( m_prevRadio
== NULL
)
1165 // start of a new radio group
1167 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1169 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1170 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1172 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1173 // reparse key accel
1174 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1175 if (accel_key
!= GDK_VoidSymbol
)
1177 gtk_widget_add_accelerator (menuItem
,
1179 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1186 else // continue the radio group
1189 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1190 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1192 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1193 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1194 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1196 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1197 // reparse key accel
1198 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1199 if (accel_key
!= GDK_VoidSymbol
)
1201 gtk_widget_add_accelerator (menuItem
,
1203 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1214 wxFAIL_MSG( _T("unexpected menu item kind") );
1220 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1222 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1223 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1225 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1226 // reparse key accel
1227 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1228 if (accel_key
!= GDK_VoidSymbol
)
1230 gtk_widget_add_accelerator (menuItem
,
1232 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1243 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1244 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1248 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1250 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1254 GdkModifierType accel_mods
;
1255 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1257 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1259 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1262 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1270 gtk_widget_show( menuItem
);
1272 if ( !mitem
->IsSeparator() )
1274 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1276 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1277 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1280 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1281 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1285 mitem
->SetMenuItem(menuItem
);
1289 // This doesn't even exist!
1290 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1296 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1298 if (!GtkAppend(mitem
))
1301 return wxMenuBase::DoAppend(mitem
);
1304 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1306 if ( !wxMenuBase::DoInsert(pos
, item
) )
1310 if ( !GtkAppend(item
, (int)pos
) )
1316 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1318 if ( !wxMenuBase::DoRemove(item
) )
1319 return (wxMenuItem
*)NULL
;
1321 // TODO: this code doesn't delete the item factory item and this seems
1322 // impossible as of GTK 1.2.6.
1323 gtk_widget_destroy( item
->GetMenuItem() );
1328 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1330 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1333 wxMenuItem
*item
= node
->GetData();
1334 if (item
->GetMenuItem() == menuItem
)
1335 return item
->GetId();
1336 node
= node
->GetNext();
1342 // ----------------------------------------------------------------------------
1344 // ----------------------------------------------------------------------------
1348 static wxString
GetHotKey( const wxMenuItem
& item
)
1352 wxAcceleratorEntry
*accel
= item
.GetAccel();
1355 int flags
= accel
->GetFlags();
1356 if ( flags
& wxACCEL_ALT
)
1357 hotkey
+= wxT("<alt>");
1358 if ( flags
& wxACCEL_CTRL
)
1359 hotkey
+= wxT("<control>");
1360 if ( flags
& wxACCEL_SHIFT
)
1361 hotkey
+= wxT("<shift>");
1363 int code
= accel
->GetKeyCode();
1378 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1381 // TODO: we should use gdk_keyval_name() (a.k.a.
1382 // XKeysymToString) here as well as hardcoding the keysym
1383 // names this might be not portable
1384 case WXK_NUMPAD_INSERT
:
1385 hotkey
<< wxT("KP_Insert" );
1387 case WXK_NUMPAD_DELETE
:
1388 hotkey
<< wxT("KP_Delete" );
1391 hotkey
<< wxT("Insert" );
1394 hotkey
<< wxT("Delete" );
1397 hotkey
<< wxT("Up" );
1400 hotkey
<< wxT("Down" );
1404 hotkey
<< wxT("Prior" );
1408 hotkey
<< wxT("Next" );
1411 hotkey
<< wxT("Left" );
1414 hotkey
<< wxT("Right" );
1417 hotkey
<< wxT("Home" );
1420 hotkey
<< wxT("End" );
1423 hotkey
<< wxT("Return" );
1426 // if there are any other keys wxGetAccelFromString() may
1427 // return, we should process them here
1432 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1440 wxFAIL_MSG( wxT("unknown keyboard accel") );
1449 #endif // wxUSE_ACCEL
1452 //-----------------------------------------------------------------------------
1453 // substitute for missing GtkPixmapMenuItem
1454 //-----------------------------------------------------------------------------
1459 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1460 * All rights reserved.
1462 * This file is part of the Gnome Library.
1464 * The Gnome Library is free software; you can redistribute it and/or
1465 * modify it under the terms of the GNU Library General Public License as
1466 * published by the Free Software Foundation; either version 2 of the
1467 * License, or (at your option) any later version.
1469 * The Gnome Library is distributed in the hope that it will be useful,
1470 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1471 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1472 * Library General Public License for more details.
1474 * You should have received a copy of the GNU Library General Public
1475 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1476 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1477 * Boston, MA 02111-1307, USA.
1483 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1485 #include <gtk/gtkaccellabel.h>
1486 #include <gtk/gtksignal.h>
1487 #include <gtk/gtkmenuitem.h>
1488 #include <gtk/gtkmenu.h>
1489 #include <gtk/gtkcontainer.h>
1494 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1495 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1496 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1497 GdkRectangle
*area
);
1498 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1499 GdkEventExpose
*event
);
1501 /* we must override the following functions */
1503 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1504 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1505 GtkAllocation
*allocation
);
1506 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1507 gboolean include_internals
,
1508 GtkCallback callback
,
1509 gpointer callback_data
);
1510 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1511 GtkRequisition
*requisition
);
1512 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1515 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1517 static GtkMenuItemClass
*parent_class
= NULL
;
1521 #define BORDER_SPACING 3
1522 #define PMAP_WIDTH 20
1525 gtk_pixmap_menu_item_get_type (void)
1527 static GtkType pixmap_menu_item_type
= 0;
1529 if (!pixmap_menu_item_type
)
1531 GtkTypeInfo pixmap_menu_item_info
=
1533 (char *)"GtkPixmapMenuItem",
1534 sizeof (GtkPixmapMenuItem
),
1535 sizeof (GtkPixmapMenuItemClass
),
1536 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1537 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1538 /* reserved_1 */ NULL
,
1539 /* reserved_2 */ NULL
,
1540 (GtkClassInitFunc
) NULL
,
1543 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1544 &pixmap_menu_item_info
);
1547 return pixmap_menu_item_type
;
1551 * gtk_pixmap_menu_item_new
1553 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1554 * to set the pixmap wich is displayed at the left side.
1557 * &GtkWidget pointer to new menu item
1561 gtk_pixmap_menu_item_new (void)
1563 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1567 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1569 GtkObjectClass
*object_class
;
1570 GtkWidgetClass
*widget_class
;
1571 GtkMenuItemClass
*menu_item_class
;
1572 GtkContainerClass
*container_class
;
1574 object_class
= (GtkObjectClass
*) klass
;
1575 widget_class
= (GtkWidgetClass
*) klass
;
1576 menu_item_class
= (GtkMenuItemClass
*) klass
;
1577 container_class
= (GtkContainerClass
*) klass
;
1579 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1581 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1582 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1583 widget_class
->map
= gtk_pixmap_menu_item_map
;
1584 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1585 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1587 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1588 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1590 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1591 klass
->have_pixmap_count
= 0;
1595 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1599 mi
= GTK_MENU_ITEM (menu_item
);
1601 menu_item
->pixmap
= NULL
;
1605 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1608 g_return_if_fail (widget
!= NULL
);
1609 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1610 g_return_if_fail (area
!= NULL
);
1612 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1613 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1615 if (GTK_WIDGET_DRAWABLE (widget
) &&
1616 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1617 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1622 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1623 GdkEventExpose
*event
)
1625 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1626 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1627 g_return_val_if_fail (event
!= NULL
, FALSE
);
1629 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1630 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1632 if (GTK_WIDGET_DRAWABLE (widget
) &&
1633 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1634 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1641 * gtk_pixmap_menu_item_set_pixmap
1642 * @menu_item: Pointer to the pixmap menu item
1643 * @pixmap: Pointer to a pixmap widget
1645 * Set the pixmap of the menu item.
1650 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1653 g_return_if_fail (menu_item
!= NULL
);
1654 g_return_if_fail (pixmap
!= NULL
);
1655 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1656 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1657 g_return_if_fail (menu_item
->pixmap
== NULL
);
1659 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1660 menu_item
->pixmap
= pixmap
;
1662 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1663 !GTK_WIDGET_REALIZED (pixmap
))
1664 gtk_widget_realize (pixmap
);
1666 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1667 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1668 GTK_WIDGET_VISIBLE(pixmap
) &&
1669 !GTK_WIDGET_MAPPED (pixmap
))
1670 gtk_widget_map (pixmap
);
1673 changed_have_pixmap_status(menu_item
);
1675 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1676 gtk_widget_queue_resize (pixmap
);
1680 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1682 GtkPixmapMenuItem
*menu_item
;
1684 g_return_if_fail (widget
!= NULL
);
1685 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1687 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1689 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1691 if (menu_item
->pixmap
&&
1692 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1693 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1694 gtk_widget_map (menu_item
->pixmap
);
1698 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1699 GtkAllocation
*allocation
)
1701 GtkPixmapMenuItem
*pmenu_item
;
1703 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1705 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1707 GtkAllocation child_allocation
;
1710 border_width
= GTK_CONTAINER (widget
)->border_width
;
1712 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1713 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1714 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1715 child_allocation
.y
= (border_width
+ BORDER_SPACING
1716 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1717 / 2)); /* center pixmaps vertically */
1718 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1721 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1722 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1726 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1727 gboolean include_internals
,
1728 GtkCallback callback
,
1729 gpointer callback_data
)
1731 GtkPixmapMenuItem
*menu_item
;
1733 g_return_if_fail (container
!= NULL
);
1734 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1735 g_return_if_fail (callback
!= NULL
);
1737 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1739 if (menu_item
->pixmap
)
1740 (* callback
) (menu_item
->pixmap
, callback_data
);
1742 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1743 callback
,callback_data
);
1747 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1748 GtkRequisition
*requisition
)
1750 GtkPixmapMenuItem
*menu_item
;
1751 GtkRequisition req
= {0, 0};
1753 g_return_if_fail (widget
!= NULL
);
1754 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1755 g_return_if_fail (requisition
!= NULL
);
1757 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1759 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1761 if (menu_item
->pixmap
)
1762 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1764 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1765 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1769 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1773 gboolean widget_was_visible
;
1775 g_return_if_fail (container
!= NULL
);
1776 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1777 g_return_if_fail (child
!= NULL
);
1778 g_return_if_fail (GTK_IS_WIDGET (child
));
1780 bin
= GTK_BIN (container
);
1781 g_return_if_fail ((bin
->child
== child
||
1782 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1784 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1786 gtk_widget_unparent (child
);
1787 if (bin
->child
== child
)
1790 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1791 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1794 if (widget_was_visible
)
1795 gtk_widget_queue_resize (GTK_WIDGET (container
));
1799 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1801 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1803 if (menu_item
->pixmap
!= NULL
) {
1804 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1806 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1807 /* Install pixmap toggle size */
1808 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1811 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1813 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1814 /* Install normal toggle size */
1815 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1819 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1820 whenever the klass->toggle_size changes; but by doing it anytime
1821 this function is called, we get the same effect, just because of
1822 how the preferences option to show pixmaps works. Bogus, broken.
1824 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1825 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));