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
;
660 if(menu
->IsAttached())
661 frame
= menu
->GetMenuBar()->GetFrame();
663 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
664 // normally wxMenu::SendEvent() should be enough, if it doesn't work
665 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
666 // should be fixed instead of working around it here...
669 // If it is attached then let the frame send the event.
670 // Don't call frame->ProcessCommand(id) because it toggles
671 // checkable items and we've already done that above.
672 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
673 commandEvent
.SetEventObject(frame
);
674 if (item
->IsCheckable())
675 commandEvent
.SetInt(item
->IsChecked());
676 commandEvent
.SetEventObject(menu
);
678 frame
->GetEventHandler()->ProcessEvent(commandEvent
);
682 // otherwise let the menu have it
683 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
687 //-----------------------------------------------------------------------------
689 //-----------------------------------------------------------------------------
691 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
693 if (g_isIdle
) wxapp_install_idle_handler();
695 int id
= menu
->FindMenuIdByMenuItem(widget
);
697 wxASSERT( id
!= -1 ); // should find it!
699 if (!menu
->IsEnabled(id
))
702 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
703 event
.SetEventObject( menu
);
705 wxEvtHandler
* handler
= menu
->GetEventHandler();
706 if (handler
&& handler
->ProcessEvent(event
))
709 wxWindow
*win
= menu
->GetInvokingWindow();
710 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
713 //-----------------------------------------------------------------------------
715 //-----------------------------------------------------------------------------
717 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
719 if (g_isIdle
) wxapp_install_idle_handler();
721 int id
= menu
->FindMenuIdByMenuItem(widget
);
723 wxASSERT( id
!= -1 ); // should find it!
725 if (!menu
->IsEnabled(id
))
728 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
729 event
.SetEventObject( menu
);
731 wxEvtHandler
* handler
= menu
->GetEventHandler();
732 if (handler
&& handler
->ProcessEvent(event
))
735 wxWindow
*win
= menu
->GetInvokingWindow();
737 win
->GetEventHandler()->ProcessEvent( event
);
740 //-----------------------------------------------------------------------------
742 //-----------------------------------------------------------------------------
744 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
746 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
748 const wxString
& name
,
749 const wxString
& help
,
753 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
756 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
758 const wxString
& text
,
759 const wxString
& help
,
762 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
767 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
769 const wxString
& text
,
770 const wxString
& help
,
773 : wxMenuItemBase(parentMenu
, id
, text
, help
,
774 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
779 void wxMenuItem::Init(const wxString
& text
)
781 m_labelWidget
= (GtkWidget
*) NULL
;
782 m_menuItem
= (GtkWidget
*) NULL
;
787 wxMenuItem::~wxMenuItem()
789 // don't delete menu items, the menus take care of that
792 // return the menu item text without any menu accels
794 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
798 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
800 if ( *pc
== wxT('_') )
802 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
809 if ( *pc
== wxT('\\') )
811 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
818 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
821 // "&" is doubled to indicate "&" instead of accelerator
828 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
833 void wxMenuItem::SetText( const wxString
& str
)
835 // Some optimization to avoid flicker
836 wxString oldLabel
= m_text
;
837 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
838 oldLabel
.Replace(wxT("_"), wxT(""));
839 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
840 if (oldLabel
== label1
)
849 label
= (GtkLabel
*) m_labelWidget
;
851 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
854 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
857 gtk_label_set( label
, wxGTK_CONV( m_text
) );
860 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
861 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
866 // it's valid for this function to be called even if m_menuItem == NULL
867 void wxMenuItem::DoSetText( const wxString
& str
)
869 // '\t' is the deliminator indicating a hot key
871 const wxChar
*pc
= str
;
872 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
874 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
876 // "&" is doubled to indicate "&" instead of accelerator
880 else if (*pc
== wxT('&'))
884 else if ( *pc
== wxT('_') ) // escape underscores
895 // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() );
908 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
913 return (wxAcceleratorEntry
*)NULL
;
916 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
918 label
<< wxT('\t') << GetHotKey();
920 return wxGetAccelFromString(label
);
923 #endif // wxUSE_ACCEL
925 void wxMenuItem::Check( bool check
)
927 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
929 if (check
== m_isChecked
)
932 wxMenuItemBase::Check( check
);
938 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
942 wxFAIL_MSG( _T("can't check this item") );
946 void wxMenuItem::Enable( bool enable
)
948 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
950 gtk_widget_set_sensitive( m_menuItem
, enable
);
951 wxMenuItemBase::Enable( enable
);
954 bool wxMenuItem::IsChecked() const
956 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
958 wxCHECK_MSG( IsCheckable(), FALSE
,
959 wxT("can't get state of uncheckable item!") );
961 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
964 //-----------------------------------------------------------------------------
966 //-----------------------------------------------------------------------------
968 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
972 m_accel
= gtk_accel_group_new();
973 m_menu
= gtk_menu_new();
975 m_owner
= (GtkWidget
*) NULL
;
977 // Tearoffs are entries, just like separators. So if we want this
978 // menu to be a tear-off one, we just append a tearoff entry
980 if(m_style
& wxMENU_TEAROFF
)
982 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
984 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
989 // append the title as the very first entry if we have it
999 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1001 if ( GTK_IS_WIDGET( m_menu
))
1002 gtk_widget_destroy( m_menu
);
1005 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
1007 GtkWidget
*menuItem
;
1009 if ( mitem
->IsSeparator() )
1012 menuItem
= gtk_separator_menu_item_new();
1015 menuItem
= gtk_menu_item_new();
1017 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1020 else if ( mitem
->IsSubMenu() )
1022 // text has "_" instead of "&" after mitem->SetText()
1023 wxString
text( mitem
->GetText() );
1026 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1028 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1029 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1031 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1032 // reparse key accel
1033 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1034 if (accel_key
!= GDK_VoidSymbol
)
1036 gtk_widget_add_accelerator (menuItem
,
1038 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1045 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1046 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1048 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1050 // if adding a submenu to a menu already existing in the menu bar, we
1051 // must set invoking window to allow processing events from this
1053 if ( m_invokingWindow
)
1054 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1058 else if (mitem
->GetBitmap().Ok())
1060 wxString text
= mitem
->GetText();
1061 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1062 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1063 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1066 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1068 GtkWidget
*image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1069 gtk_widget_show(image
);
1071 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1073 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1074 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1077 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1080 menuItem
= gtk_pixmap_menu_item_new ();
1081 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1082 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1083 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1085 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1087 GdkModifierType accel_mods
;
1089 // accelerator for the item, as specified by its label
1090 // (ex. Ctrl+O for open)
1091 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1093 if (accel_key
!= GDK_VoidSymbol
)
1095 gtk_widget_add_accelerator (menuItem
,
1098 accel_key
, accel_mods
,
1102 // accelerator for the underlined char (ex ALT+F for the File menu)
1103 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1104 if (accel_key
!= GDK_VoidSymbol
)
1106 gtk_widget_add_accelerator (menuItem
,
1108 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1114 gtk_widget_show (label
);
1116 mitem
->SetLabelWidget(label
);
1118 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1119 gtk_widget_show(pixmap
);
1120 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1122 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1123 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1126 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1127 gtk_widget_show( menuItem
);
1132 else // a normal item
1134 // text has "_" instead of "&" after mitem->SetText() so don't use it
1135 wxString
text( mitem
->GetText() );
1137 switch ( mitem
->GetKind() )
1142 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1144 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1145 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1147 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1148 // reparse key accel
1149 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1150 if (accel_key
!= GDK_VoidSymbol
)
1152 gtk_widget_add_accelerator (menuItem
,
1154 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1166 GSList
*group
= NULL
;
1167 if ( m_prevRadio
== NULL
)
1169 // start of a new radio group
1171 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1173 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1174 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1176 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1177 // reparse key accel
1178 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1179 if (accel_key
!= GDK_VoidSymbol
)
1181 gtk_widget_add_accelerator (menuItem
,
1183 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1190 else // continue the radio group
1193 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1194 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1196 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1197 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1198 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1200 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1201 // reparse key accel
1202 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1203 if (accel_key
!= GDK_VoidSymbol
)
1205 gtk_widget_add_accelerator (menuItem
,
1207 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1218 wxFAIL_MSG( _T("unexpected menu item kind") );
1224 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1226 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1227 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1229 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1230 // reparse key accel
1231 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1232 if (accel_key
!= GDK_VoidSymbol
)
1234 gtk_widget_add_accelerator (menuItem
,
1236 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1247 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1248 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1251 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1255 GdkModifierType accel_mods
;
1256 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1258 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1260 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1263 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1271 gtk_widget_show( menuItem
);
1273 if ( !mitem
->IsSeparator() )
1275 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1277 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1278 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1281 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1282 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1286 mitem
->SetMenuItem(menuItem
);
1290 // This doesn't even exist!
1291 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1297 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1299 if (!GtkAppend(mitem
))
1302 return wxMenuBase::DoAppend(mitem
);
1305 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1307 if ( !wxMenuBase::DoInsert(pos
, item
) )
1311 if ( !GtkAppend(item
) )
1317 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1319 if ( !wxMenuBase::DoRemove(item
) )
1320 return (wxMenuItem
*)NULL
;
1322 // TODO: this code doesn't delete the item factory item and this seems
1323 // impossible as of GTK 1.2.6.
1324 gtk_widget_destroy( item
->GetMenuItem() );
1329 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1331 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1334 wxMenuItem
*item
= node
->GetData();
1335 if (item
->GetMenuItem() == menuItem
)
1336 return item
->GetId();
1337 node
= node
->GetNext();
1343 // ----------------------------------------------------------------------------
1345 // ----------------------------------------------------------------------------
1349 static wxString
GetHotKey( const wxMenuItem
& item
)
1353 wxAcceleratorEntry
*accel
= item
.GetAccel();
1356 int flags
= accel
->GetFlags();
1357 if ( flags
& wxACCEL_ALT
)
1358 hotkey
+= wxT("<alt>");
1359 if ( flags
& wxACCEL_CTRL
)
1360 hotkey
+= wxT("<control>");
1361 if ( flags
& wxACCEL_SHIFT
)
1362 hotkey
+= wxT("<shift>");
1364 int code
= accel
->GetKeyCode();
1379 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1382 // TODO: we should use gdk_keyval_name() (a.k.a.
1383 // XKeysymToString) here as well as hardcoding the keysym
1384 // names this might be not portable
1385 case WXK_NUMPAD_INSERT
:
1386 hotkey
<< wxT("KP_Insert" );
1388 case WXK_NUMPAD_DELETE
:
1389 hotkey
<< wxT("KP_Delete" );
1392 hotkey
<< wxT("Insert" );
1395 hotkey
<< wxT("Delete" );
1398 hotkey
<< wxT("Up" );
1401 hotkey
<< wxT("Down" );
1405 hotkey
<< wxT("Prior" );
1409 hotkey
<< wxT("Next" );
1412 hotkey
<< wxT("Left" );
1415 hotkey
<< wxT("Right" );
1418 hotkey
<< wxT("Home" );
1421 hotkey
<< wxT("End" );
1424 hotkey
<< wxT("Return" );
1427 // if there are any other keys wxGetAccelFromString() may
1428 // return, we should process them here
1433 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1441 wxFAIL_MSG( wxT("unknown keyboard accel") );
1450 #endif // wxUSE_ACCEL
1453 //-----------------------------------------------------------------------------
1454 // substitute for missing GtkPixmapMenuItem
1455 //-----------------------------------------------------------------------------
1460 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1461 * All rights reserved.
1463 * This file is part of the Gnome Library.
1465 * The Gnome Library is free software; you can redistribute it and/or
1466 * modify it under the terms of the GNU Library General Public License as
1467 * published by the Free Software Foundation; either version 2 of the
1468 * License, or (at your option) any later version.
1470 * The Gnome Library is distributed in the hope that it will be useful,
1471 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1472 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1473 * Library General Public License for more details.
1475 * You should have received a copy of the GNU Library General Public
1476 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1477 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1478 * Boston, MA 02111-1307, USA.
1484 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1486 #include <gtk/gtkaccellabel.h>
1487 #include <gtk/gtksignal.h>
1488 #include <gtk/gtkmenuitem.h>
1489 #include <gtk/gtkmenu.h>
1490 #include <gtk/gtkcontainer.h>
1495 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1496 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1497 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1498 GdkRectangle
*area
);
1499 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1500 GdkEventExpose
*event
);
1502 /* we must override the following functions */
1504 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1505 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1506 GtkAllocation
*allocation
);
1507 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1508 gboolean include_internals
,
1509 GtkCallback callback
,
1510 gpointer callback_data
);
1511 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1512 GtkRequisition
*requisition
);
1513 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1516 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1518 static GtkMenuItemClass
*parent_class
= NULL
;
1522 #define BORDER_SPACING 3
1523 #define PMAP_WIDTH 20
1526 gtk_pixmap_menu_item_get_type (void)
1528 static GtkType pixmap_menu_item_type
= 0;
1530 if (!pixmap_menu_item_type
)
1532 GtkTypeInfo pixmap_menu_item_info
=
1534 (char *)"GtkPixmapMenuItem",
1535 sizeof (GtkPixmapMenuItem
),
1536 sizeof (GtkPixmapMenuItemClass
),
1537 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1538 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1539 /* reserved_1 */ NULL
,
1540 /* reserved_2 */ NULL
,
1541 (GtkClassInitFunc
) NULL
,
1544 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1545 &pixmap_menu_item_info
);
1548 return pixmap_menu_item_type
;
1552 * gtk_pixmap_menu_item_new
1554 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1555 * to set the pixmap wich is displayed at the left side.
1558 * &GtkWidget pointer to new menu item
1562 gtk_pixmap_menu_item_new (void)
1564 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1568 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1570 GtkObjectClass
*object_class
;
1571 GtkWidgetClass
*widget_class
;
1572 GtkMenuItemClass
*menu_item_class
;
1573 GtkContainerClass
*container_class
;
1575 object_class
= (GtkObjectClass
*) klass
;
1576 widget_class
= (GtkWidgetClass
*) klass
;
1577 menu_item_class
= (GtkMenuItemClass
*) klass
;
1578 container_class
= (GtkContainerClass
*) klass
;
1580 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1582 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1583 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1584 widget_class
->map
= gtk_pixmap_menu_item_map
;
1585 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1586 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1588 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1589 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1591 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1592 klass
->have_pixmap_count
= 0;
1596 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1600 mi
= GTK_MENU_ITEM (menu_item
);
1602 menu_item
->pixmap
= NULL
;
1606 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1609 g_return_if_fail (widget
!= NULL
);
1610 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1611 g_return_if_fail (area
!= NULL
);
1613 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1614 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1616 if (GTK_WIDGET_DRAWABLE (widget
) &&
1617 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1618 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1623 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1624 GdkEventExpose
*event
)
1626 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1627 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1628 g_return_val_if_fail (event
!= NULL
, FALSE
);
1630 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1631 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1633 if (GTK_WIDGET_DRAWABLE (widget
) &&
1634 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1635 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1642 * gtk_pixmap_menu_item_set_pixmap
1643 * @menu_item: Pointer to the pixmap menu item
1644 * @pixmap: Pointer to a pixmap widget
1646 * Set the pixmap of the menu item.
1651 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1654 g_return_if_fail (menu_item
!= NULL
);
1655 g_return_if_fail (pixmap
!= NULL
);
1656 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1657 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1658 g_return_if_fail (menu_item
->pixmap
== NULL
);
1660 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1661 menu_item
->pixmap
= pixmap
;
1663 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1664 !GTK_WIDGET_REALIZED (pixmap
))
1665 gtk_widget_realize (pixmap
);
1667 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1668 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1669 GTK_WIDGET_VISIBLE(pixmap
) &&
1670 !GTK_WIDGET_MAPPED (pixmap
))
1671 gtk_widget_map (pixmap
);
1674 changed_have_pixmap_status(menu_item
);
1676 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1677 gtk_widget_queue_resize (pixmap
);
1681 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1683 GtkPixmapMenuItem
*menu_item
;
1685 g_return_if_fail (widget
!= NULL
);
1686 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1688 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1690 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1692 if (menu_item
->pixmap
&&
1693 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1694 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1695 gtk_widget_map (menu_item
->pixmap
);
1699 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1700 GtkAllocation
*allocation
)
1702 GtkPixmapMenuItem
*pmenu_item
;
1704 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1706 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1708 GtkAllocation child_allocation
;
1711 border_width
= GTK_CONTAINER (widget
)->border_width
;
1713 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1714 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1715 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1716 child_allocation
.y
= (border_width
+ BORDER_SPACING
1717 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1718 / 2)); /* center pixmaps vertically */
1719 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1722 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1723 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1727 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1728 gboolean include_internals
,
1729 GtkCallback callback
,
1730 gpointer callback_data
)
1732 GtkPixmapMenuItem
*menu_item
;
1734 g_return_if_fail (container
!= NULL
);
1735 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1736 g_return_if_fail (callback
!= NULL
);
1738 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1740 if (menu_item
->pixmap
)
1741 (* callback
) (menu_item
->pixmap
, callback_data
);
1743 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1744 callback
,callback_data
);
1748 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1749 GtkRequisition
*requisition
)
1751 GtkPixmapMenuItem
*menu_item
;
1752 GtkRequisition req
= {0, 0};
1754 g_return_if_fail (widget
!= NULL
);
1755 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1756 g_return_if_fail (requisition
!= NULL
);
1758 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1760 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1762 if (menu_item
->pixmap
)
1763 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1765 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1766 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1770 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1774 gboolean widget_was_visible
;
1776 g_return_if_fail (container
!= NULL
);
1777 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1778 g_return_if_fail (child
!= NULL
);
1779 g_return_if_fail (GTK_IS_WIDGET (child
));
1781 bin
= GTK_BIN (container
);
1782 g_return_if_fail ((bin
->child
== child
||
1783 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1785 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1787 gtk_widget_unparent (child
);
1788 if (bin
->child
== child
)
1791 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1792 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1795 if (widget_was_visible
)
1796 gtk_widget_queue_resize (GTK_WIDGET (container
));
1800 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1802 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1804 if (menu_item
->pixmap
!= NULL
) {
1805 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1807 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1808 /* Install pixmap toggle size */
1809 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1812 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1814 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1815 /* Install normal toggle size */
1816 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1820 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1821 whenever the klass->toggle_size changes; but by doing it anytime
1822 this function is called, we get the same effect, just because of
1823 how the preferences option to show pixmaps works. Bogus, broken.
1825 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1826 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));