~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Externals/wxWidgets3/src/gtk/menu.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/gtk/menu.cpp
 
3
// Purpose:     implementation of wxMenuBar and wxMenu classes for wxGTK
 
4
// Author:      Robert Roebling
 
5
// Copyright:   (c) 1998 Robert Roebling
 
6
// Licence:     wxWindows licence
 
7
/////////////////////////////////////////////////////////////////////////////
 
8
 
 
9
// For compilers that support precompilation, includes "wx.h".
 
10
#include "wx/wxprec.h"
 
11
 
 
12
#if wxUSE_MENUS
 
13
 
 
14
#include "wx/menu.h"
 
15
 
 
16
#ifndef WX_PRECOMP
 
17
    #include "wx/intl.h"
 
18
    #include "wx/log.h"
 
19
    #include "wx/dialog.h"
 
20
    #include "wx/frame.h"
 
21
    #include "wx/bitmap.h"
 
22
    #include "wx/app.h"
 
23
#endif
 
24
 
 
25
#include "wx/accel.h"
 
26
#include "wx/stockitem.h"
 
27
 
 
28
#include <gtk/gtk.h>
 
29
#include "wx/gtk/private.h"
 
30
#include "wx/gtk/private/gtk2-compat.h"
 
31
#include "wx/gtk/private/mnemonics.h"
 
32
 
 
33
// Number of currently open modal dialogs, defined in src/gtk/toplevel.cpp.
 
34
extern int wxOpenModalDialogsCount;
 
35
 
 
36
// we use normal item but with a special id for the menu title
 
37
static const int wxGTK_TITLE_ID = -3;
 
38
 
 
39
// forward declare it as it's used by wxMenuBar too when using Hildon
 
40
extern "C"
 
41
{
 
42
    static void menuitem_activate(GtkWidget*, wxMenuItem* item);
 
43
}
 
44
 
 
45
#if wxUSE_ACCEL
 
46
static void wxGetGtkAccel(const wxMenuItem*, guint*, GdkModifierType*);
 
47
#endif
 
48
 
 
49
// Unity hack: under Ubuntu Unity the global menu bar is not affected by a
 
50
// modal dialog being shown, so the user can select a menu item before hiding
 
51
// the dialog and, in particular, a new instance of the same dialog can be
 
52
// shown again, breaking a lot of programs not expecting this.
 
53
//
 
54
// So explicitly ignore any menu events generated while any modal dialogs
 
55
// are opened except for the events generated by a context menu within the
 
56
// modal dialog itself that should have a dialog as their invoking window.
 
57
static bool IsMenuEventAllowed(wxMenu* menu)
 
58
{
 
59
    if ( wxOpenModalDialogsCount )
 
60
    {
 
61
        wxWindow* tlw = wxGetTopLevelParent(menu->GetWindow());
 
62
        if ( !tlw || !wxDynamicCast(tlw, wxDialog) )
 
63
        {
 
64
            // This must be an event from a menu bar of one of the frames.
 
65
            return false;
 
66
        }
 
67
    }
 
68
 
 
69
    return true;
 
70
}
 
71
 
 
72
static void DoCommonMenuCallbackCode(wxMenu *menu, wxMenuEvent& event)
 
73
{
 
74
    if ( !IsMenuEventAllowed(menu) )
 
75
        return;
 
76
 
 
77
    event.SetEventObject( menu );
 
78
 
 
79
    wxEvtHandler* handler = menu->GetEventHandler();
 
80
    if (handler && handler->SafelyProcessEvent(event))
 
81
        return;
 
82
 
 
83
    wxWindow *win = menu->GetWindow();
 
84
    wxCHECK_RET( win, "event for a menu without associated window?" );
 
85
 
 
86
    win->HandleWindowEvent( event );
 
87
}
 
88
 
 
89
//-----------------------------------------------------------------------------
 
90
// wxMenuBar
 
91
//-----------------------------------------------------------------------------
 
92
 
 
93
wxMenuBar::~wxMenuBar()
 
94
{
 
95
}
 
96
 
 
97
void wxMenuBar::Init(size_t n, wxMenu *menus[], const wxString titles[], long style)
 
98
{
 
99
#if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
 
100
    // Hildon window uses a single menu instead of a menu bar, so wxMenuBar is
 
101
    // the same as menu in this case
 
102
    m_widget =
 
103
    m_menubar = gtk_menu_new();
 
104
#else // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
 
105
    if (!PreCreation( NULL, wxDefaultPosition, wxDefaultSize ) ||
 
106
        !CreateBase( NULL, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("menubar") ))
 
107
    {
 
108
        wxFAIL_MSG( wxT("wxMenuBar creation failed") );
 
109
        return;
 
110
    }
 
111
 
 
112
    m_menubar = gtk_menu_bar_new();
 
113
 
 
114
    if (style & wxMB_DOCKABLE)
 
115
    {
 
116
        m_widget = gtk_handle_box_new();
 
117
        gtk_container_add(GTK_CONTAINER(m_widget), m_menubar);
 
118
        gtk_widget_show(m_menubar);
 
119
    }
 
120
    else
 
121
    {
 
122
        m_widget = m_menubar;
 
123
    }
 
124
 
 
125
    PostCreation();
 
126
#endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2/!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
 
127
 
 
128
    g_object_ref_sink(m_widget);
 
129
 
 
130
    for (size_t i = 0; i < n; ++i )
 
131
        Append(menus[i], titles[i]);
 
132
}
 
133
 
 
134
wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxString titles[], long style)
 
135
{
 
136
    Init(n, menus, titles, style);
 
137
}
 
138
 
 
139
wxMenuBar::wxMenuBar(long style)
 
140
{
 
141
    Init(0, NULL, NULL, style);
 
142
}
 
143
 
 
144
wxMenuBar::wxMenuBar()
 
145
{
 
146
    Init(0, NULL, NULL, 0);
 
147
}
 
148
 
 
149
// recursive helpers for wxMenuBar::Attach() and Detach(): they are called to
 
150
// associate the menus with the frame they belong to or dissociate them from it
 
151
namespace
 
152
{
 
153
 
 
154
// This should be called when detaching menus to ensure that they don't keep
 
155
// focus grab, because if they do, they continue getting all GTK+ messages
 
156
// which they can't process any more in their (soon to be) unrealized state.
 
157
void
 
158
EnsureNoGrab(GtkWidget* widget)
 
159
{
 
160
#if !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
 
161
    gtk_widget_hide(widget);
 
162
    gtk_grab_remove(widget);
 
163
#endif // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
 
164
}
 
165
 
 
166
void
 
167
DetachFromFrame(wxMenu* menu, wxFrame* frame)
 
168
{
 
169
    // support for native hot keys
 
170
    if (menu->m_accel)
 
171
    {
 
172
        // Note that wxGetTopLevelParent() is really needed because this frame
 
173
        // can be an MDI child frame which is a fake frame and not a TLW at all
 
174
        GtkWindow * const tlw = GTK_WINDOW(wxGetTopLevelParent(frame)->m_widget);
 
175
        if (g_slist_find(gtk_accel_groups_from_object(G_OBJECT(tlw)), menu->m_accel))
 
176
            gtk_window_remove_accel_group(tlw, menu->m_accel);
 
177
    }
 
178
 
 
179
    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
 
180
    while (node)
 
181
    {
 
182
        wxMenuItem *menuitem = node->GetData();
 
183
        if (menuitem->IsSubMenu())
 
184
            DetachFromFrame(menuitem->GetSubMenu(), frame);
 
185
        node = node->GetNext();
 
186
    }
 
187
 
 
188
    EnsureNoGrab(menu->m_menu);
 
189
}
 
190
 
 
191
void
 
192
AttachToFrame(wxMenu* menu, wxFrame* frame)
 
193
{
 
194
    // support for native hot keys
 
195
    if (menu->m_accel)
 
196
    {
 
197
        GtkWindow * const tlw = GTK_WINDOW(wxGetTopLevelParent(frame)->m_widget);
 
198
        if (!g_slist_find(gtk_accel_groups_from_object(G_OBJECT(tlw)), menu->m_accel))
 
199
            gtk_window_add_accel_group(tlw, menu->m_accel);
 
200
    }
 
201
 
 
202
    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
 
203
    while (node)
 
204
    {
 
205
        wxMenuItem *menuitem = node->GetData();
 
206
        if (menuitem->IsSubMenu())
 
207
            AttachToFrame(menuitem->GetSubMenu(), frame);
 
208
        node = node->GetNext();
 
209
    }
 
210
}
 
211
 
 
212
} // anonymous namespace
 
