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 //-----------------------------------------------------------------------------
51 //-----------------------------------------------------------------------------
53 extern void wxapp_install_idle_handler();
57 static wxString
GetHotKey( const wxMenuItem
& item
);
60 //-----------------------------------------------------------------------------
61 // substitute for missing GtkPixmapMenuItem
62 //-----------------------------------------------------------------------------
66 #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ())
67 #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem))
68 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass))
69 #define GTK_IS_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
70 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM))
71 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
72 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
74 #ifndef GTK_MENU_ITEM_GET_CLASS
75 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
78 typedef struct _GtkPixmapMenuItem GtkPixmapMenuItem
;
79 typedef struct _GtkPixmapMenuItemClass GtkPixmapMenuItemClass
;
81 struct _GtkPixmapMenuItem
83 GtkMenuItem menu_item
;
88 struct _GtkPixmapMenuItemClass
90 GtkMenuItemClass parent_class
;
92 guint orig_toggle_size
;
93 guint have_pixmap_count
;
97 GtkType
gtk_pixmap_menu_item_get_type (void);
98 GtkWidget
* gtk_pixmap_menu_item_new (void);
99 void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
103 //-----------------------------------------------------------------------------
105 //-----------------------------------------------------------------------------
107 static wxString
wxReplaceUnderscore( const wxString
& title
)
111 // GTK 1.2 wants to have "_" instead of "&" for accelerators
114 while (*pc
!= wxT('\0'))
116 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
118 // "&" is doubled to indicate "&" instead of accelerator
122 else if (*pc
== wxT('&'))
128 if ( *pc
== wxT('_') )
130 // underscores must be doubled to prevent them from being
131 // interpreted as accelerator character prefix by GTK
140 // wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() );
145 //-----------------------------------------------------------------------------
146 // activate message from GTK
147 //-----------------------------------------------------------------------------
149 static void gtk_menu_open_callback( GtkWidget
*widget
, wxMenu
*menu
)
151 if (g_isIdle
) wxapp_install_idle_handler();
153 wxMenuEvent
event( wxEVT_MENU_OPEN
, -1, menu
);
154 event
.SetEventObject( menu
);
156 wxEvtHandler
* handler
= menu
->GetEventHandler();
157 if (handler
&& handler
->ProcessEvent(event
))
160 wxWindow
*win
= menu
->GetInvokingWindow();
161 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
164 //-----------------------------------------------------------------------------
166 //-----------------------------------------------------------------------------
168 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
170 wxMenuBar::wxMenuBar( long style
)
172 // the parent window is known after wxFrame::SetMenu()
173 m_needParent
= FALSE
;
175 m_invokingWindow
= (wxWindow
*) NULL
;
177 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
178 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
180 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
184 m_menubar
= gtk_menu_bar_new();
186 m_accel
= gtk_accel_group_new();
189 if (style
& wxMB_DOCKABLE
)
191 m_widget
= gtk_handle_box_new();
192 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
193 gtk_widget_show( GTK_WIDGET(m_menubar
) );
197 m_widget
= GTK_WIDGET(m_menubar
);
205 wxMenuBar::wxMenuBar()
207 // the parent window is known after wxFrame::SetMenu()
208 m_needParent
= FALSE
;
210 m_invokingWindow
= (wxWindow
*) NULL
;
212 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
213 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
215 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
219 m_menubar
= gtk_menu_bar_new();
221 m_accel
= gtk_accel_group_new();
224 m_widget
= GTK_WIDGET(m_menubar
);
231 wxMenuBar::~wxMenuBar()
235 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
237 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
239 wxWindow
*top_frame
= win
;
240 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
241 top_frame
= top_frame
->GetParent();
244 // support for native hot keys
245 gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
248 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
251 wxMenuItem
*menuitem
= node
->GetData();
252 if (menuitem
->IsSubMenu())
253 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
254 node
= node
->GetNext();
258 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
260 menu
->SetInvokingWindow( win
);
262 wxWindow
*top_frame
= win
;
263 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
264 top_frame
= top_frame
->GetParent();
266 // support for native hot keys
267 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
268 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
269 gtk_accel_group_attach( menu
->m_accel
, obj
);
271 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
274 wxMenuItem
*menuitem
= node
->GetData();
275 if (menuitem
->IsSubMenu())
276 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
277 node
= node
->GetNext();
281 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
283 m_invokingWindow
= win
;
284 wxWindow
*top_frame
= win
;
285 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
286 top_frame
= top_frame
->GetParent();
289 // support for native key accelerators indicated by underscroes
290 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
291 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
292 gtk_accel_group_attach( m_accel
, obj
);
295 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
298 wxMenu
*menu
= node
->GetData();
299 wxMenubarSetInvokingWindow( menu
, win
);
300 node
= node
->GetNext();
304 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
306 m_invokingWindow
= (wxWindow
*) NULL
;
307 wxWindow
*top_frame
= win
;
308 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
309 top_frame
= top_frame
->GetParent();
312 // support for native key accelerators indicated by underscroes
313 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
316 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
319 wxMenu
*menu
= node
->GetData();
320 wxMenubarUnsetInvokingWindow( menu
, win
);
321 node
= node
->GetNext();
325 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
327 if ( !wxMenuBarBase::Append( menu
, title
) )
330 return GtkAppend(menu
, title
);
333 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
)
335 wxString
str( wxReplaceUnderscore( title
) );
337 // This doesn't have much effect right now.
338 menu
->SetTitle( str
);
340 // The "m_owner" is the "menu item"
342 menu
->m_owner
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str
) );
344 menu
->m_owner
= gtk_menu_item_new_with_label( wxGTK_CONV( str
) );
345 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
347 gtk_label_set_text( label
, wxGTK_CONV( str
) );
349 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
350 if (accel_key
!= GDK_VoidSymbol
)
352 gtk_widget_add_accelerator (menu
->m_owner
,
354 m_accel
,//gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)),
361 gtk_widget_show( menu
->m_owner
);
363 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
365 gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
);
367 gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate",
368 GTK_SIGNAL_FUNC(gtk_menu_open_callback
),
371 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
372 // addings menu later on.
373 if (m_invokingWindow
)
375 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
377 // OPTIMISE ME: we should probably cache this, or pass it
378 // directly, but for now this is a minimal
379 // change to validate the new dynamic sizing.
380 // see (and refactor :) similar code in Remove
383 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
386 frame
->UpdateMenuBarSize();
392 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
394 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
399 if ( !GtkAppend(menu
, title
) )
405 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
407 // remove the old item and insert a new one
408 wxMenu
*menuOld
= Remove(pos
);
409 if ( menuOld
&& !Insert(pos
, menu
, title
) )
411 return (wxMenu
*) NULL
;
414 // either Insert() succeeded or Remove() failed and menuOld is NULL
418 static wxMenu
*CopyMenu (wxMenu
*menu
)
420 wxMenu
*menucopy
= new wxMenu ();
421 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
424 wxMenuItem
*item
= node
->GetData();
425 int itemid
= item
->GetId();
426 wxString text
= item
->GetText();
427 text
.Replace(wxT("_"), wxT("&"));
428 wxMenu
*submenu
= item
->GetSubMenu();
431 wxMenuItem
* itemcopy
= new wxMenuItem(menucopy
,
433 menu
->GetHelpString(itemid
));
434 itemcopy
->SetBitmap(item
->GetBitmap());
435 itemcopy
->SetCheckable(item
->IsCheckable());
436 menucopy
->Append(itemcopy
);
439 menucopy
->Append (itemid
, text
, CopyMenu(submenu
),
440 menu
->GetHelpString(itemid
));
442 node
= node
->GetNext();
448 wxMenu
*wxMenuBar::Remove(size_t pos
)
450 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
452 return (wxMenu
*) NULL
;
454 wxMenu
*menucopy
= CopyMenu( menu
);
456 // unparent calls unref() and that would delete the widget so we raise
457 // the ref count to 2 artificially before invoking unparent.
458 gtk_widget_ref( menu
->m_menu
);
459 gtk_widget_unparent( menu
->m_menu
);
461 gtk_widget_destroy( menu
->m_owner
);
466 if (m_invokingWindow
)
468 // OPTIMISE ME: see comment in GtkAppend
469 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
472 frame
->UpdateMenuBarSize();
478 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
480 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
482 int res
= menu
->FindItem( itemString
);
483 if (res
!= wxNOT_FOUND
)
487 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
490 wxMenuItem
*item
= node
->GetData();
491 if (item
->IsSubMenu())
492 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
494 node
= node
->GetNext();
500 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
502 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
505 wxMenu
*menu
= node
->GetData();
506 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
509 node
= node
->GetNext();
515 // Find a wxMenuItem using its id. Recurses down into sub-menus
516 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
518 wxMenuItem
* result
= menu
->FindChildItem(id
);
520 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
521 while ( node
&& result
== NULL
)
523 wxMenuItem
*item
= node
->GetData();
524 if (item
->IsSubMenu())
526 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
528 node
= node
->GetNext();
534 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
536 wxMenuItem
* result
= 0;
537 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
538 while (node
&& result
== 0)
540 wxMenu
*menu
= node
->GetData();
541 result
= FindMenuItemByIdRecursive( menu
, id
);
542 node
= node
->GetNext();
547 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
553 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
555 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
557 wxCHECK_RET( node
, wxT("menu not found") );
559 wxMenu
* menu
= node
->GetData();
562 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
565 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
567 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
569 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
571 wxMenu
* menu
= node
->GetData();
574 wxString
text( menu
->GetTitle() );
575 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
577 if ( *pc
== wxT('_') )
579 // '_' is the escape character for GTK+
583 // don't remove ampersands '&' since if we have them in the menu title
584 // it means that they were doubled to indicate "&" instead of accelerator
592 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
594 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
596 wxCHECK_RET( node
, wxT("menu not found") );
598 wxMenu
* menu
= node
->GetData();
600 wxString
str( wxReplaceUnderscore( label
) );
602 menu
->SetTitle( str
);
606 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
609 gtk_label_set( label
, wxGTK_CONV( str
) );
611 /* reparse key accel */
612 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
613 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
618 //-----------------------------------------------------------------------------
620 //-----------------------------------------------------------------------------
622 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
625 wxapp_install_idle_handler();
627 int id
= menu
->FindMenuIdByMenuItem(widget
);
629 /* should find it for normal (not popup) menu */
630 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
631 _T("menu item not found in gtk_menu_clicked_callback") );
633 if (!menu
->IsEnabled(id
))
636 wxMenuItem
* item
= menu
->FindChildItem( id
);
637 wxCHECK_RET( item
, wxT("error in menu item callback") );
639 if (item
->IsCheckable())
641 bool isReallyChecked
= item
->IsChecked(),
642 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
644 // ensure that the internal state is always consistent with what is
645 // shown on the screen
646 item
->wxMenuItemBase::Check(isReallyChecked
);
648 // we must not report the events for the radio button going up nor the
649 // events resulting from the calls to wxMenuItem::Check()
650 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
651 (isInternallyChecked
== isReallyChecked
) )
658 // Is this menu on a menubar? (possibly nested)
659 wxFrame
* frame
= NULL
;
661 while ( pm
&& !frame
)
663 if ( pm
->IsAttached() )
664 frame
= pm
->GetMenuBar()->GetFrame();
665 pm
= pm
->GetParent();
668 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
669 // normally wxMenu::SendEvent() should be enough, if it doesn't work
670 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
671 // should be fixed instead of working around it here...
674 // If it is attached then let the frame send the event.
675 // Don't call frame->ProcessCommand(id) because it toggles
676 // checkable items and we've already done that above.
677 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
678 commandEvent
.SetEventObject(frame
);
679 if (item
->IsCheckable())
680 commandEvent
.SetInt(item
->IsChecked());
681 commandEvent
.SetEventObject(menu
);
683 frame
->GetEventHandler()->ProcessEvent(commandEvent
);
687 // otherwise let the menu have it
688 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
692 //-----------------------------------------------------------------------------
694 //-----------------------------------------------------------------------------
696 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
698 if (g_isIdle
) wxapp_install_idle_handler();
700 int id
= menu
->FindMenuIdByMenuItem(widget
);
702 wxASSERT( id
!= -1 ); // should find it!
704 if (!menu
->IsEnabled(id
))
707 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
708 event
.SetEventObject( menu
);
710 wxEvtHandler
* handler
= menu
->GetEventHandler();
711 if (handler
&& handler
->ProcessEvent(event
))
714 wxWindow
*win
= menu
->GetInvokingWindow();
715 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
718 //-----------------------------------------------------------------------------
720 //-----------------------------------------------------------------------------
722 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
724 if (g_isIdle
) wxapp_install_idle_handler();
726 int id
= menu
->FindMenuIdByMenuItem(widget
);
728 wxASSERT( id
!= -1 ); // should find it!
730 if (!menu
->IsEnabled(id
))
733 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
734 event
.SetEventObject( menu
);
736 wxEvtHandler
* handler
= menu
->GetEventHandler();
737 if (handler
&& handler
->ProcessEvent(event
))
740 wxWindow
*win
= menu
->GetInvokingWindow();
742 win
->GetEventHandler()->ProcessEvent( event
);
745 //-----------------------------------------------------------------------------
747 //-----------------------------------------------------------------------------
749 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
751 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
753 const wxString
& name
,
754 const wxString
& help
,
758 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
761 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
763 const wxString
& text
,
764 const wxString
& help
,
767 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
772 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
774 const wxString
& text
,
775 const wxString
& help
,
778 : wxMenuItemBase(parentMenu
, id
, text
, help
,
779 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
784 void wxMenuItem::Init(const wxString
& text
)
786 m_labelWidget
= (GtkWidget
*) NULL
;
787 m_menuItem
= (GtkWidget
*) NULL
;
792 wxMenuItem::~wxMenuItem()
794 // don't delete menu items, the menus take care of that
797 // return the menu item text without any menu accels
799 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
803 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
805 if ( *pc
== wxT('_') )
807 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
814 if ( *pc
== wxT('\\') )
816 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
823 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
826 // "&" is doubled to indicate "&" instead of accelerator
833 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
838 void wxMenuItem::SetText( const wxString
& str
)
840 // Some optimization to avoid flicker
841 wxString oldLabel
= m_text
;
842 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
843 oldLabel
.Replace(wxT("_"), wxT(""));
844 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
845 if (oldLabel
== label1
)
854 label
= (GtkLabel
*) m_labelWidget
;
856 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
859 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
862 gtk_label_set( label
, wxGTK_CONV( m_text
) );
865 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
866 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
871 // it's valid for this function to be called even if m_menuItem == NULL
872 void wxMenuItem::DoSetText( const wxString
& str
)
874 // '\t' is the deliminator indicating a hot key
876 const wxChar
*pc
= str
;
877 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
879 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
881 // "&" is doubled to indicate "&" instead of accelerator
885 else if (*pc
== wxT('&'))
889 else if ( *pc
== wxT('_') ) // escape underscores
900 // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() );
913 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
918 return (wxAcceleratorEntry
*)NULL
;
921 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
923 label
<< wxT('\t') << GetHotKey();
925 return wxGetAccelFromString(label
);
928 #endif // wxUSE_ACCEL
930 void wxMenuItem::Check( bool check
)
932 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
934 if (check
== m_isChecked
)
937 wxMenuItemBase::Check( check
);
943 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
947 wxFAIL_MSG( _T("can't check this item") );
951 void wxMenuItem::Enable( bool enable
)
953 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
955 gtk_widget_set_sensitive( m_menuItem
, enable
);
956 wxMenuItemBase::Enable( enable
);
959 bool wxMenuItem::IsChecked() const
961 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
963 wxCHECK_MSG( IsCheckable(), FALSE
,
964 wxT("can't get state of uncheckable item!") );
966 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
969 //-----------------------------------------------------------------------------
971 //-----------------------------------------------------------------------------
973 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
977 m_accel
= gtk_accel_group_new();
978 m_menu
= gtk_menu_new();
980 m_owner
= (GtkWidget
*) NULL
;
982 // Tearoffs are entries, just like separators. So if we want this
983 // menu to be a tear-off one, we just append a tearoff entry
985 if(m_style
& wxMENU_TEAROFF
)
987 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
989 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
994 // append the title as the very first entry if we have it
1004 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1006 if ( GTK_IS_WIDGET( m_menu
))
1007 gtk_widget_destroy( m_menu
);
1010 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
1012 GtkWidget
*menuItem
;
1014 if ( mitem
->IsSeparator() )
1017 menuItem
= gtk_separator_menu_item_new();
1020 menuItem
= gtk_menu_item_new();
1022 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1025 else if ( mitem
->IsSubMenu() )
1027 // text has "_" instead of "&" after mitem->SetText()
1028 wxString
text( mitem
->GetText() );
1031 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1033 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1034 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1036 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1037 // reparse key accel
1038 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1039 if (accel_key
!= GDK_VoidSymbol
)
1041 gtk_widget_add_accelerator (menuItem
,
1043 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1050 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1051 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1053 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1055 // if adding a submenu to a menu already existing in the menu bar, we
1056 // must set invoking window to allow processing events from this
1058 if ( m_invokingWindow
)
1059 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1063 else if (mitem
->GetBitmap().Ok())
1065 wxString text
= mitem
->GetText();
1066 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1067 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1068 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1071 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1073 GtkWidget
*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
),
1082 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1085 menuItem
= gtk_pixmap_menu_item_new ();
1086 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1087 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1088 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1090 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1092 GdkModifierType accel_mods
;
1094 // accelerator for the item, as specified by its label
1095 // (ex. Ctrl+O for open)
1096 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1098 if (accel_key
!= GDK_VoidSymbol
)
1100 gtk_widget_add_accelerator (menuItem
,
1103 accel_key
, accel_mods
,
1107 // accelerator for the underlined char (ex ALT+F for the File menu)
1108 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1109 if (accel_key
!= GDK_VoidSymbol
)
1111 gtk_widget_add_accelerator (menuItem
,
1113 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1119 gtk_widget_show (label
);
1121 mitem
->SetLabelWidget(label
);
1123 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1124 gtk_widget_show(pixmap
);
1125 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1127 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1128 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1131 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
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
),
1256 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1260 GdkModifierType accel_mods
;
1261 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1263 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1265 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1268 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1276 gtk_widget_show( menuItem
);
1278 if ( !mitem
->IsSeparator() )
1280 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1282 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1283 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1286 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1287 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1291 mitem
->SetMenuItem(menuItem
);
1295 // This doesn't even exist!
1296 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1302 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1304 if (!GtkAppend(mitem
))
1307 return wxMenuBase::DoAppend(mitem
);
1310 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1312 if ( !wxMenuBase::DoInsert(pos
, item
) )
1316 if ( !GtkAppend(item
) )
1322 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1324 if ( !wxMenuBase::DoRemove(item
) )
1325 return (wxMenuItem
*)NULL
;
1327 // TODO: this code doesn't delete the item factory item and this seems
1328 // impossible as of GTK 1.2.6.
1329 gtk_widget_destroy( item
->GetMenuItem() );
1334 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1336 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1339 wxMenuItem
*item
= node
->GetData();
1340 if (item
->GetMenuItem() == menuItem
)
1341 return item
->GetId();
1342 node
= node
->GetNext();
1348 // ----------------------------------------------------------------------------
1350 // ----------------------------------------------------------------------------
1354 static wxString
GetHotKey( const wxMenuItem
& item
)
1358 wxAcceleratorEntry
*accel
= item
.GetAccel();
1361 int flags
= accel
->GetFlags();
1362 if ( flags
& wxACCEL_ALT
)
1363 hotkey
+= wxT("<alt>");
1364 if ( flags
& wxACCEL_CTRL
)
1365 hotkey
+= wxT("<control>");
1366 if ( flags
& wxACCEL_SHIFT
)
1367 hotkey
+= wxT("<shift>");
1369 int code
= accel
->GetKeyCode();
1384 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1387 // TODO: we should use gdk_keyval_name() (a.k.a.
1388 // XKeysymToString) here as well as hardcoding the keysym
1389 // names this might be not portable
1390 case WXK_NUMPAD_INSERT
:
1391 hotkey
<< wxT("KP_Insert" );
1393 case WXK_NUMPAD_DELETE
:
1394 hotkey
<< wxT("KP_Delete" );
1397 hotkey
<< wxT("Insert" );
1400 hotkey
<< wxT("Delete" );
1403 hotkey
<< wxT("Up" );
1406 hotkey
<< wxT("Down" );
1410 hotkey
<< wxT("Prior" );
1414 hotkey
<< wxT("Next" );
1417 hotkey
<< wxT("Left" );
1420 hotkey
<< wxT("Right" );
1423 hotkey
<< wxT("Home" );
1426 hotkey
<< wxT("End" );
1429 hotkey
<< wxT("Return" );
1432 // if there are any other keys wxGetAccelFromString() may
1433 // return, we should process them here
1438 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1446 wxFAIL_MSG( wxT("unknown keyboard accel") );
1455 #endif // wxUSE_ACCEL
1458 //-----------------------------------------------------------------------------
1459 // substitute for missing GtkPixmapMenuItem
1460 //-----------------------------------------------------------------------------
1465 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1466 * All rights reserved.
1468 * This file is part of the Gnome Library.
1470 * The Gnome Library is free software; you can redistribute it and/or
1471 * modify it under the terms of the GNU Library General Public License as
1472 * published by the Free Software Foundation; either version 2 of the
1473 * License, or (at your option) any later version.
1475 * The Gnome Library is distributed in the hope that it will be useful,
1476 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1477 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1478 * Library General Public License for more details.
1480 * You should have received a copy of the GNU Library General Public
1481 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1482 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1483 * Boston, MA 02111-1307, USA.
1489 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1491 #include <gtk/gtkaccellabel.h>
1492 #include <gtk/gtksignal.h>
1493 #include <gtk/gtkmenuitem.h>
1494 #include <gtk/gtkmenu.h>
1495 #include <gtk/gtkcontainer.h>
1500 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1501 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1502 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1503 GdkRectangle
*area
);
1504 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1505 GdkEventExpose
*event
);
1507 /* we must override the following functions */
1509 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1510 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1511 GtkAllocation
*allocation
);
1512 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1513 gboolean include_internals
,
1514 GtkCallback callback
,
1515 gpointer callback_data
);
1516 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1517 GtkRequisition
*requisition
);
1518 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1521 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1523 static GtkMenuItemClass
*parent_class
= NULL
;
1527 #define BORDER_SPACING 3
1528 #define PMAP_WIDTH 20
1531 gtk_pixmap_menu_item_get_type (void)
1533 static GtkType pixmap_menu_item_type
= 0;
1535 if (!pixmap_menu_item_type
)
1537 GtkTypeInfo pixmap_menu_item_info
=
1539 (char *)"GtkPixmapMenuItem",
1540 sizeof (GtkPixmapMenuItem
),
1541 sizeof (GtkPixmapMenuItemClass
),
1542 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1543 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1544 /* reserved_1 */ NULL
,
1545 /* reserved_2 */ NULL
,
1546 (GtkClassInitFunc
) NULL
,
1549 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1550 &pixmap_menu_item_info
);
1553 return pixmap_menu_item_type
;
1557 * gtk_pixmap_menu_item_new
1559 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1560 * to set the pixmap wich is displayed at the left side.
1563 * &GtkWidget pointer to new menu item
1567 gtk_pixmap_menu_item_new (void)
1569 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1573 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1575 GtkObjectClass
*object_class
;
1576 GtkWidgetClass
*widget_class
;
1577 GtkMenuItemClass
*menu_item_class
;
1578 GtkContainerClass
*container_class
;
1580 object_class
= (GtkObjectClass
*) klass
;
1581 widget_class
= (GtkWidgetClass
*) klass
;
1582 menu_item_class
= (GtkMenuItemClass
*) klass
;
1583 container_class
= (GtkContainerClass
*) klass
;
1585 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1587 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1588 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1589 widget_class
->map
= gtk_pixmap_menu_item_map
;
1590 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1591 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1593 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1594 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1596 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1597 klass
->have_pixmap_count
= 0;
1601 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1605 mi
= GTK_MENU_ITEM (menu_item
);
1607 menu_item
->pixmap
= NULL
;
1611 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1614 g_return_if_fail (widget
!= NULL
);
1615 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1616 g_return_if_fail (area
!= NULL
);
1618 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1619 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1621 if (GTK_WIDGET_DRAWABLE (widget
) &&
1622 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1623 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1628 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1629 GdkEventExpose
*event
)
1631 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1632 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1633 g_return_val_if_fail (event
!= NULL
, FALSE
);
1635 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1636 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1638 if (GTK_WIDGET_DRAWABLE (widget
) &&
1639 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1640 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1647 * gtk_pixmap_menu_item_set_pixmap
1648 * @menu_item: Pointer to the pixmap menu item
1649 * @pixmap: Pointer to a pixmap widget
1651 * Set the pixmap of the menu item.
1656 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1659 g_return_if_fail (menu_item
!= NULL
);
1660 g_return_if_fail (pixmap
!= NULL
);
1661 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1662 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1663 g_return_if_fail (menu_item
->pixmap
== NULL
);
1665 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1666 menu_item
->pixmap
= pixmap
;
1668 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1669 !GTK_WIDGET_REALIZED (pixmap
))
1670 gtk_widget_realize (pixmap
);
1672 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1673 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1674 GTK_WIDGET_VISIBLE(pixmap
) &&
1675 !GTK_WIDGET_MAPPED (pixmap
))
1676 gtk_widget_map (pixmap
);
1679 changed_have_pixmap_status(menu_item
);
1681 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1682 gtk_widget_queue_resize (pixmap
);
1686 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1688 GtkPixmapMenuItem
*menu_item
;
1690 g_return_if_fail (widget
!= NULL
);
1691 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1693 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1695 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1697 if (menu_item
->pixmap
&&
1698 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1699 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1700 gtk_widget_map (menu_item
->pixmap
);
1704 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1705 GtkAllocation
*allocation
)
1707 GtkPixmapMenuItem
*pmenu_item
;
1709 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1711 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1713 GtkAllocation child_allocation
;
1716 border_width
= GTK_CONTAINER (widget
)->border_width
;
1718 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1719 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1720 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1721 child_allocation
.y
= (border_width
+ BORDER_SPACING
1722 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1723 / 2)); /* center pixmaps vertically */
1724 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1727 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1728 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1732 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1733 gboolean include_internals
,
1734 GtkCallback callback
,
1735 gpointer callback_data
)
1737 GtkPixmapMenuItem
*menu_item
;
1739 g_return_if_fail (container
!= NULL
);
1740 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1741 g_return_if_fail (callback
!= NULL
);
1743 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1745 if (menu_item
->pixmap
)
1746 (* callback
) (menu_item
->pixmap
, callback_data
);
1748 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1749 callback
,callback_data
);
1753 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1754 GtkRequisition
*requisition
)
1756 GtkPixmapMenuItem
*menu_item
;
1757 GtkRequisition req
= {0, 0};
1759 g_return_if_fail (widget
!= NULL
);
1760 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1761 g_return_if_fail (requisition
!= NULL
);
1763 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1765 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1767 if (menu_item
->pixmap
)
1768 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1770 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1771 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1775 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1779 gboolean widget_was_visible
;
1781 g_return_if_fail (container
!= NULL
);
1782 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1783 g_return_if_fail (child
!= NULL
);
1784 g_return_if_fail (GTK_IS_WIDGET (child
));
1786 bin
= GTK_BIN (container
);
1787 g_return_if_fail ((bin
->child
== child
||
1788 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1790 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1792 gtk_widget_unparent (child
);
1793 if (bin
->child
== child
)
1796 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1797 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1800 if (widget_was_visible
)
1801 gtk_widget_queue_resize (GTK_WIDGET (container
));
1805 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1807 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1809 if (menu_item
->pixmap
!= NULL
) {
1810 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1812 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1813 /* Install pixmap toggle size */
1814 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1817 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1819 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1820 /* Install normal toggle size */
1821 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1825 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1826 whenever the klass->toggle_size changes; but by doing it anytime
1827 this function is called, we get the same effect, just because of
1828 how the preferences option to show pixmaps works. Bogus, broken.
1830 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1831 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));