]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/menu.cpp
64 bit clean implementation
[wxWidgets.git] / src / gtk / menu.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
88a7a4e1 2// Name: src/gtk/menu.cpp
28fcfbfe 3// Purpose: implementation of wxMenuBar and wxMenu classes for wxGTK
c801d85f 4// Author: Robert Roebling
96fd301f 5// Id: $Id$
a81258be 6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
28fcfbfe
VZ
13#if wxUSE_MENUS
14
e1bf3ad3 15#include "wx/menu.h"
88a7a4e1
WS
16
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
e4db172a 19 #include "wx/log.h"
d281df50 20 #include "wx/frame.h"
0bca0373 21 #include "wx/bitmap.h"
7d02e0d6 22 #include "wx/app.h"
88a7a4e1
WS
23#endif
24
d281df50 25#include "wx/accel.h"
ab73fe8d 26#include "wx/stockitem.h"
9e691f46 27#include "wx/gtk/private.h"
b1f17bf0 28#include "wx/gtk/private/mnemonics.h"
9e691f46 29
9e691f46 30// FIXME: is this right? somehow I don't think so (VZ)
0d2c4443
PC
31
32#define gtk_accel_group_attach(g, o) gtk_window_add_accel_group((o), (g))
05b743ba 33#define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g))
0d2c4443
PC
34//#define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m)
35
36#define ACCEL_OBJECT GtkWindow
37#define ACCEL_OBJECTS(a) (a)->acceleratables
38#define ACCEL_OBJ_CAST(obj) ((GtkWindow*) obj)
83624f79 39
9959e2b6
VZ
40// we use normal item but with a special id for the menu title
41static const int wxGTK_TITLE_ID = -3;
42
5e6f2fe9
VZ
43// forward declare it as it's used by wxMenuBar too when using Hildon
44extern "C"
45{
46 static void gtk_menu_clicked_callback(GtkWidget *widget, wxMenu *menu);
47}
6c76d1ce 48
acfd422a
RR
49//-----------------------------------------------------------------------------
50// idle system
51//-----------------------------------------------------------------------------
52
6d971354 53#if wxUSE_ACCEL
98f29783 54static wxString GetGtkHotKey( const wxMenuItem& item );
717a57c2
VZ
55#endif
56
e6396ed4
JS
57//-----------------------------------------------------------------------------
58// activate message from GTK
59//-----------------------------------------------------------------------------
60
cdf003d4 61static void DoCommonMenuCallbackCode(wxMenu *menu, wxMenuEvent& event)
e6396ed4 62{
e6396ed4
JS
63 event.SetEventObject( menu );
64
a01fe3d6
RD
65 wxEvtHandler* handler = menu->GetEventHandler();
66 if (handler && handler->ProcessEvent(event))
e6396ed4
JS
67 return;
68
69 wxWindow *win = menu->GetInvokingWindow();
cdf003d4
VZ
70 if (win)
71 win->GetEventHandler()->ProcessEvent( event );
72}
73
74extern "C" {
75
e4161a2a
VZ
76static void
77gtk_menu_open_callback(GtkWidget * WXUNUSED(widget), wxMenu *menu)
cdf003d4
VZ
78{
79 wxMenuEvent event(wxEVT_MENU_OPEN, -1, menu);
80
81 DoCommonMenuCallbackCode(menu, event);
82}
83
e4161a2a
VZ
84static void
85gtk_menu_close_callback(GtkWidget * WXUNUSED(widget), wxMenuBar *menubar)
cdf003d4 86{
13d35112
VZ
87 if ( !menubar->GetMenuCount() )
88 {
89 // if menubar is empty we can't call GetMenu(0) below
90 return;
91 }
cdf003d4 92
13d35112
VZ
93 wxMenuEvent event( wxEVT_MENU_CLOSE, -1, NULL );
94
95 DoCommonMenuCallbackCode(menubar->GetMenu(0), event);
e6396ed4 96}
cdf003d4 97
865bb325 98}
e6396ed4 99
c801d85f
KB
100//-----------------------------------------------------------------------------
101// wxMenuBar
102//-----------------------------------------------------------------------------
103
104IMPLEMENT_DYNAMIC_CLASS(wxMenuBar,wxWindow)
105
294ea16d 106void wxMenuBar::Init(size_t n, wxMenu *menus[], const wxString titles[], long style)
3502e687 107{
ae53c98c 108 m_style = style;
e8375af8 109 m_invokingWindow = NULL;
23280650 110
e2f3bc41
VZ
111#if wxUSE_LIBHILDON
112 // Hildon window uses a single menu instead of a menu bar, so wxMenuBar is
113 // the same as menu in this case
114 m_widget =
115 m_menubar = gtk_menu_new();
116#else // !wxUSE_LIBHILDON
e8375af8
VZ
117 if (!PreCreation( NULL, wxDefaultPosition, wxDefaultSize ) ||
118 !CreateBase( NULL, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("menubar") ))
4dcaf11a 119 {
223d09f6 120 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
455fadaa 121 return;
4dcaf11a 122 }
3502e687 123
3502e687
RR
124 m_menubar = gtk_menu_bar_new();
125
126 if (style & wxMB_DOCKABLE)
127 {
128 m_widget = gtk_handle_box_new();
10bd1f7d
PC
129 gtk_container_add(GTK_CONTAINER(m_widget), m_menubar);
130 gtk_widget_show(m_menubar);
3502e687
RR
131 }
132 else
133 {
10bd1f7d 134 m_widget = m_menubar;
3502e687
RR
135 }
136
137 PostCreation();
c4608a8a 138
db434467 139 ApplyWidgetStyle();
e2f3bc41 140#endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON
294ea16d
VZ
141
142 for (size_t i = 0; i < n; ++i )
143 Append(menus[i], titles[i]);
13d35112
VZ
144
145 // VZ: for some reason connecting to menus "deactivate" doesn't work (we
146 // don't get it when the menu is dismissed by clicking outside the
147 // toolbar) so we connect to the global one, even if it means that we
148 // can't pass the menu which was closed in wxMenuEvent object
9fa72bd2
MR
149 g_signal_connect (m_menubar, "deactivate",
150 G_CALLBACK (gtk_menu_close_callback), this);
3502e687
RR
151}
152
294ea16d 153wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxString titles[], long style)
c801d85f 154{
294ea16d
VZ
155 Init(n, menus, titles, style);
156}
96fd301f 157
294ea16d
VZ
158wxMenuBar::wxMenuBar(long style)
159{
160 Init(0, NULL, NULL, style);
161}
c4608a8a 162
294ea16d
VZ
163wxMenuBar::wxMenuBar()
164{
165 Init(0, NULL, NULL, 0);
6de97a3b 166}
c801d85f 167
1e133b7d
RR
168wxMenuBar::~wxMenuBar()
169{
1e133b7d
RR
170}
171
5bd9e519
RR
172static void wxMenubarUnsetInvokingWindow( wxMenu *menu, wxWindow *win )
173{
174 menu->SetInvokingWindow( (wxWindow*) NULL );
175
5bd9e519 176 wxWindow *top_frame = win;
8487f887 177 while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
bd77da97 178 top_frame = top_frame->GetParent();
5bd9e519 179
05b743ba
RR
180 // support for native hot keys
181 ACCEL_OBJECT *obj = ACCEL_OBJ_CAST(top_frame->m_widget);
182 if ( menu->m_accel && g_slist_find( ACCEL_OBJECTS(menu->m_accel), obj ) )
183 gtk_accel_group_detach( menu->m_accel, obj );
184
222ed1d6 185 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
5bd9e519
RR
186 while (node)
187 {
1987af7e 188 wxMenuItem *menuitem = node->GetData();
5bd9e519
RR
189 if (menuitem->IsSubMenu())
190 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu(), win );
1987af7e 191 node = node->GetNext();
5bd9e519
RR
192 }
193}
194
195static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
196{
197 menu->SetInvokingWindow( win );
198
5bd9e519 199 wxWindow *top_frame = win;
8487f887 200 while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
bd77da97 201 top_frame = top_frame->GetParent();
5bd9e519 202
6d971354 203 // support for native hot keys
9e691f46
VZ
204 ACCEL_OBJECT *obj = ACCEL_OBJ_CAST(top_frame->m_widget);
205 if ( !g_slist_find( ACCEL_OBJECTS(menu->m_accel), obj ) )
b4da05a6 206 gtk_accel_group_attach( menu->m_accel, obj );
5bd9e519 207
222ed1d6 208 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
5bd9e519
RR
209 while (node)
210 {
1987af7e 211 wxMenuItem *menuitem = node->GetData();
5bd9e519
RR
212 if (menuitem->IsSubMenu())
213 wxMenubarSetInvokingWindow( menuitem->GetSubMenu(), win );
1987af7e 214 node = node->GetNext();
5bd9e519
RR
215 }
216}
217
218void wxMenuBar::SetInvokingWindow( wxWindow *win )
219{
9c884972 220 m_invokingWindow = win;
5bd9e519 221 wxWindow *top_frame = win;
8487f887 222 while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
bd77da97 223 top_frame = top_frame->GetParent();
5bd9e519 224
222ed1d6 225 wxMenuList::compatibility_iterator node = m_menus.GetFirst();
5bd9e519
RR
226 while (node)
227 {
1987af7e 228 wxMenu *menu = node->GetData();
5bd9e519 229 wxMenubarSetInvokingWindow( menu, win );
1987af7e 230 node = node->GetNext();
5bd9e519
RR
231 }
232}
233
978af864
VZ
234void wxMenuBar::SetLayoutDirection(wxLayoutDirection dir)
235{
236 if ( dir == wxLayout_Default )
237 {
238 const wxWindow *const frame = GetFrame();
239 if ( frame )
240 {
241 // inherit layout from frame.
242 dir = frame->GetLayoutDirection();
243 }
244 else // use global layout
245 {
246 dir = wxTheApp->GetLayoutDirection();
247 }
248 }
249
250 if ( dir == wxLayout_Default )
251 return;
252
253 GTKSetLayout(m_menubar, dir);
254
255 // also set the layout of all menus we already have (new ones will inherit
256 // the current layout)
257 for ( wxMenuList::compatibility_iterator node = m_menus.GetFirst();
258 node;
259 node = node->GetNext() )
260 {
261 wxMenu *const menu = node->GetData();
262 menu->SetLayoutDirection(dir);
263 }
264}
265
266wxLayoutDirection wxMenuBar::GetLayoutDirection() const
267{
268 return GTKGetLayout(m_menubar);
269}
270
271void wxMenuBar::Attach(wxFrame *frame)
272{
273 wxMenuBarBase::Attach(frame);
274
275 SetLayoutDirection(wxLayout_Default);
276}
277
5bd9e519
RR
278void wxMenuBar::UnsetInvokingWindow( wxWindow *win )
279{
9c884972 280 m_invokingWindow = (wxWindow*) NULL;
5bd9e519 281 wxWindow *top_frame = win;
8487f887 282 while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
bd77da97 283 top_frame = top_frame->GetParent();
9959e2b6 284
222ed1d6 285 wxMenuList::compatibility_iterator node = m_menus.GetFirst();
5bd9e519
RR
286 while (node)
287 {
1987af7e 288 wxMenu *menu = node->GetData();
5bd9e519 289 wxMenubarUnsetInvokingWindow( menu, win );
1987af7e 290 node = node->GetNext();
5bd9e519
RR
291 }
292}
293
3dfac970 294bool wxMenuBar::Append( wxMenu *menu, const wxString &title )
c801d85f 295{
f03ec224 296 if ( !wxMenuBarBase::Append( menu, title ) )
670f9935 297 return false;
f03ec224
VZ
298
299 return GtkAppend(menu, title);
300}
23280650 301
49826dab 302bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title, int pos)
f03ec224 303{
6c76d1ce 304 menu->SetLayoutDirection(GetLayoutDirection());
1e133b7d 305
6c76d1ce
VZ
306#if wxUSE_LIBHILDON
307 // if the menu has only one item, append it directly to the top level menu
308 // instead of inserting a useless submenu
309 if ( menu->GetMenuItemCount() == 1 )
310 {
311 wxMenuItem * const item = menu->FindItemByPosition(0);
23280650 312
6c76d1ce
VZ
313 // remove both mnemonics and accelerator: neither is useful under Maemo
314 const wxString str(wxStripMenuCodes(item->GetItemLabel()));
96fd301f 315
6c76d1ce
VZ
316 if ( item->IsSubMenu() )
317 return GtkAppend(item->GetSubMenu(), str, pos);
318
319 menu->m_owner = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str ) );
9959e2b6 320
6c76d1ce
VZ
321 g_signal_connect(menu->m_owner, "activate",
322 G_CALLBACK(gtk_menu_clicked_callback), menu);
323 item->SetMenuItem(menu->m_owner);
324 }
325 else
326#endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON
327 {
328 const wxString str(wxConvertMnemonicsToGTK(title));
329
330 // This doesn't have much effect right now.
331 menu->SetTitle( str );
332
333 // The "m_owner" is the "menu item"
334 menu->m_owner = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str ) );
335
336 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu->m_owner), menu->m_menu );
337 }
338
339 gtk_widget_show( menu->m_owner );
9959e2b6 340
49826dab
RD
341 if (pos == -1)
342 gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar), menu->m_owner );
343 else
344 gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar), menu->m_owner, pos );
9959e2b6 345
9fa72bd2
MR
346 g_signal_connect (menu->m_owner, "activate",
347 G_CALLBACK (gtk_menu_open_callback),
348 menu);
e6396ed4 349
9c884972 350 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
2b5f62a0 351 // addings menu later on.
9c884972
RR
352 if (m_invokingWindow)
353 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
3dfac970 354
670f9935 355 return true;
3dfac970
VZ
356}
357
358bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
359{
360 if ( !wxMenuBarBase::Insert(pos, menu, title) )
670f9935 361 return false;
3dfac970 362
6d971354 363 // TODO
9959e2b6 364
49826dab 365 if ( !GtkAppend(menu, title, (int)pos) )
670f9935 366 return false;
f03ec224 367
670f9935 368 return true;
3dfac970
VZ
369}
370
371wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
372{
f03ec224
VZ
373 // remove the old item and insert a new one
374 wxMenu *menuOld = Remove(pos);
375 if ( menuOld && !Insert(pos, menu, title) )
376 {
1d62a8b4 377 return (wxMenu*) NULL;
f03ec224 378 }
3dfac970 379
f03ec224
VZ
380 // either Insert() succeeded or Remove() failed and menuOld is NULL
381 return menuOld;
3dfac970
VZ
382}
383
384wxMenu *wxMenuBar::Remove(size_t pos)
385{
f03ec224
VZ
386 wxMenu *menu = wxMenuBarBase::Remove(pos);
387 if ( !menu )
1d62a8b4 388 return (wxMenu*) NULL;
f03ec224 389
defc0789
VS
390 gtk_menu_item_remove_submenu( GTK_MENU_ITEM(menu->m_owner) );
391 gtk_container_remove(GTK_CONTAINER(m_menubar), menu->m_owner);
c4608a8a 392
1d62a8b4 393 gtk_widget_destroy( menu->m_owner );
defc0789 394 menu->m_owner = NULL;
c4608a8a 395
2b5f62a0 396 if (m_invokingWindow)
05b743ba 397 wxMenubarUnsetInvokingWindow( menu, m_invokingWindow );
e4161a2a 398
1d62a8b4 399 return menu;
6de97a3b 400}
96fd301f 401
716b7364 402static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString, const wxString &itemString )
c801d85f 403{
b1f17bf0 404 if (wxMenuItem::GetLabelText(wxConvertMnemonicsFromGTK(menu->GetTitle())) == wxMenuItem::GetLabelText(menuString))
83624f79
RR
405 {
406 int res = menu->FindItem( itemString );
c626a8b7
VZ
407 if (res != wxNOT_FOUND)
408 return res;
83624f79 409 }
c626a8b7 410
222ed1d6 411 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
83624f79
RR
412 while (node)
413 {
1987af7e 414 wxMenuItem *item = node->GetData();
83624f79
RR
415 if (item->IsSubMenu())
416 return FindMenuItemRecursive(item->GetSubMenu(), menuString, itemString);
2b1c162e 417
1987af7e 418 node = node->GetNext();
83624f79
RR
419 }
420
c626a8b7
VZ
421 return wxNOT_FOUND;
422}
423
c801d85f
KB
424int wxMenuBar::FindMenuItem( const wxString &menuString, const wxString &itemString ) const
425{
222ed1d6 426 wxMenuList::compatibility_iterator node = m_menus.GetFirst();
83624f79
RR
427 while (node)
428 {
1987af7e 429 wxMenu *menu = node->GetData();
83624f79 430 int res = FindMenuItemRecursive( menu, menuString, itemString);
1987af7e
VZ
431 if (res != -1)
432 return res;
433 node = node->GetNext();
83624f79 434 }
1987af7e
VZ
435
436 return wxNOT_FOUND;
6de97a3b 437}
c801d85f 438
c626a8b7 439// Find a wxMenuItem using its id. Recurses down into sub-menus
96fd301f 440static wxMenuItem* FindMenuItemByIdRecursive(const wxMenu* menu, int id)
716b7364 441{
717a57c2 442 wxMenuItem* result = menu->FindChildItem(id);
716b7364 443
222ed1d6 444 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
c626a8b7 445 while ( node && result == NULL )
83624f79 446 {
1987af7e 447 wxMenuItem *item = node->GetData();
83624f79 448 if (item->IsSubMenu())
c626a8b7 449 {
83624f79 450 result = FindMenuItemByIdRecursive( item->GetSubMenu(), id );
c626a8b7 451 }
1987af7e 452 node = node->GetNext();
83624f79 453 }
96fd301f 454
83624f79 455 return result;
6de97a3b 456}
716b7364 457
3dfac970 458wxMenuItem* wxMenuBar::FindItem( int id, wxMenu **menuForItem ) const
716b7364 459{
83624f79 460 wxMenuItem* result = 0;
222ed1d6 461 wxMenuList::compatibility_iterator node = m_menus.GetFirst();
83624f79
RR
462 while (node && result == 0)
463 {
1987af7e 464 wxMenu *menu = node->GetData();
83624f79 465 result = FindMenuItemByIdRecursive( menu, id );
1987af7e 466 node = node->GetNext();
83624f79 467 }
c626a8b7 468
3dfac970
VZ
469 if ( menuForItem )
470 {
471 *menuForItem = result ? result->GetMenu() : (wxMenu *)NULL;
472 }
c626a8b7 473
3dfac970 474 return result;
bbe0af5b
RR
475}
476
3dfac970 477void wxMenuBar::EnableTop( size_t pos, bool flag )
bbe0af5b 478{
222ed1d6 479 wxMenuList::compatibility_iterator node = m_menus.Item( pos );
c626a8b7 480
223d09f6 481 wxCHECK_RET( node, wxT("menu not found") );
c626a8b7 482
3dfac970 483 wxMenu* menu = node->GetData();
c626a8b7
VZ
484
485 if (menu->m_owner)
486 gtk_widget_set_sensitive( menu->m_owner, flag );
bbe0af5b
RR
487}
488
52af3158 489wxString wxMenuBar::GetMenuLabel( size_t pos ) const
bbe0af5b 490{
222ed1d6 491 wxMenuList::compatibility_iterator node = m_menus.Item( pos );
c626a8b7 492
223d09f6 493 wxCHECK_MSG( node, wxT("invalid"), wxT("menu not found") );
c626a8b7 494
3dfac970 495 wxMenu* menu = node->GetData();
c626a8b7 496
b1f17bf0 497 return wxConvertMnemonicsFromGTK(menu->GetTitle());
bbe0af5b
RR
498}
499
52af3158 500void wxMenuBar::SetMenuLabel( size_t pos, const wxString& label )
bbe0af5b 501{
222ed1d6 502 wxMenuList::compatibility_iterator node = m_menus.Item( pos );
c626a8b7 503
223d09f6 504 wxCHECK_RET( node, wxT("menu not found") );
c626a8b7 505
3dfac970 506 wxMenu* menu = node->GetData();
c626a8b7 507
b1f17bf0 508 const wxString str(wxConvertMnemonicsToGTK(label));
f6bcfd97
BP
509
510 menu->SetTitle( str );
511
512 if (menu->m_owner)
8394218c 513 gtk_label_set_text_with_mnemonic( GTK_LABEL( GTK_BIN(menu->m_owner)->child), wxGTK_CONV(str) );
bbe0af5b
RR
514}
515
c801d85f 516//-----------------------------------------------------------------------------
cf7a7e13 517// "activate"
c801d85f
KB
518//-----------------------------------------------------------------------------
519
865bb325 520extern "C" {
6de97a3b 521static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu )
c801d85f 522{
83624f79 523 int id = menu->FindMenuIdByMenuItem(widget);
96fd301f 524
83624f79 525 /* should find it for normal (not popup) menu */
1e6feb95
VZ
526 wxASSERT_MSG( (id != -1) || (menu->GetInvokingWindow() != NULL),
527 _T("menu item not found in gtk_menu_clicked_callback") );
96fd301f 528
c626a8b7
VZ
529 if (!menu->IsEnabled(id))
530 return;
96fd301f 531
4e6beae5
RD
532 wxMenuItem* item = menu->FindChildItem( id );
533 wxCHECK_RET( item, wxT("error in menu item callback") );
534
9959e2b6
VZ
535 if ( item->GetId() == wxGTK_TITLE_ID )
536 {
537 // ignore events from the menu title
538 return;
539 }
540
4e6beae5
RD
541 if (item->IsCheckable())
542 {
543 bool isReallyChecked = item->IsChecked(),
544 isInternallyChecked = item->wxMenuItemBase::IsChecked();
545
546 // ensure that the internal state is always consistent with what is
547 // shown on the screen
548 item->wxMenuItemBase::Check(isReallyChecked);
549
550 // we must not report the events for the radio button going up nor the
551 // events resulting from the calls to wxMenuItem::Check()
552 if ( (item->GetKind() == wxITEM_RADIO && !isReallyChecked) ||
553 (isInternallyChecked == isReallyChecked) )
554 {
555 return;
556 }
557 }
558
559
02822c8c
RD
560 // Is this menu on a menubar? (possibly nested)
561 wxFrame* frame = NULL;
6edf1107
DE
562 if(menu->IsAttached())
563 frame = menu->GetMenuBar()->GetFrame();
02822c8c 564
da0b5338
VZ
565 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
566 // normally wxMenu::SendEvent() should be enough, if it doesn't work
567 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
568 // should be fixed instead of working around it here...
02822c8c 569 if (frame)
2d17d68f 570 {
4e6beae5
RD
571 // If it is attached then let the frame send the event.
572 // Don't call frame->ProcessCommand(id) because it toggles
573 // checkable items and we've already done that above.
574 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
575 commandEvent.SetEventObject(frame);
576 if (item->IsCheckable())
577 commandEvent.SetInt(item->IsChecked());
578
579 frame->GetEventHandler()->ProcessEvent(commandEvent);
a01fe3d6
RD
580 }
581 else
582 {
4e6beae5 583 // otherwise let the menu have it
a01fe3d6 584 menu->SendEvent(id, item->IsCheckable() ? item->IsChecked() : -1);
2d17d68f 585 }
cf7a7e13 586}
865bb325 587}
cf7a7e13
RR
588
589//-----------------------------------------------------------------------------
590// "select"
591//-----------------------------------------------------------------------------
592
865bb325 593extern "C" {
cf7a7e13
RR
594static void gtk_menu_hilight_callback( GtkWidget *widget, wxMenu *menu )
595{
83624f79
RR
596 int id = menu->FindMenuIdByMenuItem(widget);
597
598 wxASSERT( id != -1 ); // should find it!
cf7a7e13 599
c626a8b7
VZ
600 if (!menu->IsEnabled(id))
601 return;
cf7a7e13 602
342b6a2f 603 wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, id );
83624f79 604 event.SetEventObject( menu );
cf7a7e13 605
a01fe3d6
RD
606 wxEvtHandler* handler = menu->GetEventHandler();
607 if (handler && handler->ProcessEvent(event))
c626a8b7 608 return;
6de97a3b 609
83624f79
RR
610 wxWindow *win = menu->GetInvokingWindow();
611 if (win) win->GetEventHandler()->ProcessEvent( event );
6de97a3b 612}
865bb325 613}
c801d85f 614
cd743a6f
RR
615//-----------------------------------------------------------------------------
616// "deselect"
617//-----------------------------------------------------------------------------
618
865bb325 619extern "C" {
cd743a6f
RR
620static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu )
621{
622 int id = menu->FindMenuIdByMenuItem(widget);
623
624 wxASSERT( id != -1 ); // should find it!
625
c626a8b7
VZ
626 if (!menu->IsEnabled(id))
627 return;
cd743a6f
RR
628
629 wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, -1 );
630 event.SetEventObject( menu );
631
a01fe3d6
RD
632 wxEvtHandler* handler = menu->GetEventHandler();
633 if (handler && handler->ProcessEvent(event))
c626a8b7 634 return;
cd743a6f
RR
635
636 wxWindow *win = menu->GetInvokingWindow();
c626a8b7
VZ
637 if (win)
638 win->GetEventHandler()->ProcessEvent( event );
cd743a6f 639}
865bb325 640}
cd743a6f 641
cf7a7e13 642//-----------------------------------------------------------------------------
db1b4961 643// wxMenuItem
cf7a7e13
RR
644//-----------------------------------------------------------------------------
645
7dbf5360 646IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
974e8d94
VZ
647
648wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
649 int id,
650 const wxString& name,
651 const wxString& help,
d65c269b 652 wxItemKind kind,
974e8d94
VZ
653 wxMenu *subMenu)
654{
d65c269b 655 return new wxMenuItem(parentMenu, id, name, help, kind, subMenu);
974e8d94 656}
96fd301f 657
974e8d94
VZ
658wxMenuItem::wxMenuItem(wxMenu *parentMenu,
659 int id,
660 const wxString& text,
661 const wxString& help,
d65c269b 662 wxItemKind kind,
974e8d94 663 wxMenu *subMenu)
d65c269b 664 : wxMenuItemBase(parentMenu, id, text, help, kind, subMenu)
2368dcda 665{
092f7536 666 Init(text);
2368dcda
VZ
667}
668
669wxMenuItem::wxMenuItem(wxMenu *parentMenu,
670 int id,
671 const wxString& text,
672 const wxString& help,
673 bool isCheckable,
674 wxMenu *subMenu)
675 : wxMenuItemBase(parentMenu, id, text, help,
676 isCheckable ? wxITEM_CHECK : wxITEM_NORMAL, subMenu)
677{
092f7536 678 Init(text);
2368dcda
VZ
679}
680
092f7536 681void wxMenuItem::Init(const wxString& text)
c801d85f 682{
37d403aa 683 m_labelWidget = (GtkWidget *) NULL;
83624f79 684 m_menuItem = (GtkWidget *) NULL;
974e8d94 685
092f7536 686 DoSetText(text);
6de97a3b 687}
c801d85f 688
d1b15f03
RR
689wxMenuItem::~wxMenuItem()
690{
691 // don't delete menu items, the menus take care of that
692}
693
717a57c2 694// return the menu item text without any menu accels
3b59cdbf 695/* static */
52af3158 696
52af3158 697wxString wxMenuItemBase::GetLabelText(const wxString& text)
717a57c2 698{
52af3158
JS
699 // The argument to this function will now always be in wxWidgets standard label
700 // format, not GTK+ format, so we do what the other ports do.
701
702 return wxStripMenuCodes(text);
703
704#if 0
717a57c2 705 wxString label;
2368dcda 706
3b59cdbf 707 for ( const wxChar *pc = text.c_str(); *pc; pc++ )
717a57c2 708 {
f0b72e0d
RR
709 if ( *pc == wxT('\t'))
710 break;
9959e2b6 711
7cf4f7e2 712 if ( *pc == wxT('_') )
717a57c2 713 {
2b5f62a0 714 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
d76419bd
RR
715 pc++;
716 label += *pc;
717 continue;
718 }
2368dcda 719
2b5f62a0 720 if ( *pc == wxT('\\') )
d76419bd 721 {
2b5f62a0
VZ
722 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
723 pc++;
724 label += *pc;
717a57c2
VZ
725 continue;
726 }
727
7cf4f7e2
GD
728 if ( (*pc == wxT('&')) && (*(pc+1) != wxT('&')) )
729 {
730 // wxMSW escapes "&"
731 // "&" is doubled to indicate "&" instead of accelerator
732 continue;
733 }
a01fe3d6 734
717a57c2
VZ
735 label += *pc;
736 }
a01fe3d6 737
52af3158 738 // wxPrintf( wxT("GetLabelText(): text %s label %s\n"), text.c_str(), label.c_str() );
d9e403cc 739
717a57c2 740 return label;
52af3158 741#endif
717a57c2
VZ
742}
743
52af3158
JS
744wxString wxMenuItem::GetItemLabel() const
745{
b1f17bf0 746 wxString label = wxConvertMnemonicsFromGTK(m_text);
a738f87c 747 if (!m_hotKey.IsEmpty())
b1f17bf0 748 label << "\t" << m_hotKey;
a738f87c 749 return label;
52af3158
JS
750}
751
752void wxMenuItem::SetItemLabel( const wxString& str )
717a57c2 753{
ee0a94cf
RR
754 // cache some data which must be used later
755 bool isstock = wxIsStockID(GetId());
756 const char *stockid = NULL;
757 if (isstock)
758 stockid = wxGetStockGtkID(GetId());
759
5869f93f
JS
760 // Some optimization to avoid flicker
761 wxString oldLabel = m_text;
98f29783 762 oldLabel = wxStripMenuCodes(oldLabel);
5869f93f 763 oldLabel.Replace(wxT("_"), wxT(""));
98f29783 764 wxString label1 = wxStripMenuCodes(str);
6c309653 765#if wxUSE_ACCEL
a8e607d9 766 wxString oldhotkey = GetHotKey(); // Store the old hotkey in Ctrl-foo format
5f11fef5 767 wxCharBuffer oldbuf = wxGTK_CONV_SYS( GetGtkHotKey(*this) ); // and as <control>foo
6c309653 768#endif // wxUSE_ACCEL
a01fe3d6 769
717a57c2 770 DoSetText(str);
354aa1e3 771
6c309653 772#if wxUSE_ACCEL
88d19775 773 if (oldLabel == label1 &&
ee0a94cf 774 oldhotkey == GetHotKey()) // Make sure we can change a hotkey even if the label is unaltered
98f29783
RR
775 return;
776
354aa1e3
RR
777 if (m_menuItem)
778 {
37d403aa
JS
779 GtkLabel *label;
780 if (m_labelWidget)
2b5f62a0 781 label = (GtkLabel*) m_labelWidget;
37d403aa 782 else
2b5f62a0 783 label = GTK_LABEL( GTK_BIN(m_menuItem)->child );
717a57c2 784
ee0a94cf
RR
785 // stock menu items can have empty labels:
786 wxString text = m_text;
787 if (text.IsEmpty() && !IsSeparator())
788 {
789 wxASSERT_MSG(isstock, wxT("A non-stock menu item with an empty label?"));
790 text = wxGetStockLabel(GetId());
791
792 // need & => _ conversion
793 text = GTKProcessMenuItemLabel(text, NULL);
794 }
795
796 gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV_SYS(text) );
354aa1e3 797 }
98f29783 798
ee0a94cf 799 // remove old accelerator from our parent's accelerator group, if present
98f29783
RR
800 guint accel_key;
801 GdkModifierType accel_mods;
ee0a94cf 802 if (oldbuf[(size_t)0] != '\0')
98f29783 803 {
ee0a94cf
RR
804 gtk_accelerator_parse( (const char*) oldbuf, &accel_key, &accel_mods);
805 if (accel_key != 0)
806 {
10bd1f7d 807 gtk_widget_remove_accelerator(m_menuItem,
ee0a94cf
RR
808 m_parentMenu->m_accel,
809 accel_key,
810 accel_mods );
811 }
812 }
813 else if (isstock)
814 {
815 // if the accelerator was taken from a stock ID, just get it back from GTK+ stock
816 if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key))
10bd1f7d 817 gtk_widget_remove_accelerator( m_menuItem,
ee0a94cf
RR
818 m_parentMenu->m_accel,
819 accel_key,
820 accel_mods );
98f29783
RR
821 }
822
ee0a94cf 823 // add new accelerator to our parent's accelerator group
5f11fef5 824 wxCharBuffer buf = wxGTK_CONV_SYS( GetGtkHotKey(*this) );
ee0a94cf 825 if (buf[(size_t)0] != '\0')
98f29783 826 {
ee0a94cf
RR
827 gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods);
828 if (accel_key != 0)
829 {
10bd1f7d 830 gtk_widget_add_accelerator( m_menuItem,
ee0a94cf
RR
831 "activate",
832 m_parentMenu->m_accel,
833 accel_key,
834 accel_mods,
835 GTK_ACCEL_VISIBLE);
836 }
837 }
838 else if (isstock)
839 {
840 // if the accelerator was taken from a stock ID, just get it back from GTK+ stock
841 if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key))
10bd1f7d 842 gtk_widget_remove_accelerator( m_menuItem,
ee0a94cf
RR
843 m_parentMenu->m_accel,
844 accel_key,
845 accel_mods );
98f29783 846 }
6c309653 847#endif // wxUSE_FILECTRL
354aa1e3
RR
848}
849
ee0a94cf 850// NOTE: this function is different from the similar functions GTKProcessMnemonics()
52af3158 851// implemented in control.cpp and from wxMenuItemBase::GetLabelText...
ee0a94cf
RR
852// so there's no real code duplication
853wxString wxMenuItem::GTKProcessMenuItemLabel(const wxString& str, wxString *hotKey)
716b7364 854{
ee0a94cf
RR
855 wxString text;
856
2b5f62a0 857 // '\t' is the deliminator indicating a hot key
e0a050e3
VS
858 wxString::const_iterator pc = str.begin();
859 while ( pc != str.end() && *pc != wxT('\t') )
83624f79 860 {
e0a050e3 861 if (*pc == wxT('&'))
23280650 862 {
e0a050e3
VS
863 wxString::const_iterator next = pc + 1;
864 if (next != str.end() && *next == wxT('&'))
865 {
866 // "&" is doubled to indicate "&" instead of accelerator
867 ++pc;
868 text << wxT('&');
869 }
870 else
871 {
872 text << wxT('_');
873 }
572d7461 874 }
2b5f62a0
VZ
875 else if ( *pc == wxT('_') ) // escape underscores
876 {
ee0a94cf 877 text << wxT("__");
2b5f62a0 878 }
9959e2b6 879 else
23280650 880 {
ee0a94cf 881 text << *pc;
2b5f62a0
VZ
882 }
883 ++pc;
83624f79 884 }
a01fe3d6 885
ee0a94cf 886 if (hotKey)
d7dbc98a 887 {
ee0a94cf
RR
888 hotKey->Empty();
889 if(*pc == wxT('\t'))
890 {
891 pc++;
e0a050e3 892 hotKey->assign(pc, str.end());
ee0a94cf 893 }
d7dbc98a 894 }
88d19775 895
ee0a94cf
RR
896 return text;
897}
898
899// it's valid for this function to be called even if m_menuItem == NULL
900void wxMenuItem::DoSetText( const wxString& str )
901{
902 m_text.Empty();
903 m_text = GTKProcessMenuItemLabel(str, &m_hotKey);
716b7364
RR
904}
905
717a57c2
VZ
906#if wxUSE_ACCEL
907
908wxAcceleratorEntry *wxMenuItem::GetAccel() const
909{
1987af7e 910 if ( !GetHotKey() )
717a57c2
VZ
911 {
912 // nothing
90527a50 913 return NULL;
717a57c2
VZ
914 }
915
90527a50
VZ
916 // accelerator parsing code looks for them after a TAB, so insert a dummy
917 // one here
717a57c2 918 wxString label;
1987af7e 919 label << wxT('\t') << GetHotKey();
717a57c2 920
90527a50 921 return wxAcceleratorEntry::Create(label);
717a57c2
VZ
922}
923
924#endif // wxUSE_ACCEL
925
96fd301f 926void wxMenuItem::Check( bool check )
716b7364 927{
223d09f6 928 wxCHECK_RET( m_menuItem, wxT("invalid menu item") );
db1b4961 929
974e8d94
VZ
930 if (check == m_isChecked)
931 return;
2d17d68f 932
974e8d94 933 wxMenuItemBase::Check( check );
0472ece7 934
24bcaec3 935 switch ( GetKind() )
0472ece7 936 {
24bcaec3
VZ
937 case wxITEM_CHECK:
938 case wxITEM_RADIO:
8394218c 939 gtk_check_menu_item_set_active( (GtkCheckMenuItem*)m_menuItem, (gint)check );
24bcaec3
VZ
940 break;
941
942 default:
943 wxFAIL_MSG( _T("can't check this item") );
0472ece7 944 }
716b7364
RR
945}
946
8bbe427f
VZ
947void wxMenuItem::Enable( bool enable )
948{
223d09f6 949 wxCHECK_RET( m_menuItem, wxT("invalid menu item") );
db1b4961 950
83624f79 951 gtk_widget_set_sensitive( m_menuItem, enable );
974e8d94 952 wxMenuItemBase::Enable( enable );
a9c96bcc
RR
953}
954
96fd301f 955bool wxMenuItem::IsChecked() const
716b7364 956{
670f9935 957 wxCHECK_MSG( m_menuItem, false, wxT("invalid menu item") );
db1b4961 958
670f9935 959 wxCHECK_MSG( IsCheckable(), false,
974e8d94 960 wxT("can't get state of uncheckable item!") );
96fd301f 961
974e8d94 962 return ((GtkCheckMenuItem*)m_menuItem)->active != 0;
716b7364
RR
963}
964
db1b4961 965//-----------------------------------------------------------------------------
83624f79 966// wxMenu
db1b4961
RR
967//-----------------------------------------------------------------------------
968
c801d85f
KB
969IMPLEMENT_DYNAMIC_CLASS(wxMenu,wxEvtHandler)
970
717a57c2 971void wxMenu::Init()
c801d85f 972{
034be888 973 m_accel = gtk_accel_group_new();
6d971354 974 m_menu = gtk_menu_new();
defc0789
VS
975 // NB: keep reference to the menu so that it is not destroyed behind
976 // our back by GTK+ e.g. when it is removed from menubar:
977 gtk_widget_ref(m_menu);
8bbe427f 978
2b1c162e 979 m_owner = (GtkWidget*) NULL;
2b2edbed 980
d9e403cc
RR
981 // Tearoffs are entries, just like separators. So if we want this
982 // menu to be a tear-off one, we just append a tearoff entry
983 // immediately.
9959e2b6 984 if ( m_style & wxMENU_TEAROFF )
2b2edbed 985 {
9959e2b6 986 GtkWidget *tearoff = gtk_tearoff_menu_item_new();
6d971354 987
1ab9e06d 988 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu), tearoff);
9959e2b6 989 }
6d971354 990
9959e2b6 991 m_prevRadio = NULL;
c801d85f 992
717a57c2 993 // append the title as the very first entry if we have it
9959e2b6 994 if ( !m_title.empty() )
d1b15f03 995 {
9959e2b6 996 Append(wxGTK_TITLE_ID, m_title);
717a57c2 997 AppendSeparator();
d1b15f03 998 }
717a57c2 999}
15a2076a 1000
717a57c2
VZ
1001wxMenu::~wxMenu()
1002{
368a4a47 1003 if ( GTK_IS_WIDGET( m_menu ))
defc0789 1004 {
a761df69 1005 // see wxMenu::Init
88d19775 1006 gtk_widget_unref( m_menu );
b8a922d0 1007 g_object_unref( m_accel );
52af3158 1008
a761df69
VS
1009 // if the menu is inserted in another menu at this time, there was
1010 // one more reference to it:
1011 if ( m_owner )
1012 gtk_widget_destroy( m_menu );
defc0789 1013 }
e4161a2a
VZ
1014
1015 // This must come after we release GTK resources above. Otherwise, GTK will
1016 // give warnings/errors when attempting to free accelerator resources from
1017 // child items that just were destroyed (the m_menu widget can contain
1018 // references to accelerators in child items. Problem detected when removing
1019 // a menu from a wxMenuBar, and the removed menu had submenus with accelerators.)
05b743ba 1020 WX_CLEAR_LIST(wxMenuItemList, m_items);
c2dd8380
GL
1021}
1022
978af864
VZ
1023void wxMenu::SetLayoutDirection(const wxLayoutDirection dir)
1024{
1025 if ( m_owner )
1026 wxWindow::GTKSetLayout(m_owner, dir);
1027 //else: will be called later by wxMenuBar again
1028}
1029
1030wxLayoutDirection wxMenu::GetLayoutDirection() const
1031{
1032 return wxWindow::GTKGetLayout(m_owner);
1033}
1034
49826dab 1035bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos)
c2dd8380 1036{
717a57c2 1037 GtkWidget *menuItem;
96fd301f 1038
ee0a94cf 1039 // cache some data used later
84c51319 1040 wxString text = mitem->wxMenuItemBase::GetItemLabel();
ee0a94cf
RR
1041 int id = mitem->GetId();
1042 bool isstock = wxIsStockID(id);
1043 const char *stockid = NULL;
1044 if (isstock)
1045 stockid = wxGetStockGtkID(mitem->GetId());
1046
1047 // stock menu items can have an empty label
1048 if (text.IsEmpty() && !mitem->IsSeparator())
1049 {
1050 wxASSERT_MSG(isstock, wxT("A non-stock menu item with an empty label?"));
1051 text = wxGetStockLabel(id);
1052
1053 // need & => _ conversion
1054 text = wxMenuItem::GTKProcessMenuItemLabel(text, NULL);
1055 }
e31126cb 1056
717a57c2
VZ
1057 if ( mitem->IsSeparator() )
1058 {
6d971354 1059 menuItem = gtk_separator_menu_item_new();
837904f2 1060 }
ab73fe8d 1061 else if ( mitem->GetBitmap().Ok() ||
ee0a94cf 1062 (mitem->GetKind() == wxITEM_NORMAL && isstock) )
37d403aa 1063 {
ab73fe8d 1064 wxBitmap bitmap(mitem->GetBitmap());
9959e2b6 1065
5f11fef5 1066 menuItem = gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV_SYS( text ) );
9959e2b6 1067
b1ad1424 1068 GtkWidget *image;
ab73fe8d 1069 if ( !bitmap.Ok() )
b1ad1424 1070 {
ab73fe8d
VZ
1071 // use stock bitmap for this item if available on the assumption
1072 // that it never hurts to follow GTK+ conventions more closely
ee0a94cf
RR
1073 image = stockid ? gtk_image_new_from_stock(stockid, GTK_ICON_SIZE_MENU)
1074 : NULL;
b1ad1424 1075 }
ab73fe8d 1076 else // we have a custom bitmap
b1ad1424 1077 {
ab73fe8d
VZ
1078 wxASSERT_MSG( mitem->GetKind() == wxITEM_NORMAL,
1079 _T("only normal menu items can have bitmaps") );
1080
1081 if ( bitmap.HasPixbuf() )
1082 {
1083 image = gtk_image_new_from_pixbuf(bitmap.GetPixbuf());
1084 }
1085 else
1086 {
1087 GdkPixmap *gdk_pixmap = bitmap.GetPixmap();
1088 GdkBitmap *gdk_bitmap = bitmap.GetMask() ?
1089 bitmap.GetMask()->GetBitmap() :
1090 (GdkBitmap*) NULL;
1091 image = gtk_image_new_from_pixmap( gdk_pixmap, gdk_bitmap );
1092 }
b1ad1424 1093 }
88d19775 1094
ab73fe8d
VZ
1095 if ( image )
1096 {
1097 gtk_widget_show(image);
9959e2b6 1098
ab73fe8d
VZ
1099 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem), image );
1100 }
9959e2b6 1101
6d971354
RR
1102 m_prevRadio = NULL;
1103 }
717a57c2
VZ
1104 else // a normal item
1105 {
52af3158 1106 // NB: 'text' variable has "_" instead of "&" after mitem->SetItemLabel()
ee0a94cf 1107 // so don't use it
717a57c2 1108
d65c269b
VZ
1109 switch ( mitem->GetKind() )
1110 {
546bfbea 1111 case wxITEM_CHECK:
6d971354 1112 {
5f11fef5 1113 menuItem = gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV_SYS( text ) );
6d971354 1114 m_prevRadio = NULL;
d65c269b 1115 break;
6d971354 1116 }
d65c269b 1117
546bfbea 1118 case wxITEM_RADIO:
6d971354
RR
1119 {
1120 GSList *group = NULL;
1121 if ( m_prevRadio == NULL )
d65c269b
VZ
1122 {
1123 // start of a new radio group
5f11fef5
VZ
1124 m_prevRadio = menuItem =
1125 gtk_radio_menu_item_new_with_mnemonic( group, wxGTK_CONV_SYS( text ) );
d65c269b
VZ
1126 }
1127 else // continue the radio group
1128 {
6d971354 1129 group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio));
5f11fef5
VZ
1130 m_prevRadio = menuItem =
1131 gtk_radio_menu_item_new_with_mnemonic( group, wxGTK_CONV_SYS( text ) );
d65c269b 1132 }
c0d0a552 1133 break;
6d971354 1134 }
d65c269b
VZ
1135
1136 default:
1137 wxFAIL_MSG( _T("unexpected menu item kind") );
1138 // fall through
1139
546bfbea 1140 case wxITEM_NORMAL:
6d971354 1141 {
5f11fef5 1142 menuItem = gtk_menu_item_new_with_mnemonic( wxGTK_CONV_SYS( text ) );
6d971354 1143 m_prevRadio = NULL;
d65c269b 1144 break;
6d971354 1145 }
d65c269b
VZ
1146 }
1147
6d971354 1148 }
9959e2b6 1149
6c309653 1150#if wxUSE_ACCEL
6d971354
RR
1151 guint accel_key;
1152 GdkModifierType accel_mods;
5f11fef5 1153 wxCharBuffer buf = wxGTK_CONV_SYS( GetGtkHotKey(*mitem) );
9959e2b6 1154
ee0a94cf
RR
1155 if (buf[(size_t)0] != '\0')
1156 {
1157 gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods);
1158 if (accel_key != 0)
1159 {
10bd1f7d 1160 gtk_widget_add_accelerator (menuItem,
ee0a94cf
RR
1161 "activate",
1162 m_accel,
1163 accel_key,
1164 accel_mods,
1165 GTK_ACCEL_VISIBLE);
1166 }
1167 }
1168 else if (isstock)
6d971354 1169 {
ee0a94cf
RR
1170 // if the accelerator was taken from a stock ID, just get it back from GTK+ stock
1171 if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key))
10bd1f7d 1172 gtk_widget_add_accelerator( menuItem,
ee0a94cf
RR
1173 "activate",
1174 m_accel,
1175 accel_key,
1176 accel_mods,
1177 GTK_ACCEL_VISIBLE);
717a57c2 1178 }
6c309653 1179#endif // wxUSE_FILECTRL
9959e2b6 1180
e31126cb
RR
1181 if (pos == -1)
1182 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu), menuItem);
1183 else
1184 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu), menuItem, pos);
1185
6d971354 1186 gtk_widget_show( menuItem );
23280650 1187
717a57c2
VZ
1188 if ( !mitem->IsSeparator() )
1189 {
2b5f62a0 1190 wxASSERT_MSG( menuItem, wxT("invalid menuitem") );
a01fe3d6 1191
9fa72bd2
MR
1192 g_signal_connect (menuItem, "select",
1193 G_CALLBACK (gtk_menu_hilight_callback), this);
1194 g_signal_connect (menuItem, "deselect",
1195 G_CALLBACK (gtk_menu_nolight_callback), this);
e31126cb 1196
88d19775
MR
1197 if ( mitem->IsSubMenu() && mitem->GetKind() != wxITEM_RADIO && mitem->GetKind() != wxITEM_CHECK )
1198 {
e31126cb
RR
1199 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), mitem->GetSubMenu()->m_menu );
1200
1201 gtk_widget_show( mitem->GetSubMenu()->m_menu );
1202
1203 // if adding a submenu to a menu already existing in the menu bar, we
1204 // must set invoking window to allow processing events from this
1205 // submenu
1206 if ( m_invokingWindow )
1207 wxMenubarSetInvokingWindow(mitem->GetSubMenu(), m_invokingWindow);
88d19775
MR
1208 }
1209 else
1210 {
9fa72bd2
MR
1211 g_signal_connect (menuItem, "activate",
1212 G_CALLBACK (gtk_menu_clicked_callback),
1213 this);
88d19775 1214 }
717a57c2 1215 }
23280650 1216
837904f2 1217 mitem->SetMenuItem(menuItem);
837904f2 1218
6d971354 1219 if (ms_locked)
d65c269b 1220 {
6d971354
RR
1221 // This doesn't even exist!
1222 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
d65c269b 1223 }
d65c269b 1224
670f9935 1225 return true;
6de97a3b 1226}
c801d85f 1227
9add9367 1228wxMenuItem* wxMenu::DoAppend(wxMenuItem *mitem)
828f655f 1229{
9add9367
RD
1230 if (!GtkAppend(mitem))
1231 return NULL;
9959e2b6 1232
9add9367 1233 return wxMenuBase::DoAppend(mitem);
c33c4050
RR
1234}
1235
9add9367 1236wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
c33c4050 1237{
717a57c2 1238 if ( !wxMenuBase::DoInsert(pos, item) )
9add9367 1239 return NULL;
c626a8b7 1240
6d971354 1241 // TODO
49826dab 1242 if ( !GtkAppend(item, (int)pos) )
9add9367 1243 return NULL;
32db328c 1244
9add9367 1245 return item;
c33c4050
RR
1246}
1247
717a57c2 1248wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
c33c4050 1249{
717a57c2
VZ
1250 if ( !wxMenuBase::DoRemove(item) )
1251 return (wxMenuItem *)NULL;
c626a8b7 1252
717a57c2
VZ
1253 // TODO: this code doesn't delete the item factory item and this seems
1254 // impossible as of GTK 1.2.6.
1255 gtk_widget_destroy( item->GetMenuItem() );
c626a8b7 1256
717a57c2 1257 return item;
c33c4050
RR
1258}
1259
96fd301f
VZ
1260int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const
1261{
222ed1d6 1262 wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
83624f79
RR
1263 while (node)
1264 {
b1d4dd7a 1265 wxMenuItem *item = node->GetData();
83624f79 1266 if (item->GetMenuItem() == menuItem)
88d19775 1267 return item->GetId();
b1d4dd7a 1268 node = node->GetNext();
83624f79 1269 }
96fd301f 1270
c626a8b7 1271 return wxNOT_FOUND;
6de97a3b 1272}
c801d85f 1273
978af864
VZ
1274void wxMenu::Attach(wxMenuBarBase *menubar)
1275{
1276 wxMenuBase::Attach(menubar);
1277
1278 // inherit layout direction from menubar.
1279 SetLayoutDirection(menubar->GetLayoutDirection());
1280}
1281
717a57c2
VZ
1282// ----------------------------------------------------------------------------
1283// helpers
1284// ----------------------------------------------------------------------------
1285
6d971354 1286#if wxUSE_ACCEL
a070d8ce 1287
98f29783 1288static wxString GetGtkHotKey( const wxMenuItem& item )
c801d85f 1289{
717a57c2
VZ
1290 wxString hotkey;
1291
1292 wxAcceleratorEntry *accel = item.GetAccel();
1293 if ( accel )
83624f79 1294 {
717a57c2
VZ
1295 int flags = accel->GetFlags();
1296 if ( flags & wxACCEL_ALT )
1297 hotkey += wxT("<alt>");
1298 if ( flags & wxACCEL_CTRL )
1299 hotkey += wxT("<control>");
1300 if ( flags & wxACCEL_SHIFT )
1301 hotkey += wxT("<shift>");
1302
1303 int code = accel->GetKeyCode();
1304 switch ( code )
c626a8b7 1305 {
717a57c2
VZ
1306 case WXK_F1:
1307 case WXK_F2:
1308 case WXK_F3:
1309 case WXK_F4:
1310 case WXK_F5:
1311 case WXK_F6:
1312 case WXK_F7:
1313 case WXK_F8:
1314 case WXK_F9:
1315 case WXK_F10:
1316 case WXK_F11:
1317 case WXK_F12:
bbcd4085
RR
1318 case WXK_F13:
1319 case WXK_F14:
1320 case WXK_F15:
1321 case WXK_F16:
1322 case WXK_F17:
1323 case WXK_F18:
1324 case WXK_F19:
1325 case WXK_F20:
1326 case WXK_F21:
1327 case WXK_F22:
1328 case WXK_F23:
1329 case WXK_F24:
04cc1e93 1330 hotkey += wxString::Format(wxT("F%d"), code - WXK_F1 + 1);
717a57c2 1331 break;
2368dcda 1332
a070d8ce
VZ
1333 // TODO: we should use gdk_keyval_name() (a.k.a.
1334 // XKeysymToString) here as well as hardcoding the keysym
1335 // names this might be not portable
bbcd4085 1336 case WXK_INSERT:
3ca6a5f0
BP
1337 hotkey << wxT("Insert" );
1338 break;
1339 case WXK_DELETE:
1340 hotkey << wxT("Delete" );
1341 break;
2b5f62a0
VZ
1342 case WXK_UP:
1343 hotkey << wxT("Up" );
1344 break;
1345 case WXK_DOWN:
1346 hotkey << wxT("Down" );
1347 break;
1348 case WXK_PAGEUP:
f005ea42 1349 hotkey << wxT("Page_Up" );
2b5f62a0
VZ
1350 break;
1351 case WXK_PAGEDOWN:
f005ea42 1352 hotkey << wxT("Page_Down" );
2b5f62a0
VZ
1353 break;
1354 case WXK_LEFT:
1355 hotkey << wxT("Left" );
1356 break;
1357 case WXK_RIGHT:
1358 hotkey << wxT("Right" );
1359 break;
1360 case WXK_HOME:
1361 hotkey << wxT("Home" );
1362 break;
1363 case WXK_END:
1364 hotkey << wxT("End" );
1365 break;
1366 case WXK_RETURN:
1367 hotkey << wxT("Return" );
1368 break;
bbcd4085
RR
1369 case WXK_BACK:
1370 hotkey << wxT("BackSpace" );
1371 break;
1372 case WXK_TAB:
1373 hotkey << wxT("Tab" );
1374 break;
1375 case WXK_ESCAPE:
1376 hotkey << wxT("Esc" );
1377 break;
1378 case WXK_SPACE:
1379 hotkey << wxT("space" );
1380 break;
1381 case WXK_MULTIPLY:
1382 hotkey << wxT("Multiply" );
1383 break;
1384 case WXK_ADD:
1385 hotkey << wxT("Add" );
1386 break;
1387 case WXK_SEPARATOR:
1388 hotkey << wxT("Separator" );
1389 break;
1390 case WXK_SUBTRACT:
1391 hotkey << wxT("Subtract" );
1392 break;
1393 case WXK_DECIMAL:
1394 hotkey << wxT("Decimal" );
1395 break;
1396 case WXK_DIVIDE:
1397 hotkey << wxT("Divide" );
1398 break;
1399 case WXK_CANCEL:
1400 hotkey << wxT("Cancel" );
1401 break;
1402 case WXK_CLEAR:
1403 hotkey << wxT("Clear" );
1404 break;
1405 case WXK_MENU:
1406 hotkey << wxT("Menu" );
1407 break;
1408 case WXK_PAUSE:
1409 hotkey << wxT("Pause" );
1410 break;
1411 case WXK_CAPITAL:
1412 hotkey << wxT("Capital" );
1413 break;
1414 case WXK_SELECT:
1415 hotkey << wxT("Select" );
1416 break;
1417 case WXK_PRINT:
1418 hotkey << wxT("Print" );
1419 break;
1420 case WXK_EXECUTE:
1421 hotkey << wxT("Execute" );
1422 break;
1423 case WXK_SNAPSHOT:
1424 hotkey << wxT("Snapshot" );
1425 break;
1426 case WXK_HELP:
1427 hotkey << wxT("Help" );
1428 break;
1429 case WXK_NUMLOCK:
1430 hotkey << wxT("Num_Lock" );
1431 break;
1432 case WXK_SCROLL:
1433 hotkey << wxT("Scroll_Lock" );
1434 break;
1435 case WXK_NUMPAD_INSERT:
1436 hotkey << wxT("KP_Insert" );
1437 break;
1438 case WXK_NUMPAD_DELETE:
1439 hotkey << wxT("KP_Delete" );
1440 break;
1441 case WXK_NUMPAD_SPACE:
1442 hotkey << wxT("KP_Space" );
1443 break;
1444 case WXK_NUMPAD_TAB:
1445 hotkey << wxT("KP_Tab" );
1446 break;
1447 case WXK_NUMPAD_ENTER:
1448 hotkey << wxT("KP_Enter" );
1449 break;
1450 case WXK_NUMPAD_F1: case WXK_NUMPAD_F2: case WXK_NUMPAD_F3:
1451 case WXK_NUMPAD_F4:
1452 hotkey += wxString::Format(wxT("KP_F%d"), code - WXK_NUMPAD_F1 + 1);
1453 break;
1454 case WXK_NUMPAD_HOME:
1455 hotkey << wxT("KP_Home" );
1456 break;
1457 case WXK_NUMPAD_LEFT:
1458 hotkey << wxT("KP_Left" );
1459 break;
1460 case WXK_NUMPAD_UP:
1461 hotkey << wxT("KP_Up" );
1462 break;
1463 case WXK_NUMPAD_RIGHT:
1464 hotkey << wxT("KP_Right" );
1465 break;
1466 case WXK_NUMPAD_DOWN:
1467 hotkey << wxT("KP_Down" );
1468 break;
5bd24f72 1469 case WXK_NUMPAD_PAGEUP:
f005ea42 1470 hotkey << wxT("KP_Page_Up" );
bbcd4085 1471 break;
5bd24f72 1472 case WXK_NUMPAD_PAGEDOWN:
f005ea42 1473 hotkey << wxT("KP_Page_Down" );
bbcd4085
RR
1474 break;
1475 case WXK_NUMPAD_END:
1476 hotkey << wxT("KP_End" );
1477 break;
1478 case WXK_NUMPAD_BEGIN:
1479 hotkey << wxT("KP_Begin" );
1480 break;
1481 case WXK_NUMPAD_EQUAL:
1482 hotkey << wxT("KP_Equal" );
1483 break;
1484 case WXK_NUMPAD_MULTIPLY:
1485 hotkey << wxT("KP_Multiply" );
1486 break;
1487 case WXK_NUMPAD_ADD:
1488 hotkey << wxT("KP_Add" );
1489 break;
1490 case WXK_NUMPAD_SEPARATOR:
1491 hotkey << wxT("KP_Separator" );
1492 break;
1493 case WXK_NUMPAD_SUBTRACT:
1494 hotkey << wxT("KP_Subtract" );
1495 break;
1496 case WXK_NUMPAD_DECIMAL:
1497 hotkey << wxT("KP_Decimal" );
1498 break;
1499 case WXK_NUMPAD_DIVIDE:
1500 hotkey << wxT("KP_Divide" );
1501 break;
1502 case WXK_NUMPAD0: case WXK_NUMPAD1: case WXK_NUMPAD2:
1503 case WXK_NUMPAD3: case WXK_NUMPAD4: case WXK_NUMPAD5:
1504 case WXK_NUMPAD6: case WXK_NUMPAD7: case WXK_NUMPAD8: case WXK_NUMPAD9:
1505 hotkey += wxString::Format(wxT("KP_%d"), code - WXK_NUMPAD0);
1506 break;
1507 case WXK_WINDOWS_LEFT:
1508 hotkey << wxT("Super_L" );
1509 break;
1510 case WXK_WINDOWS_RIGHT:
1511 hotkey << wxT("Super_R" );
1512 break;
1513 case WXK_WINDOWS_MENU:
1514 hotkey << wxT("Menu" );
1515 break;
1516 case WXK_COMMAND:
1517 hotkey << wxT("Command" );
1518 break;
1519 /* These probably wouldn't work as there is no SpecialX in gdk/keynames.txt
88d19775
MR
1520 case WXK_SPECIAL1: case WXK_SPECIAL2: case WXK_SPECIAL3: case WXK_SPECIAL4:
1521 case WXK_SPECIAL5: case WXK_SPECIAL6: case WXK_SPECIAL7: case WXK_SPECIAL8:
1522 case WXK_SPECIAL9: case WXK_SPECIAL10: case WXK_SPECIAL11: case WXK_SPECIAL12:
1523 case WXK_SPECIAL13: case WXK_SPECIAL14: case WXK_SPECIAL15: case WXK_SPECIAL16:
bbcd4085
RR
1524 case WXK_SPECIAL17: case WXK_SPECIAL18: case WXK_SPECIAL19: case WXK_SPECIAL20:
1525 hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1);
1526 break;
1527 */
90527a50 1528 // if there are any other keys wxAcceleratorEntry::Create() may
a070d8ce 1529 // return, we should process them here
8bbe427f 1530
717a57c2 1531 default:
a070d8ce 1532 if ( code < 127 )
717a57c2 1533 {
30083ad8
VZ
1534 const wxString
1535 name = wxGTK_CONV_BACK_SYS(gdk_keyval_name((guint)code));
1536 if ( !name.empty() )
a070d8ce
VZ
1537 {
1538 hotkey << name;
1539 break;
1540 }
717a57c2 1541 }
c801d85f 1542
717a57c2
VZ
1543 wxFAIL_MSG( wxT("unknown keyboard accel") );
1544 }
c801d85f 1545
717a57c2 1546 delete accel;
631f1bfe 1547 }
717a57c2
VZ
1548
1549 return hotkey;
631f1bfe 1550}
a070d8ce 1551
717a57c2 1552#endif // wxUSE_ACCEL
43a11e2a
VZ
1553
1554// ----------------------------------------------------------------------------
1555// Pop-up menu stuff
1556// ----------------------------------------------------------------------------
1557
1558#if wxUSE_MENUS_NATIVE
1559
81939780 1560extern "C" WXDLLIMPEXP_CORE
43a11e2a
VZ
1561void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
1562{
670f9935 1563 *is_waiting = false;
43a11e2a
VZ
1564}
1565
81939780 1566WXDLLIMPEXP_CORE void SetInvokingWindow( wxMenu *menu, wxWindow* win )
43a11e2a
VZ
1567{
1568 menu->SetInvokingWindow( win );
1569
1570 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
1571 while (node)
1572 {
1573 wxMenuItem *menuitem = node->GetData();
1574 if (menuitem->IsSubMenu())
1575 {
1576 SetInvokingWindow( menuitem->GetSubMenu(), win );
1577 }
1578
1579 node = node->GetNext();
1580 }
1581}
1582
81939780 1583extern "C" WXDLLIMPEXP_CORE
43a11e2a
VZ
1584void wxPopupMenuPositionCallback( GtkMenu *menu,
1585 gint *x, gint *y,
43a11e2a 1586 gboolean * WXUNUSED(whatever),
43a11e2a
VZ
1587 gpointer user_data )
1588{
1589 // ensure that the menu appears entirely on screen
1590 GtkRequisition req;
1591 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
1592
1593 wxSize sizeScreen = wxGetDisplaySize();
1594 wxPoint *pos = (wxPoint*)user_data;
1595
1596 gint xmax = sizeScreen.x - req.width,
1597 ymax = sizeScreen.y - req.height;
1598
1599 *x = pos->x < xmax ? pos->x : xmax;
1600 *y = pos->y < ymax ? pos->y : ymax;
1601}
1602
1603bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
1604{
1605 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
1606
1607 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
1608
1609 // NOTE: if you change this code, you need to update
1610 // the same code in taskbar.cpp as well. This
1611 // is ugly code duplication, I know.
1612
1613 SetInvokingWindow( menu, this );
1614
1615 menu->UpdateUI();
1616
1617 bool is_waiting = true;
1618
9fa72bd2
MR
1619 gulong handler = g_signal_connect (menu->m_menu, "hide",
1620 G_CALLBACK (gtk_pop_hide_callback),
1621 &is_waiting);
43a11e2a
VZ
1622
1623 wxPoint pos;
1624 gpointer userdata;
1625 GtkMenuPositionFunc posfunc;
1626 if ( x == -1 && y == -1 )
1627 {
1628 // use GTK's default positioning algorithm
1629 userdata = NULL;
1630 posfunc = NULL;
1631 }
1632 else
1633 {
1634 pos = ClientToScreen(wxPoint(x, y));
1635 userdata = &pos;
1636 posfunc = wxPopupMenuPositionCallback;
1637 }
1638
1639 wxMenuEvent eventOpen(wxEVT_MENU_OPEN, -1, menu);
1640 DoCommonMenuCallbackCode(menu, eventOpen);
1641
1642 gtk_menu_popup(
1643 GTK_MENU(menu->m_menu),
1644 (GtkWidget *) NULL, // parent menu shell
1645 (GtkWidget *) NULL, // parent menu item
1646 posfunc, // function to position it
1647 userdata, // client data
1648 0, // button used to activate it
43a11e2a 1649 gtk_get_current_event_time()
43a11e2a
VZ
1650 );
1651
1652 while (is_waiting)
1653 {
1654 gtk_main_iteration();
1655 }
1656
9fa72bd2 1657 g_signal_handler_disconnect (menu->m_menu, handler);
43a11e2a
VZ
1658
1659 wxMenuEvent eventClose(wxEVT_MENU_CLOSE, -1, menu);
1660 DoCommonMenuCallbackCode(menu, eventClose);
1661
1662 return true;
1663}
1664
1665#endif // wxUSE_MENUS_NATIVE
bcf881ef 1666
bcf881ef
JS
1667#include <gtk/gtk.h>
1668
1669const char *wxGetStockGtkID(wxWindowID id)
1670{
1671 #define STOCKITEM(wx,gtk) \
1672 case wx: \
1673 return gtk;
1674
1675 #define STOCKITEM_MISSING(wx) \
1676 case wx: \
1677 return NULL;
1678
1679 #if GTK_CHECK_VERSION(2,4,0)
1680 #define STOCKITEM_24(wx,gtk) STOCKITEM(wx,gtk)
1681 #else
1682 #define STOCKITEM_24(wx,gtk) STOCKITEM_MISSING(wx)
1683 #endif
1684
1685 #if GTK_CHECK_VERSION(2,6,0)
1686 #define STOCKITEM_26(wx,gtk) STOCKITEM(wx,gtk)
1687 #else
1688 #define STOCKITEM_26(wx,gtk) STOCKITEM_MISSING(wx)
1689 #endif
1690
1691 #if GTK_CHECK_VERSION(2,10,0)
1692 #define STOCKITEM_210(wx,gtk) STOCKITEM(wx,gtk)
1693 #else
1694 #define STOCKITEM_210(wx,gtk) STOCKITEM_MISSING(wx)
1695 #endif
1696
1697
1698 switch (id)
1699 {
1700 STOCKITEM_26(wxID_ABOUT, GTK_STOCK_ABOUT)
1701 STOCKITEM(wxID_ADD, GTK_STOCK_ADD)
1702 STOCKITEM(wxID_APPLY, GTK_STOCK_APPLY)
1703 STOCKITEM(wxID_BOLD, GTK_STOCK_BOLD)
1704 STOCKITEM(wxID_CANCEL, GTK_STOCK_CANCEL)
1705 STOCKITEM(wxID_CLEAR, GTK_STOCK_CLEAR)
1706 STOCKITEM(wxID_CLOSE, GTK_STOCK_CLOSE)
1707 STOCKITEM(wxID_COPY, GTK_STOCK_COPY)
1708 STOCKITEM(wxID_CUT, GTK_STOCK_CUT)
1709 STOCKITEM(wxID_DELETE, GTK_STOCK_DELETE)
1710 STOCKITEM_26(wxID_EDIT, GTK_STOCK_EDIT)
1711 STOCKITEM(wxID_FIND, GTK_STOCK_FIND)
1712 STOCKITEM_26(wxID_FILE, GTK_STOCK_FILE)
1713 STOCKITEM(wxID_REPLACE, GTK_STOCK_FIND_AND_REPLACE)
1714 STOCKITEM(wxID_BACKWARD, GTK_STOCK_GO_BACK)
1715 STOCKITEM(wxID_DOWN, GTK_STOCK_GO_DOWN)
1716 STOCKITEM(wxID_FORWARD, GTK_STOCK_GO_FORWARD)
1717 STOCKITEM(wxID_UP, GTK_STOCK_GO_UP)
1718 STOCKITEM(wxID_HELP, GTK_STOCK_HELP)
1719 STOCKITEM(wxID_HOME, GTK_STOCK_HOME)
1720 STOCKITEM_24(wxID_INDENT, GTK_STOCK_INDENT)
1721 STOCKITEM(wxID_INDEX, GTK_STOCK_INDEX)
1722 STOCKITEM(wxID_ITALIC, GTK_STOCK_ITALIC)
1723 STOCKITEM(wxID_JUSTIFY_CENTER, GTK_STOCK_JUSTIFY_CENTER)
1724 STOCKITEM(wxID_JUSTIFY_FILL, GTK_STOCK_JUSTIFY_FILL)
1725 STOCKITEM(wxID_JUSTIFY_LEFT, GTK_STOCK_JUSTIFY_LEFT)
1726 STOCKITEM(wxID_JUSTIFY_RIGHT, GTK_STOCK_JUSTIFY_RIGHT)
1727 STOCKITEM(wxID_NEW, GTK_STOCK_NEW)
1728 STOCKITEM(wxID_NO, GTK_STOCK_NO)
1729 STOCKITEM(wxID_OK, GTK_STOCK_OK)
1730 STOCKITEM(wxID_OPEN, GTK_STOCK_OPEN)
1731 STOCKITEM(wxID_PASTE, GTK_STOCK_PASTE)
1732 STOCKITEM(wxID_PREFERENCES, GTK_STOCK_PREFERENCES)
1733 STOCKITEM(wxID_PRINT, GTK_STOCK_PRINT)
1734 STOCKITEM(wxID_PREVIEW, GTK_STOCK_PRINT_PREVIEW)
1735 STOCKITEM(wxID_PROPERTIES, GTK_STOCK_PROPERTIES)
1736 STOCKITEM(wxID_EXIT, GTK_STOCK_QUIT)
1737 STOCKITEM(wxID_REDO, GTK_STOCK_REDO)
1738 STOCKITEM(wxID_REFRESH, GTK_STOCK_REFRESH)
1739 STOCKITEM(wxID_REMOVE, GTK_STOCK_REMOVE)
1740 STOCKITEM(wxID_REVERT_TO_SAVED, GTK_STOCK_REVERT_TO_SAVED)
1741 STOCKITEM(wxID_SAVE, GTK_STOCK_SAVE)
1742 STOCKITEM(wxID_SAVEAS, GTK_STOCK_SAVE_AS)
1743 STOCKITEM_210(wxID_SELECTALL, GTK_STOCK_SELECT_ALL)
1744 STOCKITEM(wxID_STOP, GTK_STOCK_STOP)
1745 STOCKITEM(wxID_UNDELETE, GTK_STOCK_UNDELETE)
1746 STOCKITEM(wxID_UNDERLINE, GTK_STOCK_UNDERLINE)
1747 STOCKITEM(wxID_UNDO, GTK_STOCK_UNDO)
1748 STOCKITEM_24(wxID_UNINDENT, GTK_STOCK_UNINDENT)
1749 STOCKITEM(wxID_YES, GTK_STOCK_YES)
1750 STOCKITEM(wxID_ZOOM_100, GTK_STOCK_ZOOM_100)
1751 STOCKITEM(wxID_ZOOM_FIT, GTK_STOCK_ZOOM_FIT)
1752 STOCKITEM(wxID_ZOOM_IN, GTK_STOCK_ZOOM_IN)
1753 STOCKITEM(wxID_ZOOM_OUT, GTK_STOCK_ZOOM_OUT)
1754
1755 default:
1756 wxFAIL_MSG( _T("invalid stock item ID") );
1757 break;
1758 };
1759
1760 #undef STOCKITEM
1761
1762 return NULL;
1763}
1764
1765bool wxGetStockGtkAccelerator(const char *id, GdkModifierType *mod, guint *key)
1766{
1767 if (!id)
1768 return false;
1769
1770 GtkStockItem stock_item;
1771 if (gtk_stock_lookup (id, &stock_item))
1772 {
1773 if (key) *key = stock_item.keyval;
1774 if (mod) *mod = stock_item.modifier;
1775
1776 // some GTK stock items have zero values for the keyval;
1777 // it means that they do not have an accelerator...
1778 if (stock_item.keyval)
1779 return true;
1780 }
1781
1782 return false;
1783}
1784
28fcfbfe 1785#endif // wxUSE_MENUS