213
 
 
214
void wxMenuBar::SetLayoutDirection(wxLayoutDirection dir)
 
215
{
 
216
    if ( dir == wxLayout_Default )
 
217
    {
 
218
        const wxWindow *const frame = GetFrame();
 
219
        if ( frame )
 
220
        {
 
221
            // inherit layout from frame.
 
222
            dir = frame->GetLayoutDirection();
 
223
        }
 
224
        else // use global layout
 
225
        {
 
226
            dir = wxTheApp->GetLayoutDirection();
 
227
        }
 
228
    }
 
229
 
 
230
    if ( dir == wxLayout_Default )
 
231
        return;
 
232
 
 
233
    GTKSetLayout(m_menubar, dir);
 
234
 
 
235
    // also set the layout of all menus we already have (new ones will inherit
 
236
    // the current layout)
 
237
    for ( wxMenuList::compatibility_iterator node = m_menus.GetFirst();
 
238
          node;
 
239
          node = node->GetNext() )
 
240
    {
 
241
        wxMenu *const menu = node->GetData();
 
242
        menu->SetLayoutDirection(dir);
 
243
    }
 
244
}
 
245
 
 
246
wxLayoutDirection wxMenuBar::GetLayoutDirection() const
 
247
{
 
248
    return GTKGetLayout(m_menubar);
 
249
}
 
250
 
 
251
void wxMenuBar::Attach(wxFrame *frame)
 
252
{
 
253
    wxMenuBarBase::Attach(frame);
 
254
 
 
255
    wxMenuList::compatibility_iterator node = m_menus.GetFirst();
 
256
    while (node)
 
257
    {
 
258
        wxMenu *menu = node->GetData();
 
259
        AttachToFrame( menu, frame );
 
260
        node = node->GetNext();
 
261
    }
 
262
 
 
263
    SetLayoutDirection(wxLayout_Default);
 
264
}
 
265
 
 
266
void wxMenuBar::Detach()
 
267
{
 
268
    wxMenuList::compatibility_iterator node = m_menus.GetFirst();
 
269
    while (node)
 
270
    {
 
271
        wxMenu *menu = node->GetData();
 
272
        DetachFromFrame( menu, m_menuBarFrame );
 
273
        node = node->GetNext();
 
274
    }
 
275
 
 
276
    EnsureNoGrab(m_widget);
 
277
 
 
278
    wxMenuBarBase::Detach();
 
279
}
 
280
 
 
281
bool wxMenuBar::Append( wxMenu *menu, const wxString &title )
 
282
{
 
283
    if (wxMenuBarBase::Append(menu, title))
 
284
    {
 
285
        GtkAppend(menu, title);
 
286
        return true;
 
287
    }
 
288
    return false;
 
289
}
 
290
 
 
291
void wxMenuBar::GtkAppend(wxMenu* menu, const wxString& title, int pos)
 
292
{
 
293
    menu->SetLayoutDirection(GetLayoutDirection());
 
294
 
 
295
#if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
 
296
    // if the menu has only one item, append it directly to the top level menu
 
297
    // instead of inserting a useless submenu
 
298
    if ( menu->GetMenuItemCount() == 1 )
 
299
    {
 
300
        wxMenuItem * const item = menu->FindItemByPosition(0);
 
301
 
 
302
        // remove both mnemonics and accelerator: neither is useful under Maemo
 
303
        const wxString str(wxStripMenuCodes(item->GetItemLabel()));
 
304
 
 
305
        if ( item->IsSubMenu() )
 
306
        {
 
307
            GtkAppend(item->GetSubMenu(), str, pos);
 
308
            return;
 
309
        }
 
310
 
 
311
        menu->m_owner = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str ) );
 
312
 
 
313
        g_signal_connect(menu->m_owner, "activate",
 
314
                         G_CALLBACK(menuitem_activate), item);
 
315
        item->SetMenuItem(menu->m_owner);
 
316
    }
 
317
    else
 
318
#endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2 /!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
 
319
    {
 
320
        // This doesn't have much effect right now.
 
321
        menu->SetTitle( title );
 
322
 
 
323
        const wxString str(wxConvertMnemonicsToGTK(title));
 
324
        // The "m_owner" is the "menu item"
 
325
        menu->m_owner = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str ) );
 
326
 
 
327
        gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu->m_owner), menu->m_menu );
 
328
    }
 
329
    g_object_ref(menu->m_owner);
 
330
 
 
331
    gtk_widget_show( menu->m_owner );
 
332
 
 
333
    if (pos == -1)
 
334
        gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar), menu->m_owner );
 
335
    else
 
336
        gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar), menu->m_owner, pos );
 
337
 
 
338
    if ( m_menuBarFrame )
 
339
        AttachToFrame( menu, m_menuBarFrame );
 
340
}
 
341
 
 
342
bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
 
343
{
 
344
    if (wxMenuBarBase::Insert(pos, menu, title))
 
345
    {
 
346
        GtkAppend(menu, title, int(pos));
 
347
        return true;
 
348
    }
 
349
    return false;
 
350
}
 
351
 
 
352
wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
 
353
{
 
354
    // remove the old item and insert a new one
 
355
    wxMenu *menuOld = Remove(pos);
 
356
    if ( menuOld && !Insert(pos, menu, title) )
 
357
    {
 
358
        return NULL;
 
359
    }
 
360
 
 
361
    // either Insert() succeeded or Remove() failed and menuOld is NULL
 
362
    return menuOld;
 
363
}
 
364
 
 
365
wxMenu *wxMenuBar::Remove(size_t pos)
 
366
{
 
367
    wxMenu *menu = wxMenuBarBase::Remove(pos);
 
368
    if ( !menu )
 
369
        return NULL;
 
370
 
 
371
    // remove item from menubar before destroying item to avoid spurious
 
372
    // warnings from Ubuntu libdbusmenu
 
373
    gtk_container_remove(GTK_CONTAINER(m_menubar), menu->m_owner);
 
374
    // remove submenu to avoid destroying it when item is destroyed
 
375
#ifdef __WXGTK3__
 
376
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->m_owner), NULL);
 
377
#else
 
378
    gtk_menu_item_remove_submenu(GTK_MENU_ITEM(menu->m_owner));
 
379
#endif
 
380
 
 
381
    gtk_widget_destroy( menu->m_owner );
 
382
    g_object_unref(menu->m_owner);
 
383
    menu->m_owner = NULL;
 
384
 
 
385
    if ( m_menuBarFrame )
 
386
        DetachFromFrame( menu, m_menuBarFrame );
 
387
 
 
388
    return menu;
 
389
}
 
390
 
 
391
static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString, const wxString &itemString )
 
