wxGLCanvas steals plain alphanumeric shortcuts for menus on GTK

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
Gabriele Giuseppini
Experienced Solver
Experienced Solver
Posts: 56
Joined: Fri Oct 12, 2018 6:12 pm
Location: Amsterdam, the Netherlands

wxGLCanvas steals plain alphanumeric shortcuts for menus on GTK

Post by Gabriele Giuseppini »

Dear wx gurus, I'm facing a difference in behavior between MSW and GTK3.

My app (a physics simulator) consists of a frame with a wxGLCanvas in it.

The frame has a menu bar with menu items having different shortcuts - some are plain alphanumerical characters (e.g. with label "Test1\tA") while others have modifiers (e.g. with label "Test3\tCTRL+A").

The canvas is supposed to get mouse events, and thus I bind mouse event handlers to it, and allow it to get focus.

The app works fine on MSW - the canvas gets mouse events, and hitting for example "A" invokes the target of the respective menu handler. However, on GTK3 (Ubuntu 18.04, gcc 8.4.0) the plain alphanumerical shortcuts don't work anymore, while the ones with modifiers work. Referring to the example above, hitting "A" is a nop, while hitting CTRL+A invokes the respective menu handler. Removing the GLCanvas creation allows the simple alphanumerical shortcuts to work again.

Here's a minimal repro, builds and reproduces on both MSW and Linux:

Code: Select all

#include <wx/wx.h>
#include <wx/glcanvas.h>

#include <memory>

class MyApp : public wxApp
{
public:
    MyApp();
    virtual bool OnInit() wxOVERRIDE;
};

class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);

    void OnQuit(wxCommandEvent& event);

    void OnTest1(wxCommandEvent & event);
    void OnTest2(wxCommandEvent & event);
    void OnTest3(wxCommandEvent & event);

private:

    wxDECLARE_EVENT_TABLE();
};

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_EXIT,  MyFrame::OnQuit)
wxEND_EVENT_TABLE()

long const ID_MAIN_CANVAS = wxNewId();
long const ID_TEST1_MENUITEM = wxNewId();
long const ID_TEST2_MENUITEM = wxNewId();
long const ID_TEST3_MENUITEM = wxNewId();

// ============================================================================
// implementation
// ============================================================================

wxIMPLEMENT_APP(MyApp);

#if defined(__linux__) || defined(linux) || defined(__linux)
#include <X11/Xlib.h>
#endif

MyApp::MyApp()
{
}

bool MyApp::OnInit()
{
    if ( !wxApp::OnInit() )
        return false;

    wxInitAllImageHandlers();

    MyFrame *frame = new MyFrame("Minimal wxWidgets App");
    SetTopWindow(frame);
    return true;
}

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------

MyFrame::MyFrame(const wxString& title)
       : wxFrame(
           nullptr,
           wxID_ANY,
           title,
           wxDefaultPosition,
           wxSize(640, 480),
           wxDEFAULT_FRAME_STYLE,
           _T("Main Frame"))
{
    {
        wxMenuBar * menuBar = new wxMenuBar();

        {
            wxMenu * fileMenu = new wxMenu;
            fileMenu->Append(wxID_EXIT, "E&xit\tAlt-X", "Quit this program");
            menuBar->Append(fileMenu, "&File");
        }

        {
            wxMenu * testMenu = new wxMenu;
            {
                wxMenuItem * menuItem = new wxMenuItem(testMenu, ID_TEST1_MENUITEM, "Test1\tA", wxEmptyString, wxITEM_NORMAL);
                testMenu->Append(menuItem);
                Connect(ID_TEST1_MENUITEM, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&MyFrame::OnTest1);
            }
            {
                wxMenuItem * menuItem = new wxMenuItem(testMenu, ID_TEST2_MENUITEM, "Test2\tB", wxEmptyString, wxITEM_NORMAL);
                testMenu->Append(menuItem);
                Connect(ID_TEST2_MENUITEM, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&MyFrame::OnTest2);
            }
            {
                wxMenuItem * menuItem = new wxMenuItem(testMenu, ID_TEST3_MENUITEM, "Test3\tCTRL+A", wxEmptyString, wxITEM_NORMAL);
                testMenu->Append(menuItem);
                Connect(ID_TEST3_MENUITEM, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&MyFrame::OnTest3);
            }

            testMenu->Append(new wxMenuItem(testMenu, wxID_SEPARATOR));

            menuBar->Append(testMenu, "&Test");
        }

        SetMenuBar(menuBar);
    }


    // Comment this block out to verify "A" and "B" work
    {
        auto * sizer = new wxBoxSizer(wxVERTICAL);

        static int glCanvasAttributes[] =
        {
            WX_GL_RGBA,
            WX_GL_DOUBLEBUFFER,
            WX_GL_DEPTH_SIZE,      16,
            0, 0
        };

        auto * glCanvas = new wxGLCanvas(this, ID_MAIN_CANVAS, glCanvasAttributes, wxDefaultPosition, wxDefaultSize, 0L);

        sizer->Add(glCanvas, 1, wxEXPAND, 0);

        SetSizer(sizer);
    }

    SetCursor(wxCursor(wxCURSOR_CROSS));

    Show();
}

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}

void MyFrame::OnTest1(wxCommandEvent & event)
{
    wxMessageBox("Test 1!");
}

void MyFrame::OnTest2(wxCommandEvent & event)
{
    wxMessageBox("Test 2!");
}

void MyFrame::OnTest3(wxCommandEvent & event)
{
    wxMessageBox("Test 3!");
}
From this example and from my imperfect understanding of event propagation, it seems to me that the canvas somehow "steals" the alphanumerical key events and doesn't propagate them up to the parent, while the keys with modifiers are allowed to go up.

I've got two questions here. First, which of the two platforms is "at fault" here - in other words, is the canvas' stealing of the keys expected, or is it not?

Secondly, can anyone think of a workaround? Would it be as simple as registering key handlers with the canvas and explicitly propagating them up to the parent? Is there instead something that sounds less hacky?

Many thanks in advance for any pointers!
Gabriele Giuseppini
Experienced Solver
Experienced Solver
Posts: 56
Joined: Fri Oct 12, 2018 6:12 pm
Location: Amsterdam, the Netherlands

Re: wxGLCanvas steals plain alphanumeric shortcuts for menus on GTK

Post by Gabriele Giuseppini »

In case anyone's interested, it seems I'm hitting this: https://trac.wxwidgets.org/ticket/17611

It looks like the ticket won't be fixed any time soon, so I've been able to work around it by explicitly using a wxAccelerator only for the "simple" main shortcuts - on top of the shortcuts declared in the menu item labels.
Post Reply