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"
22 #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 void wxMenuBar::Init(size_t n
, wxMenu
*menus
[], const wxString titles
[], 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
);
207 for (size_t i
= 0; i
< n
; ++i
)
208 Append(menus
[i
], titles
[i
]);
211 wxMenuBar::wxMenuBar(size_t n
, wxMenu
*menus
[], const wxString titles
[], long style
)
213 Init(n
, menus
, titles
, style
);
216 wxMenuBar::wxMenuBar(long style
)
218 Init(0, NULL
, NULL
, style
);
221 wxMenuBar::wxMenuBar()
223 Init(0, NULL
, NULL
, 0);
226 wxMenuBar::~wxMenuBar()
230 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
232 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
234 wxWindow
*top_frame
= win
;
235 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
236 top_frame
= top_frame
->GetParent();
239 // support for native hot keys
240 gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
243 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
246 wxMenuItem
*menuitem
= node
->GetData();
247 if (menuitem
->IsSubMenu())
248 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
249 node
= node
->GetNext();
253 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
255 menu
->SetInvokingWindow( win
);
257 wxWindow
*top_frame
= win
;
258 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
259 top_frame
= top_frame
->GetParent();
261 // support for native hot keys
262 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
263 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
264 gtk_accel_group_attach( menu
->m_accel
, obj
);
266 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
269 wxMenuItem
*menuitem
= node
->GetData();
270 if (menuitem
->IsSubMenu())
271 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
272 node
= node
->GetNext();
276 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
278 m_invokingWindow
= win
;
279 wxWindow
*top_frame
= win
;
280 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
281 top_frame
= top_frame
->GetParent();
284 // support for native key accelerators indicated by underscroes
285 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
286 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
287 gtk_accel_group_attach( m_accel
, obj
);
290 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
293 wxMenu
*menu
= node
->GetData();
294 wxMenubarSetInvokingWindow( menu
, win
);
295 node
= node
->GetNext();
299 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
301 m_invokingWindow
= (wxWindow
*) NULL
;
302 wxWindow
*top_frame
= win
;
303 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
304 top_frame
= top_frame
->GetParent();
307 // support for native key accelerators indicated by underscroes
308 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
311 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
314 wxMenu
*menu
= node
->GetData();
315 wxMenubarUnsetInvokingWindow( menu
, win
);
316 node
= node
->GetNext();
320 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
322 if ( !wxMenuBarBase::Append( menu
, title
) )
325 return GtkAppend(menu
, title
);
328 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
, int pos
)
330 wxString
str( wxReplaceUnderscore( title
) );
332 // This doesn't have much effect right now.
333 menu
->SetTitle( str
);
335 // The "m_owner" is the "menu item"
337 menu
->m_owner
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str
) );
339 menu
->m_owner
= gtk_menu_item_new_with_label( wxGTK_CONV( str
) );
340 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
342 gtk_label_set_text( label
, wxGTK_CONV( str
) );
344 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
345 if (accel_key
!= GDK_VoidSymbol
)
347 gtk_widget_add_accelerator (menu
->m_owner
,
349 m_accel
,//gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)),
356 gtk_widget_show( menu
->m_owner
);
358 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
361 gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
);
363 gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
, pos
);
365 gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate",
366 GTK_SIGNAL_FUNC(gtk_menu_open_callback
),
369 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
370 // addings menu later on.
371 if (m_invokingWindow
)
373 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
375 // OPTIMISE ME: we should probably cache this, or pass it
376 // directly, but for now this is a minimal
377 // change to validate the new dynamic sizing.
378 // see (and refactor :) similar code in Remove
381 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
384 frame
->UpdateMenuBarSize();
390 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
392 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
397 if ( !GtkAppend(menu
, title
, (int)pos
) )
403 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
405 // remove the old item and insert a new one
406 wxMenu
*menuOld
= Remove(pos
);
407 if ( menuOld
&& !Insert(pos
, menu
, title
) )
409 return (wxMenu
*) NULL
;
412 // either Insert() succeeded or Remove() failed and menuOld is NULL
416 wxMenu
*wxMenuBar::Remove(size_t pos
)
418 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
420 return (wxMenu
*) NULL
;
422 gtk_menu_item_remove_submenu( GTK_MENU_ITEM(menu
->m_owner
) );
423 gtk_container_remove(GTK_CONTAINER(m_menubar
), menu
->m_owner
);
425 gtk_widget_destroy( menu
->m_owner
);
426 menu
->m_owner
= NULL
;
428 if (m_invokingWindow
)
430 // OPTIMISE ME: see comment in GtkAppend
431 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
434 frame
->UpdateMenuBarSize();
440 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
442 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
444 int res
= menu
->FindItem( itemString
);
445 if (res
!= wxNOT_FOUND
)
449 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
452 wxMenuItem
*item
= node
->GetData();
453 if (item
->IsSubMenu())
454 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
456 node
= node
->GetNext();
462 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
464 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
467 wxMenu
*menu
= node
->GetData();
468 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
471 node
= node
->GetNext();
477 // Find a wxMenuItem using its id. Recurses down into sub-menus
478 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
480 wxMenuItem
* result
= menu
->FindChildItem(id
);
482 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
483 while ( node
&& result
== NULL
)
485 wxMenuItem
*item
= node
->GetData();
486 if (item
->IsSubMenu())
488 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
490 node
= node
->GetNext();
496 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
498 wxMenuItem
* result
= 0;
499 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
500 while (node
&& result
== 0)
502 wxMenu
*menu
= node
->GetData();
503 result
= FindMenuItemByIdRecursive( menu
, id
);
504 node
= node
->GetNext();
509 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
515 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
517 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
519 wxCHECK_RET( node
, wxT("menu not found") );
521 wxMenu
* menu
= node
->GetData();
524 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
527 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
529 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
531 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
533 wxMenu
* menu
= node
->GetData();
536 wxString
text( menu
->GetTitle() );
537 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
539 if ( *pc
== wxT('_') )
541 // '_' is the escape character for GTK+
545 // don't remove ampersands '&' since if we have them in the menu title
546 // it means that they were doubled to indicate "&" instead of accelerator
554 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
556 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
558 wxCHECK_RET( node
, wxT("menu not found") );
560 wxMenu
* menu
= node
->GetData();
562 wxString
str( wxReplaceUnderscore( label
) );
564 menu
->SetTitle( str
);
568 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
571 gtk_label_set( label
, wxGTK_CONV( str
) );
573 /* reparse key accel */
574 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
575 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
580 //-----------------------------------------------------------------------------
582 //-----------------------------------------------------------------------------
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);
655 //-----------------------------------------------------------------------------
657 //-----------------------------------------------------------------------------
659 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
661 if (g_isIdle
) wxapp_install_idle_handler();
663 int id
= menu
->FindMenuIdByMenuItem(widget
);
665 wxASSERT( id
!= -1 ); // should find it!
667 if (!menu
->IsEnabled(id
))
670 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
671 event
.SetEventObject( menu
);
673 wxEvtHandler
* handler
= menu
->GetEventHandler();
674 if (handler
&& handler
->ProcessEvent(event
))
677 wxWindow
*win
= menu
->GetInvokingWindow();
678 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
681 //-----------------------------------------------------------------------------
683 //-----------------------------------------------------------------------------
685 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
687 if (g_isIdle
) wxapp_install_idle_handler();
689 int id
= menu
->FindMenuIdByMenuItem(widget
);
691 wxASSERT( id
!= -1 ); // should find it!
693 if (!menu
->IsEnabled(id
))
696 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
697 event
.SetEventObject( menu
);
699 wxEvtHandler
* handler
= menu
->GetEventHandler();
700 if (handler
&& handler
->ProcessEvent(event
))
703 wxWindow
*win
= menu
->GetInvokingWindow();
705 win
->GetEventHandler()->ProcessEvent( event
);
708 //-----------------------------------------------------------------------------
710 //-----------------------------------------------------------------------------
712 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
714 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
716 const wxString
& name
,
717 const wxString
& help
,
721 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
724 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
726 const wxString
& text
,
727 const wxString
& help
,
730 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
735 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
737 const wxString
& text
,
738 const wxString
& help
,
741 : wxMenuItemBase(parentMenu
, id
, text
, help
,
742 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
747 void wxMenuItem::Init(const wxString
& text
)
749 m_labelWidget
= (GtkWidget
*) NULL
;
750 m_menuItem
= (GtkWidget
*) NULL
;
755 wxMenuItem::~wxMenuItem()
757 // don't delete menu items, the menus take care of that
760 // return the menu item text without any menu accels
762 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
766 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
768 if ( *pc
== wxT('\t'))
771 if ( *pc
== wxT('_') )
773 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
780 if ( *pc
== wxT('\\') )
782 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
789 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
792 // "&" is doubled to indicate "&" instead of accelerator
799 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
804 void wxMenuItem::SetText( const wxString
& str
)
806 // Some optimization to avoid flicker
807 wxString oldLabel
= m_text
;
808 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
809 oldLabel
.Replace(wxT("_"), wxT(""));
810 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
811 if (oldLabel
== label1
)
820 label
= (GtkLabel
*) m_labelWidget
;
822 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
825 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
828 gtk_label_set( label
, wxGTK_CONV( m_text
) );
831 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
832 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
837 // it's valid for this function to be called even if m_menuItem == NULL
838 void wxMenuItem::DoSetText( const wxString
& str
)
840 // '\t' is the deliminator indicating a hot key
842 const wxChar
*pc
= str
;
843 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
845 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
847 // "&" is doubled to indicate "&" instead of accelerator
851 else if (*pc
== wxT('&'))
855 else if ( *pc
== wxT('_') ) // escape underscores
866 // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() );
879 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
884 return (wxAcceleratorEntry
*)NULL
;
887 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
889 label
<< wxT('\t') << GetHotKey();
891 return wxGetAccelFromString(label
);
894 #endif // wxUSE_ACCEL
896 void wxMenuItem::Check( bool check
)
898 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
900 if (check
== m_isChecked
)
903 wxMenuItemBase::Check( check
);
909 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
913 wxFAIL_MSG( _T("can't check this item") );
917 void wxMenuItem::Enable( bool enable
)
919 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
921 gtk_widget_set_sensitive( m_menuItem
, enable
);
922 wxMenuItemBase::Enable( enable
);
925 bool wxMenuItem::IsChecked() const
927 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
929 wxCHECK_MSG( IsCheckable(), FALSE
,
930 wxT("can't get state of uncheckable item!") );
932 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
935 //-----------------------------------------------------------------------------
937 //-----------------------------------------------------------------------------
939 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
943 m_accel
= gtk_accel_group_new();
944 m_menu
= gtk_menu_new();
945 // NB: keep reference to the menu so that it is not destroyed behind
946 // our back by GTK+ e.g. when it is removed from menubar:
947 gtk_widget_ref(m_menu
);
949 m_owner
= (GtkWidget
*) NULL
;
951 // Tearoffs are entries, just like separators. So if we want this
952 // menu to be a tear-off one, we just append a tearoff entry
954 if ( m_style
& wxMENU_TEAROFF
)
956 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
958 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
963 // append the title as the very first entry if we have it
964 if ( !m_title
.empty() )
966 Append(wxGTK_TITLE_ID
, m_title
);
973 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
975 if ( GTK_IS_WIDGET( m_menu
))
978 gtk_widget_unref( m_menu
);
979 // if the menu is inserted in another menu at this time, there was
980 // one more reference to it:
982 gtk_widget_destroy( m_menu
);
986 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
990 if ( mitem
->IsSeparator() )
993 menuItem
= gtk_separator_menu_item_new();
996 menuItem
= gtk_menu_item_new();
999 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1001 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1003 else if ( mitem
->IsSubMenu() )
1005 // text has "_" instead of "&" after mitem->SetText()
1006 wxString
text( mitem
->GetText() );
1009 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1011 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1012 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1014 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1015 // reparse key accel
1016 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1017 if (accel_key
!= GDK_VoidSymbol
)
1019 gtk_widget_add_accelerator (menuItem
,
1021 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1028 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1030 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1032 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1034 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1036 // if adding a submenu to a menu already existing in the menu bar, we
1037 // must set invoking window to allow processing events from this
1039 if ( m_invokingWindow
)
1040 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1044 else if (mitem
->GetBitmap().Ok())
1046 wxString text
= mitem
->GetText();
1047 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1050 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1053 if (bitmap
->HasPixbuf())
1055 image
= gtk_image_new_from_pixbuf(bitmap
->GetPixbuf());
1059 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1060 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ?
1061 bitmap
->GetMask()->GetBitmap() :
1063 image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1066 gtk_widget_show(image
);
1068 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1070 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1071 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1075 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1077 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1079 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1080 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1082 menuItem
= gtk_pixmap_menu_item_new ();
1083 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1084 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1085 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1087 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1089 GdkModifierType accel_mods
;
1091 // accelerator for the item, as specified by its label
1092 // (ex. Ctrl+O for open)
1093 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1095 if (accel_key
!= GDK_VoidSymbol
)
1097 gtk_widget_add_accelerator (menuItem
,
1100 accel_key
, accel_mods
,
1104 // accelerator for the underlined char (ex ALT+F for the File menu)
1105 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1106 if (accel_key
!= GDK_VoidSymbol
)
1108 gtk_widget_add_accelerator (menuItem
,
1110 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1116 gtk_widget_show (label
);
1118 mitem
->SetLabelWidget(label
);
1120 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1121 gtk_widget_show(pixmap
);
1122 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1124 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1125 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1129 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1131 gtk_menu_insert( GTK_MENU(m_menu
), menuItem
, pos
);
1132 gtk_widget_show( menuItem
);
1137 else // a normal item
1139 // text has "_" instead of "&" after mitem->SetText() so don't use it
1140 wxString
text( mitem
->GetText() );
1142 switch ( mitem
->GetKind() )
1147 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1149 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1150 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1152 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1153 // reparse key accel
1154 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1155 if (accel_key
!= GDK_VoidSymbol
)
1157 gtk_widget_add_accelerator (menuItem
,
1159 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1171 GSList
*group
= NULL
;
1172 if ( m_prevRadio
== NULL
)
1174 // start of a new radio group
1176 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1178 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1179 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1181 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1182 // reparse key accel
1183 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1184 if (accel_key
!= GDK_VoidSymbol
)
1186 gtk_widget_add_accelerator (menuItem
,
1188 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1195 else // continue the radio group
1198 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1199 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1201 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1202 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1203 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1205 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1206 // reparse key accel
1207 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1208 if (accel_key
!= GDK_VoidSymbol
)
1210 gtk_widget_add_accelerator (menuItem
,
1212 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1223 wxFAIL_MSG( _T("unexpected menu item kind") );
1229 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1231 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1232 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1234 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1235 // reparse key accel
1236 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1237 if (accel_key
!= GDK_VoidSymbol
)
1239 gtk_widget_add_accelerator (menuItem
,
1241 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1252 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1253 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1257 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1259 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1263 GdkModifierType accel_mods
;
1264 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1266 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1268 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1271 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1279 gtk_widget_show( menuItem
);
1281 if ( !mitem
->IsSeparator() )
1283 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1285 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1286 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1289 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1290 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1294 mitem
->SetMenuItem(menuItem
);
1298 // This doesn't even exist!
1299 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1305 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1307 if (!GtkAppend(mitem
))
1310 return wxMenuBase::DoAppend(mitem
);
1313 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1315 if ( !wxMenuBase::DoInsert(pos
, item
) )
1319 if ( !GtkAppend(item
, (int)pos
) )
1325 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1327 if ( !wxMenuBase::DoRemove(item
) )
1328 return (wxMenuItem
*)NULL
;
1330 // TODO: this code doesn't delete the item factory item and this seems
1331 // impossible as of GTK 1.2.6.
1332 gtk_widget_destroy( item
->GetMenuItem() );
1337 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1339 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1342 wxMenuItem
*item
= node
->GetData();
1343 if (item
->GetMenuItem() == menuItem
)
1344 return item
->GetId();
1345 node
= node
->GetNext();
1351 // ----------------------------------------------------------------------------
1353 // ----------------------------------------------------------------------------
1357 static wxString
GetHotKey( const wxMenuItem
& item
)
1361 wxAcceleratorEntry
*accel
= item
.GetAccel();
1364 int flags
= accel
->GetFlags();
1365 if ( flags
& wxACCEL_ALT
)
1366 hotkey
+= wxT("<alt>");
1367 if ( flags
& wxACCEL_CTRL
)
1368 hotkey
+= wxT("<control>");
1369 if ( flags
& wxACCEL_SHIFT
)
1370 hotkey
+= wxT("<shift>");
1372 int code
= accel
->GetKeyCode();
1387 hotkey
+= wxString::Format(wxT("F%d"), code
- WXK_F1
+ 1);
1390 // TODO: we should use gdk_keyval_name() (a.k.a.
1391 // XKeysymToString) here as well as hardcoding the keysym
1392 // names this might be not portable
1393 case WXK_NUMPAD_INSERT
:
1394 hotkey
<< wxT("KP_Insert" );
1396 case WXK_NUMPAD_DELETE
:
1397 hotkey
<< wxT("KP_Delete" );
1400 hotkey
<< wxT("Insert" );
1403 hotkey
<< wxT("Delete" );
1406 hotkey
<< wxT("Up" );
1409 hotkey
<< wxT("Down" );
1413 hotkey
<< wxT("Prior" );
1417 hotkey
<< wxT("Next" );
1420 hotkey
<< wxT("Left" );
1423 hotkey
<< wxT("Right" );
1426 hotkey
<< wxT("Home" );
1429 hotkey
<< wxT("End" );
1432 hotkey
<< wxT("Return" );
1435 // if there are any other keys wxGetAccelFromString() may
1436 // return, we should process them here
1441 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1449 wxFAIL_MSG( wxT("unknown keyboard accel") );
1458 #endif // wxUSE_ACCEL
1461 //-----------------------------------------------------------------------------
1462 // substitute for missing GtkPixmapMenuItem
1463 //-----------------------------------------------------------------------------
1468 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1469 * All rights reserved.
1471 * This file is part of the Gnome Library.
1473 * The Gnome Library is free software; you can redistribute it and/or
1474 * modify it under the terms of the GNU Library General Public License as
1475 * published by the Free Software Foundation; either version 2 of the
1476 * License, or (at your option) any later version.
1478 * The Gnome Library is distributed in the hope that it will be useful,
1479 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1480 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1481 * Library General Public License for more details.
1483 * You should have received a copy of the GNU Library General Public
1484 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1485 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1486 * Boston, MA 02111-1307, USA.
1492 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1494 #include <gtk/gtkaccellabel.h>
1495 #include <gtk/gtksignal.h>
1496 #include <gtk/gtkmenuitem.h>
1497 #include <gtk/gtkmenu.h>
1498 #include <gtk/gtkcontainer.h>
1503 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1504 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1505 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1506 GdkRectangle
*area
);
1507 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1508 GdkEventExpose
*event
);
1510 /* we must override the following functions */
1512 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1513 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1514 GtkAllocation
*allocation
);
1515 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1516 gboolean include_internals
,
1517 GtkCallback callback
,
1518 gpointer callback_data
);
1519 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1520 GtkRequisition
*requisition
);
1521 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1524 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1526 static GtkMenuItemClass
*parent_class
= NULL
;
1530 #define BORDER_SPACING 3
1531 #define PMAP_WIDTH 20
1534 gtk_pixmap_menu_item_get_type (void)
1536 static GtkType pixmap_menu_item_type
= 0;
1538 if (!pixmap_menu_item_type
)
1540 GtkTypeInfo pixmap_menu_item_info
=
1542 (char *)"GtkPixmapMenuItem",
1543 sizeof (GtkPixmapMenuItem
),
1544 sizeof (GtkPixmapMenuItemClass
),
1545 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1546 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1547 /* reserved_1 */ NULL
,
1548 /* reserved_2 */ NULL
,
1549 (GtkClassInitFunc
) NULL
,
1552 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1553 &pixmap_menu_item_info
);
1556 return pixmap_menu_item_type
;
1560 * gtk_pixmap_menu_item_new
1562 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1563 * to set the pixmap wich is displayed at the left side.
1566 * &GtkWidget pointer to new menu item
1570 gtk_pixmap_menu_item_new (void)
1572 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1576 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1578 GtkObjectClass
*object_class
;
1579 GtkWidgetClass
*widget_class
;
1580 GtkMenuItemClass
*menu_item_class
;
1581 GtkContainerClass
*container_class
;
1583 object_class
= (GtkObjectClass
*) klass
;
1584 widget_class
= (GtkWidgetClass
*) klass
;
1585 menu_item_class
= (GtkMenuItemClass
*) klass
;
1586 container_class
= (GtkContainerClass
*) klass
;
1588 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1590 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1591 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1592 widget_class
->map
= gtk_pixmap_menu_item_map
;
1593 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1594 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1596 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1597 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1599 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1600 klass
->have_pixmap_count
= 0;
1604 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1608 mi
= GTK_MENU_ITEM (menu_item
);
1610 menu_item
->pixmap
= NULL
;
1614 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1617 g_return_if_fail (widget
!= NULL
);
1618 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1619 g_return_if_fail (area
!= NULL
);
1621 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1622 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1624 if (GTK_WIDGET_DRAWABLE (widget
) &&
1625 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1626 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1631 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1632 GdkEventExpose
*event
)
1634 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1635 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1636 g_return_val_if_fail (event
!= NULL
, FALSE
);
1638 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1639 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1641 if (GTK_WIDGET_DRAWABLE (widget
) &&
1642 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1643 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1650 * gtk_pixmap_menu_item_set_pixmap
1651 * @menu_item: Pointer to the pixmap menu item
1652 * @pixmap: Pointer to a pixmap widget
1654 * Set the pixmap of the menu item.
1659 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1662 g_return_if_fail (menu_item
!= NULL
);
1663 g_return_if_fail (pixmap
!= NULL
);
1664 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1665 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1666 g_return_if_fail (menu_item
->pixmap
== NULL
);
1668 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1669 menu_item
->pixmap
= pixmap
;
1671 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1672 !GTK_WIDGET_REALIZED (pixmap
))
1673 gtk_widget_realize (pixmap
);
1675 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1676 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1677 GTK_WIDGET_VISIBLE(pixmap
) &&
1678 !GTK_WIDGET_MAPPED (pixmap
))
1679 gtk_widget_map (pixmap
);
1682 changed_have_pixmap_status(menu_item
);
1684 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1685 gtk_widget_queue_resize (pixmap
);
1689 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1691 GtkPixmapMenuItem
*menu_item
;
1693 g_return_if_fail (widget
!= NULL
);
1694 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1696 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1698 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1700 if (menu_item
->pixmap
&&
1701 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1702 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1703 gtk_widget_map (menu_item
->pixmap
);
1707 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1708 GtkAllocation
*allocation
)
1710 GtkPixmapMenuItem
*pmenu_item
;
1712 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1714 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1716 GtkAllocation child_allocation
;
1719 border_width
= GTK_CONTAINER (widget
)->border_width
;
1721 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1722 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1723 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1724 child_allocation
.y
= (border_width
+ BORDER_SPACING
1725 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1726 / 2)); /* center pixmaps vertically */
1727 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1730 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1731 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1735 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1736 gboolean include_internals
,
1737 GtkCallback callback
,
1738 gpointer callback_data
)
1740 GtkPixmapMenuItem
*menu_item
;
1742 g_return_if_fail (container
!= NULL
);
1743 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1744 g_return_if_fail (callback
!= NULL
);
1746 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1748 if (menu_item
->pixmap
)
1749 (* callback
) (menu_item
->pixmap
, callback_data
);
1751 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1752 callback
,callback_data
);
1756 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1757 GtkRequisition
*requisition
)
1759 GtkPixmapMenuItem
*menu_item
;
1760 GtkRequisition req
= {0, 0};
1762 g_return_if_fail (widget
!= NULL
);
1763 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1764 g_return_if_fail (requisition
!= NULL
);
1766 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1768 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1770 if (menu_item
->pixmap
)
1771 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1773 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1774 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1778 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1782 gboolean widget_was_visible
;
1784 g_return_if_fail (container
!= NULL
);
1785 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1786 g_return_if_fail (child
!= NULL
);
1787 g_return_if_fail (GTK_IS_WIDGET (child
));
1789 bin
= GTK_BIN (container
);
1790 g_return_if_fail ((bin
->child
== child
||
1791 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1793 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1795 gtk_widget_unparent (child
);
1796 if (bin
->child
== child
)
1799 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1800 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1803 if (widget_was_visible
)
1804 gtk_widget_queue_resize (GTK_WIDGET (container
));
1808 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1810 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1812 if (menu_item
->pixmap
!= NULL
) {
1813 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1815 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1816 /* Install pixmap toggle size */
1817 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1820 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1822 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1823 /* Install normal toggle size */
1824 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1828 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1829 whenever the klass->toggle_size changes; but by doing it anytime
1830 this function is called, we get the same effect, just because of
1831 how the preferences option to show pixmaps works. Bogus, broken.
1833 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1834 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));