392
{
 
393
    if (wxMenuItem::GetLabelText(menu->GetTitle()) == wxMenuItem::GetLabelText(menuString))
 
394
    {
 
395
        int res = menu->FindItem( itemString );
 
396
        if (res != wxNOT_FOUND)
 
397
            return res;
 
398
    }
 
399
 
 
400
    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
 
401
    while (node)
 
402
    {
 
403
        wxMenuItem *item = node->GetData();
 
404
        if (item->IsSubMenu())
 
405
            return FindMenuItemRecursive(item->GetSubMenu(), menuString, itemString);
 
406
 
 
407
        node = node->GetNext();
 
408
    }
 
409
 
 
410
    return wxNOT_FOUND;
 
411
}
 
412
 
 
413
int wxMenuBar::FindMenuItem( const wxString &menuString, const wxString &itemString ) const
 
414
{
 
415
    wxMenuList::compatibility_iterator node = m_menus.GetFirst();
 
416
    while (node)
 
417
    {
 
418
        wxMenu *menu = node->GetData();
 
419
        int res = FindMenuItemRecursive( menu, menuString, itemString);
 
420
        if (res != -1)
 
421
            return res;
 
422
        node = node->GetNext();
 
423
    }
 
424
 
 
425
    return wxNOT_FOUND;
 
426
}
 
427
 
 
428
// Find a wxMenuItem using its id. Recurses down into sub-menus
 
429
static wxMenuItem* FindMenuItemByIdRecursive(const wxMenu* menu, int id)
 
430
{
 
431
    wxMenuItem* result = menu->FindChildItem(id);
 
432
 
 
433
    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
 
434
    while ( node && result == NULL )
 
435
    {
 
436
        wxMenuItem *item = node->GetData();
 
437
        if (item->IsSubMenu())
 
438
        {
 
439
            result = FindMenuItemByIdRecursive( item->GetSubMenu(), id );
 
440
        }
 
441
        node = node->GetNext();
 
442
    }
 
443
 
 
444
    return result;
 
445
}
 
446
 
 
447
wxMenuItem* wxMenuBar::FindItem( int id, wxMenu **menuForItem ) const
 
448
{
 
449
    wxMenuItem* result = 0;
 
450
    wxMenuList::compatibility_iterator node = m_menus.GetFirst();
 
451
    while (node && result == 0)
 
452
    {
 
453
        wxMenu *menu = node->GetData();
 
454
        result = FindMenuItemByIdRecursive( menu, id );
 
455
        node = node->GetNext();
 
456
    }
 
457
 
 
458
    if ( menuForItem )
 
459
    {
 
460
        *menuForItem = result ? result->GetMenu() : NULL;
 
461
    }
 
462
 
 
463
    return result;
 
464
}
 
465
 
 
466
void wxMenuBar::EnableTop( size_t pos, bool flag )
 
467
{
 
468
    wxMenuList::compatibility_iterator node = m_menus.Item( pos );
 
469
 
 
470
    wxCHECK_RET( node, wxT("menu not found") );
 
471
 
 
472
    wxMenu* menu = node->GetData();
 
473
 
 
474
    if (menu->m_owner)
 
475
        gtk_widget_set_sensitive( menu->m_owner, flag );
 
476
}
 
477
 
 
478
bool wxMenuBar::IsEnabledTop(size_t pos) const
 
479
{
 
480
    wxMenuList::compatibility_iterator node = m_menus.Item( pos );
 
481
    wxCHECK_MSG( node, false, wxS("invalid index in IsEnabledTop") );
 
482
    wxMenu* const menu = node->GetData();
 
483
    wxCHECK_MSG( menu->m_owner, true, wxS("no menu owner?") );
 
484
    return gtk_widget_get_sensitive( menu->m_owner ) != 0;
 
485
}
 
486
 
 
487
wxString wxMenuBar::GetMenuLabel( size_t pos ) const
 
488
{
 
489
    wxMenuList::compatibility_iterator node = m_menus.Item( pos );
 
490
 
 
491
    wxCHECK_MSG( node, wxT("invalid"), wxT("menu not found") );
 
492
 
 
493
    wxMenu* menu = node->GetData();
 
494
 
 
495
    return menu->GetTitle();
 
496
}
 
497
 
 
498
void wxMenuBar::SetMenuLabel( size_t pos, const wxString& label )
 
499
{
 
500
    wxMenuList::compatibility_iterator node = m_menus.Item( pos );
 
501
 
 
502
    wxCHECK_RET( node, wxT("menu not found") );
 
503
 
 
504
    wxMenu* menu = node->GetData();
 
505
 
 
506
    menu->SetTitle( label );
 
507
 
 
508
    const wxString str(wxConvertMnemonicsToGTK(label));
 
509
    if (menu->m_owner)
 
510
        gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_bin_get_child(GTK_BIN(menu->m_owner))), wxGTK_CONV(str));
 
511
}
 
512
 
 
513
//-----------------------------------------------------------------------------
 
514
// "activate"
 
515
//-----------------------------------------------------------------------------
 
516
 
 
517
extern "C" {
 
518
static void menuitem_activate(GtkWidget*, wxMenuItem* item)
 
519
{
 
520
    if (!item->IsEnabled())
 
521
        return;
 
522
 
 
523
    if ( !IsMenuEventAllowed(item->GetMenu()) )
 
524
        return;
 
525
 
 
526
    int id = item->GetId();
 
527
    if (id == wxGTK_TITLE_ID)
 
528
    {
 
529
        // ignore events from the menu title
 
530
        return;
 
531
    }
 
532
 
 
533
    if (item->IsCheckable())
 
534
    {
 
535
        bool isReallyChecked = item->IsChecked(),
 
536
            isInternallyChecked = item->wxMenuItemBase::IsChecked();
 
537
 
 
538
        // ensure that the internal state is always consistent with what is
 
539
        // shown on the screen
 
540
        item->wxMenuItemBase::Check(isReallyChecked);
 
541
 
 
542
        // we must not report the events for the radio button going up nor the
 
543
        // events resulting from the calls to wxMenuItem::Check()
 
544
        if ( (item->GetKind() == wxITEM_RADIO && !isReallyChecked) ||
 
545
             (isInternallyChecked == isReallyChecked) )
 
546
        {
 
547
            return;
 
548
        }
 
549
    }
 
550
 
 
551
    wxMenu* menu = item->GetMenu();
 
552
    menu->SendEvent(id, item->IsCheckable() ? item->IsChecked() : -1);
 
553
 
 
554
    // A lot of existing code, including any program that closes its main
 
555
    // window from a menu handler and expects the program to exit -- as our own
 
556
    // minimal sample -- relies on getting an idle event after a menu event.
 
557
    // But when using Ubuntu Unity detached menus, we get called from a DBUS
 
558
    // handler called from g_timeout_dispatch() and Glib doesn't send us any
 
559
    // idle events after it. So ask explicitly for an idle event to get one.
 
560
    wxWakeUpIdle();
 
561
}
 
562
}
 
563
 
 
564
//-----------------------------------------------------------------------------
 
565
// "select"
 
566
//-----------------------------------------------------------------------------
 
567
 
 
568
extern "C" {
 
569
static void menuitem_select(GtkWidget*, wxMenuItem* item)
 
570
{
 
571
    if (!item->IsEnabled())
 
572
        return;
 
573
 
 
574
    wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item->GetId());
 
575
    DoCommonMenuCallbackCode(item->GetMenu(), event);
 
576
}
 
577
}
 
578
 
 
579
//-----------------------------------------------------------------------------
 
580
// "deselect"
 
581
//-----------------------------------------------------------------------------
 
582
 
 
583
extern "C" {
 
584
static void menuitem_deselect(GtkWidget*, wxMenuItem* item)
 
585
{
 
586
    if (!item->IsEnabled())
 
587
        return;
 
588
 
 
589
    wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, -1 );
 
590
    DoCommonMenuCallbackCode(item->GetMenu(), event);
 
591
}
 
592
}
 
593
 
 
594
//-----------------------------------------------------------------------------
 
