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();
1058 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1061 if (bitmap
->HasPixbuf())
1063 image
= gtk_image_new_from_pixbuf(bitmap
->GetPixbuf());
1067 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1068 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ?
1069 bitmap
->GetMask()->GetBitmap() :
1071 image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1074 gtk_widget_show(image
);
1076 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1078 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1079 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1083 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1085 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1087 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1088 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1090 menuItem
= gtk_pixmap_menu_item_new ();
1091 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1092 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1093 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1095 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1097 GdkModifierType accel_mods
;
1099 // accelerator for the item, as specified by its label
1100 // (ex. Ctrl+O for open)
1101 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1103 if (accel_key
!= GDK_VoidSymbol
)
1105 gtk_widget_add_accelerator (menuItem
,
1108 accel_key
, accel_mods
,
1112 // accelerator for the underlined char (ex ALT+F for the File menu)
1113 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1114 if (accel_key
!= GDK_VoidSymbol
)
1116 gtk_widget_add_accelerator (menuItem
,
1118 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1124 gtk_widget_show (label
);
1126 mitem
->SetLabelWidget(label
);
1128 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1129 gtk_widget_show(pixmap
);
1130 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1132 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1133 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1137 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1139 gtk_menu_insert( GTK_MENU(m_menu
), menuItem
, pos
);
1140 gtk_widget_show( menuItem
);
1145 else // a normal item
1147 // text has "_" instead of "&" after mitem->SetText() so don't use it
1148 wxString
text( mitem
->GetText() );
1150 switch ( mitem
->GetKind() )
1155 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1157 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1158 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1160 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1161 // reparse key accel
1162 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1163 if (accel_key
!= GDK_VoidSymbol
)
1165 gtk_widget_add_accelerator (menuItem
,
1167 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1179 GSList
*group
= NULL
;
1180 if ( m_prevRadio
== NULL
)
1182 // start of a new radio group
1184 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1186 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1187 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1189 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1190 // reparse key accel
1191 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1192 if (accel_key
!= GDK_VoidSymbol
)
1194 gtk_widget_add_accelerator (menuItem
,
1196 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1203 else // continue the radio group
1206 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1207 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1209 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1210 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1211 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1213 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1214 // reparse key accel
1215 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1216 if (accel_key
!= GDK_VoidSymbol
)
1218 gtk_widget_add_accelerator (menuItem
,
1220 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1231 wxFAIL_MSG( _T("unexpected menu item kind") );
1237 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1239 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1240 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1242 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1243 // reparse key accel
1244 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1245 if (accel_key
!= GDK_VoidSymbol
)
1247 gtk_widget_add_accelerator (menuItem
,
1249 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1260 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1261 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1265 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1267 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1271 GdkModifierType accel_mods
;
1272 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1274 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1276 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1279 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1287 gtk_widget_show( menuItem
);
1289 if ( !mitem
->IsSeparator() )
1291 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1293 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1294 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1297 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1298 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1302 mitem
->SetMenuItem(menuItem
);
1306 // This doesn't even exist!
1307 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1313 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1315 if (!GtkAppend(mitem
))
1318 return wxMenuBase::DoAppend(mitem
);
1321 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1323 if ( !wxMenuBase::DoInsert(pos
, item
) )
1327 if ( !GtkAppend(item
, (int)pos
) )
1333 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1335 if ( !wxMenuBase::DoRemove(item
) )
1336 return (wxMenuItem
*)NULL
;
1338 // TODO: this code doesn't delete the item factory item and this seems
1339 // impossible as of GTK 1.2.6.
1340 gtk_widget_destroy( item
->GetMenuItem() );
1345 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1347 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1350 wxMenuItem
*item
= node
->GetData();
1351 if (item
->GetMenuItem() == menuItem
)
1352 return item
->GetId();
1353 node
= node
->GetNext();
1359 // ----------------------------------------------------------------------------
1361 // ----------------------------------------------------------------------------
1365 static wxString
GetHotKey( const wxMenuItem
& item
)
1369 wxAcceleratorEntry
*accel
= item
.GetAccel();
1372 int flags
= accel
->GetFlags();
1373 if ( flags
& wxACCEL_ALT
)
1374 hotkey
+= wxT("<alt>");
1375 if ( flags
& wxACCEL_CTRL
)
1376 hotkey
+= wxT("<control>");
1377 if ( flags
& wxACCEL_SHIFT
)
1378 hotkey
+= wxT("<shift>");
1380 int code
= accel
->GetKeyCode();
1395 hotkey
+= wxString::Format(wxT("F%d"), code
- WXK_F1
+ 1);
1398 // TODO: we should use gdk_keyval_name() (a.k.a.
1399 // XKeysymToString) here as well as hardcoding the keysym
1400 // names this might be not portable
1401 case WXK_NUMPAD_INSERT
:
1402 hotkey
<< wxT("KP_Insert" );
1404 case WXK_NUMPAD_DELETE
:
1405 hotkey
<< wxT("KP_Delete" );
1408 hotkey
<< wxT("Insert" );
1411 hotkey
<< wxT("Delete" );
1414 hotkey
<< wxT("Up" );
1417 hotkey
<< wxT("Down" );
1421 hotkey
<< wxT("Prior" );
1425 hotkey
<< wxT("Next" );
1428 hotkey
<< wxT("Left" );
1431 hotkey
<< wxT("Right" );
1434 hotkey
<< wxT("Home" );
1437 hotkey
<< wxT("End" );
1440 hotkey
<< wxT("Return" );
1443 // if there are any other keys wxGetAccelFromString() may
1444 // return, we should process them here
1449 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1457 wxFAIL_MSG( wxT("unknown keyboard accel") );
1466 #endif // wxUSE_ACCEL
1469 //-----------------------------------------------------------------------------
1470 // substitute for missing GtkPixmapMenuItem
1471 //-----------------------------------------------------------------------------
1476 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1477 * All rights reserved.
1479 * This file is part of the Gnome Library.
1481 * The Gnome Library is free software; you can redistribute it and/or
1482 * modify it under the terms of the GNU Library General Public License as
1483 * published by the Free Software Foundation; either version 2 of the
1484 * License, or (at your option) any later version.
1486 * The Gnome Library is distributed in the hope that it will be useful,
1487 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1488 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1489 * Library General Public License for more details.
1491 * You should have received a copy of the GNU Library General Public
1492 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1493 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1494 * Boston, MA 02111-1307, USA.
1500 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1502 #include <gtk/gtkaccellabel.h>
1503 #include <gtk/gtksignal.h>
1504 #include <gtk/gtkmenuitem.h>
1505 #include <gtk/gtkmenu.h>
1506 #include <gtk/gtkcontainer.h>
1511 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1512 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1513 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1514 GdkRectangle
*area
);
1515 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1516 GdkEventExpose
*event
);
1518 /* we must override the following functions */
1520 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1521 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1522 GtkAllocation
*allocation
);
1523 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1524 gboolean include_internals
,
1525 GtkCallback callback
,
1526 gpointer callback_data
);
1527 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1528 GtkRequisition
*requisition
);
1529 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1532 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1534 static GtkMenuItemClass
*parent_class
= NULL
;
1538 #define BORDER_SPACING 3
1539 #define PMAP_WIDTH 20
1542 gtk_pixmap_menu_item_get_type (void)
1544 static GtkType pixmap_menu_item_type
= 0;
1546 if (!pixmap_menu_item_type
)
1548 GtkTypeInfo pixmap_menu_item_info
=
1550 (char *)"GtkPixmapMenuItem",
1551 sizeof (GtkPixmapMenuItem
),
1552 sizeof (GtkPixmapMenuItemClass
),
1553 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1554 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1555 /* reserved_1 */ NULL
,
1556 /* reserved_2 */ NULL
,
1557 (GtkClassInitFunc
) NULL
,
1560 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1561 &pixmap_menu_item_info
);
1564 return pixmap_menu_item_type
;
1568 * gtk_pixmap_menu_item_new
1570 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1571 * to set the pixmap wich is displayed at the left side.
1574 * &GtkWidget pointer to new menu item
1578 gtk_pixmap_menu_item_new (void)
1580 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1584 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1586 GtkObjectClass
*object_class
;
1587 GtkWidgetClass
*widget_class
;
1588 GtkMenuItemClass
*menu_item_class
;
1589 GtkContainerClass
*container_class
;
1591 object_class
= (GtkObjectClass
*) klass
;
1592 widget_class
= (GtkWidgetClass
*) klass
;
1593 menu_item_class
= (GtkMenuItemClass
*) klass
;
1594 container_class
= (GtkContainerClass
*) klass
;
1596 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1598 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1599 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1600 widget_class
->map
= gtk_pixmap_menu_item_map
;
1601 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1602 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1604 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1605 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1607 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1608 klass
->have_pixmap_count
= 0;
1612 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1616 mi
= GTK_MENU_ITEM (menu_item
);
1618 menu_item
->pixmap
= NULL
;
1622 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1625 g_return_if_fail (widget
!= NULL
);
1626 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1627 g_return_if_fail (area
!= NULL
);
1629 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1630 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1632 if (GTK_WIDGET_DRAWABLE (widget
) &&
1633 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1634 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1639 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1640 GdkEventExpose
*event
)
1642 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1643 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1644 g_return_val_if_fail (event
!= NULL
, FALSE
);
1646 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1647 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1649 if (GTK_WIDGET_DRAWABLE (widget
) &&
1650 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1651 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1658 * gtk_pixmap_menu_item_set_pixmap
1659 * @menu_item: Pointer to the pixmap menu item
1660 * @pixmap: Pointer to a pixmap widget
1662 * Set the pixmap of the menu item.
1667 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1670 g_return_if_fail (menu_item
!= NULL
);
1671 g_return_if_fail (pixmap
!= NULL
);
1672 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1673 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1674 g_return_if_fail (menu_item
->pixmap
== NULL
);
1676 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1677 menu_item
->pixmap
= pixmap
;
1679 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1680 !GTK_WIDGET_REALIZED (pixmap
))
1681 gtk_widget_realize (pixmap
);
1683 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1684 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1685 GTK_WIDGET_VISIBLE(pixmap
) &&
1686 !GTK_WIDGET_MAPPED (pixmap
))
1687 gtk_widget_map (pixmap
);
1690 changed_have_pixmap_status(menu_item
);
1692 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1693 gtk_widget_queue_resize (pixmap
);
1697 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1699 GtkPixmapMenuItem
*menu_item
;
1701 g_return_if_fail (widget
!= NULL
);
1702 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1704 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1706 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1708 if (menu_item
->pixmap
&&
1709 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1710 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1711 gtk_widget_map (menu_item
->pixmap
);
1715 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1716 GtkAllocation
*allocation
)
1718 GtkPixmapMenuItem
*pmenu_item
;
1720 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1722 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1724 GtkAllocation child_allocation
;
1727 border_width
= GTK_CONTAINER (widget
)->border_width
;
1729 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1730 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1731 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1732 child_allocation
.y
= (border_width
+ BORDER_SPACING
1733 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1734 / 2)); /* center pixmaps vertically */
1735 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1738 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1739 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1743 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1744 gboolean include_internals
,
1745 GtkCallback callback
,
1746 gpointer callback_data
)
1748 GtkPixmapMenuItem
*menu_item
;
1750 g_return_if_fail (container
!= NULL
);
1751 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1752 g_return_if_fail (callback
!= NULL
);
1754 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1756 if (menu_item
->pixmap
)
1757 (* callback
) (menu_item
->pixmap
, callback_data
);
1759 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1760 callback
,callback_data
);
1764 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1765 GtkRequisition
*requisition
)
1767 GtkPixmapMenuItem
*menu_item
;
1768 GtkRequisition req
= {0, 0};
1770 g_return_if_fail (widget
!= NULL
);
1771 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1772 g_return_if_fail (requisition
!= NULL
);
1774 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1776 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1778 if (menu_item
->pixmap
)
1779 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1781 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1782 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1786 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1790 gboolean widget_was_visible
;
1792 g_return_if_fail (container
!= NULL
);
1793 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1794 g_return_if_fail (child
!= NULL
);
1795 g_return_if_fail (GTK_IS_WIDGET (child
));
1797 bin
= GTK_BIN (container
);
1798 g_return_if_fail ((bin
->child
== child
||
1799 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1801 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1803 gtk_widget_unparent (child
);
1804 if (bin
->child
== child
)
1807 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1808 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1811 if (widget_was_visible
)
1812 gtk_widget_queue_resize (GTK_WIDGET (container
));
1816 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1818 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1820 if (menu_item
->pixmap
!= NULL
) {
1821 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1823 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1824 /* Install pixmap toggle size */
1825 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1828 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1830 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1831 /* Install normal toggle size */
1832 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1836 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1837 whenever the klass->toggle_size changes; but by doing it anytime
1838 this function is called, we get the same effect, just because of
1839 how the preferences option to show pixmaps works. Bogus, broken.
1841 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1842 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));