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 static wxMenu
*CopyMenu (wxMenu
*menu
)
426 wxMenu
*menucopy
= new wxMenu ();
427 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
430 wxMenuItem
*item
= node
->GetData();
431 int itemid
= item
->GetId();
432 wxString text
= item
->GetText();
433 text
.Replace(wxT("_"), wxT("&"));
434 wxMenu
*submenu
= item
->GetSubMenu();
437 wxMenuItem
* itemcopy
= new wxMenuItem(menucopy
,
439 menu
->GetHelpString(itemid
));
440 itemcopy
->SetBitmap(item
->GetBitmap());
441 itemcopy
->SetCheckable(item
->IsCheckable());
442 menucopy
->Append(itemcopy
);
445 menucopy
->Append (itemid
, text
, CopyMenu(submenu
),
446 menu
->GetHelpString(itemid
));
448 node
= node
->GetNext();
454 wxMenu
*wxMenuBar::Remove(size_t pos
)
456 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
458 return (wxMenu
*) NULL
;
460 wxMenu
*menucopy
= CopyMenu( menu
);
462 // unparent calls unref() and that would delete the widget so we raise
463 // the ref count to 2 artificially before invoking unparent.
464 gtk_widget_ref( menu
->m_menu
);
465 gtk_widget_unparent( menu
->m_menu
);
467 gtk_widget_destroy( menu
->m_owner
);
472 if (m_invokingWindow
)
474 // OPTIMISE ME: see comment in GtkAppend
475 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
478 frame
->UpdateMenuBarSize();
484 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
486 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
488 int res
= menu
->FindItem( itemString
);
489 if (res
!= wxNOT_FOUND
)
493 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
496 wxMenuItem
*item
= node
->GetData();
497 if (item
->IsSubMenu())
498 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
500 node
= node
->GetNext();
506 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
508 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
511 wxMenu
*menu
= node
->GetData();
512 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
515 node
= node
->GetNext();
521 // Find a wxMenuItem using its id. Recurses down into sub-menus
522 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
524 wxMenuItem
* result
= menu
->FindChildItem(id
);
526 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
527 while ( node
&& result
== NULL
)
529 wxMenuItem
*item
= node
->GetData();
530 if (item
->IsSubMenu())
532 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
534 node
= node
->GetNext();
540 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
542 wxMenuItem
* result
= 0;
543 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
544 while (node
&& result
== 0)
546 wxMenu
*menu
= node
->GetData();
547 result
= FindMenuItemByIdRecursive( menu
, id
);
548 node
= node
->GetNext();
553 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
559 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
561 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
563 wxCHECK_RET( node
, wxT("menu not found") );
565 wxMenu
* menu
= node
->GetData();
568 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
571 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
573 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
575 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
577 wxMenu
* menu
= node
->GetData();
580 wxString
text( menu
->GetTitle() );
581 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
583 if ( *pc
== wxT('_') )
585 // '_' is the escape character for GTK+
589 // don't remove ampersands '&' since if we have them in the menu title
590 // it means that they were doubled to indicate "&" instead of accelerator
598 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
600 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
602 wxCHECK_RET( node
, wxT("menu not found") );
604 wxMenu
* menu
= node
->GetData();
606 wxString
str( wxReplaceUnderscore( label
) );
608 menu
->SetTitle( str
);
612 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
615 gtk_label_set( label
, wxGTK_CONV( str
) );
617 /* reparse key accel */
618 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
619 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
624 //-----------------------------------------------------------------------------
626 //-----------------------------------------------------------------------------
628 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
631 wxapp_install_idle_handler();
633 int id
= menu
->FindMenuIdByMenuItem(widget
);
635 /* should find it for normal (not popup) menu */
636 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
637 _T("menu item not found in gtk_menu_clicked_callback") );
639 if (!menu
->IsEnabled(id
))
642 wxMenuItem
* item
= menu
->FindChildItem( id
);
643 wxCHECK_RET( item
, wxT("error in menu item callback") );
645 if ( item
->GetId() == wxGTK_TITLE_ID
)
647 // ignore events from the menu title
651 if (item
->IsCheckable())
653 bool isReallyChecked
= item
->IsChecked(),
654 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
656 // ensure that the internal state is always consistent with what is
657 // shown on the screen
658 item
->wxMenuItemBase::Check(isReallyChecked
);
660 // we must not report the events for the radio button going up nor the
661 // events resulting from the calls to wxMenuItem::Check()
662 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
663 (isInternallyChecked
== isReallyChecked
) )
670 // Is this menu on a menubar? (possibly nested)
671 wxFrame
* frame
= NULL
;
672 if(menu
->IsAttached())
673 frame
= menu
->GetMenuBar()->GetFrame();
675 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
676 // normally wxMenu::SendEvent() should be enough, if it doesn't work
677 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
678 // should be fixed instead of working around it here...
681 // If it is attached then let the frame send the event.
682 // Don't call frame->ProcessCommand(id) because it toggles
683 // checkable items and we've already done that above.
684 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
685 commandEvent
.SetEventObject(frame
);
686 if (item
->IsCheckable())
687 commandEvent
.SetInt(item
->IsChecked());
688 commandEvent
.SetEventObject(menu
);
690 frame
->GetEventHandler()->ProcessEvent(commandEvent
);
694 // otherwise let the menu have it
695 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
699 //-----------------------------------------------------------------------------
701 //-----------------------------------------------------------------------------
703 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
705 if (g_isIdle
) wxapp_install_idle_handler();
707 int id
= menu
->FindMenuIdByMenuItem(widget
);
709 wxASSERT( id
!= -1 ); // should find it!
711 if (!menu
->IsEnabled(id
))
714 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
715 event
.SetEventObject( menu
);
717 wxEvtHandler
* handler
= menu
->GetEventHandler();
718 if (handler
&& handler
->ProcessEvent(event
))
721 wxWindow
*win
= menu
->GetInvokingWindow();
722 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
725 //-----------------------------------------------------------------------------
727 //-----------------------------------------------------------------------------
729 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
731 if (g_isIdle
) wxapp_install_idle_handler();
733 int id
= menu
->FindMenuIdByMenuItem(widget
);
735 wxASSERT( id
!= -1 ); // should find it!
737 if (!menu
->IsEnabled(id
))
740 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
741 event
.SetEventObject( menu
);
743 wxEvtHandler
* handler
= menu
->GetEventHandler();
744 if (handler
&& handler
->ProcessEvent(event
))
747 wxWindow
*win
= menu
->GetInvokingWindow();
749 win
->GetEventHandler()->ProcessEvent( event
);
752 //-----------------------------------------------------------------------------
754 //-----------------------------------------------------------------------------
756 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
758 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
760 const wxString
& name
,
761 const wxString
& help
,
765 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
768 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
770 const wxString
& text
,
771 const wxString
& help
,
774 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
779 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
781 const wxString
& text
,
782 const wxString
& help
,
785 : wxMenuItemBase(parentMenu
, id
, text
, help
,
786 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
791 void wxMenuItem::Init(const wxString
& text
)
793 m_labelWidget
= (GtkWidget
*) NULL
;
794 m_menuItem
= (GtkWidget
*) NULL
;
799 wxMenuItem::~wxMenuItem()
801 // don't delete menu items, the menus take care of that
804 // return the menu item text without any menu accels
806 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
810 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
812 if ( *pc
== wxT('\t'))
815 if ( *pc
== wxT('_') )
817 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
824 if ( *pc
== wxT('\\') )
826 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
833 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
836 // "&" is doubled to indicate "&" instead of accelerator
843 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
848 void wxMenuItem::SetText( const wxString
& str
)
850 // Some optimization to avoid flicker
851 wxString oldLabel
= m_text
;
852 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
853 oldLabel
.Replace(wxT("_"), wxT(""));
854 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
855 if (oldLabel
== label1
)
864 label
= (GtkLabel
*) m_labelWidget
;
866 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
869 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
872 gtk_label_set( label
, wxGTK_CONV( m_text
) );
875 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
876 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
881 // it's valid for this function to be called even if m_menuItem == NULL
882 void wxMenuItem::DoSetText( const wxString
& str
)
884 // '\t' is the deliminator indicating a hot key
886 const wxChar
*pc
= str
;
887 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
889 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
891 // "&" is doubled to indicate "&" instead of accelerator
895 else if (*pc
== wxT('&'))
899 else if ( *pc
== wxT('_') ) // escape underscores
910 // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() );
923 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
928 return (wxAcceleratorEntry
*)NULL
;
931 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
933 label
<< wxT('\t') << GetHotKey();
935 return wxGetAccelFromString(label
);
938 #endif // wxUSE_ACCEL
940 void wxMenuItem::Check( bool check
)
942 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
944 if (check
== m_isChecked
)
947 wxMenuItemBase::Check( check
);
953 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
957 wxFAIL_MSG( _T("can't check this item") );
961 void wxMenuItem::Enable( bool enable
)
963 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
965 gtk_widget_set_sensitive( m_menuItem
, enable
);
966 wxMenuItemBase::Enable( enable
);
969 bool wxMenuItem::IsChecked() const
971 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
973 wxCHECK_MSG( IsCheckable(), FALSE
,
974 wxT("can't get state of uncheckable item!") );
976 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
979 //-----------------------------------------------------------------------------
981 //-----------------------------------------------------------------------------
983 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
987 m_accel
= gtk_accel_group_new();
988 m_menu
= gtk_menu_new();
990 m_owner
= (GtkWidget
*) NULL
;
992 // Tearoffs are entries, just like separators. So if we want this
993 // menu to be a tear-off one, we just append a tearoff entry
995 if ( m_style
& wxMENU_TEAROFF
)
997 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
999 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
1004 // append the title as the very first entry if we have it
1005 if ( !m_title
.empty() )
1007 Append(wxGTK_TITLE_ID
, m_title
);
1014 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1016 if ( GTK_IS_WIDGET( m_menu
))
1017 gtk_widget_destroy( m_menu
);
1020 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
1022 GtkWidget
*menuItem
;
1024 if ( mitem
->IsSeparator() )
1027 menuItem
= gtk_separator_menu_item_new();
1030 menuItem
= gtk_menu_item_new();
1033 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1035 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1037 else if ( mitem
->IsSubMenu() )
1039 // text has "_" instead of "&" after mitem->SetText()
1040 wxString
text( mitem
->GetText() );
1043 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1045 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1046 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1048 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1049 // reparse key accel
1050 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1051 if (accel_key
!= GDK_VoidSymbol
)
1053 gtk_widget_add_accelerator (menuItem
,
1055 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1062 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1064 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1066 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1068 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1070 // if adding a submenu to a menu already existing in the menu bar, we
1071 // must set invoking window to allow processing events from this
1073 if ( m_invokingWindow
)
1074 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1078 else if (mitem
->GetBitmap().Ok())
1080 wxString text
= mitem
->GetText();
1081 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1082 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1083 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1086 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1088 GtkWidget
*image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1089 gtk_widget_show(image
);
1091 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1093 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1094 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1098 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1100 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1103 menuItem
= gtk_pixmap_menu_item_new ();
1104 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1105 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1106 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1108 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1110 GdkModifierType accel_mods
;
1112 // accelerator for the item, as specified by its label
1113 // (ex. Ctrl+O for open)
1114 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1116 if (accel_key
!= GDK_VoidSymbol
)
1118 gtk_widget_add_accelerator (menuItem
,
1121 accel_key
, accel_mods
,
1125 // accelerator for the underlined char (ex ALT+F for the File menu)
1126 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1127 if (accel_key
!= GDK_VoidSymbol
)
1129 gtk_widget_add_accelerator (menuItem
,
1131 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1137 gtk_widget_show (label
);
1139 mitem
->SetLabelWidget(label
);
1141 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1142 gtk_widget_show(pixmap
);
1143 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1145 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1146 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1150 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1152 gtk_menu_insert( GTK_MENU(m_menu
), menuItem
, pos
);
1153 gtk_widget_show( menuItem
);
1158 else // a normal item
1160 // text has "_" instead of "&" after mitem->SetText() so don't use it
1161 wxString
text( mitem
->GetText() );
1163 switch ( mitem
->GetKind() )
1168 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1170 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1171 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1173 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1174 // reparse key accel
1175 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1176 if (accel_key
!= GDK_VoidSymbol
)
1178 gtk_widget_add_accelerator (menuItem
,
1180 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1192 GSList
*group
= NULL
;
1193 if ( m_prevRadio
== NULL
)
1195 // start of a new radio group
1197 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1199 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1200 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1202 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1203 // reparse key accel
1204 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1205 if (accel_key
!= GDK_VoidSymbol
)
1207 gtk_widget_add_accelerator (menuItem
,
1209 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1216 else // continue the radio group
1219 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1220 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1222 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1223 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1224 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1226 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1227 // reparse key accel
1228 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1229 if (accel_key
!= GDK_VoidSymbol
)
1231 gtk_widget_add_accelerator (menuItem
,
1233 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1244 wxFAIL_MSG( _T("unexpected menu item kind") );
1250 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1252 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1253 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1255 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1256 // reparse key accel
1257 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1258 if (accel_key
!= GDK_VoidSymbol
)
1260 gtk_widget_add_accelerator (menuItem
,
1262 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1273 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1274 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1278 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1280 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1284 GdkModifierType accel_mods
;
1285 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1287 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1289 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1292 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1300 gtk_widget_show( menuItem
);
1302 if ( !mitem
->IsSeparator() )
1304 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1306 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1307 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1310 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1311 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1315 mitem
->SetMenuItem(menuItem
);
1319 // This doesn't even exist!
1320 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1326 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1328 if (!GtkAppend(mitem
))
1331 return wxMenuBase::DoAppend(mitem
);
1334 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1336 if ( !wxMenuBase::DoInsert(pos
, item
) )
1340 if ( !GtkAppend(item
, (int)pos
) )
1346 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1348 if ( !wxMenuBase::DoRemove(item
) )
1349 return (wxMenuItem
*)NULL
;
1351 // TODO: this code doesn't delete the item factory item and this seems
1352 // impossible as of GTK 1.2.6.
1353 gtk_widget_destroy( item
->GetMenuItem() );
1358 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1360 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1363 wxMenuItem
*item
= node
->GetData();
1364 if (item
->GetMenuItem() == menuItem
)
1365 return item
->GetId();
1366 node
= node
->GetNext();
1372 // ----------------------------------------------------------------------------
1374 // ----------------------------------------------------------------------------
1378 static wxString
GetHotKey( const wxMenuItem
& item
)
1382 wxAcceleratorEntry
*accel
= item
.GetAccel();
1385 int flags
= accel
->GetFlags();
1386 if ( flags
& wxACCEL_ALT
)
1387 hotkey
+= wxT("<alt>");
1388 if ( flags
& wxACCEL_CTRL
)
1389 hotkey
+= wxT("<control>");
1390 if ( flags
& wxACCEL_SHIFT
)
1391 hotkey
+= wxT("<shift>");
1393 int code
= accel
->GetKeyCode();
1408 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1411 // TODO: we should use gdk_keyval_name() (a.k.a.
1412 // XKeysymToString) here as well as hardcoding the keysym
1413 // names this might be not portable
1414 case WXK_NUMPAD_INSERT
:
1415 hotkey
<< wxT("KP_Insert" );
1417 case WXK_NUMPAD_DELETE
:
1418 hotkey
<< wxT("KP_Delete" );
1421 hotkey
<< wxT("Insert" );
1424 hotkey
<< wxT("Delete" );
1427 hotkey
<< wxT("Up" );
1430 hotkey
<< wxT("Down" );
1434 hotkey
<< wxT("Prior" );
1438 hotkey
<< wxT("Next" );
1441 hotkey
<< wxT("Left" );
1444 hotkey
<< wxT("Right" );
1447 hotkey
<< wxT("Home" );
1450 hotkey
<< wxT("End" );
1453 hotkey
<< wxT("Return" );
1456 // if there are any other keys wxGetAccelFromString() may
1457 // return, we should process them here
1462 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1470 wxFAIL_MSG( wxT("unknown keyboard accel") );
1479 #endif // wxUSE_ACCEL
1482 //-----------------------------------------------------------------------------
1483 // substitute for missing GtkPixmapMenuItem
1484 //-----------------------------------------------------------------------------
1489 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1490 * All rights reserved.
1492 * This file is part of the Gnome Library.
1494 * The Gnome Library is free software; you can redistribute it and/or
1495 * modify it under the terms of the GNU Library General Public License as
1496 * published by the Free Software Foundation; either version 2 of the
1497 * License, or (at your option) any later version.
1499 * The Gnome Library is distributed in the hope that it will be useful,
1500 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1501 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1502 * Library General Public License for more details.
1504 * You should have received a copy of the GNU Library General Public
1505 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1506 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1507 * Boston, MA 02111-1307, USA.
1513 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1515 #include <gtk/gtkaccellabel.h>
1516 #include <gtk/gtksignal.h>
1517 #include <gtk/gtkmenuitem.h>
1518 #include <gtk/gtkmenu.h>
1519 #include <gtk/gtkcontainer.h>
1524 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1525 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1526 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1527 GdkRectangle
*area
);
1528 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1529 GdkEventExpose
*event
);
1531 /* we must override the following functions */
1533 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1534 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1535 GtkAllocation
*allocation
);
1536 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1537 gboolean include_internals
,
1538 GtkCallback callback
,
1539 gpointer callback_data
);
1540 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1541 GtkRequisition
*requisition
);
1542 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1545 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1547 static GtkMenuItemClass
*parent_class
= NULL
;
1551 #define BORDER_SPACING 3
1552 #define PMAP_WIDTH 20
1555 gtk_pixmap_menu_item_get_type (void)
1557 static GtkType pixmap_menu_item_type
= 0;
1559 if (!pixmap_menu_item_type
)
1561 GtkTypeInfo pixmap_menu_item_info
=
1563 (char *)"GtkPixmapMenuItem",
1564 sizeof (GtkPixmapMenuItem
),
1565 sizeof (GtkPixmapMenuItemClass
),
1566 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1567 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1568 /* reserved_1 */ NULL
,
1569 /* reserved_2 */ NULL
,
1570 (GtkClassInitFunc
) NULL
,
1573 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1574 &pixmap_menu_item_info
);
1577 return pixmap_menu_item_type
;
1581 * gtk_pixmap_menu_item_new
1583 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1584 * to set the pixmap wich is displayed at the left side.
1587 * &GtkWidget pointer to new menu item
1591 gtk_pixmap_menu_item_new (void)
1593 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1597 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1599 GtkObjectClass
*object_class
;
1600 GtkWidgetClass
*widget_class
;
1601 GtkMenuItemClass
*menu_item_class
;
1602 GtkContainerClass
*container_class
;
1604 object_class
= (GtkObjectClass
*) klass
;
1605 widget_class
= (GtkWidgetClass
*) klass
;
1606 menu_item_class
= (GtkMenuItemClass
*) klass
;
1607 container_class
= (GtkContainerClass
*) klass
;
1609 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1611 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1612 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1613 widget_class
->map
= gtk_pixmap_menu_item_map
;
1614 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1615 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1617 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1618 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1620 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1621 klass
->have_pixmap_count
= 0;
1625 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1629 mi
= GTK_MENU_ITEM (menu_item
);
1631 menu_item
->pixmap
= NULL
;
1635 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1638 g_return_if_fail (widget
!= NULL
);
1639 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1640 g_return_if_fail (area
!= NULL
);
1642 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1643 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1645 if (GTK_WIDGET_DRAWABLE (widget
) &&
1646 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1647 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1652 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1653 GdkEventExpose
*event
)
1655 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1656 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1657 g_return_val_if_fail (event
!= NULL
, FALSE
);
1659 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1660 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1662 if (GTK_WIDGET_DRAWABLE (widget
) &&
1663 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1664 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1671 * gtk_pixmap_menu_item_set_pixmap
1672 * @menu_item: Pointer to the pixmap menu item
1673 * @pixmap: Pointer to a pixmap widget
1675 * Set the pixmap of the menu item.
1680 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1683 g_return_if_fail (menu_item
!= NULL
);
1684 g_return_if_fail (pixmap
!= NULL
);
1685 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1686 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1687 g_return_if_fail (menu_item
->pixmap
== NULL
);
1689 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1690 menu_item
->pixmap
= pixmap
;
1692 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1693 !GTK_WIDGET_REALIZED (pixmap
))
1694 gtk_widget_realize (pixmap
);
1696 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1697 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1698 GTK_WIDGET_VISIBLE(pixmap
) &&
1699 !GTK_WIDGET_MAPPED (pixmap
))
1700 gtk_widget_map (pixmap
);
1703 changed_have_pixmap_status(menu_item
);
1705 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1706 gtk_widget_queue_resize (pixmap
);
1710 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1712 GtkPixmapMenuItem
*menu_item
;
1714 g_return_if_fail (widget
!= NULL
);
1715 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1717 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1719 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1721 if (menu_item
->pixmap
&&
1722 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1723 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1724 gtk_widget_map (menu_item
->pixmap
);
1728 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1729 GtkAllocation
*allocation
)
1731 GtkPixmapMenuItem
*pmenu_item
;
1733 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1735 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1737 GtkAllocation child_allocation
;
1740 border_width
= GTK_CONTAINER (widget
)->border_width
;
1742 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1743 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1744 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1745 child_allocation
.y
= (border_width
+ BORDER_SPACING
1746 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1747 / 2)); /* center pixmaps vertically */
1748 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1751 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1752 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1756 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1757 gboolean include_internals
,
1758 GtkCallback callback
,
1759 gpointer callback_data
)
1761 GtkPixmapMenuItem
*menu_item
;
1763 g_return_if_fail (container
!= NULL
);
1764 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1765 g_return_if_fail (callback
!= NULL
);
1767 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1769 if (menu_item
->pixmap
)
1770 (* callback
) (menu_item
->pixmap
, callback_data
);
1772 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1773 callback
,callback_data
);
1777 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1778 GtkRequisition
*requisition
)
1780 GtkPixmapMenuItem
*menu_item
;
1781 GtkRequisition req
= {0, 0};
1783 g_return_if_fail (widget
!= NULL
);
1784 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1785 g_return_if_fail (requisition
!= NULL
);
1787 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1789 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1791 if (menu_item
->pixmap
)
1792 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1794 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1795 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1799 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1803 gboolean widget_was_visible
;
1805 g_return_if_fail (container
!= NULL
);
1806 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1807 g_return_if_fail (child
!= NULL
);
1808 g_return_if_fail (GTK_IS_WIDGET (child
));
1810 bin
= GTK_BIN (container
);
1811 g_return_if_fail ((bin
->child
== child
||
1812 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1814 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1816 gtk_widget_unparent (child
);
1817 if (bin
->child
== child
)
1820 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1821 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1824 if (widget_was_visible
)
1825 gtk_widget_queue_resize (GTK_WIDGET (container
));
1829 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1831 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1833 if (menu_item
->pixmap
!= NULL
) {
1834 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1836 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1837 /* Install pixmap toggle size */
1838 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1841 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1843 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1844 /* Install normal toggle size */
1845 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1849 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1850 whenever the klass->toggle_size changes; but by doing it anytime
1851 this function is called, we get the same effect, just because of
1852 how the preferences option to show pixmaps works. Bogus, broken.
1854 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1855 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));