595
// wxMenuItem
 
596
//-----------------------------------------------------------------------------
 
597
 
 
598
wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
 
599
                                int id,
 
600
                                const wxString& name,
 
601
                                const wxString& help,
 
602
                                wxItemKind kind,
 
603
                                wxMenu *subMenu)
 
604
{
 
605
    return new wxMenuItem(parentMenu, id, name, help, kind, subMenu);
 
606
}
 
607
 
 
608
wxMenuItem::wxMenuItem(wxMenu *parentMenu,
 
609
                       int id,
 
610
                       const wxString& text,
 
611
                       const wxString& help,
 
612
                       wxItemKind kind,
 
613
                       wxMenu *subMenu)
 
614
          : wxMenuItemBase(parentMenu, id, text, help, kind, subMenu)
 
615
{
 
616
    m_menuItem = NULL;
 
617
}
 
618
 
 
619
#if WXWIN_COMPATIBILITY_2_8
 
620
wxMenuItem::wxMenuItem(wxMenu *parentMenu,
 
621
                       int id,
 
622
                       const wxString& text,
 
623
                       const wxString& help,
 
624
                       bool isCheckable,
 
625
                       wxMenu *subMenu)
 
626
          : wxMenuItemBase(parentMenu, id, text, help,
 
627
                           isCheckable ? wxITEM_CHECK : wxITEM_NORMAL, subMenu)
 
628
{
 
629
    m_menuItem = NULL;
 
630
}
 
631
#endif
 
632
 
 
633
wxMenuItem::~wxMenuItem()
 
634
{
 
635
    if (m_menuItem)
 
636
        g_object_unref(m_menuItem);
 
637
   // don't delete menu items, the menus take care of that
 
638
}
 
639
 
 
640
void wxMenuItem::SetMenuItem(GtkWidget* menuItem)
 
641
{
 
642
    if (m_menuItem)
 
643
        g_object_unref(m_menuItem);
 
644
    m_menuItem = menuItem;
 
645
    if (menuItem)
 
646
        g_object_ref(menuItem);
 
647
}
 
648
 
 
649
void wxMenuItem::SetItemLabel( const wxString& str )
 
650
{
 
651
#if wxUSE_ACCEL
 
652
    if (m_menuItem)
 
653
    {
 
654
        // remove old accelerator
 
655
        guint accel_key;
 
656
        GdkModifierType accel_mods;
 
657
        wxGetGtkAccel(this, &accel_key, &accel_mods);
 
658
        if (accel_key)
 
659
        {
 
660
            gtk_widget_remove_accelerator(
 
661
                m_menuItem, m_parentMenu->m_accel, accel_key, accel_mods);
 
662
        }
 
663
    }
 
664
#endif // wxUSE_ACCEL
 
665
    wxMenuItemBase::SetItemLabel(str);
 
666
    if (m_menuItem)
 
667
        SetGtkLabel();
 
668
}
 
669
 
 
670
void wxMenuItem::SetGtkLabel()
 
671
{
 
672
    const wxString text = wxConvertMnemonicsToGTK(m_text.BeforeFirst('\t'));
 
673
    GtkLabel* label = GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_menuItem)));
 
674
    gtk_label_set_text_with_mnemonic(label, wxGTK_CONV_SYS(text));
 
675
#if wxUSE_ACCEL
 
676
    guint accel_key;
 
677
    GdkModifierType accel_mods;
 
678
    wxGetGtkAccel(this, &accel_key, &accel_mods);
 
679
    if (accel_key)
 
680
    {
 
681
        gtk_widget_add_accelerator(
 
682
            m_menuItem, "activate", m_parentMenu->m_accel,
 
683
            accel_key, accel_mods, GTK_ACCEL_VISIBLE);
 
684
    }
 
685
#endif // wxUSE_ACCEL
 
686
}
 
687
 
 
688
void wxMenuItem::SetBitmap(const wxBitmap& bitmap)
 
689
{
 
690
    if (m_kind == wxITEM_NORMAL)
 
691
        m_bitmap = bitmap;
 
692
    else
 
693
    {
 
694
        wxFAIL_MSG("only normal menu items can have bitmaps");
 
695
    }
 
696
}
 
697
 
 
698
void wxMenuItem::Check( bool check )
 
699
{
 
700
    wxCHECK_RET( m_menuItem, wxT("invalid menu item") );
 
701
 
 
702
    if (check == m_isChecked)
 
703
        return;
 
704
 
 
705
    wxMenuItemBase::Check( check );
 
706
 
 
707
    switch ( GetKind() )
 
708
    {
 
709
        case wxITEM_CHECK:
 
710
        case wxITEM_RADIO:
 
711
            gtk_check_menu_item_set_active( (GtkCheckMenuItem*)m_menuItem, (gint)check );
 
712
            break;
 
713
 
 
714
        default:
 
715
            wxFAIL_MSG( wxT("can't check this item") );
 
716
    }
 
717
}
 
718
 
 
719
void wxMenuItem::Enable( bool enable )
 
720
{
 
721
    wxCHECK_RET( m_menuItem, wxT("invalid menu item") );
 
722
 
 
723
    gtk_widget_set_sensitive( m_menuItem, enable );
 
724
    wxMenuItemBase::Enable( enable );
 
725
}
 
726
 
 
727
bool wxMenuItem::IsChecked() const
 
728
{
 
729
    wxCHECK_MSG( m_menuItem, false, wxT("invalid menu item") );
 
730
 
 
731
    wxCHECK_MSG( IsCheckable(), false,
 
732
                 wxT("can't get state of uncheckable item!") );
 
733
 
 
734
    return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(m_menuItem)) != 0;
 
735
}
 
736
 
 
737
//-----------------------------------------------------------------------------
 
738
// wxMenu
 
739
//-----------------------------------------------------------------------------
 
740
 
 
741
extern "C" {
 
742
// "map" from m_menu
 
743
static void menu_map(GtkWidget*, wxMenu* menu)
 
744
{
 
745
    wxMenuEvent event(wxEVT_MENU_OPEN, menu->m_popupShown ? -1 : 0, menu);
 
746
    DoCommonMenuCallbackCode(menu, event);
 
747
}
 
748
 
 
749
// "hide" from m_menu
 
750
static void menu_hide(GtkWidget*, wxMenu* menu)
 
751
{
 
752
    // When using Ubuntu Unity desktop environment we get "hide" signal even
 
753
    // when the window is not shown yet because Unity hides all the menus to
 
754
    // show them only in the global menu bar. Just ignore this even instead of
 
755
    // crashing in DoCommonMenuCallbackCode().
 
756
    if ( !menu->GetWindow() )
 
757
        return;
 
758
 
 
759
    wxMenuEvent event(wxEVT_MENU_CLOSE, menu->m_popupShown ? -1 : 0, menu);
 
760
    menu->m_popupShown = false;
 
761
    DoCommonMenuCallbackCode(menu, event);
 
762
}
 
763
}
 
764
 
 
765
// "can_activate_accel" from menu item
 
766
extern "C" {
 
767
static gboolean can_activate_accel(GtkWidget*, guint, wxMenu* menu)
 
768
{
 
769
    menu->UpdateUI();
 
770
    // always allow our "activate" handler to be called
 
771
    return true;
 
772
}
 
773
}
 
774
 
 
775
void wxMenu::Init()
 
