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
))
986 gtk_widget_unref( m_menu
);
987 // if the menu is inserted in another menu at this time, there was
988 // one more reference to it:
990 gtk_widget_destroy( m_menu
);
994 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
998 if ( mitem
->IsSeparator() )
1001 menuItem
= gtk_separator_menu_item_new();
1004 menuItem
= gtk_menu_item_new();
1007 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1009 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1011 else if ( mitem
->IsSubMenu() )
1013 // text has "_" instead of "&" after mitem->SetText()
1014 wxString
text( mitem
->GetText() );
1017 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1019 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1020 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1022 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1023 // reparse key accel
1024 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1025 if (accel_key
!= GDK_VoidSymbol
)
1027 gtk_widget_add_accelerator (menuItem
,
1029 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1036 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1038 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1040 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1042 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1044 // if adding a submenu to a menu already existing in the menu bar, we
1045 // must set invoking window to allow processing events from this
1047 if ( m_invokingWindow
)
1048 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1052 else if (mitem
->GetBitmap().Ok())
1054 wxString text
= mitem
->GetText();
1055 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1056 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1057 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1060 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1062 GtkWidget
*image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1063 gtk_widget_show(image
);
1065 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1067 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1068 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1072 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1074 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1077 menuItem
= gtk_pixmap_menu_item_new ();
1078 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1079 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1080 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1082 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1084 GdkModifierType accel_mods
;
1086 // accelerator for the item, as specified by its label
1087 // (ex. Ctrl+O for open)
1088 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1090 if (accel_key
!= GDK_VoidSymbol
)
1092 gtk_widget_add_accelerator (menuItem
,
1095 accel_key
, accel_mods
,
1099 // accelerator for the underlined char (ex ALT+F for the File menu)
1100 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1101 if (accel_key
!= GDK_VoidSymbol
)
1103 gtk_widget_add_accelerator (menuItem
,
1105 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1111 gtk_widget_show (label
);
1113 mitem
->SetLabelWidget(label
);
1115 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1116 gtk_widget_show(pixmap
);
1117 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1119 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1120 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1124 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1126 gtk_menu_insert( GTK_MENU(m_menu
), menuItem
, pos
);
1127 gtk_widget_show( menuItem
);
1132 else // a normal item
1134 // text has "_" instead of "&" after mitem->SetText() so don't use it
1135 wxString
text( mitem
->GetText() );
1137 switch ( mitem
->GetKind() )
1142 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1144 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1145 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1147 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1148 // reparse key accel
1149 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1150 if (accel_key
!= GDK_VoidSymbol
)
1152 gtk_widget_add_accelerator (menuItem
,
1154 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1166 GSList
*group
= NULL
;
1167 if ( m_prevRadio
== NULL
)
1169 // start of a new radio group
1171 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1173 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1174 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1176 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1177 // reparse key accel
1178 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1179 if (accel_key
!= GDK_VoidSymbol
)
1181 gtk_widget_add_accelerator (menuItem
,
1183 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1190 else // continue the radio group
1193 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1194 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1196 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1197 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1198 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1200 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1201 // reparse key accel
1202 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1203 if (accel_key
!= GDK_VoidSymbol
)
1205 gtk_widget_add_accelerator (menuItem
,
1207 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1218 wxFAIL_MSG( _T("unexpected menu item kind") );
1224 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1226 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1227 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1229 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1230 // reparse key accel
1231 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1232 if (accel_key
!= GDK_VoidSymbol
)
1234 gtk_widget_add_accelerator (menuItem
,
1236 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1247 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1248 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1252 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1254 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1258 GdkModifierType accel_mods
;
1259 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1261 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1263 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1266 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1274 gtk_widget_show( menuItem
);
1276 if ( !mitem
->IsSeparator() )
1278 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1280 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1281 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1284 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1285 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1289 mitem
->SetMenuItem(menuItem
);
1293 // This doesn't even exist!
1294 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1300 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1302 if (!GtkAppend(mitem
))
1305 return wxMenuBase::DoAppend(mitem
);
1308 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1310 if ( !wxMenuBase::DoInsert(pos
, item
) )
1314 if ( !GtkAppend(item
, (int)pos
) )
1320 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1322 if ( !wxMenuBase::DoRemove(item
) )
1323 return (wxMenuItem
*)NULL
;
1325 // TODO: this code doesn't delete the item factory item and this seems
1326 // impossible as of GTK 1.2.6.
1327 gtk_widget_destroy( item
->GetMenuItem() );
1332 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1334 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1337 wxMenuItem
*item
= node
->GetData();
1338 if (item
->GetMenuItem() == menuItem
)
1339 return item
->GetId();
1340 node
= node
->GetNext();
1346 // ----------------------------------------------------------------------------
1348 // ----------------------------------------------------------------------------
1352 static wxString
GetHotKey( const wxMenuItem
& item
)
1356 wxAcceleratorEntry
*accel
= item
.GetAccel();
1359 int flags
= accel
->GetFlags();
1360 if ( flags
& wxACCEL_ALT
)
1361 hotkey
+= wxT("<alt>");
1362 if ( flags
& wxACCEL_CTRL
)
1363 hotkey
+= wxT("<control>");
1364 if ( flags
& wxACCEL_SHIFT
)
1365 hotkey
+= wxT("<shift>");
1367 int code
= accel
->GetKeyCode();
1382 hotkey
+= wxString::Format(wxT("F%d"), code
- WXK_F1
+ 1);
1385 // TODO: we should use gdk_keyval_name() (a.k.a.
1386 // XKeysymToString) here as well as hardcoding the keysym
1387 // names this might be not portable
1388 case WXK_NUMPAD_INSERT
:
1389 hotkey
<< wxT("KP_Insert" );
1391 case WXK_NUMPAD_DELETE
:
1392 hotkey
<< wxT("KP_Delete" );
1395 hotkey
<< wxT("Insert" );
1398 hotkey
<< wxT("Delete" );
1401 hotkey
<< wxT("Up" );
1404 hotkey
<< wxT("Down" );
1408 hotkey
<< wxT("Prior" );
1412 hotkey
<< wxT("Next" );
1415 hotkey
<< wxT("Left" );
1418 hotkey
<< wxT("Right" );
1421 hotkey
<< wxT("Home" );
1424 hotkey
<< wxT("End" );
1427 hotkey
<< wxT("Return" );
1430 // if there are any other keys wxGetAccelFromString() may
1431 // return, we should process them here
1436 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1444 wxFAIL_MSG( wxT("unknown keyboard accel") );
1453 #endif // wxUSE_ACCEL
1456 //-----------------------------------------------------------------------------
1457 // substitute for missing GtkPixmapMenuItem
1458 //-----------------------------------------------------------------------------
1463 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1464 * All rights reserved.
1466 * This file is part of the Gnome Library.
1468 * The Gnome Library is free software; you can redistribute it and/or
1469 * modify it under the terms of the GNU Library General Public License as
1470 * published by the Free Software Foundation; either version 2 of the
1471 * License, or (at your option) any later version.
1473 * The Gnome Library is distributed in the hope that it will be useful,
1474 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1475 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1476 * Library General Public License for more details.
1478 * You should have received a copy of the GNU Library General Public
1479 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1480 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1481 * Boston, MA 02111-1307, USA.
1487 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1489 #include <gtk/gtkaccellabel.h>
1490 #include <gtk/gtksignal.h>
1491 #include <gtk/gtkmenuitem.h>
1492 #include <gtk/gtkmenu.h>
1493 #include <gtk/gtkcontainer.h>
1498 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1499 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1500 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1501 GdkRectangle
*area
);
1502 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1503 GdkEventExpose
*event
);
1505 /* we must override the following functions */
1507 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1508 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1509 GtkAllocation
*allocation
);
1510 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1511 gboolean include_internals
,
1512 GtkCallback callback
,
1513 gpointer callback_data
);
1514 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1515 GtkRequisition
*requisition
);
1516 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1519 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1521 static GtkMenuItemClass
*parent_class
= NULL
;
1525 #define BORDER_SPACING 3
1526 #define PMAP_WIDTH 20
1529 gtk_pixmap_menu_item_get_type (void)
1531 static GtkType pixmap_menu_item_type
= 0;
1533 if (!pixmap_menu_item_type
)
1535 GtkTypeInfo pixmap_menu_item_info
=
1537 (char *)"GtkPixmapMenuItem",
1538 sizeof (GtkPixmapMenuItem
),
1539 sizeof (GtkPixmapMenuItemClass
),
1540 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1541 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1542 /* reserved_1 */ NULL
,
1543 /* reserved_2 */ NULL
,
1544 (GtkClassInitFunc
) NULL
,
1547 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1548 &pixmap_menu_item_info
);
1551 return pixmap_menu_item_type
;
1555 * gtk_pixmap_menu_item_new
1557 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1558 * to set the pixmap wich is displayed at the left side.
1561 * &GtkWidget pointer to new menu item
1565 gtk_pixmap_menu_item_new (void)
1567 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1571 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1573 GtkObjectClass
*object_class
;
1574 GtkWidgetClass
*widget_class
;
1575 GtkMenuItemClass
*menu_item_class
;
1576 GtkContainerClass
*container_class
;
1578 object_class
= (GtkObjectClass
*) klass
;
1579 widget_class
= (GtkWidgetClass
*) klass
;
1580 menu_item_class
= (GtkMenuItemClass
*) klass
;
1581 container_class
= (GtkContainerClass
*) klass
;
1583 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1585 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1586 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1587 widget_class
->map
= gtk_pixmap_menu_item_map
;
1588 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1589 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1591 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1592 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1594 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1595 klass
->have_pixmap_count
= 0;
1599 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1603 mi
= GTK_MENU_ITEM (menu_item
);
1605 menu_item
->pixmap
= NULL
;
1609 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1612 g_return_if_fail (widget
!= NULL
);
1613 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1614 g_return_if_fail (area
!= NULL
);
1616 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1617 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1619 if (GTK_WIDGET_DRAWABLE (widget
) &&
1620 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1621 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1626 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1627 GdkEventExpose
*event
)
1629 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1630 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1631 g_return_val_if_fail (event
!= NULL
, FALSE
);
1633 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1634 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1636 if (GTK_WIDGET_DRAWABLE (widget
) &&
1637 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1638 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1645 * gtk_pixmap_menu_item_set_pixmap
1646 * @menu_item: Pointer to the pixmap menu item
1647 * @pixmap: Pointer to a pixmap widget
1649 * Set the pixmap of the menu item.
1654 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1657 g_return_if_fail (menu_item
!= NULL
);
1658 g_return_if_fail (pixmap
!= NULL
);
1659 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1660 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1661 g_return_if_fail (menu_item
->pixmap
== NULL
);
1663 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1664 menu_item
->pixmap
= pixmap
;
1666 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1667 !GTK_WIDGET_REALIZED (pixmap
))
1668 gtk_widget_realize (pixmap
);
1670 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1671 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1672 GTK_WIDGET_VISIBLE(pixmap
) &&
1673 !GTK_WIDGET_MAPPED (pixmap
))
1674 gtk_widget_map (pixmap
);
1677 changed_have_pixmap_status(menu_item
);
1679 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1680 gtk_widget_queue_resize (pixmap
);
1684 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1686 GtkPixmapMenuItem
*menu_item
;
1688 g_return_if_fail (widget
!= NULL
);
1689 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1691 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1693 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1695 if (menu_item
->pixmap
&&
1696 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1697 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1698 gtk_widget_map (menu_item
->pixmap
);
1702 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1703 GtkAllocation
*allocation
)
1705 GtkPixmapMenuItem
*pmenu_item
;
1707 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1709 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1711 GtkAllocation child_allocation
;
1714 border_width
= GTK_CONTAINER (widget
)->border_width
;
1716 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1717 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1718 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1719 child_allocation
.y
= (border_width
+ BORDER_SPACING
1720 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1721 / 2)); /* center pixmaps vertically */
1722 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1725 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1726 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1730 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1731 gboolean include_internals
,
1732 GtkCallback callback
,
1733 gpointer callback_data
)
1735 GtkPixmapMenuItem
*menu_item
;
1737 g_return_if_fail (container
!= NULL
);
1738 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1739 g_return_if_fail (callback
!= NULL
);
1741 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1743 if (menu_item
->pixmap
)
1744 (* callback
) (menu_item
->pixmap
, callback_data
);
1746 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1747 callback
,callback_data
);
1751 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1752 GtkRequisition
*requisition
)
1754 GtkPixmapMenuItem
*menu_item
;
1755 GtkRequisition req
= {0, 0};
1757 g_return_if_fail (widget
!= NULL
);
1758 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1759 g_return_if_fail (requisition
!= NULL
);
1761 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1763 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1765 if (menu_item
->pixmap
)
1766 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1768 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1769 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1773 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1777 gboolean widget_was_visible
;
1779 g_return_if_fail (container
!= NULL
);
1780 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1781 g_return_if_fail (child
!= NULL
);
1782 g_return_if_fail (GTK_IS_WIDGET (child
));
1784 bin
= GTK_BIN (container
);
1785 g_return_if_fail ((bin
->child
== child
||
1786 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1788 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1790 gtk_widget_unparent (child
);
1791 if (bin
->child
== child
)
1794 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1795 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1798 if (widget_was_visible
)
1799 gtk_widget_queue_resize (GTK_WIDGET (container
));
1803 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1805 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1807 if (menu_item
->pixmap
!= NULL
) {
1808 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1810 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1811 /* Install pixmap toggle size */
1812 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1815 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1817 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1818 /* Install normal toggle size */
1819 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1823 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1824 whenever the klass->toggle_size changes; but by doing it anytime
1825 this function is called, we get the same effect, just because of
1826 how the preferences option to show pixmaps works. Bogus, broken.
1828 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1829 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));