From 842dd1cfd96aeff4a9206d99e85a16c38df840c9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 21 Nov 2017 19:23:34 +0100 Subject: [PATCH] Add wxWindow::EnableTouchEvents() Don't request touch event generation for all windows by default, this has an inherent overhead and is not needed for 99% of the application windows, so require calling EnableTouchEvents() explicitly to do it instead. Note that this requires properly initializing gesture recognizers in wxOSX now that they're not always allocated, otherwise releasing them when destroying the window would crash. --- include/wx/gtk/window.h | 3 ++ include/wx/msw/window.h | 1 + include/wx/osx/cocoa/private.h | 1 + include/wx/osx/core/private.h | 2 ++ include/wx/osx/iphone/private.h | 1 + include/wx/osx/window.h | 1 + include/wx/window.h | 14 ++++++++++ interface/wx/event.h | 4 +++ interface/wx/window.h | 13 +++++++++ samples/event/gestures.cpp | 7 +++++ src/gtk/window.cpp | 26 +++++++++++++---- src/msw/window.cpp | 49 +++++++++++++++++++-------------- src/osx/cocoa/window.mm | 40 ++++++++++++++++++++------- src/osx/window_osx.cpp | 5 ++++ 14 files changed, 131 insertions(+), 36 deletions(-) diff --git a/include/wx/gtk/window.h b/include/wx/gtk/window.h index d9db061dc6..0e6d2633c3 100644 --- a/include/wx/gtk/window.h +++ b/include/wx/gtk/window.h @@ -77,6 +77,9 @@ public: virtual bool Reparent( wxWindowBase *newParent ) wxOVERRIDE; virtual void WarpPointer(int x, int y) wxOVERRIDE; +#ifdef __WXGTK3__ + virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE; +#endif // __WXGTK3__ virtual void Refresh( bool eraseBackground = true, const wxRect *rect = (const wxRect *) NULL ) wxOVERRIDE; diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index 7f710a5870..1a6af48f5b 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -100,6 +100,7 @@ public: virtual bool Reparent(wxWindowBase *newParent) wxOVERRIDE; virtual void WarpPointer(int x, int y) wxOVERRIDE; + virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE; virtual void Refresh( bool eraseBackground = true, const wxRect *rect = (const wxRect *) NULL ) wxOVERRIDE; diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index 9fd9101a84..dd20e0074e 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -128,6 +128,7 @@ public : void SetToolTip( wxToolTip* tooltip ); void InstallEventHandler( WXWidget control = NULL ); + bool EnableTouchEvents(int eventsMask); virtual bool ShouldHandleKeyNavigation(const wxKeyEvent &event) const; bool DoHandleKeyNavigation(const wxKeyEvent &event); diff --git a/include/wx/osx/core/private.h b/include/wx/osx/core/private.h index a372aa529a..5b012f9048 100644 --- a/include/wx/osx/core/private.h +++ b/include/wx/osx/core/private.h @@ -326,6 +326,8 @@ public : virtual void InstallEventHandler( WXWidget control = NULL ) = 0; + virtual bool EnableTouchEvents(int eventsMask) = 0; + // Mechanism used to keep track of whether a change should send an event // Do SendEvents(false) when starting actions that would trigger programmatic events // and SendEvents(true) at the end of the block. diff --git a/include/wx/osx/iphone/private.h b/include/wx/osx/iphone/private.h index b88a863a54..484e7525ee 100644 --- a/include/wx/osx/iphone/private.h +++ b/include/wx/osx/iphone/private.h @@ -105,6 +105,7 @@ public : void SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack = true ); void InstallEventHandler( WXWidget control = NULL ); + bool EnableTouchEvents(int WXUNUSED(eventsMask)) { return false; } virtual void DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* otherWindow); diff --git a/include/wx/osx/window.h b/include/wx/osx/window.h index 7db20f4810..caee9c1659 100644 --- a/include/wx/osx/window.h +++ b/include/wx/osx/window.h @@ -77,6 +77,7 @@ public: virtual void SetFocus() wxOVERRIDE; virtual void WarpPointer( int x, int y ) wxOVERRIDE; + virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE; virtual void Refresh( bool eraseBackground = true, const wxRect *rect = NULL ) wxOVERRIDE; diff --git a/include/wx/window.h b/include/wx/window.h index 440f097a21..27a9c856cb 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -133,6 +133,13 @@ enum wxShowEffect wxSHOW_EFFECT_MAX }; +// Values for EnableTouchEvents() mask. +enum +{ + wxTOUCH_NONE = 0x0000, + wxTOUCH_ALL_GESTURES = 0x00ff +}; + // flags for SendSizeEvent() enum { @@ -1033,6 +1040,13 @@ public: virtual bool HasCapture() const { return (wxWindow *)this == GetCapture(); } + // enable the specified touch events for this window, return false if + // the requested events are not supported + virtual bool EnableTouchEvents(int WXUNUSED(eventsMask)) + { + return false; + } + // painting the window // ------------------- diff --git a/interface/wx/event.h b/interface/wx/event.h index 13460cf42e..ae1eaeee9a 100644 --- a/interface/wx/event.h +++ b/interface/wx/event.h @@ -3649,6 +3649,10 @@ public: /** @class wxGestureEvent This is the base class for all supported gesture events. + @note Gesture events are not generated by default, you must call + wxWindow::EnableTouchEvents() with the appropriate parameter to + request their generation. + @library{wxcore} @category{events} diff --git a/interface/wx/window.h b/interface/wx/window.h index 0fa2a58c50..b0712fb378 100644 --- a/interface/wx/window.h +++ b/interface/wx/window.h @@ -3424,6 +3424,19 @@ public: */ virtual void WarpPointer(int x, int y); + /** + Request generation of touch events for this window. + + @param eventsMask Either wxTOUCH_NONE or wxTOUCH_ALL_GESTURES to + disable or enable gesture events for this window. + + @return @true if the specified events were enabled or @false if the + current platform doesn't support touch events. + + @since 3.1.1 + */ + virtual bool EnableTouchEvents(int eventsMask); + //@} diff --git a/samples/event/gestures.cpp b/samples/event/gestures.cpp index ae32890feb..06b6cd794a 100644 --- a/samples/event/gestures.cpp +++ b/samples/event/gestures.cpp @@ -43,6 +43,13 @@ MyGesturePanel::MyGesturePanel(MyGestureFrame *parent) : wxPanel(parent, wxID_AN Bind(wxEVT_PAINT, &MyGesturePanel::OnPaint, this); } + if ( !EnableTouchEvents(wxTOUCH_ALL_GESTURES) ) + { + wxLogError("Failed to enable touch events"); + + // Still bind event handlers just in case they still work? + } + // Event handlers Bind(wxEVT_GESTURE_PAN, &MyGesturePanel::OnPan, this); Bind(wxEVT_GESTURE_ZOOM, &MyGesturePanel::OnZoom, this); diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 36c049b5d2..26bc0734b7 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -3435,6 +3435,26 @@ wxWindowGesturesData::~wxWindowGesturesData() #endif // wxGTK_HAS_GESTURES_SUPPORT +// This method must be always defined for GTK+ 3 as it's declared in the +// header, where we can't (easily) test for wxGTK_HAS_GESTURES_SUPPORT. +#ifdef __WXGTK3__ + +bool wxWindowGTK::EnableTouchEvents(int eventsMask) +{ +#ifdef wxGTK_HAS_GESTURES_SUPPORT + // Check if gestures support is also available during run-time. + if ( gtk_check_version(3, 14, 0) == NULL ) + { + m_gesturesData = new wxWindowGesturesData(this, GetConnectWidget()); + return true; + } +#endif // wxGTK_HAS_GESTURES_SUPPORT + + return wxWindowBase::EnableTouchEvents(eventsMask); +} + +#endif // __WXGTK3__ + void wxWindowGTK::ConnectWidget( GtkWidget *widget ) { static bool isSourceAttached; @@ -3477,12 +3497,6 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget ) G_CALLBACK (gtk_window_enter_callback), this); g_signal_connect (widget, "leave_notify_event", G_CALLBACK (gtk_window_leave_callback), this); - -#ifdef wxGTK_HAS_GESTURES_SUPPORT - // Check if gestures support is also available during run-time. - if ( gtk_check_version(3, 14, 0) == NULL ) - m_gesturesData = new wxWindowGesturesData(this, widget); -#endif // wxGTK_HAS_GESTURES_SUPPORT } void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 9fb00bffeb..0de02b2508 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -906,6 +906,35 @@ void wxWindowMSW::WarpPointer(int x, int y) } } +bool wxWindowMSW::EnableTouchEvents(int eventsMask) +{ +#ifdef WM_GESTURE + if ( GestureFuncs::IsOk() && eventsMask == wxTOUCH_ALL_GESTURES ) + { + // Configure to receive all gestures + GESTURECONFIG gestureConfig = {0, GC_ALLGESTURES, 0}; + + if ( !GestureFuncs::SetGestureConfig() + ( + m_hWnd, + 0, // Reserved, must be always 0. + 1, // Number of gesture configurations. + &gestureConfig, // Pointer to the first one. + sizeof(GESTURECONFIG) // Size of each configuration. + ) + ) + { + wxLogLastError("SetGestureConfig"); + return false; + } + + return true; + } +#endif // WM_GESTURE + + return wxWindowBase::EnableTouchEvents(eventsMask); +} + void wxWindowMSW::MSWUpdateUIState(int action, int state) { // we send WM_CHANGEUISTATE so if nothing needs changing then the system @@ -3814,26 +3843,6 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, return false; } -#ifdef WM_GESTURE - if ( GestureFuncs::IsOk() ) - { - // Configure to receive all gestures - GESTURECONFIG gestureConfig = {0, GC_ALLGESTURES, 0}; - - if ( !GestureFuncs::SetGestureConfig() - ( - m_hWnd, - 0, // Reserved, must be always 0. - 1, // Number of gesture configurations. - &gestureConfig, // Pointer to the first one. - sizeof(GESTURECONFIG) // Size of each configuration. - ) - ) - { - wxLogLastError("SetGestureConfig"); - } - } -#endif // WM_GESTURE SubclassWin(m_hWnd); diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 8901482c27..15abbc43b3 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -2240,16 +2240,6 @@ void wxOSXCocoaClassAddWXMethods(Class c) wxOSX_CLASS_ADD_METHOD(c, @selector(mouseEntered:), (IMP) wxOSX_mouseEvent, "v@:@" ) wxOSX_CLASS_ADD_METHOD(c, @selector(mouseExited:), (IMP) wxOSX_mouseEvent, "v@:@" ) -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 - wxOSX_CLASS_ADD_METHOD(c, @selector(handlePanGesture:), (IMP) wxOSX_panGestureEvent, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(handleZoomGesture:), (IMP) wxOSX_zoomGestureEvent, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(handleRotateGesture:), (IMP) wxOSX_rotateGestureEvent, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(handleLongPressGesture:), (IMP) wxOSX_longPressEvent, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(touchesBeganWithEvent:), (IMP) wxOSX_touchesBegan, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(touchesMovedWithEvent:), (IMP) wxOSX_touchesMoved, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(touchesEndedWithEvent:), (IMP) wxOSX_touchesEnded, "v@:@" ) -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 - wxOSX_CLASS_ADD_METHOD(c, @selector(magnifyWithEvent:), (IMP)wxOSX_mouseEvent, "v@:@") wxOSX_CLASS_ADD_METHOD(c, @selector(cursorUpdate:), (IMP) wxOSX_cursorUpdate, "v@:@" ) @@ -2333,6 +2323,11 @@ void wxWidgetCocoaImpl::Init() m_hasEditor = false; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 + m_panGestureRecognizer = nil; + m_magnificationGestureRecognizer = nil; + m_rotationGestureRecognizer = nil; + m_pressGestureRecognizer = nil; + m_touchCount = 0; m_lastTouchTime = 0; m_allowedGestures = 0; @@ -3289,23 +3284,43 @@ void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control ) NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil]; [m_osxView addTrackingArea: area]; [area release]; +} +bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask) +{ #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 if ( wxPlatformInfo::Get().CheckOSVersion(10, 10) ) { if ( IsUserPane() ) { + Class cls = [m_osxView class]; + m_panGestureRecognizer = [[NSPanGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handlePanGesture:)]; + if ( !class_respondsToSelector(cls, @selector(handlePanGesture:)) ) + class_addMethod(cls, @selector(handlePanGesture:), (IMP) wxOSX_panGestureEvent, "v@:@" ); m_magnificationGestureRecognizer = [[NSMagnificationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleZoomGesture:)]; + if ( !class_respondsToSelector(cls, @selector(handleZoomGesture:)) ) + class_addMethod(cls, @selector(handleZoomGesture:), (IMP) wxOSX_zoomGestureEvent, "v@:@" ); m_rotationGestureRecognizer = [[NSRotationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleRotateGesture:)]; + if ( !class_respondsToSelector(cls, @selector(handleRotateGesture:)) ) + class_addMethod(cls, @selector(handleRotateGesture:), (IMP) wxOSX_rotateGestureEvent, "v@:@" ); m_pressGestureRecognizer = [[NSPressGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleLongPressGesture:)]; + if ( !class_respondsToSelector(cls, @selector(handleLongPressGesture:)) ) + class_addMethod(cls, @selector(handleLongPressGesture:), (IMP) wxOSX_longPressEvent, "v@:@" ); + + if ( !class_respondsToSelector(cls, @selector(touchesBeganWithEvent:)) ) + class_addMethod(cls, @selector(touchesBeganWithEvent:), (IMP) wxOSX_touchesBegan, "v@:@" ); + if ( !class_respondsToSelector(cls, @selector(touchesMovedWithEvent:)) ) + class_addMethod(cls, @selector(touchesMovedWithEvent:), (IMP) wxOSX_touchesMoved, "v@:@" ); + if ( !class_respondsToSelector(cls, @selector(touchesEndedWithEvent:)) ) + class_addMethod(cls, @selector(touchesEndedWithEvent:), (IMP) wxOSX_touchesEnded, "v@:@" ); [m_osxView addGestureRecognizer:m_panGestureRecognizer]; [m_osxView addGestureRecognizer:m_magnificationGestureRecognizer]; @@ -3313,9 +3328,14 @@ void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control ) [m_osxView addGestureRecognizer:m_pressGestureRecognizer]; [m_osxView setAcceptsTouchEvents:YES]; + + return true; } } #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 + + wxUnusedVar(eventsMask); + return false; } bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text) diff --git a/src/osx/window_osx.cpp b/src/osx/window_osx.cpp index 823c0beae8..c725ef8d57 100644 --- a/src/osx/window_osx.cpp +++ b/src/osx/window_osx.cpp @@ -1429,6 +1429,11 @@ void wxWindowMac::WarpPointer(int x_pos, int y_pos) #endif } +bool wxWindowMac::EnableTouchEvents(int eventsMask) +{ + return GetPeer() ? GetPeer()->EnableTouchEvents(eventsMask) : false; +} + int wxWindowMac::GetScrollPos(int orient) const { #if wxUSE_SCROLLBAR