776
{
 
777
    m_popupShown = false;
 
778
 
 
779
    m_accel = gtk_accel_group_new();
 
780
    m_menu = gtk_menu_new();
 
781
    g_object_ref_sink(m_menu);
 
782
 
 
783
    m_owner = NULL;
 
784
 
 
785
    // Tearoffs are entries, just like separators. So if we want this
 
786
    // menu to be a tear-off one, we just append a tearoff entry
 
787
    // immediately.
 
788
    if ( m_style & wxMENU_TEAROFF )
 
789
    {
 
790
        GtkWidget *tearoff = gtk_tearoff_menu_item_new();
 
791
 
 
792
        gtk_menu_shell_append(GTK_MENU_SHELL(m_menu), tearoff);
 
793
    }
 
794
 
 
795
    // append the title as the very first entry if we have it
 
796
    if ( !m_title.empty() )
 
797
    {
 
798
        Append(wxGTK_TITLE_ID, m_title);
 
799
        AppendSeparator();
 
800
    }
 
801
 
 
802
    // "show" occurs for sub-menus which are not showing, so use "map" instead
 
803
    g_signal_connect(m_menu, "map", G_CALLBACK(menu_map), this);
 
804
    g_signal_connect(m_menu, "hide", G_CALLBACK(menu_hide), this);
 
805
}
 
806
 
 
807
wxMenu::~wxMenu()
 
808
{
 
809
    // Destroying a menu generates a "hide" signal even if it's not shown
 
810
    // currently, so disconnect it to avoid dummy wxEVT_MENU_CLOSE events
 
811
    // generation.
 
812
    g_signal_handlers_disconnect_matched(m_menu,
 
813
        GSignalMatchType(G_SIGNAL_MATCH_DATA), 0, 0, NULL, NULL, this);
 
814
 
 
815
    if (m_owner)
 
816
    {
 
817
        gtk_widget_destroy(m_owner);
 
818
        g_object_unref(m_owner);
 
819
    }
 
820
    else
 
821
        gtk_widget_destroy(m_menu);
 
822
 
 
823
    g_object_unref(m_menu);
 
824
    g_object_unref(m_accel);
 
825
}
 
826
 
 
827
void wxMenu::SetLayoutDirection(const wxLayoutDirection dir)
 
828
{
 
829
    if ( m_owner )
 
830
        wxWindow::GTKSetLayout(m_owner, dir);
 
831
    //else: will be called later by wxMenuBar again
 
832
}
 
833
 
 
834
wxLayoutDirection wxMenu::GetLayoutDirection() const
 
835
{
 
836
    return wxWindow::GTKGetLayout(m_owner);
 
837
}
 
838
 
 
839
wxString wxMenu::GetTitle() const
 
840
{
 
841
    return wxConvertMnemonicsFromGTK(wxMenuBase::GetTitle());
 
842
}
 
843
 
 
844
void wxMenu::SetTitle(const wxString& title)
 
845
{
 
846
    wxMenuBase::SetTitle(wxConvertMnemonicsToGTK(title));
 
847
}
 
848
 
 
849
void wxMenu::GtkAppend(wxMenuItem* mitem, int pos)
 
850
{
 
851
    GtkWidget *menuItem;
 
852
    switch (mitem->GetKind())
 
853
    {
 
854
        case wxITEM_SEPARATOR:
 
855
            menuItem = gtk_separator_menu_item_new();
 
856
            break;
 
857
        case wxITEM_CHECK:
 
858
            menuItem = gtk_check_menu_item_new_with_label("");
 
859
            break;
 
860
        case wxITEM_RADIO:
 
861
            {
 
862
                // See if we need to create a new radio group for this item or
 
863
                // add it to an existing one.
 
864
                wxMenuItem* radioGroupItem = NULL;
 
865
 
 
866
                const size_t numItems = GetMenuItemCount();
 
867
                const size_t n = pos == -1 ? numItems - 1 : size_t(pos);
 
868
 
 
869
                if (n != 0)
 
870
                {
 
871
                    wxMenuItem* const itemPrev = FindItemByPosition(n - 1);
 
872
                    if ( itemPrev->GetKind() == wxITEM_RADIO )
 
873
                    {
 
874
                        // Appending an item after an existing radio item puts
 
875
                        // it into the same radio group.
 
876
                        radioGroupItem = itemPrev;
 
877
                    }
 
878
                }
 
879
 
 
880
                if (radioGroupItem == NULL && n != numItems - 1)
 
881
                {
 
882
                    wxMenuItem* const itemNext = FindItemByPosition(n + 1);
 
883
                    if ( itemNext->GetKind() == wxITEM_RADIO )
 
884
                    {
 
885
                        // Inserting an item before an existing radio item
 
886
                        // also puts it into the existing radio group.
 
887
                        radioGroupItem = itemNext;
 
888
                    }
 
889
                }
 
890
 
 
891
                GSList* group = NULL;
 
892
                if ( radioGroupItem )
 
893
                {
 
894
                    group = gtk_radio_menu_item_get_group(
 
895
                              GTK_RADIO_MENU_ITEM(radioGroupItem->GetMenuItem())
 
896
                            );
 
897
                }
 
898
 
 
899
                menuItem = gtk_radio_menu_item_new_with_label(group, "");
 
900
            }
 
901
            break;
 
902
        default:
 
903
            wxFAIL_MSG("unexpected menu item kind");
 
904
            // fall through
 
905
        case wxITEM_NORMAL:
 
906
            const wxBitmap& bitmap = mitem->GetBitmap();
 
907
            const char* stockid;
 
908
            if (bitmap.IsOk())
 
909
            {
 
910
                // always use pixbuf, because pixmap mask does not
 
911
                // work with disabled images in some themes
 
912
                GtkWidget* image = gtk_image_new_from_pixbuf(bitmap.GetPixbuf());
 
913
                menuItem = gtk_image_menu_item_new_with_label("");
 
914
                gtk_widget_show(image);
 
915
                gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuItem), image);
 
916
            }
 
917
            else if ((stockid = wxGetStockGtkID(mitem->GetId())) != NULL)
 
918
                // use stock bitmap for this item if available on the assumption
 
919
                // that it never hurts to follow GTK+ conventions more closely
 
920
                menuItem = gtk_image_menu_item_new_from_stock(stockid, NULL);
 
921
            else
 
922
                menuItem = gtk_menu_item_new_with_label("");
 
923
            break;
 
924
    }
 
925
    mitem->SetMenuItem(menuItem);
 
926
 
 
927
    gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu), menuItem, pos);
 
928
 
 
929
    gtk_widget_show( menuItem );
 
930
 
 
931
    if ( !mitem->IsSeparator() )
 
932
    {
 
933
        mitem->SetGtkLabel();
 
934
        g_signal_connect (menuItem, "select",
 
935
                          G_CALLBACK(menuitem_select), mitem);
 
936
        g_signal_connect (menuItem, "deselect",
 
937
                          G_CALLBACK(menuitem_deselect), mitem);
 
938
 
 
939
        if ( mitem->IsSubMenu() && mitem->GetKind() != wxITEM_RADIO && mitem->GetKind() != wxITEM_CHECK )
 
940
        {
 
941
            gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), mitem->GetSubMenu()->m_menu );
 
942
 
 
943
            gtk_widget_show( mitem->GetSubMenu()->m_menu );
 
944
        }
 
945
        else
 
946
        {
 
947
            g_signal_connect(menuItem, "can_activate_accel",
 
948
                G_CALLBACK(can_activate_accel), this);
 
949
            g_signal_connect (menuItem, "activate",
 
950
                              G_CALLBACK(menuitem_activate),
 
951
                              mitem);
 
952
        }
 
953
    }
 
954
}
 
955
 
 
956
wxMenuItem* wxMenu::DoAppend(wxMenuItem *mitem)
 
957
{
 
958
    if (wxMenuBase::DoAppend(mitem))
 
959
    {
 
960
        GtkAppend(mitem);
 
961
        return mitem;
 
962
    }
 
963
    return NULL;
 
964
}
 
965
 
 
966
wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
 
