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('\t'))
803 if ( *pc
== wxT('_') )
805 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
812 if ( *pc
== wxT('\\') )
814 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
821 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
824 // "&" is doubled to indicate "&" instead of accelerator
831 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
836 void wxMenuItem::SetText( const wxString
& str
)
838 // Some optimization to avoid flicker
839 wxString oldLabel
= m_text
;
840 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
841 oldLabel
.Replace(wxT("_"), wxT(""));
842 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
843 if (oldLabel
== label1
)
852 label
= (GtkLabel
*) m_labelWidget
;
854 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
857 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
860 gtk_label_set( label
, wxGTK_CONV( m_text
) );
863 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
864 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
869 // it's valid for this function to be called even if m_menuItem == NULL
870 void wxMenuItem::DoSetText( const wxString
& str
)
872 // '\t' is the deliminator indicating a hot key
874 const wxChar
*pc
= str
;
875 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
877 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
879 // "&" is doubled to indicate "&" instead of accelerator
883 else if (*pc
== wxT('&'))
887 else if ( *pc
== wxT('_') ) // escape underscores
898 // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() );
911 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
916 return (wxAcceleratorEntry
*)NULL
;
919 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
921 label
<< wxT('\t') << GetHotKey();
923 return wxGetAccelFromString(label
);
926 #endif // wxUSE_ACCEL
928 void wxMenuItem::Check( bool check
)
930 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
932 if (check
== m_isChecked
)
935 wxMenuItemBase::Check( check
);
941 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
945 wxFAIL_MSG( _T("can't check this item") );
949 void wxMenuItem::Enable( bool enable
)
951 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
953 gtk_widget_set_sensitive( m_menuItem
, enable
);
954 wxMenuItemBase::Enable( enable
);
957 bool wxMenuItem::IsChecked() const
959 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
961 wxCHECK_MSG( IsCheckable(), FALSE
,
962 wxT("can't get state of uncheckable item!") );
964 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
967 //-----------------------------------------------------------------------------
969 //-----------------------------------------------------------------------------
971 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
975 m_accel
= gtk_accel_group_new();
976 m_menu
= gtk_menu_new();
978 m_owner
= (GtkWidget
*) NULL
;
980 // Tearoffs are entries, just like separators. So if we want this
981 // menu to be a tear-off one, we just append a tearoff entry
983 if(m_style
& wxMENU_TEAROFF
)
985 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
987 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
992 // append the title as the very first entry if we have it
1002 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1004 if ( GTK_IS_WIDGET( m_menu
))
1005 gtk_widget_destroy( m_menu
);
1008 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
1010 GtkWidget
*menuItem
;
1012 if ( mitem
->IsSeparator() )
1015 menuItem
= gtk_separator_menu_item_new();
1018 menuItem
= gtk_menu_item_new();
1020 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1023 else if ( mitem
->IsSubMenu() )
1025 // text has "_" instead of "&" after mitem->SetText()
1026 wxString
text( mitem
->GetText() );
1029 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1031 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1032 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1034 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1035 // reparse key accel
1036 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1037 if (accel_key
!= GDK_VoidSymbol
)
1039 gtk_widget_add_accelerator (menuItem
,
1041 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1048 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1049 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1051 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1053 // if adding a submenu to a menu already existing in the menu bar, we
1054 // must set invoking window to allow processing events from this
1056 if ( m_invokingWindow
)
1057 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1061 else if (mitem
->GetBitmap().Ok())
1063 wxString text
= mitem
->GetText();
1064 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1065 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1066 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1069 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1071 GtkWidget
*image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1072 gtk_widget_show(image
);
1074 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1076 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1077 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1080 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1083 menuItem
= gtk_pixmap_menu_item_new ();
1084 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1085 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1086 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1088 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1090 GdkModifierType accel_mods
;
1092 // accelerator for the item, as specified by its label
1093 // (ex. Ctrl+O for open)
1094 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1096 if (accel_key
!= GDK_VoidSymbol
)
1098 gtk_widget_add_accelerator (menuItem
,
1101 accel_key
, accel_mods
,
1105 // accelerator for the underlined char (ex ALT+F for the File menu)
1106 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1107 if (accel_key
!= GDK_VoidSymbol
)
1109 gtk_widget_add_accelerator (menuItem
,
1111 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1117 gtk_widget_show (label
);
1119 mitem
->SetLabelWidget(label
);
1121 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1122 gtk_widget_show(pixmap
);
1123 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1125 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1126 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1129 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1130 gtk_widget_show( menuItem
);
1135 else // a normal item
1137 // text has "_" instead of "&" after mitem->SetText() so don't use it
1138 wxString
text( mitem
->GetText() );
1140 switch ( mitem
->GetKind() )
1145 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1147 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1148 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1150 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1151 // reparse key accel
1152 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1153 if (accel_key
!= GDK_VoidSymbol
)
1155 gtk_widget_add_accelerator (menuItem
,
1157 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1169 GSList
*group
= NULL
;
1170 if ( m_prevRadio
== NULL
)
1172 // start of a new radio group
1174 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1176 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1177 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1179 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1180 // reparse key accel
1181 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1182 if (accel_key
!= GDK_VoidSymbol
)
1184 gtk_widget_add_accelerator (menuItem
,
1186 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1193 else // continue the radio group
1196 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1197 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1199 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1200 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1201 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1203 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1204 // reparse key accel
1205 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1206 if (accel_key
!= GDK_VoidSymbol
)
1208 gtk_widget_add_accelerator (menuItem
,
1210 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1221 wxFAIL_MSG( _T("unexpected menu item kind") );
1227 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1229 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1230 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1232 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1233 // reparse key accel
1234 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1235 if (accel_key
!= GDK_VoidSymbol
)
1237 gtk_widget_add_accelerator (menuItem
,
1239 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1250 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1251 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1254 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1258 GdkModifierType accel_mods
;
1259 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1261 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1263 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1266 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1274 gtk_widget_show( menuItem
);
1276 if ( !mitem
->IsSeparator() )
1278 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1280 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1281 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1284 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1285 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1289 mitem
->SetMenuItem(menuItem
);
1293 // This doesn't even exist!
1294 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1300 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1302 if (!GtkAppend(mitem
))
1305 return wxMenuBase::DoAppend(mitem
);
1308 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1310 if ( !wxMenuBase::DoInsert(pos
, item
) )
1314 if ( !GtkAppend(item
) )
1320 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1322 if ( !wxMenuBase::DoRemove(item
) )
1323 return (wxMenuItem
*)NULL
;
1325 // TODO: this code doesn't delete the item factory item and this seems
1326 // impossible as of GTK 1.2.6.
1327 gtk_widget_destroy( item
->GetMenuItem() );
1332 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1334 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1337 wxMenuItem
*item
= node
->GetData();
1338 if (item
->GetMenuItem() == menuItem
)
1339 return item
->GetId();
1340 node
= node
->GetNext();
1346 // ----------------------------------------------------------------------------
1348 // ----------------------------------------------------------------------------
1352 static wxString
GetHotKey( const wxMenuItem
& item
)
1356 wxAcceleratorEntry
*accel
= item
.GetAccel();
1359 int flags
= accel
->GetFlags();
1360 if ( flags
& wxACCEL_ALT
)
1361 hotkey
+= wxT("<alt>");
1362 if ( flags
& wxACCEL_CTRL
)
1363 hotkey
+= wxT("<control>");
1364 if ( flags
& wxACCEL_SHIFT
)
1365 hotkey
+= wxT("<shift>");
1367 int code
= accel
->GetKeyCode();
1382 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1385 // TODO: we should use gdk_keyval_name() (a.k.a.
1386 // XKeysymToString) here as well as hardcoding the keysym
1387 // names this might be not portable
1388 case WXK_NUMPAD_INSERT
:
1389 hotkey
<< wxT("KP_Insert" );
1391 case WXK_NUMPAD_DELETE
:
1392 hotkey
<< wxT("KP_Delete" );
1395 hotkey
<< wxT("Insert" );
1398 hotkey
<< wxT("Delete" );
1401 hotkey
<< wxT("Up" );
1404 hotkey
<< wxT("Down" );
1408 hotkey
<< wxT("Prior" );
1412 hotkey
<< wxT("Next" );
1415 hotkey
<< wxT("Left" );
1418 hotkey
<< wxT("Right" );
1421 hotkey
<< wxT("Home" );
1424 hotkey
<< wxT("End" );
1427 hotkey
<< wxT("Return" );
1430 // if there are any other keys wxGetAccelFromString() may
1431 // return, we should process them here
1436 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1444 wxFAIL_MSG( wxT("unknown keyboard accel") );
1453 #endif // wxUSE_ACCEL
1456 //-----------------------------------------------------------------------------
1457 // substitute for missing GtkPixmapMenuItem
1458 //-----------------------------------------------------------------------------
1463 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1464 * All rights reserved.
1466 * This file is part of the Gnome Library.
1468 * The Gnome Library is free software; you can redistribute it and/or
1469 * modify it under the terms of the GNU Library General Public License as
1470 * published by the Free Software Foundation; either version 2 of the
1471 * License, or (at your option) any later version.
1473 * The Gnome Library is distributed in the hope that it will be useful,
1474 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1475 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1476 * Library General Public License for more details.
1478 * You should have received a copy of the GNU Library General Public
1479 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1480 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1481 * Boston, MA 02111-1307, USA.
1487 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1489 #include <gtk/gtkaccellabel.h>
1490 #include <gtk/gtksignal.h>
1491 #include <gtk/gtkmenuitem.h>
1492 #include <gtk/gtkmenu.h>
1493 #include <gtk/gtkcontainer.h>
1498 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1499 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1500 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1501 GdkRectangle
*area
);
1502 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1503 GdkEventExpose
*event
);
1505 /* we must override the following functions */
1507 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1508 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1509 GtkAllocation
*allocation
);
1510 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1511 gboolean include_internals
,
1512 GtkCallback callback
,
1513 gpointer callback_data
);
1514 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1515 GtkRequisition
*requisition
);
1516 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1519 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1521 static GtkMenuItemClass
*parent_class
= NULL
;
1525 #define BORDER_SPACING 3
1526 #define PMAP_WIDTH 20
1529 gtk_pixmap_menu_item_get_type (void)
1531 static GtkType pixmap_menu_item_type
= 0;
1533 if (!pixmap_menu_item_type
)
1535 GtkTypeInfo pixmap_menu_item_info
=
1537 (char *)"GtkPixmapMenuItem",
1538 sizeof (GtkPixmapMenuItem
),
1539 sizeof (GtkPixmapMenuItemClass
),
1540 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1541 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1542 /* reserved_1 */ NULL
,
1543 /* reserved_2 */ NULL
,
1544 (GtkClassInitFunc
) NULL
,
1547 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1548 &pixmap_menu_item_info
);
1551 return pixmap_menu_item_type
;
1555 * gtk_pixmap_menu_item_new
1557 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1558 * to set the pixmap wich is displayed at the left side.
1561 * &GtkWidget pointer to new menu item
1565 gtk_pixmap_menu_item_new (void)
1567 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1571 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1573 GtkObjectClass
*object_class
;
1574 GtkWidgetClass
*widget_class
;
1575 GtkMenuItemClass
*menu_item_class
;
1576 GtkContainerClass
*container_class
;
1578 object_class
= (GtkObjectClass
*) klass
;
1579 widget_class
= (GtkWidgetClass
*) klass
;
1580 menu_item_class
= (GtkMenuItemClass
*) klass
;
1581 container_class
= (GtkContainerClass
*) klass
;
1583 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1585 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1586 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1587 widget_class
->map
= gtk_pixmap_menu_item_map
;
1588 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1589 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1591 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1592 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1594 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1595 klass
->have_pixmap_count
= 0;
1599 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1603 mi
= GTK_MENU_ITEM (menu_item
);
1605 menu_item
->pixmap
= NULL
;
1609 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1612 g_return_if_fail (widget
!= NULL
);
1613 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1614 g_return_if_fail (area
!= NULL
);
1616 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1617 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1619 if (GTK_WIDGET_DRAWABLE (widget
) &&
1620 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1621 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1626 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1627 GdkEventExpose
*event
)
1629 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1630 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1631 g_return_val_if_fail (event
!= NULL
, FALSE
);
1633 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1634 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1636 if (GTK_WIDGET_DRAWABLE (widget
) &&
1637 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1638 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1645 * gtk_pixmap_menu_item_set_pixmap
1646 * @menu_item: Pointer to the pixmap menu item
1647 * @pixmap: Pointer to a pixmap widget
1649 * Set the pixmap of the menu item.
1654 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1657 g_return_if_fail (menu_item
!= NULL
);
1658 g_return_if_fail (pixmap
!= NULL
);
1659 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1660 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1661 g_return_if_fail (menu_item
->pixmap
== NULL
);
1663 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1664 menu_item
->pixmap
= pixmap
;
1666 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1667 !GTK_WIDGET_REALIZED (pixmap
))
1668 gtk_widget_realize (pixmap
);
1670 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1671 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1672 GTK_WIDGET_VISIBLE(pixmap
) &&
1673 !GTK_WIDGET_MAPPED (pixmap
))
1674 gtk_widget_map (pixmap
);
1677 changed_have_pixmap_status(menu_item
);
1679 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1680 gtk_widget_queue_resize (pixmap
);
1684 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1686 GtkPixmapMenuItem
*menu_item
;
1688 g_return_if_fail (widget
!= NULL
);
1689 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1691 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1693 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1695 if (menu_item
->pixmap
&&
1696 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1697 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1698 gtk_widget_map (menu_item
->pixmap
);
1702 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1703 GtkAllocation
*allocation
)
1705 GtkPixmapMenuItem
*pmenu_item
;
1707 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1709 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1711 GtkAllocation child_allocation
;
1714 border_width
= GTK_CONTAINER (widget
)->border_width
;
1716 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1717 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1718 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1719 child_allocation
.y
= (border_width
+ BORDER_SPACING
1720 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1721 / 2)); /* center pixmaps vertically */
1722 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1725 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1726 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1730 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1731 gboolean include_internals
,
1732 GtkCallback callback
,
1733 gpointer callback_data
)
1735 GtkPixmapMenuItem
*menu_item
;
1737 g_return_if_fail (container
!= NULL
);
1738 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1739 g_return_if_fail (callback
!= NULL
);
1741 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1743 if (menu_item
->pixmap
)
1744 (* callback
) (menu_item
->pixmap
, callback_data
);
1746 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1747 callback
,callback_data
);
1751 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1752 GtkRequisition
*requisition
)
1754 GtkPixmapMenuItem
*menu_item
;
1755 GtkRequisition req
= {0, 0};
1757 g_return_if_fail (widget
!= NULL
);
1758 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1759 g_return_if_fail (requisition
!= NULL
);
1761 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1763 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1765 if (menu_item
->pixmap
)
1766 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1768 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1769 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1773 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1777 gboolean widget_was_visible
;
1779 g_return_if_fail (container
!= NULL
);
1780 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1781 g_return_if_fail (child
!= NULL
);
1782 g_return_if_fail (GTK_IS_WIDGET (child
));
1784 bin
= GTK_BIN (container
);
1785 g_return_if_fail ((bin
->child
== child
||
1786 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1788 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1790 gtk_widget_unparent (child
);
1791 if (bin
->child
== child
)
1794 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1795 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1798 if (widget_was_visible
)
1799 gtk_widget_queue_resize (GTK_WIDGET (container
));
1803 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1805 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1807 if (menu_item
->pixmap
!= NULL
) {
1808 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1810 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1811 /* Install pixmap toggle size */
1812 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1815 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1817 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1818 /* Install normal toggle size */
1819 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1823 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1824 whenever the klass->toggle_size changes; but by doing it anytime
1825 this function is called, we get the same effect, just because of
1826 how the preferences option to show pixmaps works. Bogus, broken.
1828 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1829 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));