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