diff --git a/include/wx/window.h b/include/wx/window.h index 20e8ec5119..92cd592644 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -1514,6 +1514,12 @@ public: // Returns true if more idle time is requested. virtual bool SendIdleEvents(wxIdleEvent& event); + // Send wxContextMenuEvent and return true if it was processed. + // + // Note that the event may end up being sent to a different window, if this + // window is part of a composite control. + bool WXSendContextMenuEvent(const wxPoint& posInScreenCoords); + // get the handle of the window for the underlying window system: this // is only used for wxWin itself or for user code which wants to call // platform-specific APIs diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index bc68dae5dc..df7810c7d6 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -614,6 +614,8 @@ GridFrame::GridFrame() grid->SetAttr(11, 11, new wxGridCellAttr); grid->SetAttr(11, 11, NULL); + grid->Bind(wxEVT_CONTEXT_MENU, &GridFrame::OnGridContextMenu, this, grid->GetId()); + wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL ); topSizer->Add( grid, 1, @@ -797,6 +799,23 @@ void GridFrame::SetTabCustomHandler(wxCommandEvent&) grid->Bind(wxEVT_GRID_TABBING, &GridFrame::OnGridCustomTab, this); } +void GridFrame::OnGridContextMenu(wxContextMenuEvent& event) +{ + // This is not supposed to happen: even if the grid consists of different + // subwindows internally, all context menu events should be seen as coming + // from the grid itself. + if ( event.GetEventObject() != grid ) + { + wxLogError("Context menu unexpectedly sent from non-grid window."); + } + else + { + wxLogMessage("wxEVT_CONTEXT_MENU in the grid at at (%d, %d)", + event.GetPosition().x, event.GetPosition().y); + } + + event.Skip(); +} void GridFrame::ToggleGridLines( wxCommandEvent& WXUNUSED(ev) ) { diff --git a/samples/grid/griddemo.h b/samples/grid/griddemo.h index 9c7ab3e8f3..a80c366b7b 100644 --- a/samples/grid/griddemo.h +++ b/samples/grid/griddemo.h @@ -122,6 +122,8 @@ class GridFrame : public wxFrame void OnGridCustomTab(wxGridEvent& event); + void OnGridContextMenu(wxContextMenuEvent& event); + public: GridFrame(); ~GridFrame(); diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index 9d0ef0a1b8..0b744892fd 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -3069,6 +3069,20 @@ wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y) #endif // wxUSE_MENUS +bool wxWindowBase::WXSendContextMenuEvent(const wxPoint& posInScreenCoords) +{ + // When the mouse click happens in a subwindow of a composite control, + // the user-visible event should seem to originate from the main window + // and, notably, use its ID and not the (usually auto-generated and so + // not very useful) ID of the subwindow. + wxWindow* const mainWin = GetMainWindowOfCompositeControl(); + + wxContextMenuEvent + evtCtx(wxEVT_CONTEXT_MENU, mainWin->GetId(), posInScreenCoords); + evtCtx.SetEventObject(mainWin); + return mainWin->HandleWindowEvent(evtCtx); +} + // methods for drawing the sizers in a visible way: this is currently only // enabled for "full debug" builds with wxDEBUG_LEVEL==2 as it doesn't work // that well and also because we don't want to leave it enabled in default diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index c211ece237..ee6e7db6d6 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -1706,12 +1706,8 @@ gtk_window_button_press_callback( GtkWidget* WXUNUSED_IN_GTK3(widget), // (a) it's a command event and so is propagated to the parent // (b) under some ports it can be generated from kbd too // (c) it uses screen coords (because of (a)) - wxContextMenuEvent evtCtx( - wxEVT_CONTEXT_MENU, - win->GetId(), - win->ClientToScreen(event.GetPosition())); - evtCtx.SetEventObject(win); - return win->GTKProcessEvent(evtCtx); + const wxPoint pos = win->ClientToScreen(event.GetPosition()); + return win->WXSendContextMenuEvent(pos); } return FALSE; diff --git a/src/gtk1/window.cpp b/src/gtk1/window.cpp index fdc2e37a2c..98224b25fb 100644 --- a/src/gtk1/window.cpp +++ b/src/gtk1/window.cpp @@ -1629,12 +1629,8 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, // (a) it's a command event and so is propagated to the parent // (b) under some ports it can be generated from kbd too // (c) it uses screen coords (because of (a)) - wxContextMenuEvent evtCtx( - wxEVT_CONTEXT_MENU, - win->GetId(), - win->ClientToScreen(event.GetPosition())); - evtCtx.SetEventObject(win); - return win->HandleWindowEvent(evtCtx); + const wxPoint pos = win->ClientToScreen(event.GetPosition()); + return win->WXSendContextMenuEvent(pos); } return FALSE; diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 23c965885c..957b185bd7 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -3636,8 +3636,6 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result, // the event may be handled by a parent window wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); - // we could have got an event from our child, reflect it back // to it if this is the case wxWindowMSW *win = NULL; @@ -3650,8 +3648,7 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result, if ( !win ) win = this; - evtCtx.SetEventObject(win); - processed = win->HandleWindowEvent(evtCtx); + processed = win->WXSendContextMenuEvent(pt); if ( !processed ) { diff --git a/src/osx/window_osx.cpp b/src/osx/window_osx.cpp index f3c4260ac7..51686ffd13 100644 --- a/src/osx/window_osx.cpp +++ b/src/osx/window_osx.cpp @@ -2338,20 +2338,7 @@ void wxWindowMac::OnMouseEvent( wxMouseEvent &event ) { if ( event.GetEventType() == wxEVT_RIGHT_DOWN ) { - // copied from wxGTK : CS - // VZ: shouldn't we move this to base class then? - - // generate a "context menu" event: this is similar to wxEVT_RIGHT_DOWN - // except that: - // - // (a) it's a command event and so is propagated to the parent - // (b) under MSW it can be generated from kbd too - // (c) it uses screen coords (because of (a)) - wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, - this->GetId(), - this->ClientToScreen(event.GetPosition())); - evtCtx.SetEventObject(this); - if ( ! HandleWindowEvent(evtCtx) ) + if ( !WXSendContextMenuEvent(ClientToScreen(event.GetPosition())) ) event.Skip() ; } else diff --git a/src/qt/window.cpp b/src/qt/window.cpp index 7a31b7a928..5e1ac194ef 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -1619,15 +1619,11 @@ bool wxWindowQt::QtHandleCloseEvent ( QWidget *handler, QCloseEvent *WXUNUSED( e bool wxWindowQt::QtHandleContextMenuEvent ( QWidget *WXUNUSED( handler ), QContextMenuEvent *event ) { - wxContextMenuEvent e( wxEVT_CONTEXT_MENU, GetId() ); - e.SetPosition( + const wxPoint pos = event->reason() == QContextMenuEvent::Keyboard ? wxDefaultPosition - : wxQtConvertPoint( event->globalPos() ) - ); - e.SetEventObject(this); - - return ProcessWindowEvent( e ); + : wxQtConvertPoint( event->globalPos() ); + return WXSendContextMenuEvent(pos); } bool wxWindowQt::QtHandleFocusEvent ( QWidget *WXUNUSED( handler ), QFocusEvent *event )