1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "menu.h"
12 #pragma implementation "menuitem.h"
18 #include "wx/bitmap.h"
26 #include <gdk/gdkkeysyms.h>
29 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
33 extern void wxapp_install_idle_handler();
36 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL
37 static wxString
GetHotKey( const wxMenuItem
& item
);
40 //-----------------------------------------------------------------------------
41 // substitute for missing GtkPixmapMenuItem
42 //-----------------------------------------------------------------------------
44 #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ())
45 #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem))
46 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass))
47 #define GTK_IS_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
48 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM))
49 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
50 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
52 #ifndef GTK_MENU_ITEM_GET_CLASS
53 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
56 typedef struct _GtkPixmapMenuItem GtkPixmapMenuItem
;
57 typedef struct _GtkPixmapMenuItemClass GtkPixmapMenuItemClass
;
59 struct _GtkPixmapMenuItem
61 GtkMenuItem menu_item
;
66 struct _GtkPixmapMenuItemClass
68 GtkMenuItemClass parent_class
;
70 guint orig_toggle_size
;
71 guint have_pixmap_count
;
75 GtkType
gtk_pixmap_menu_item_get_type (void);
76 GtkWidget
* gtk_pixmap_menu_item_new (void);
77 void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
80 //-----------------------------------------------------------------------------
82 //-----------------------------------------------------------------------------
84 static wxString
wxReplaceUnderscore( const wxString
& title
)
88 /* GTK 1.2 wants to have "_" instead of "&" for accelerators */
90 for ( pc
= title
; *pc
!= wxT('\0'); pc
++ )
94 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
97 else if (*pc
== wxT('/'))
105 if ( *pc
== wxT('_') )
107 // underscores must be doubled to prevent them from being
108 // interpreted as accelerator character prefix by GTK
119 //-----------------------------------------------------------------------------
121 //-----------------------------------------------------------------------------
123 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
125 wxMenuBar::wxMenuBar( long style
)
127 /* the parent window is known after wxFrame::SetMenu() */
128 m_needParent
= FALSE
;
130 m_invokingWindow
= (wxWindow
*) NULL
;
132 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
133 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
135 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
139 m_menus
.DeleteContents( TRUE
);
141 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
142 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
143 m_accel
= gtk_accel_group_new();
144 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
145 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
147 m_menubar
= gtk_menu_bar_new();
150 if (style
& wxMB_DOCKABLE
)
152 m_widget
= gtk_handle_box_new();
153 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
154 gtk_widget_show( GTK_WIDGET(m_menubar
) );
158 m_widget
= GTK_WIDGET(m_menubar
);
166 wxMenuBar::wxMenuBar()
168 /* the parent window is known after wxFrame::SetMenu() */
169 m_needParent
= FALSE
;
171 m_invokingWindow
= (wxWindow
*) NULL
;
173 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
174 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
176 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
180 m_menus
.DeleteContents( TRUE
);
182 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
183 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
184 m_accel
= gtk_accel_group_new();
185 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
186 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
188 m_menubar
= gtk_menu_bar_new();
191 m_widget
= GTK_WIDGET(m_menubar
);
198 wxMenuBar::~wxMenuBar()
200 // gtk_object_unref( GTK_OBJECT(m_factory) ); why not ?
203 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
205 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
207 #if (GTK_MINOR_VERSION > 0)
208 wxWindow
*top_frame
= win
;
209 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
210 top_frame
= top_frame
->GetParent();
212 /* support for native hot keys */
213 gtk_accel_group_detach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
216 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
219 wxMenuItem
*menuitem
= node
->GetData();
220 if (menuitem
->IsSubMenu())
221 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
222 node
= node
->GetNext();
226 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
228 menu
->SetInvokingWindow( win
);
230 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
231 wxWindow
*top_frame
= win
;
232 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
233 top_frame
= top_frame
->GetParent();
235 /* support for native hot keys */
236 GtkObject
*obj
= GTK_OBJECT(top_frame
->m_widget
);
237 if ( !g_slist_find( menu
->m_accel
->attach_objects
, obj
) )
238 gtk_accel_group_attach( menu
->m_accel
, obj
);
241 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
244 wxMenuItem
*menuitem
= node
->GetData();
245 if (menuitem
->IsSubMenu())
246 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
247 node
= node
->GetNext();
251 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
253 m_invokingWindow
= win
;
254 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
255 wxWindow
*top_frame
= win
;
256 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
257 top_frame
= top_frame
->GetParent();
259 /* support for native key accelerators indicated by underscroes */
260 GtkObject
*obj
= GTK_OBJECT(top_frame
->m_widget
);
261 if ( !g_slist_find( m_accel
->attach_objects
, obj
) )
262 gtk_accel_group_attach( m_accel
, obj
);
265 wxMenuList::Node
*node
= m_menus
.GetFirst();
268 wxMenu
*menu
= node
->GetData();
269 wxMenubarSetInvokingWindow( menu
, win
);
270 node
= node
->GetNext();
274 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
276 m_invokingWindow
= (wxWindow
*) NULL
;
277 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
278 wxWindow
*top_frame
= win
;
279 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
280 top_frame
= top_frame
->GetParent();
282 /* support for native key accelerators indicated by underscroes */
283 gtk_accel_group_detach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
286 wxMenuList::Node
*node
= m_menus
.GetFirst();
289 wxMenu
*menu
= node
->GetData();
290 wxMenubarUnsetInvokingWindow( menu
, win
);
291 node
= node
->GetNext();
295 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
297 if ( !wxMenuBarBase::Append( menu
, title
) )
300 return GtkAppend(menu
, title
);
303 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
)
305 wxString
str( wxReplaceUnderscore( title
) );
307 /* this doesn't have much effect right now */
308 menu
->SetTitle( str
);
310 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
311 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
313 /* local buffer in multibyte form */
315 buf
<< wxT('/') << str
.c_str();
317 char *cbuf
= new char[buf
.Length()+1];
318 strcpy(cbuf
, buf
.mbc_str());
320 GtkItemFactoryEntry entry
;
321 entry
.path
= (gchar
*)cbuf
; // const_cast
322 entry
.accelerator
= (gchar
*) NULL
;
323 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
324 entry
.callback_action
= 0;
325 entry
.item_type
= "<Branch>";
327 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
328 /* in order to get the pointer to the item we need the item text _without_ underscores */
329 wxString tmp
= wxT("<main>/");
331 for ( pc
= str
; *pc
!= wxT('\0'); pc
++ )
333 // contrary to the common sense, we must throw out _all_ underscores,
334 // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we
335 // might naively think). IMHO it's a bug in GTK+ (VZ)
336 while (*pc
== wxT('_'))
340 menu
->m_owner
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() );
341 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
345 menu
->m_owner
= gtk_menu_item_new_with_label( str
.mb_str() );
346 gtk_widget_show( menu
->m_owner
);
347 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
349 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
353 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
354 // adding menu later on.
355 if (m_invokingWindow
)
356 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
361 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
363 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
367 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
368 // of version 1.2.6), so we first append the item and then change its
370 if ( !GtkAppend(menu
, title
) )
373 if (pos
+1 >= m_menus
.GetCount())
376 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
377 gpointer data
= g_list_last(menu_shell
->children
)->data
;
378 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
379 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
383 // this should be easy to do with GTK 1.0 - can use standard functions for
384 // this and don't need any hacks like above, but as I don't have GTK 1.0
385 // any more I can't do it
386 wxFAIL_MSG( wxT("TODO") );
389 #endif // GTK 1.2/1.0
392 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
394 // remove the old item and insert a new one
395 wxMenu
*menuOld
= Remove(pos
);
396 if ( menuOld
&& !Insert(pos
, menu
, title
) )
398 return (wxMenu
*) NULL
;
401 // either Insert() succeeded or Remove() failed and menuOld is NULL
405 wxMenu
*wxMenuBar::Remove(size_t pos
)
407 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
409 return (wxMenu
*) NULL
;
412 GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget);
414 printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) );
415 printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) );
418 // unparent calls unref() and that would delete the widget so we raise
419 // the ref count to 2 artificially before invoking unparent.
420 gtk_widget_ref( menu
->m_menu
);
421 gtk_widget_unparent( menu
->m_menu
);
423 gtk_widget_destroy( menu
->m_owner
);
426 printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) );
427 printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) );
433 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
435 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
437 int res
= menu
->FindItem( itemString
);
438 if (res
!= wxNOT_FOUND
)
442 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
445 wxMenuItem
*item
= node
->GetData();
446 if (item
->IsSubMenu())
447 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
449 node
= node
->GetNext();
455 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
457 wxMenuList::Node
*node
= m_menus
.GetFirst();
460 wxMenu
*menu
= node
->GetData();
461 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
464 node
= node
->GetNext();
470 // Find a wxMenuItem using its id. Recurses down into sub-menus
471 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
473 wxMenuItem
* result
= menu
->FindChildItem(id
);
475 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
476 while ( node
&& result
== NULL
)
478 wxMenuItem
*item
= node
->GetData();
479 if (item
->IsSubMenu())
481 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
483 node
= node
->GetNext();
489 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
491 wxMenuItem
* result
= 0;
492 wxMenuList::Node
*node
= m_menus
.GetFirst();
493 while (node
&& result
== 0)
495 wxMenu
*menu
= node
->GetData();
496 result
= FindMenuItemByIdRecursive( menu
, id
);
497 node
= node
->GetNext();
502 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
508 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
510 wxMenuList::Node
*node
= m_menus
.Item( pos
);
512 wxCHECK_RET( node
, wxT("menu not found") );
514 wxMenu
* menu
= node
->GetData();
517 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
520 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
522 wxMenuList::Node
*node
= m_menus
.Item( pos
);
524 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
526 wxMenu
* menu
= node
->GetData();
529 wxString
text( menu
->GetTitle() );
530 #if (GTK_MINOR_VERSION > 0)
531 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
533 if ( *pc
== wxT('_') || *pc
== wxT('&') )
535 // '_' is the escape character for GTK+ and '&' is the one for
536 // wxWindows - skip both of them
544 #endif // GTK+ 1.2/1.0
549 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
551 wxMenuList::Node
*node
= m_menus
.Item( pos
);
553 wxCHECK_RET( node
, wxT("menu not found") );
555 wxMenu
* menu
= node
->GetData();
557 wxString
str( wxReplaceUnderscore( label
) );
559 menu
->SetTitle( str
);
563 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
566 gtk_label_set( label
, str
.mb_str());
568 /* reparse key accel */
569 (void)gtk_label_parse_uline (GTK_LABEL(label
), str
.mb_str() );
570 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
575 //-----------------------------------------------------------------------------
577 //-----------------------------------------------------------------------------
579 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
581 if (g_isIdle
) wxapp_install_idle_handler();
583 int id
= menu
->FindMenuIdByMenuItem(widget
);
585 /* should find it for normal (not popup) menu */
586 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
588 if (!menu
->IsEnabled(id
))
591 wxMenuItem
* item
= menu
->FindChildItem( id
);
592 wxCHECK_RET( item
, wxT("error in menu item callback") );
594 if (item
->IsCheckable())
596 bool isReallyChecked
= item
->IsChecked();
597 if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked
)
599 /* the menu item has been checked by calling wxMenuItem->Check() */
604 /* the user pressed on the menu item -> report and make consistent
606 item
->wxMenuItemBase::Check(isReallyChecked
);
610 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
611 event
.SetEventObject( menu
);
612 if (item
->IsCheckable())
613 event
.SetInt( item
->IsChecked() );
615 #if wxUSE_MENU_CALLBACK
616 if (menu
->GetCallback())
618 (void) (*(menu
->GetCallback())) (*menu
, event
);
621 #endif // wxUSE_MENU_CALLBACK
623 if (menu
->GetEventHandler()->ProcessEvent(event
))
626 wxWindow
*win
= menu
->GetInvokingWindow();
628 win
->GetEventHandler()->ProcessEvent( event
);
631 //-----------------------------------------------------------------------------
633 //-----------------------------------------------------------------------------
635 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
637 if (g_isIdle
) wxapp_install_idle_handler();
639 int id
= menu
->FindMenuIdByMenuItem(widget
);
641 wxASSERT( id
!= -1 ); // should find it!
643 if (!menu
->IsEnabled(id
))
646 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
647 event
.SetEventObject( menu
);
649 if (menu
->GetEventHandler()->ProcessEvent(event
))
652 wxWindow
*win
= menu
->GetInvokingWindow();
653 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
656 //-----------------------------------------------------------------------------
658 //-----------------------------------------------------------------------------
660 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
662 if (g_isIdle
) wxapp_install_idle_handler();
664 int id
= menu
->FindMenuIdByMenuItem(widget
);
666 wxASSERT( id
!= -1 ); // should find it!
668 if (!menu
->IsEnabled(id
))
671 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
672 event
.SetEventObject( menu
);
674 if (menu
->GetEventHandler()->ProcessEvent(event
))
677 wxWindow
*win
= menu
->GetInvokingWindow();
679 win
->GetEventHandler()->ProcessEvent( event
);
682 //-----------------------------------------------------------------------------
684 //-----------------------------------------------------------------------------
686 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxMenuItemBase
)
688 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
690 const wxString
& name
,
691 const wxString
& help
,
695 return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
);
698 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
700 const wxString
& text
,
701 const wxString
& help
,
706 m_isCheckable
= isCheckable
;
710 m_parentMenu
= parentMenu
;
713 m_labelWidget
= (GtkWidget
*) NULL
;
714 m_menuItem
= (GtkWidget
*) NULL
;
719 wxMenuItem::~wxMenuItem()
721 // don't delete menu items, the menus take care of that
724 // return the menu item text without any menu accels
726 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
729 #if (GTK_MINOR_VERSION > 0)
730 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
732 if ( *pc
== wxT('_') || *pc
== wxT('&') )
734 // '_' is the escape character for GTK+ and '&' is the one for
735 // wxWindows - skip both of them
743 #endif // GTK+ 1.2/1.0
748 void wxMenuItem::SetText( const wxString
& str
)
756 label
= (GtkLabel
*) m_labelWidget
;
758 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
761 gtk_label_set( label
, m_text
.mb_str());
763 /* reparse key accel */
764 (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() );
765 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
769 // it's valid for this function to be called even if m_menuItem == NULL
770 void wxMenuItem::DoSetText( const wxString
& str
)
772 /* '\t' is the deliminator indicating a hot key */
774 const wxChar
*pc
= str
;
775 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
779 #if (GTK_MINOR_VERSION > 0)
782 else if ( *pc
== wxT('_') ) // escape underscores
786 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
788 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
795 /* only GTK 1.2 knows about hot keys */
797 #if (GTK_MINOR_VERSION > 0)
808 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
813 return (wxAcceleratorEntry
*)NULL
;
816 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
818 label
<< wxT('\t') << GetHotKey();
820 return wxGetAccelFromString(label
);
823 #endif // wxUSE_ACCEL
825 void wxMenuItem::Check( bool check
)
827 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
829 wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") )
831 if (check
== m_isChecked
)
834 wxMenuItemBase::Check( check
);
835 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
838 void wxMenuItem::Enable( bool enable
)
840 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
842 gtk_widget_set_sensitive( m_menuItem
, enable
);
843 wxMenuItemBase::Enable( enable
);
846 bool wxMenuItem::IsChecked() const
848 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
850 wxCHECK_MSG( IsCheckable(), FALSE
,
851 wxT("can't get state of uncheckable item!") );
853 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
856 wxString
wxMenuItem::GetFactoryPath() const
858 /* in order to get the pointer to the item we need the item text _without_
860 wxString
path( wxT("<main>/") );
866 //-----------------------------------------------------------------------------
868 //-----------------------------------------------------------------------------
870 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
874 #if (GTK_MINOR_VERSION > 0)
875 m_accel
= gtk_accel_group_new();
876 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
877 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
879 m_menu
= gtk_menu_new(); // Do not show!
882 m_owner
= (GtkWidget
*) NULL
;
884 #if (GTK_MINOR_VERSION > 0)
885 /* Tearoffs are entries, just like separators. So if we want this
886 menu to be a tear-off one, we just append a tearoff entry
888 if(m_style
& wxMENU_TEAROFF
)
890 GtkItemFactoryEntry entry
;
891 entry
.path
= "/tearoff";
892 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
893 entry
.callback_action
= 0;
894 entry
.item_type
= "<Tearoff>";
895 entry
.accelerator
= (gchar
*) NULL
;
896 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
897 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
901 // append the title as the very first entry if we have it
913 gtk_widget_destroy( m_menu
);
915 gtk_object_unref( GTK_OBJECT(m_factory
) );
918 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
922 bool appended
= FALSE
;
924 if ( mitem
->IsSeparator() )
926 #if (GTK_MINOR_VERSION > 0)
927 GtkItemFactoryEntry entry
;
929 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
930 entry
.callback_action
= 0;
931 entry
.item_type
= "<Separator>";
932 entry
.accelerator
= (gchar
*) NULL
;
934 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
936 /* this will be wrong for more than one separator. do we care? */
937 menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
939 menuItem
= gtk_menu_item_new();
940 #endif // GTK 1.2/1.0
942 else if ( mitem
->IsSubMenu() )
944 #if (GTK_MINOR_VERSION > 0)
945 /* text has "_" instead of "&" after mitem->SetText() */
946 wxString
text( mitem
->GetText() );
948 /* local buffer in multibyte form */
951 strcat( buf
, text
.mb_str() );
953 GtkItemFactoryEntry entry
;
955 entry
.callback
= (GtkItemFactoryCallback
) 0;
956 entry
.callback_action
= 0;
957 entry
.item_type
= "<Branch>";
958 entry
.accelerator
= (gchar
*) NULL
;
960 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
962 wxString
path( mitem
->GetFactoryPath() );
963 menuItem
= gtk_item_factory_get_item( m_factory
, path
.mb_str() );
965 menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
966 #endif // GTK 1.2/1.0
968 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
970 // if adding a submenu to a menu already existing in the menu bar, we
971 // must set invoking window to allow processing events from this
973 if ( m_invokingWindow
)
974 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
976 else if (mitem
->GetBitmap().Ok()) // An item with bitmap
978 wxString
text( mitem
->GetText() );
979 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
981 menuItem
= gtk_pixmap_menu_item_new ();
982 GtkWidget
*label
= gtk_accel_label_new (text
.mb_str());
983 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
984 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
985 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), text
.mb_str() );
986 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
987 if (accel_key
!= GDK_VoidSymbol
)
989 gtk_widget_add_accelerator (menuItem
,
991 gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu
)),
995 gtk_widget_show (label
);
997 mitem
->SetLabelWidget(label
);
999 GtkWidget
* pixmap
= gtk_pixmap_new( bitmap
->GetPixmap(), bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
* )NULL
);
1000 gtk_widget_show(pixmap
);
1001 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1003 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1004 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1006 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1007 gtk_widget_show( menuItem
);
1009 appended
= TRUE
; // We've done this, don't do it again
1011 else // a normal item
1013 #if (GTK_MINOR_VERSION > 0)
1014 /* text has "_" instead of "&" after mitem->SetText() */
1015 wxString
text( mitem
->GetText() );
1017 /* local buffer in multibyte form */
1020 strcat( buf
, text
.mb_str() );
1022 GtkItemFactoryEntry entry
;
1024 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
1025 entry
.callback_action
= 0;
1026 if ( mitem
->IsCheckable() )
1027 entry
.item_type
= "<CheckItem>";
1029 entry
.item_type
= "<Item>";
1030 entry
.accelerator
= (gchar
*) NULL
;
1033 // due to an apparent bug in GTK+, we have to use a static buffer here -
1034 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
1036 static char s_accel
[50]; // must be big enougg
1037 wxString
tmp( GetHotKey(*mitem
) );
1038 strncpy(s_accel
, tmp
.mb_str(), WXSIZEOF(s_accel
));
1039 entry
.accelerator
= s_accel
;
1040 #else // !wxUSE_ACCEL
1041 entry
.accelerator
= (char*) NULL
;
1042 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
1044 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
1046 wxString
path( mitem
->GetFactoryPath() );
1047 menuItem
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() );
1049 menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
1050 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
1052 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1053 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1055 #endif // GTK+ 1.2/1.0
1058 if ( !mitem
->IsSeparator() )
1060 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1061 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1064 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1065 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1069 #if GTK_MINOR_VERSION == 0
1072 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1073 gtk_widget_show( menuItem
);
1077 mitem
->SetMenuItem(menuItem
);
1082 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
1084 return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
);
1087 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1089 if ( !wxMenuBase::DoInsert(pos
, item
) )
1093 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
1094 // of version 1.2.6), so we first append the item and then change its
1096 if ( !GtkAppend(item
) )
1099 if ( m_style
& wxMENU_TEAROFF
)
1101 // change the position as the first item is the tear-off marker
1105 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
1106 gpointer data
= g_list_last(menu_shell
->children
)->data
;
1107 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
1108 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
1112 // this should be easy to do...
1113 wxFAIL_MSG( wxT("not implemented") );
1116 #endif // GTK 1.2/1.0
1119 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1121 if ( !wxMenuBase::DoRemove(item
) )
1122 return (wxMenuItem
*)NULL
;
1124 // TODO: this code doesn't delete the item factory item and this seems
1125 // impossible as of GTK 1.2.6.
1126 gtk_widget_destroy( item
->GetMenuItem() );
1131 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1133 wxNode
*node
= m_items
.First();
1136 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1137 if (item
->GetMenuItem() == menuItem
)
1138 return item
->GetId();
1139 node
= node
->Next();
1145 // ----------------------------------------------------------------------------
1147 // ----------------------------------------------------------------------------
1149 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL
1150 static wxString
GetHotKey( const wxMenuItem
& item
)
1154 wxAcceleratorEntry
*accel
= item
.GetAccel();
1157 int flags
= accel
->GetFlags();
1158 if ( flags
& wxACCEL_ALT
)
1159 hotkey
+= wxT("<alt>");
1160 if ( flags
& wxACCEL_CTRL
)
1161 hotkey
+= wxT("<control>");
1162 if ( flags
& wxACCEL_SHIFT
)
1163 hotkey
+= wxT("<shift>");
1165 int code
= accel
->GetKeyCode();
1180 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1183 // GTK seems to use XStringToKeySym here
1184 case WXK_NUMPAD_INSERT
:
1185 hotkey
<< wxT("KP_Insert" );
1187 case WXK_NUMPAD_DELETE
:
1188 hotkey
<< wxT("KP_Delete" );
1191 hotkey
<< wxT("Insert" );
1194 hotkey
<< wxT("Delete" );
1197 // if there are any other keys wxGetAccelFromString() may return,
1198 // we should process them here
1201 if ( wxIsalnum(code
) )
1203 hotkey
<< (wxChar
)code
;
1208 wxFAIL_MSG( wxT("unknown keyboard accel") );
1216 #endif // wxUSE_ACCEL
1219 //-----------------------------------------------------------------------------
1220 // substitute for missing GtkPixmapMenuItem
1221 //-----------------------------------------------------------------------------
1224 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1225 * All rights reserved.
1227 * This file is part of the Gnome Library.
1229 * The Gnome Library is free software; you can redistribute it and/or
1230 * modify it under the terms of the GNU Library General Public License as
1231 * published by the Free Software Foundation; either version 2 of the
1232 * License, or (at your option) any later version.
1234 * The Gnome Library is distributed in the hope that it will be useful,
1235 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1236 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1237 * Library General Public License for more details.
1239 * You should have received a copy of the GNU Library General Public
1240 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1241 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1242 * Boston, MA 02111-1307, USA.
1248 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1250 #include <gtk/gtkaccellabel.h>
1251 #include <gtk/gtksignal.h>
1252 #include <gtk/gtkmenuitem.h>
1253 #include <gtk/gtkmenu.h>
1254 #include <gtk/gtkcontainer.h>
1256 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1257 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1258 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1259 GdkRectangle
*area
);
1260 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1261 GdkEventExpose
*event
);
1263 /* we must override the following functions */
1265 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1266 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1267 GtkAllocation
*allocation
);
1268 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1269 gboolean include_internals
,
1270 GtkCallback callback
,
1271 gpointer callback_data
);
1272 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1273 GtkRequisition
*requisition
);
1274 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1277 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1279 static GtkMenuItemClass
*parent_class
= NULL
;
1281 #define BORDER_SPACING 3
1282 #define PMAP_WIDTH 20
1285 gtk_pixmap_menu_item_get_type (void)
1287 static GtkType pixmap_menu_item_type
= 0;
1289 if (!pixmap_menu_item_type
)
1291 GtkTypeInfo pixmap_menu_item_info
=
1293 "GtkPixmapMenuItem",
1294 sizeof (GtkPixmapMenuItem
),
1295 sizeof (GtkPixmapMenuItemClass
),
1296 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1297 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1298 /* reserved_1 */ NULL
,
1299 /* reserved_2 */ NULL
,
1300 (GtkClassInitFunc
) NULL
,
1303 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1304 &pixmap_menu_item_info
);
1307 return pixmap_menu_item_type
;
1311 * gtk_pixmap_menu_item_new
1313 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1314 * to set the pixmap wich is displayed at the left side.
1317 * &GtkWidget pointer to new menu item
1321 gtk_pixmap_menu_item_new (void)
1323 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1327 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1329 GtkObjectClass
*object_class
;
1330 GtkWidgetClass
*widget_class
;
1331 GtkMenuItemClass
*menu_item_class
;
1332 GtkContainerClass
*container_class
;
1334 object_class
= (GtkObjectClass
*) klass
;
1335 widget_class
= (GtkWidgetClass
*) klass
;
1336 menu_item_class
= (GtkMenuItemClass
*) klass
;
1337 container_class
= (GtkContainerClass
*) klass
;
1339 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1341 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1342 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1343 widget_class
->map
= gtk_pixmap_menu_item_map
;
1344 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1345 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1347 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1348 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1350 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1351 klass
->have_pixmap_count
= 0;
1355 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1359 mi
= GTK_MENU_ITEM (menu_item
);
1361 menu_item
->pixmap
= NULL
;
1365 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1368 g_return_if_fail (widget
!= NULL
);
1369 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1370 g_return_if_fail (area
!= NULL
);
1372 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1373 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1375 if (GTK_WIDGET_DRAWABLE (widget
) &&
1376 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1377 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1382 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1383 GdkEventExpose
*event
)
1385 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1386 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1387 g_return_val_if_fail (event
!= NULL
, FALSE
);
1389 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1390 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1392 if (GTK_WIDGET_DRAWABLE (widget
) &&
1393 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1394 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1401 * gtk_pixmap_menu_item_set_pixmap
1402 * @menu_item: Pointer to the pixmap menu item
1403 * @pixmap: Pointer to a pixmap widget
1405 * Set the pixmap of the menu item.
1410 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1413 g_return_if_fail (menu_item
!= NULL
);
1414 g_return_if_fail (pixmap
!= NULL
);
1415 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1416 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1417 g_return_if_fail (menu_item
->pixmap
== NULL
);
1419 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1420 menu_item
->pixmap
= pixmap
;
1422 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1423 !GTK_WIDGET_REALIZED (pixmap
))
1424 gtk_widget_realize (pixmap
);
1426 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1427 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1428 GTK_WIDGET_VISIBLE(pixmap
) &&
1429 !GTK_WIDGET_MAPPED (pixmap
))
1430 gtk_widget_map (pixmap
);
1433 changed_have_pixmap_status(menu_item
);
1435 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1436 gtk_widget_queue_resize (pixmap
);
1440 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1442 GtkPixmapMenuItem
*menu_item
;
1444 g_return_if_fail (widget
!= NULL
);
1445 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1447 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1449 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1451 if (menu_item
->pixmap
&&
1452 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1453 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1454 gtk_widget_map (menu_item
->pixmap
);
1458 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1459 GtkAllocation
*allocation
)
1461 GtkPixmapMenuItem
*pmenu_item
;
1463 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1465 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1467 GtkAllocation child_allocation
;
1470 border_width
= GTK_CONTAINER (widget
)->border_width
;
1472 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1473 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1474 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1475 child_allocation
.y
= (border_width
+ BORDER_SPACING
1476 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1477 / 2)); /* center pixmaps vertically */
1478 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1481 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1482 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1486 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1487 gboolean include_internals
,
1488 GtkCallback callback
,
1489 gpointer callback_data
)
1491 GtkPixmapMenuItem
*menu_item
;
1493 g_return_if_fail (container
!= NULL
);
1494 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1495 g_return_if_fail (callback
!= NULL
);
1497 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1499 if (menu_item
->pixmap
)
1500 (* callback
) (menu_item
->pixmap
, callback_data
);
1502 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1503 callback
,callback_data
);
1507 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1508 GtkRequisition
*requisition
)
1510 GtkPixmapMenuItem
*menu_item
;
1511 GtkRequisition req
= {0, 0};
1513 g_return_if_fail (widget
!= NULL
);
1514 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1515 g_return_if_fail (requisition
!= NULL
);
1517 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1519 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1521 if (menu_item
->pixmap
)
1522 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1524 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1525 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1529 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1533 gboolean widget_was_visible
;
1535 g_return_if_fail (container
!= NULL
);
1536 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1537 g_return_if_fail (child
!= NULL
);
1538 g_return_if_fail (GTK_IS_WIDGET (child
));
1540 bin
= GTK_BIN (container
);
1541 g_return_if_fail ((bin
->child
== child
||
1542 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1544 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1546 gtk_widget_unparent (child
);
1547 if (bin
->child
== child
)
1550 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1551 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1554 if (widget_was_visible
)
1555 gtk_widget_queue_resize (GTK_WIDGET (container
));
1559 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1561 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1563 if (menu_item
->pixmap
!= NULL
) {
1564 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1566 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1567 /* Install pixmap toggle size */
1568 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1571 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1573 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1574 /* Install normal toggle size */
1575 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1579 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1580 whenever the klass->toggle_size changes; but by doing it anytime
1581 this function is called, we get the same effect, just because of
1582 how the preferences option to show pixmaps works. Bogus, broken.
1584 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1585 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));