1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
17 #include "wx/bitmap.h"
23 #include "wx/gtk/private.h"
25 #include <gdk/gdkkeysyms.h>
27 // FIXME: is this right? somehow I don't think so (VZ)
29 #include <glib-object.h>
31 #define gtk_accel_group_attach(g, o) gtk_window_add_accel_group((o), (g))
32 #define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g))
33 #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m)
35 #define ACCEL_OBJECT GtkWindow
36 #define ACCEL_OBJECTS(a) (a)->acceleratables
37 #define ACCEL_OBJ_CAST(obj) ((GtkWindow*) obj)
39 #define ACCEL_OBJECT GtkObject
40 #define ACCEL_OBJECTS(a) (a)->attach_objects
41 #define ACCEL_OBJ_CAST(obj) GTK_OBJECT(obj)
44 // we use normal item but with a special id for the menu title
45 static const int wxGTK_TITLE_ID
= -3;
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
51 extern void wxapp_install_idle_handler();
55 static wxString
GetGtkHotKey( const wxMenuItem
& item
);
58 //-----------------------------------------------------------------------------
59 // substitute for missing GtkPixmapMenuItem
60 //-----------------------------------------------------------------------------
64 #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ())
65 #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem))
66 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass))
67 #define GTK_IS_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
68 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM))
69 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
70 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
72 #ifndef GTK_MENU_ITEM_GET_CLASS
73 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
76 typedef struct _GtkPixmapMenuItem GtkPixmapMenuItem
;
77 typedef struct _GtkPixmapMenuItemClass GtkPixmapMenuItemClass
;
79 struct _GtkPixmapMenuItem
81 GtkMenuItem menu_item
;
86 struct _GtkPixmapMenuItemClass
88 GtkMenuItemClass parent_class
;
90 guint orig_toggle_size
;
91 guint have_pixmap_count
;
95 GtkType
gtk_pixmap_menu_item_get_type (void);
96 GtkWidget
* gtk_pixmap_menu_item_new (void);
97 void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
101 #endif // !__WXGTK20__
103 //-----------------------------------------------------------------------------
105 //-----------------------------------------------------------------------------
107 static wxString
wxReplaceUnderscore( const wxString
& title
)
111 // GTK 1.2 wants to have "_" instead of "&" for accelerators
114 while (*pc
!= wxT('\0'))
116 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
118 // "&" is doubled to indicate "&" instead of accelerator
122 else if (*pc
== wxT('&'))
128 if ( *pc
== wxT('_') )
130 // underscores must be doubled to prevent them from being
131 // interpreted as accelerator character prefix by GTK
140 // wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() );
145 //-----------------------------------------------------------------------------
146 // activate message from GTK
147 //-----------------------------------------------------------------------------
150 static void gtk_menu_open_callback( GtkWidget
*widget
, wxMenu
*menu
)
152 if (g_isIdle
) wxapp_install_idle_handler();
154 wxMenuEvent
event( wxEVT_MENU_OPEN
, -1, menu
);
155 event
.SetEventObject( menu
);
157 wxEvtHandler
* handler
= menu
->GetEventHandler();
158 if (handler
&& handler
->ProcessEvent(event
))
161 wxWindow
*win
= menu
->GetInvokingWindow();
162 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
166 //-----------------------------------------------------------------------------
168 //-----------------------------------------------------------------------------
170 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
172 void wxMenuBar::Init(size_t n
, wxMenu
*menus
[], const wxString titles
[], long style
)
174 // the parent window is known after wxFrame::SetMenu()
175 m_needParent
= FALSE
;
177 m_invokingWindow
= (wxWindow
*) NULL
;
179 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
180 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
182 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
186 m_menubar
= gtk_menu_bar_new();
188 m_accel
= gtk_accel_group_new();
191 if (style
& wxMB_DOCKABLE
)
193 m_widget
= gtk_handle_box_new();
194 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
195 gtk_widget_show( GTK_WIDGET(m_menubar
) );
199 m_widget
= GTK_WIDGET(m_menubar
);
206 for (size_t i
= 0; i
< n
; ++i
)
207 Append(menus
[i
], titles
[i
]);
210 wxMenuBar::wxMenuBar(size_t n
, wxMenu
*menus
[], const wxString titles
[], long style
)
212 Init(n
, menus
, titles
, style
);
215 wxMenuBar::wxMenuBar(long style
)
217 Init(0, NULL
, NULL
, style
);
220 wxMenuBar::wxMenuBar()
222 Init(0, NULL
, NULL
, 0);
225 wxMenuBar::~wxMenuBar()
229 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
231 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
233 wxWindow
*top_frame
= win
;
234 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
235 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::compatibility_iterator 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 wxWindow
*top_frame
= win
;
257 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
258 top_frame
= top_frame
->GetParent();
260 // support for native hot keys
261 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
262 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
263 gtk_accel_group_attach( menu
->m_accel
, obj
);
265 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
268 wxMenuItem
*menuitem
= node
->GetData();
269 if (menuitem
->IsSubMenu())
270 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
271 node
= node
->GetNext();
275 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
277 m_invokingWindow
= win
;
278 wxWindow
*top_frame
= win
;
279 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
280 top_frame
= top_frame
->GetParent();
283 // support for native key accelerators indicated by underscroes
284 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
285 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
286 gtk_accel_group_attach( m_accel
, obj
);
289 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
292 wxMenu
*menu
= node
->GetData();
293 wxMenubarSetInvokingWindow( menu
, win
);
294 node
= node
->GetNext();
298 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
300 m_invokingWindow
= (wxWindow
*) NULL
;
301 wxWindow
*top_frame
= win
;
302 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
303 top_frame
= top_frame
->GetParent();
306 // support for native key accelerators indicated by underscroes
307 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
310 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
313 wxMenu
*menu
= node
->GetData();
314 wxMenubarUnsetInvokingWindow( menu
, win
);
315 node
= node
->GetNext();
319 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
321 if ( !wxMenuBarBase::Append( menu
, title
) )
324 return GtkAppend(menu
, title
);
327 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
, int pos
)
329 wxString
str( wxReplaceUnderscore( title
) );
331 // This doesn't have much effect right now.
332 menu
->SetTitle( str
);
334 // The "m_owner" is the "menu item"
336 menu
->m_owner
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str
) );
338 menu
->m_owner
= gtk_menu_item_new_with_label( wxGTK_CONV( str
) );
339 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
341 gtk_label_set_text( label
, wxGTK_CONV( str
) );
343 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
344 if (accel_key
!= GDK_VoidSymbol
)
346 gtk_widget_add_accelerator (menu
->m_owner
,
348 m_accel
, //gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)),
355 gtk_widget_show( menu
->m_owner
);
357 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
360 gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
);
362 gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
, pos
);
364 gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate",
365 GTK_SIGNAL_FUNC(gtk_menu_open_callback
),
368 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
369 // addings menu later on.
370 if (m_invokingWindow
)
372 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
374 // OPTIMISE ME: we should probably cache this, or pass it
375 // directly, but for now this is a minimal
376 // change to validate the new dynamic sizing.
377 // see (and refactor :) similar code in Remove
380 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
383 frame
->UpdateMenuBarSize();
389 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
391 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
396 if ( !GtkAppend(menu
, title
, (int)pos
) )
402 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
404 // remove the old item and insert a new one
405 wxMenu
*menuOld
= Remove(pos
);
406 if ( menuOld
&& !Insert(pos
, menu
, title
) )
408 return (wxMenu
*) NULL
;
411 // either Insert() succeeded or Remove() failed and menuOld is NULL
415 wxMenu
*wxMenuBar::Remove(size_t pos
)
417 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
419 return (wxMenu
*) NULL
;
421 gtk_menu_item_remove_submenu( GTK_MENU_ITEM(menu
->m_owner
) );
422 gtk_container_remove(GTK_CONTAINER(m_menubar
), menu
->m_owner
);
424 gtk_widget_destroy( menu
->m_owner
);
425 menu
->m_owner
= NULL
;
427 if (m_invokingWindow
)
429 // OPTIMISE ME: see comment in GtkAppend
430 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
433 frame
->UpdateMenuBarSize();
439 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
441 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
443 int res
= menu
->FindItem( itemString
);
444 if (res
!= wxNOT_FOUND
)
448 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
451 wxMenuItem
*item
= node
->GetData();
452 if (item
->IsSubMenu())
453 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
455 node
= node
->GetNext();
461 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
463 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
466 wxMenu
*menu
= node
->GetData();
467 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
470 node
= node
->GetNext();
476 // Find a wxMenuItem using its id. Recurses down into sub-menus
477 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
479 wxMenuItem
* result
= menu
->FindChildItem(id
);
481 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
482 while ( node
&& result
== NULL
)
484 wxMenuItem
*item
= node
->GetData();
485 if (item
->IsSubMenu())
487 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
489 node
= node
->GetNext();
495 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
497 wxMenuItem
* result
= 0;
498 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
499 while (node
&& result
== 0)
501 wxMenu
*menu
= node
->GetData();
502 result
= FindMenuItemByIdRecursive( menu
, id
);
503 node
= node
->GetNext();
508 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
514 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
516 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
518 wxCHECK_RET( node
, wxT("menu not found") );
520 wxMenu
* menu
= node
->GetData();
523 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
526 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
528 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
530 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
532 wxMenu
* menu
= node
->GetData();
535 wxString
text( menu
->GetTitle() );
536 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
538 if ( *pc
== wxT('_') )
540 // '_' is the escape character for GTK+
544 // don't remove ampersands '&' since if we have them in the menu title
545 // it means that they were doubled to indicate "&" instead of accelerator
553 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
555 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
557 wxCHECK_RET( node
, wxT("menu not found") );
559 wxMenu
* menu
= node
->GetData();
561 wxString
str( wxReplaceUnderscore( label
) );
563 menu
->SetTitle( str
);
567 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
570 gtk_label_set( label
, wxGTK_CONV( str
) );
572 /* reparse key accel */
573 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
574 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
579 //-----------------------------------------------------------------------------
581 //-----------------------------------------------------------------------------
584 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
587 wxapp_install_idle_handler();
589 int id
= menu
->FindMenuIdByMenuItem(widget
);
591 /* should find it for normal (not popup) menu */
592 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
593 _T("menu item not found in gtk_menu_clicked_callback") );
595 if (!menu
->IsEnabled(id
))
598 wxMenuItem
* item
= menu
->FindChildItem( id
);
599 wxCHECK_RET( item
, wxT("error in menu item callback") );
601 if ( item
->GetId() == wxGTK_TITLE_ID
)
603 // ignore events from the menu title
607 if (item
->IsCheckable())
609 bool isReallyChecked
= item
->IsChecked(),
610 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
612 // ensure that the internal state is always consistent with what is
613 // shown on the screen
614 item
->wxMenuItemBase::Check(isReallyChecked
);
616 // we must not report the events for the radio button going up nor the
617 // events resulting from the calls to wxMenuItem::Check()
618 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
619 (isInternallyChecked
== isReallyChecked
) )
626 // Is this menu on a menubar? (possibly nested)
627 wxFrame
* frame
= NULL
;
628 if(menu
->IsAttached())
629 frame
= menu
->GetMenuBar()->GetFrame();
631 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
632 // normally wxMenu::SendEvent() should be enough, if it doesn't work
633 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
634 // should be fixed instead of working around it here...
637 // If it is attached then let the frame send the event.
638 // Don't call frame->ProcessCommand(id) because it toggles
639 // checkable items and we've already done that above.
640 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
641 commandEvent
.SetEventObject(frame
);
642 if (item
->IsCheckable())
643 commandEvent
.SetInt(item
->IsChecked());
644 commandEvent
.SetEventObject(menu
);
646 frame
->GetEventHandler()->ProcessEvent(commandEvent
);
650 // otherwise let the menu have it
651 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
656 //-----------------------------------------------------------------------------
658 //-----------------------------------------------------------------------------
661 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
663 if (g_isIdle
) wxapp_install_idle_handler();
665 int id
= menu
->FindMenuIdByMenuItem(widget
);
667 wxASSERT( id
!= -1 ); // should find it!
669 if (!menu
->IsEnabled(id
))
672 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
673 event
.SetEventObject( menu
);
675 wxEvtHandler
* handler
= menu
->GetEventHandler();
676 if (handler
&& handler
->ProcessEvent(event
))
679 wxWindow
*win
= menu
->GetInvokingWindow();
680 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
684 //-----------------------------------------------------------------------------
686 //-----------------------------------------------------------------------------
689 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
691 if (g_isIdle
) wxapp_install_idle_handler();
693 int id
= menu
->FindMenuIdByMenuItem(widget
);
695 wxASSERT( id
!= -1 ); // should find it!
697 if (!menu
->IsEnabled(id
))
700 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
701 event
.SetEventObject( menu
);
703 wxEvtHandler
* handler
= menu
->GetEventHandler();
704 if (handler
&& handler
->ProcessEvent(event
))
707 wxWindow
*win
= menu
->GetInvokingWindow();
709 win
->GetEventHandler()->ProcessEvent( event
);
713 //-----------------------------------------------------------------------------
715 //-----------------------------------------------------------------------------
717 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
719 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
721 const wxString
& name
,
722 const wxString
& help
,
726 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
729 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
731 const wxString
& text
,
732 const wxString
& help
,
735 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
740 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
742 const wxString
& text
,
743 const wxString
& help
,
746 : wxMenuItemBase(parentMenu
, id
, text
, help
,
747 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
752 void wxMenuItem::Init(const wxString
& text
)
754 m_labelWidget
= (GtkWidget
*) NULL
;
755 m_menuItem
= (GtkWidget
*) NULL
;
760 wxMenuItem::~wxMenuItem()
762 // don't delete menu items, the menus take care of that
765 // return the menu item text without any menu accels
767 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
771 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
773 if ( *pc
== wxT('\t'))
776 if ( *pc
== wxT('_') )
778 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
785 if ( *pc
== wxT('\\') )
787 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
794 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
797 // "&" is doubled to indicate "&" instead of accelerator
804 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
809 void wxMenuItem::SetText( const wxString
& str
)
811 // Some optimization to avoid flicker
812 wxString oldLabel
= m_text
;
813 oldLabel
= wxStripMenuCodes(oldLabel
);
814 oldLabel
.Replace(wxT("_"), wxT(""));
815 wxString label1
= wxStripMenuCodes(str
);
816 wxString oldhotkey
= GetHotKey(); // Store the old hotkey in Ctrl-foo format
817 wxCharBuffer oldbuf
= wxGTK_CONV( GetGtkHotKey(*this) ); // and as <control>foo
821 if (oldLabel
== label1
&&
822 oldhotkey
== GetHotKey()) // Make sure we can change a hotkey even if the label is unaltered
829 label
= (GtkLabel
*) m_labelWidget
;
831 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
834 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
837 gtk_label_set( label
, wxGTK_CONV( m_text
) );
840 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
841 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
846 GdkModifierType accel_mods
;
847 gtk_accelerator_parse( (const char*) oldbuf
, &accel_key
, &accel_mods
);
850 gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem
),
851 m_parentMenu
->m_accel
,
856 wxCharBuffer buf
= wxGTK_CONV( GetGtkHotKey(*this) );
857 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
860 gtk_widget_add_accelerator( GTK_WIDGET(m_menuItem
),
862 m_parentMenu
->m_accel
,
869 // it's valid for this function to be called even if m_menuItem == NULL
870 void wxMenuItem::DoSetText( const wxString
& str
)
872 // '\t' is the deliminator indicating a hot key
874 const wxChar
*pc
= str
;
875 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
877 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
879 // "&" is doubled to indicate "&" instead of accelerator
883 else if (*pc
== wxT('&'))
887 else if ( *pc
== wxT('_') ) // escape underscores
906 // wxPrintf( wxT("DoSetText(): str %s m_text %s hotkey %s\n"), str.c_str(), m_text.c_str(), m_hotKey.c_str() );
911 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
916 return (wxAcceleratorEntry
*)NULL
;
919 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
921 label
<< wxT('\t') << GetHotKey();
923 return wxGetAccelFromString(label
);
926 #endif // wxUSE_ACCEL
928 void wxMenuItem::Check( bool check
)
930 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
932 if (check
== m_isChecked
)
935 wxMenuItemBase::Check( check
);
941 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
945 wxFAIL_MSG( _T("can't check this item") );
949 void wxMenuItem::Enable( bool enable
)
951 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
953 gtk_widget_set_sensitive( m_menuItem
, enable
);
954 wxMenuItemBase::Enable( enable
);
957 bool wxMenuItem::IsChecked() const
959 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
961 wxCHECK_MSG( IsCheckable(), FALSE
,
962 wxT("can't get state of uncheckable item!") );
964 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
967 //-----------------------------------------------------------------------------
969 //-----------------------------------------------------------------------------
971 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
975 m_accel
= gtk_accel_group_new();
976 m_menu
= gtk_menu_new();
977 // NB: keep reference to the menu so that it is not destroyed behind
978 // our back by GTK+ e.g. when it is removed from menubar:
979 gtk_widget_ref(m_menu
);
981 m_owner
= (GtkWidget
*) NULL
;
983 // Tearoffs are entries, just like separators. So if we want this
984 // menu to be a tear-off one, we just append a tearoff entry
986 if ( m_style
& wxMENU_TEAROFF
)
988 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
990 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
995 // append the title as the very first entry if we have it
996 if ( !m_title
.empty() )
998 Append(wxGTK_TITLE_ID
, m_title
);
1005 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1007 if ( GTK_IS_WIDGET( m_menu
))
1010 gtk_widget_unref( m_menu
);
1011 // if the menu is inserted in another menu at this time, there was
1012 // one more reference to it:
1014 gtk_widget_destroy( m_menu
);
1018 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
1020 GtkWidget
*menuItem
;
1027 if ( mitem
->IsSeparator() )
1030 menuItem
= gtk_separator_menu_item_new();
1033 menuItem
= gtk_menu_item_new();
1036 else if (mitem
->GetBitmap().Ok())
1038 text
= mitem
->GetText();
1039 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1042 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1045 if (bitmap
->HasPixbuf())
1047 image
= gtk_image_new_from_pixbuf(bitmap
->GetPixbuf());
1051 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1052 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ?
1053 bitmap
->GetMask()->GetBitmap() :
1055 image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1058 gtk_widget_show(image
);
1060 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1063 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1064 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1066 menuItem
= gtk_pixmap_menu_item_new ();
1067 label
= GTK_LABEL(gtk_accel_label_new ( wxGTK_CONV( text
) ));
1068 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1069 gtk_container_add (GTK_CONTAINER (menuItem
), GTK_WIDGET(label
));
1071 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1073 gtk_widget_show (GTK_WIDGET(label
));
1075 mitem
->SetLabelWidget(GTK_WIDGET(label
));
1077 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1078 gtk_widget_show(pixmap
);
1079 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1085 else // a normal item
1087 // text has "_" instead of "&" after mitem->SetText() so don't use it
1088 text
= mitem
->GetText() ;
1090 switch ( mitem
->GetKind() )
1095 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1097 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1098 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1100 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1108 GSList
*group
= NULL
;
1109 if ( m_prevRadio
== NULL
)
1111 // start of a new radio group
1113 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1115 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1116 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1118 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1121 else // continue the radio group
1124 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1125 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1127 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1128 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1129 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1136 wxFAIL_MSG( _T("unexpected menu item kind") );
1142 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1144 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1145 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1155 GdkModifierType accel_mods
;
1156 wxCharBuffer buf
= wxGTK_CONV( GetGtkHotKey(*mitem
) );
1158 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetGtkHotKey(*mitem).c_str() );
1159 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1162 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1171 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1173 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1175 gtk_widget_show( menuItem
);
1177 if ( !mitem
->IsSeparator() )
1179 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1181 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1182 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1185 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1186 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1189 if ( mitem
->IsSubMenu() && mitem
->GetKind() != wxITEM_RADIO
&& mitem
->GetKind() != wxITEM_CHECK
)
1191 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1193 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1195 // if adding a submenu to a menu already existing in the menu bar, we
1196 // must set invoking window to allow processing events from this
1198 if ( m_invokingWindow
)
1199 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1203 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1204 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1209 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1210 if (accel_key
!= GDK_VoidSymbol
)
1212 gtk_widget_add_accelerator (menuItem
,
1214 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1222 mitem
->SetMenuItem(menuItem
);
1226 // This doesn't even exist!
1227 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1233 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1235 if (!GtkAppend(mitem
))
1238 return wxMenuBase::DoAppend(mitem
);
1241 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1243 if ( !wxMenuBase::DoInsert(pos
, item
) )
1247 if ( !GtkAppend(item
, (int)pos
) )
1253 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1255 if ( !wxMenuBase::DoRemove(item
) )
1256 return (wxMenuItem
*)NULL
;
1258 // TODO: this code doesn't delete the item factory item and this seems
1259 // impossible as of GTK 1.2.6.
1260 gtk_widget_destroy( item
->GetMenuItem() );
1265 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1267 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1270 wxMenuItem
*item
= node
->GetData();
1271 if (item
->GetMenuItem() == menuItem
)
1272 return item
->GetId();
1273 node
= node
->GetNext();
1279 // ----------------------------------------------------------------------------
1281 // ----------------------------------------------------------------------------
1285 static wxString
GetGtkHotKey( const wxMenuItem
& item
)
1289 wxAcceleratorEntry
*accel
= item
.GetAccel();
1292 int flags
= accel
->GetFlags();
1293 if ( flags
& wxACCEL_ALT
)
1294 hotkey
+= wxT("<alt>");
1295 if ( flags
& wxACCEL_CTRL
)
1296 hotkey
+= wxT("<control>");
1297 if ( flags
& wxACCEL_SHIFT
)
1298 hotkey
+= wxT("<shift>");
1300 int code
= accel
->GetKeyCode();
1327 hotkey
+= wxString::Format(wxT("F%d"), code
- WXK_F1
+ 1);
1330 // TODO: we should use gdk_keyval_name() (a.k.a.
1331 // XKeysymToString) here as well as hardcoding the keysym
1332 // names this might be not portable
1334 hotkey
<< wxT("Insert" );
1337 hotkey
<< wxT("Delete" );
1340 hotkey
<< wxT("Up" );
1343 hotkey
<< wxT("Down" );
1347 hotkey
<< wxT("Prior" );
1351 hotkey
<< wxT("Next" );
1354 hotkey
<< wxT("Left" );
1357 hotkey
<< wxT("Right" );
1360 hotkey
<< wxT("Home" );
1363 hotkey
<< wxT("End" );
1366 hotkey
<< wxT("Return" );
1369 hotkey
<< wxT("BackSpace" );
1372 hotkey
<< wxT("Tab" );
1375 hotkey
<< wxT("Esc" );
1378 hotkey
<< wxT("space" );
1381 hotkey
<< wxT("Multiply" );
1384 hotkey
<< wxT("Add" );
1387 hotkey
<< wxT("Separator" );
1390 hotkey
<< wxT("Subtract" );
1393 hotkey
<< wxT("Decimal" );
1396 hotkey
<< wxT("Divide" );
1399 hotkey
<< wxT("Cancel" );
1402 hotkey
<< wxT("Clear" );
1405 hotkey
<< wxT("Menu" );
1408 hotkey
<< wxT("Pause" );
1411 hotkey
<< wxT("Capital" );
1414 hotkey
<< wxT("Select" );
1417 hotkey
<< wxT("Print" );
1420 hotkey
<< wxT("Execute" );
1423 hotkey
<< wxT("Snapshot" );
1426 hotkey
<< wxT("Help" );
1429 hotkey
<< wxT("Num_Lock" );
1432 hotkey
<< wxT("Scroll_Lock" );
1434 case WXK_NUMPAD_INSERT
:
1435 hotkey
<< wxT("KP_Insert" );
1437 case WXK_NUMPAD_DELETE
:
1438 hotkey
<< wxT("KP_Delete" );
1440 case WXK_NUMPAD_SPACE
:
1441 hotkey
<< wxT("KP_Space" );
1443 case WXK_NUMPAD_TAB
:
1444 hotkey
<< wxT("KP_Tab" );
1446 case WXK_NUMPAD_ENTER
:
1447 hotkey
<< wxT("KP_Enter" );
1449 case WXK_NUMPAD_F1
: case WXK_NUMPAD_F2
: case WXK_NUMPAD_F3
:
1451 hotkey
+= wxString::Format(wxT("KP_F%d"), code
- WXK_NUMPAD_F1
+ 1);
1453 case WXK_NUMPAD_HOME
:
1454 hotkey
<< wxT("KP_Home" );
1456 case WXK_NUMPAD_LEFT
:
1457 hotkey
<< wxT("KP_Left" );
1460 hotkey
<< wxT("KP_Up" );
1462 case WXK_NUMPAD_RIGHT
:
1463 hotkey
<< wxT("KP_Right" );
1465 case WXK_NUMPAD_DOWN
:
1466 hotkey
<< wxT("KP_Down" );
1468 case WXK_NUMPAD_PRIOR
: case WXK_NUMPAD_PAGEUP
:
1469 hotkey
<< wxT("KP_Prior" );
1471 case WXK_NUMPAD_NEXT
: case WXK_NUMPAD_PAGEDOWN
:
1472 hotkey
<< wxT("KP_Next" );
1474 case WXK_NUMPAD_END
:
1475 hotkey
<< wxT("KP_End" );
1477 case WXK_NUMPAD_BEGIN
:
1478 hotkey
<< wxT("KP_Begin" );
1480 case WXK_NUMPAD_EQUAL
:
1481 hotkey
<< wxT("KP_Equal" );
1483 case WXK_NUMPAD_MULTIPLY
:
1484 hotkey
<< wxT("KP_Multiply" );
1486 case WXK_NUMPAD_ADD
:
1487 hotkey
<< wxT("KP_Add" );
1489 case WXK_NUMPAD_SEPARATOR
:
1490 hotkey
<< wxT("KP_Separator" );
1492 case WXK_NUMPAD_SUBTRACT
:
1493 hotkey
<< wxT("KP_Subtract" );
1495 case WXK_NUMPAD_DECIMAL
:
1496 hotkey
<< wxT("KP_Decimal" );
1498 case WXK_NUMPAD_DIVIDE
:
1499 hotkey
<< wxT("KP_Divide" );
1501 case WXK_NUMPAD0
: case WXK_NUMPAD1
: case WXK_NUMPAD2
:
1502 case WXK_NUMPAD3
: case WXK_NUMPAD4
: case WXK_NUMPAD5
:
1503 case WXK_NUMPAD6
: case WXK_NUMPAD7
: case WXK_NUMPAD8
: case WXK_NUMPAD9
:
1504 hotkey
+= wxString::Format(wxT("KP_%d"), code
- WXK_NUMPAD0
);
1506 case WXK_WINDOWS_LEFT
:
1507 hotkey
<< wxT("Super_L" );
1509 case WXK_WINDOWS_RIGHT
:
1510 hotkey
<< wxT("Super_R" );
1512 case WXK_WINDOWS_MENU
:
1513 hotkey
<< wxT("Menu" );
1516 hotkey
<< wxT("Command" );
1518 /* These probably wouldn't work as there is no SpecialX in gdk/keynames.txt
1519 case WXK_SPECIAL1: case WXK_SPECIAL2: case WXK_SPECIAL3: case WXK_SPECIAL4:
1520 case WXK_SPECIAL5: case WXK_SPECIAL6: case WXK_SPECIAL7: case WXK_SPECIAL8:
1521 case WXK_SPECIAL9: case WXK_SPECIAL10: case WXK_SPECIAL11: case WXK_SPECIAL12:
1522 case WXK_SPECIAL13: case WXK_SPECIAL14: case WXK_SPECIAL15: case WXK_SPECIAL16:
1523 case WXK_SPECIAL17: case WXK_SPECIAL18: case WXK_SPECIAL19: case WXK_SPECIAL20:
1524 hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1);
1527 // if there are any other keys wxGetAccelFromString() may
1528 // return, we should process them here
1533 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1541 wxFAIL_MSG( wxT("unknown keyboard accel") );
1550 #endif // wxUSE_ACCEL
1553 //-----------------------------------------------------------------------------
1554 // substitute for missing GtkPixmapMenuItem
1555 //-----------------------------------------------------------------------------
1560 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1561 * All rights reserved.
1563 * This file is part of the Gnome Library.
1565 * The Gnome Library is free software; you can redistribute it and/or
1566 * modify it under the terms of the GNU Library General Public License as
1567 * published by the Free Software Foundation; either version 2 of the
1568 * License, or (at your option) any later version.
1570 * The Gnome Library is distributed in the hope that it will be useful,
1571 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1572 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1573 * Library General Public License for more details.
1575 * You should have received a copy of the GNU Library General Public
1576 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1577 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1578 * Boston, MA 02111-1307, USA.
1584 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1586 #include <gtk/gtkaccellabel.h>
1587 #include <gtk/gtksignal.h>
1588 #include <gtk/gtkmenuitem.h>
1589 #include <gtk/gtkmenu.h>
1590 #include <gtk/gtkcontainer.h>
1595 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1596 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1597 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1598 GdkRectangle
*area
);
1599 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1600 GdkEventExpose
*event
);
1602 /* we must override the following functions */
1604 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1605 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1606 GtkAllocation
*allocation
);
1607 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1608 gboolean include_internals
,
1609 GtkCallback callback
,
1610 gpointer callback_data
);
1611 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1612 GtkRequisition
*requisition
);
1613 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1616 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1618 static GtkMenuItemClass
*parent_class
= NULL
;
1622 #define BORDER_SPACING 3
1623 #define PMAP_WIDTH 20
1626 gtk_pixmap_menu_item_get_type (void)
1628 static GtkType pixmap_menu_item_type
= 0;
1630 if (!pixmap_menu_item_type
)
1632 GtkTypeInfo pixmap_menu_item_info
=
1634 (char *)"GtkPixmapMenuItem",
1635 sizeof (GtkPixmapMenuItem
),
1636 sizeof (GtkPixmapMenuItemClass
),
1637 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1638 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1639 /* reserved_1 */ NULL
,
1640 /* reserved_2 */ NULL
,
1641 (GtkClassInitFunc
) NULL
,
1644 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1645 &pixmap_menu_item_info
);
1648 return pixmap_menu_item_type
;
1654 * gtk_pixmap_menu_item_new
1656 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1657 * to set the pixmap wich is displayed at the left side.
1660 * &GtkWidget pointer to new menu item
1664 gtk_pixmap_menu_item_new (void)
1666 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1670 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1672 GtkObjectClass
*object_class
;
1673 GtkWidgetClass
*widget_class
;
1674 GtkMenuItemClass
*menu_item_class
;
1675 GtkContainerClass
*container_class
;
1677 object_class
= (GtkObjectClass
*) klass
;
1678 widget_class
= (GtkWidgetClass
*) klass
;
1679 menu_item_class
= (GtkMenuItemClass
*) klass
;
1680 container_class
= (GtkContainerClass
*) klass
;
1682 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1684 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1685 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1686 widget_class
->map
= gtk_pixmap_menu_item_map
;
1687 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1688 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1690 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1691 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1693 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1694 klass
->have_pixmap_count
= 0;
1698 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1702 mi
= GTK_MENU_ITEM (menu_item
);
1704 menu_item
->pixmap
= NULL
;
1708 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1711 g_return_if_fail (widget
!= NULL
);
1712 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1713 g_return_if_fail (area
!= NULL
);
1715 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1716 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1718 if (GTK_WIDGET_DRAWABLE (widget
) &&
1719 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1720 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1725 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1726 GdkEventExpose
*event
)
1728 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1729 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1730 g_return_val_if_fail (event
!= NULL
, FALSE
);
1732 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1733 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1735 if (GTK_WIDGET_DRAWABLE (widget
) &&
1736 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1737 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1744 * gtk_pixmap_menu_item_set_pixmap
1745 * @menu_item: Pointer to the pixmap menu item
1746 * @pixmap: Pointer to a pixmap widget
1748 * Set the pixmap of the menu item.
1753 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1756 g_return_if_fail (menu_item
!= NULL
);
1757 g_return_if_fail (pixmap
!= NULL
);
1758 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1759 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1760 g_return_if_fail (menu_item
->pixmap
== NULL
);
1762 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1763 menu_item
->pixmap
= pixmap
;
1765 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1766 !GTK_WIDGET_REALIZED (pixmap
))
1767 gtk_widget_realize (pixmap
);
1769 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1770 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1771 GTK_WIDGET_VISIBLE(pixmap
) &&
1772 !GTK_WIDGET_MAPPED (pixmap
))
1773 gtk_widget_map (pixmap
);
1776 changed_have_pixmap_status(menu_item
);
1778 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1779 gtk_widget_queue_resize (pixmap
);
1783 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1785 GtkPixmapMenuItem
*menu_item
;
1787 g_return_if_fail (widget
!= NULL
);
1788 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1790 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1792 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1794 if (menu_item
->pixmap
&&
1795 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1796 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1797 gtk_widget_map (menu_item
->pixmap
);
1801 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1802 GtkAllocation
*allocation
)
1804 GtkPixmapMenuItem
*pmenu_item
;
1806 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1808 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1810 GtkAllocation child_allocation
;
1813 border_width
= GTK_CONTAINER (widget
)->border_width
;
1815 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1816 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1817 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1818 child_allocation
.y
= (border_width
+ BORDER_SPACING
1819 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1820 / 2)); /* center pixmaps vertically */
1821 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1824 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1825 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1829 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1830 gboolean include_internals
,
1831 GtkCallback callback
,
1832 gpointer callback_data
)
1834 GtkPixmapMenuItem
*menu_item
;
1836 g_return_if_fail (container
!= NULL
);
1837 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1838 g_return_if_fail (callback
!= NULL
);
1840 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1842 if (menu_item
->pixmap
)
1843 (* callback
) (menu_item
->pixmap
, callback_data
);
1845 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1846 callback
,callback_data
);
1850 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1851 GtkRequisition
*requisition
)
1853 GtkPixmapMenuItem
*menu_item
;
1854 GtkRequisition req
= {0, 0};
1856 g_return_if_fail (widget
!= NULL
);
1857 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1858 g_return_if_fail (requisition
!= NULL
);
1860 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1862 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1864 if (menu_item
->pixmap
)
1865 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1867 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1868 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1872 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1876 gboolean widget_was_visible
;
1878 g_return_if_fail (container
!= NULL
);
1879 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1880 g_return_if_fail (child
!= NULL
);
1881 g_return_if_fail (GTK_IS_WIDGET (child
));
1883 bin
= GTK_BIN (container
);
1884 g_return_if_fail ((bin
->child
== child
||
1885 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1887 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1889 gtk_widget_unparent (child
);
1890 if (bin
->child
== child
)
1893 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1894 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1897 if (widget_was_visible
)
1898 gtk_widget_queue_resize (GTK_WIDGET (container
));
1902 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1904 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1906 if (menu_item
->pixmap
!= NULL
) {
1907 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1909 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1910 /* Install pixmap toggle size */
1911 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1914 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1916 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1917 /* Install normal toggle size */
1918 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1922 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1923 whenever the klass->toggle_size changes; but by doing it anytime
1924 this function is called, we get the same effect, just because of
1925 how the preferences option to show pixmaps works. Bogus, broken.
1927 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1928 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));
1933 #endif // !__WXGTK20__