967
{
 
968
    if (wxMenuBase::DoInsert(pos, item))
 
969
    {
 
970
        GtkAppend(item, int(pos));
 
971
        return item;
 
972
    }
 
973
    return NULL;
 
974
}
 
975
 
 
976
wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 
977
{
 
978
    if ( !wxMenuBase::DoRemove(item) )
 
979
        return NULL;
 
980
 
 
981
    GtkWidget * const mitem = item->GetMenuItem();
 
982
 
 
983
    g_signal_handlers_disconnect_matched(mitem,
 
984
        GSignalMatchType(G_SIGNAL_MATCH_DATA), 0, 0, NULL, NULL, item);
 
985
 
 
986
#ifdef __WXGTK3__
 
987
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), NULL);
 
988
#else
 
989
    gtk_menu_item_remove_submenu(GTK_MENU_ITEM(mitem));
 
990
#endif
 
991
 
 
992
    gtk_widget_destroy(mitem);
 
993
    item->SetMenuItem(NULL);
 
994
 
 
995
    return item;
 
996
}
 
997
 
 
998
void wxMenu::Attach(wxMenuBarBase *menubar)
 
999
{
 
1000
    wxMenuBase::Attach(menubar);
 
1001
 
 
1002
    // inherit layout direction from menubar.
 
1003
    SetLayoutDirection(menubar->GetLayoutDirection());
 
1004
}
 
1005
 
 
1006
// ----------------------------------------------------------------------------
 
1007
// helpers
 
1008
// ----------------------------------------------------------------------------
 
1009
 
 
1010
#if wxUSE_ACCEL
 
1011
 
 
1012
static wxString GetGtkHotKey( const wxMenuItem& item )
 
1013
{
 
1014
    wxString hotkey;
 
1015
 
 
1016
    wxAcceleratorEntry *accel = item.GetAccel();
 
1017
    if ( accel )
 
1018
    {
 
1019
        int flags = accel->GetFlags();
 
1020
        if ( flags & wxACCEL_ALT )
 
1021
            hotkey += wxT("<alt>");
 
1022
        if ( flags & wxACCEL_CTRL )
 
1023
            hotkey += wxT("<control>");
 
1024
        if ( flags & wxACCEL_SHIFT )
 
1025
            hotkey += wxT("<shift>");
 
1026
 
 
1027
        int code = accel->GetKeyCode();
 
1028
        switch ( code )
 
1029
        {
 
1030
            case WXK_F1:
 
1031
            case WXK_F2:
 
1032
            case WXK_F3:
 
1033
            case WXK_F4:
 
1034
            case WXK_F5:
 
1035
            case WXK_F6:
 
1036
            case WXK_F7:
 
1037
            case WXK_F8:
 
1038
            case WXK_F9:
 
1039
            case WXK_F10:
 
1040
            case WXK_F11:
 
1041
            case WXK_F12:
 
1042
            case WXK_F13:
 
1043
            case WXK_F14:
 
1044
            case WXK_F15:
 
1045
            case WXK_F16:
 
1046
            case WXK_F17:
 
1047
            case WXK_F18:
 
1048
            case WXK_F19:
 
1049
            case WXK_F20:
 
1050
            case WXK_F21:
 
1051
            case WXK_F22:
 
1052
            case WXK_F23:
 
1053
            case WXK_F24:
 
1054
                hotkey += wxString::Format(wxT("F%d"), code - WXK_F1 + 1);
 
1055
                break;
 
1056
 
 
1057
                // TODO: we should use gdk_keyval_name() (a.k.a.
 
1058
                //       XKeysymToString) here as well as hardcoding the keysym
 
1059
                //       names this might be not portable
 
1060
           case WXK_INSERT:
 
1061
                hotkey << wxT("Insert" );
 
1062
                break;
 
1063
            case WXK_DELETE:
 
1064
                hotkey << wxT("Delete" );
 
1065
                break;
 
1066
            case WXK_UP:
 
1067
                hotkey << wxT("Up" );
 
1068
                break;
 
1069
            case WXK_DOWN:
 
1070
                hotkey << wxT("Down" );
 
1071
                break;
 
1072
            case WXK_PAGEUP:
 
1073
                hotkey << wxT("Page_Up" );
 
1074
                break;
 
1075
            case WXK_PAGEDOWN:
 
1076
                hotkey << wxT("Page_Down" );
 
1077
                break;
 
1078
            case WXK_LEFT:
 
1079
                hotkey << wxT("Left" );
 
1080
                break;
 
1081
            case WXK_RIGHT:
 
1082
                hotkey << wxT("Right" );
 
1083
                break;
 
1084
            case WXK_HOME:
 
1085
                hotkey << wxT("Home" );
 
1086
                break;
 
1087
            case WXK_END:
 
1088
                hotkey << wxT("End" );
 
1089
                break;
 
1090
            case WXK_RETURN:
 
1091
                hotkey << wxT("Return" );
 
1092
                break;
 
1093
            case WXK_BACK:
 
1094
                hotkey << wxT("BackSpace" );
 
1095
                break;
 
1096
            case WXK_TAB:
 
1097
                hotkey << wxT("Tab" );
 
1098
                break;
 
1099
            case WXK_ESCAPE:
 
1100
                hotkey << wxT("Esc" );
 
1101
                break;
 
1102
            case WXK_SPACE:
 
1103
                hotkey << wxT("space" );
 
1104
                break;
 
1105
            case WXK_MULTIPLY:
 
1106
                hotkey << wxT("Multiply" );
 
1107
                break;
 
1108
            case WXK_ADD:
 
1109
                hotkey << wxT("Add" );
 
1110
                break;
 
1111
            case WXK_SEPARATOR:
 
1112
                hotkey << wxT("Separator" );
 
1113
                break;
 
1114
            case WXK_SUBTRACT:
 
1115
                hotkey << wxT("Subtract" );
 
1116
                break;
 
1117
            case WXK_DECIMAL:
 
1118
                hotkey << wxT("Decimal" );
 
1119
                break;
 
1120
            case WXK_DIVIDE:
 
1121
                hotkey << wxT("Divide" );
 
1122
                break;
 
1123
            case WXK_CANCEL:
 
1124
                hotkey << wxT("Cancel" );
 
1125
                break;
 
1126
            case WXK_CLEAR:
 
1127
                hotkey << wxT("Clear" );
 
1128
                break;
 
1129
            case WXK_MENU:
 
1130
                hotkey << wxT("Menu" );
 
1131
                break;
 
1132
            case WXK_PAUSE:
 
1133
                hotkey << wxT("Pause" );
 
1134
                break;
 
1135
            case WXK_CAPITAL:
 
1136
                hotkey << wxT("Capital" );
 
1137
                break;
 
1138
            case WXK_SELECT:
 
1139
                hotkey << wxT("Select" );
 
1140
                break;
 
1141
            case WXK_PRINT:
 
1142
                hotkey << wxT("Print" );
 
1143
                break;
 
1144
            case WXK_EXECUTE:
 
1145
                hotkey << wxT("Execute" );
 
1146
                break;
 
1147
            case WXK_SNAPSHOT:
 
1148
                hotkey << wxT("Snapshot" );
 
1149
                break;
 
1150
            case WXK_HELP:
 
1151
                hotkey << wxT("Help" );
 
1152
                break;
 
1153
            case WXK_NUMLOCK:
 
1154
                hotkey << wxT("Num_Lock" );
 
1155
                break;
 
1156
            case WXK_SCROLL:
 
1157
                hotkey << wxT("Scroll_Lock" );
 
1158
                break;
 
1159
            case WXK_NUMPAD_INSERT:
 
1160
                hotkey << wxT("KP_Insert" );
 
1161
                break;
 
1162
            case WXK_NUMPAD_DELETE:
 
1163
                hotkey << wxT("KP_Delete" );
 
1164
                break;
 
1165
             case WXK_NUMPAD_SPACE:
 
1166
                hotkey << wxT("KP_Space" );
 
1167
                break;
 
1168
            case WXK_NUMPAD_TAB:
 
1169
                hotkey << wxT("KP_Tab" );
 
1170
                break;
 
1171
            case WXK_NUMPAD_ENTER:
 
1172
                hotkey << wxT("KP_Enter" );
 
1173
                break;
 
1174
            case WXK_NUMPAD_F1: case WXK_NUMPAD_F2: case WXK_NUMPAD_F3:
 
1175
            case WXK_NUMPAD_F4:
 
1176
                hotkey += wxString::Format(wxT("KP_F%d"), code - WXK_NUMPAD_F1 + 1);
 
1177
                break;
 
1178
            case WXK_NUMPAD_HOME:
 
1179
                hotkey << wxT("KP_Home" );
 
1180
                break;
 
1181
            case WXK_NUMPAD_LEFT:
 
1182
                hotkey << wxT("KP_Left" );
 
1183
                break;
 
1184
             case WXK_NUMPAD_UP:
 
1185
                hotkey << wxT("KP_Up" );
 
1186
                break;
 
1187
            case WXK_NUMPAD_RIGHT:
 
1188
                hotkey << wxT("KP_Right" );
 
1189
                break;
 
1190
            case WXK_NUMPAD_DOWN:
 
1191
                hotkey << wxT("KP_Down" );
 
1192
                break;
 
1193
            case WXK_NUMPAD_PAGEUP:
 
1194
                hotkey << wxT("KP_Page_Up" );
 
1195
                break;
 
1196
            case WXK_NUMPAD_PAGEDOWN:
 
1197
                hotkey << wxT("KP_Page_Down" );
 
1198
                break;
 
1199
            case WXK_NUMPAD_END:
 
1200
                hotkey << wxT("KP_End" );
 
1201
                break;
 
1202
            case WXK_NUMPAD_BEGIN:
 
1203
                hotkey << wxT("KP_Begin" );
 
1204
                break;
 
1205
            case WXK_NUMPAD_EQUAL:
 
1206
                hotkey << wxT("KP_Equal" );
 
1207
                break;
 
1208
            case WXK_NUMPAD_MULTIPLY:
 
1209
                hotkey << wxT("KP_Multiply" );
 
1210
                break;
 
1211
            case WXK_NUMPAD_ADD:
 
1212
                hotkey << wxT("KP_Add" );
 
1213
                break;
 
1214
            case WXK_NUMPAD_SEPARATOR:
 
1215
                hotkey << wxT("KP_Separator" );
 
1216
                break;
 
1217
            case WXK_NUMPAD_SUBTRACT:
 
1218
                hotkey << wxT("KP_Subtract" );
 
1219
                break;
 
1220
            case WXK_NUMPAD_DECIMAL:
 
1221
                hotkey << wxT("KP_Decimal" );
 
1222
                break;
 
1223
            case WXK_NUMPAD_DIVIDE:
 
1224
                hotkey << wxT("KP_Divide" );
 
1225
                break;
 
1226
           case WXK_NUMPAD0: case WXK_NUMPAD1: case WXK_NUMPAD2:
 
1227
           case WXK_NUMPAD3: case WXK_NUMPAD4: case WXK_NUMPAD5:
 
1228
           case WXK_NUMPAD6: case WXK_NUMPAD7: case WXK_NUMPAD8: case WXK_NUMPAD9:
 
1229
                hotkey += wxString::Format(wxT("KP_%d"), code - WXK_NUMPAD0);
 
1230
                break;
 
1231
            case WXK_WINDOWS_LEFT:
 
1232
                hotkey << wxT("Super_L" );
 
1233
                break;
 
1234
            case WXK_WINDOWS_RIGHT:
 
1235
                hotkey << wxT("Super_R" );
 
1236
                break;
 
1237
            case WXK_WINDOWS_MENU:
 
1238
                hotkey << wxT("Menu" );
 
1239
                break;
 
1240
            case WXK_COMMAND:
 
1241
                hotkey << wxT("Command" );
 
1242
                break;
 
1243
          /* These probably wouldn't work as there is no SpecialX in gdk/keynames.txt
 
1244
            case WXK_SPECIAL1: case WXK_SPECIAL2: case WXK_SPECIAL3: case WXK_SPECIAL4:
 
1245
            case WXK_SPECIAL5: case WXK_SPECIAL6: case WXK_SPECIAL7: case WXK_SPECIAL8:
 
1246
            case WXK_SPECIAL9:  case WXK_SPECIAL10:  case WXK_SPECIAL11: case WXK_SPECIAL12:
 
1247
            case WXK_SPECIAL13: case WXK_SPECIAL14: case WXK_SPECIAL15: case WXK_SPECIAL16:
 
1248
            case WXK_SPECIAL17: case WXK_SPECIAL18: case WXK_SPECIAL19:  case WXK_SPECIAL20:
 
1249
                hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1);
 
1250
                break;
 
1251
          */
 
1252
                // if there are any other keys wxAcceleratorEntry::Create() may
 
1253
                // return, we should process them here
 
1254
 
 
1255
            default:
 
1256
                if ( code < 127 )
 
1257
                {
 
1258
                    const wxString
 
1259
                        name = wxGTK_CONV_BACK_SYS(gdk_keyval_name((guint)code));
 
1260
                    if ( !name.empty() )
 
1261
                    {
 
1262
                        hotkey << name;
 
1263
                        break;
 
1264
                    }
 
1265
                }
 
1266
 
 
1267
                wxFAIL_MSG( wxT("unknown keyboard accel") );
 
1268
        }
 
1269
 
 
1270
        delete accel;
 
1271
    }
 
1272
 
 
1273
    return hotkey;
 
1274
}
 
1275
 
 
1276
static void
 
1277
wxGetGtkAccel(const wxMenuItem* item, guint* accel_key, GdkModifierType* accel_mods)
 
1278
{
 
1279
    *accel_key = 0;
 
1280
    const wxString string = GetGtkHotKey(*item);
 
1281
    if (!string.empty())
 
1282
        gtk_accelerator_parse(wxGTK_CONV_SYS(string), accel_key, accel_mods);
 
1283
    else
 
1284
    {
 
1285
        GtkStockItem stock_item;
 
1286
        const char* stockid = wxGetStockGtkID(item->GetId());
 
1287
        if (stockid && gtk_stock_lookup(stockid, &stock_item))
 
1288
        {
 
1289
            *accel_key = stock_item.keyval;
 
1290
            *accel_mods = stock_item.modifier;
 
1291
        }
 
1292
    }
 
1293
}
 
1294
#endif // wxUSE_ACCEL
 
1295
 
 
1296
const char *wxGetStockGtkID(wxWindowID id)
 
1297
{
 
1298
    #define STOCKITEM(wx,gtk)      \
 
1299
        case wx:                   \
 
1300
            return gtk;
 
1301
 
 
1302
    #if GTK_CHECK_VERSION(2,8,0)
 
1303
        #define STOCKITEM_28(wx,gtk) STOCKITEM(wx,gtk)
 
1304
    #else
 
1305
        #define STOCKITEM_28(wx,gtk)
 
1306
    #endif
 
1307
 
 
1308
    #if GTK_CHECK_VERSION(2,10,0)
 
1309
        #define STOCKITEM_210(wx,gtk) STOCKITEM(wx,gtk)
 
1310
    #else
 
1311
        #define STOCKITEM_210(wx,gtk)
 
1312
    #endif
 
1313
 
 
1314
 
 
1315
    switch (id)
 
1316
    {
 
1317
        STOCKITEM(wxID_ABOUT,            GTK_STOCK_ABOUT)
 
1318
        STOCKITEM(wxID_ADD,              GTK_STOCK_ADD)
 
1319
        STOCKITEM(wxID_APPLY,            GTK_STOCK_APPLY)
 
1320
        STOCKITEM(wxID_BACKWARD,         GTK_STOCK_GO_BACK)
 
1321
        STOCKITEM(wxID_BOLD,             GTK_STOCK_BOLD)
 
1322
        STOCKITEM(wxID_BOTTOM,           GTK_STOCK_GOTO_BOTTOM)
 
1323
        STOCKITEM(wxID_CANCEL,           GTK_STOCK_CANCEL)
 
1324
        STOCKITEM(wxID_CDROM,            GTK_STOCK_CDROM)
 
1325
        STOCKITEM(wxID_CLEAR,            GTK_STOCK_CLEAR)
 
1326
        STOCKITEM(wxID_CLOSE,            GTK_STOCK_CLOSE)
 
1327
        STOCKITEM(wxID_CONVERT,          GTK_STOCK_CONVERT)
 
1328
        STOCKITEM(wxID_COPY,             GTK_STOCK_COPY)
 
1329
        STOCKITEM(wxID_CUT,              GTK_STOCK_CUT)
 
1330
        STOCKITEM(wxID_DELETE,           GTK_STOCK_DELETE)
 
1331
        STOCKITEM(wxID_DOWN,             GTK_STOCK_GO_DOWN)
 
1332
        STOCKITEM(wxID_EDIT,             GTK_STOCK_EDIT)
 
1333
        STOCKITEM(wxID_EXECUTE,          GTK_STOCK_EXECUTE)
 
1334
        STOCKITEM(wxID_EXIT,             GTK_STOCK_QUIT)
 
1335
        STOCKITEM(wxID_FILE,             GTK_STOCK_FILE)
 
1336
        STOCKITEM(wxID_FIND,             GTK_STOCK_FIND)
 
1337
        STOCKITEM(wxID_FIRST,            GTK_STOCK_GOTO_FIRST)
 
1338
        STOCKITEM(wxID_FLOPPY,           GTK_STOCK_FLOPPY)
 
1339
        STOCKITEM(wxID_FORWARD,          GTK_STOCK_GO_FORWARD)
 
1340
        STOCKITEM(wxID_HARDDISK,         GTK_STOCK_HARDDISK)
 
1341
        STOCKITEM(wxID_HELP,             GTK_STOCK_HELP)
 
1342
        STOCKITEM(wxID_HOME,             GTK_STOCK_HOME)
 
1343
        STOCKITEM(wxID_INDENT,           GTK_STOCK_INDENT)
 
1344
        STOCKITEM(wxID_INDEX,            GTK_STOCK_INDEX)
 
1345
        STOCKITEM_28(wxID_INFO,           GTK_STOCK_INFO)
 
1346
        STOCKITEM(wxID_ITALIC,           GTK_STOCK_ITALIC)
 
1347
        STOCKITEM(wxID_JUMP_TO,          GTK_STOCK_JUMP_TO)
 
1348
        STOCKITEM(wxID_JUSTIFY_CENTER,   GTK_STOCK_JUSTIFY_CENTER)
 
1349
        STOCKITEM(wxID_JUSTIFY_FILL,     GTK_STOCK_JUSTIFY_FILL)
 
1350
        STOCKITEM(wxID_JUSTIFY_LEFT,     GTK_STOCK_JUSTIFY_LEFT)
 
1351
        STOCKITEM(wxID_JUSTIFY_RIGHT,    GTK_STOCK_JUSTIFY_RIGHT)
 
1352
        STOCKITEM(wxID_LAST,             GTK_STOCK_GOTO_LAST)
 
1353
        STOCKITEM(wxID_NETWORK,          GTK_STOCK_NETWORK)
 
1354
        STOCKITEM(wxID_NEW,              GTK_STOCK_NEW)
 
1355
        STOCKITEM(wxID_NO,               GTK_STOCK_NO)
 
1356
        STOCKITEM(wxID_OK,               GTK_STOCK_OK)
 
1357
        STOCKITEM(wxID_OPEN,             GTK_STOCK_OPEN)
 
1358
        STOCKITEM(wxID_PASTE,            GTK_STOCK_PASTE)
 
1359
        STOCKITEM(wxID_PREFERENCES,      GTK_STOCK_PREFERENCES)
 
1360
        STOCKITEM(wxID_PREVIEW,          GTK_STOCK_PRINT_PREVIEW)
 
1361
        STOCKITEM(wxID_PRINT,            GTK_STOCK_PRINT)
 
1362
        STOCKITEM(wxID_PROPERTIES,       GTK_STOCK_PROPERTIES)
 
1363
        STOCKITEM(wxID_REDO,             GTK_STOCK_REDO)
 
1364
        STOCKITEM(wxID_REFRESH,          GTK_STOCK_REFRESH)
 
1365
        STOCKITEM(wxID_REMOVE,           GTK_STOCK_REMOVE)
 
1366
        STOCKITEM(wxID_REPLACE,          GTK_STOCK_FIND_AND_REPLACE)
 
1367
        STOCKITEM(wxID_REVERT_TO_SAVED,  GTK_STOCK_REVERT_TO_SAVED)
 
1368
        STOCKITEM(wxID_SAVE,             GTK_STOCK_SAVE)
 
1369
        STOCKITEM(wxID_SAVEAS,           GTK_STOCK_SAVE_AS)
 
1370
        STOCKITEM_210(wxID_SELECTALL,    GTK_STOCK_SELECT_ALL)
 
1371
        STOCKITEM(wxID_SELECT_COLOR,     GTK_STOCK_SELECT_COLOR)
 
1372
        STOCKITEM(wxID_SELECT_FONT,      GTK_STOCK_SELECT_FONT)
 
1373
        STOCKITEM(wxID_SORT_ASCENDING,   GTK_STOCK_SORT_ASCENDING)
 
1374
        STOCKITEM(wxID_SORT_DESCENDING,  GTK_STOCK_SORT_DESCENDING)
 
1375
        STOCKITEM(wxID_SPELL_CHECK,      GTK_STOCK_SPELL_CHECK)
 
1376
        STOCKITEM(wxID_STOP,             GTK_STOCK_STOP)
 
1377
        STOCKITEM(wxID_STRIKETHROUGH,    GTK_STOCK_STRIKETHROUGH)
 
1378
        STOCKITEM(wxID_TOP,              GTK_STOCK_GOTO_TOP)
 
1379
        STOCKITEM(wxID_UNDELETE,         GTK_STOCK_UNDELETE)
 
1380
        STOCKITEM(wxID_UNDERLINE,        GTK_STOCK_UNDERLINE)
 
1381
        STOCKITEM(wxID_UNDO,             GTK_STOCK_UNDO)
 
1382
        STOCKITEM(wxID_UNINDENT,         GTK_STOCK_UNINDENT)
 
1383
        STOCKITEM(wxID_UP,               GTK_STOCK_GO_UP)
 
1384
        STOCKITEM(wxID_YES,              GTK_STOCK_YES)
 
1385
        STOCKITEM(wxID_ZOOM_100,         GTK_STOCK_ZOOM_100)
 
1386
        STOCKITEM(wxID_ZOOM_FIT,         GTK_STOCK_ZOOM_FIT)
 
1387
        STOCKITEM(wxID_ZOOM_IN,          GTK_STOCK_ZOOM_IN)
 
1388
        STOCKITEM(wxID_ZOOM_OUT,         GTK_STOCK_ZOOM_OUT)
 
1389
 
 
1390
        default:
 
1391
            break;
 
1392
    };
 
1393
 
 
1394
    #undef STOCKITEM
 
1395
 
 
1396
    return NULL;
 
1397
}
 
1398
 
 
1399
#endif // wxUSE_MENUS