From 7d7c43c4c3de2db7000a98cee109b93bb328c582 Mon Sep 17 00:00:00 2001 From: dsr Date: Mon, 25 Jan 2021 21:44:17 -0500 Subject: [PATCH 1/9] Use localeconv() under Android, it's available there now As of NDK21d, localeconv() is available under Android and can be used in wxQt there. --- src/common/intl.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 44c4df22a8..df38f5d8ee 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1897,8 +1897,6 @@ wxString GetDateFormatFromLangInfo(wxLocaleInfo index) /* static */ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) { -// TODO: as of 2014 Android doesn't has complete locale support (use java api) -#if !(defined(__WXQT__) && defined(__ANDROID__)) lconv * const lc = localeconv(); if ( !lc ) return wxString(); @@ -1940,7 +1938,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) default: wxFAIL_MSG( "unknown wxLocaleInfo value" ); } -#endif + return wxString(); } From a3b655fd60d1a2221b3c5d4a2f17b1a80fad088e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 27 Jan 2021 18:16:06 +0100 Subject: [PATCH 2/9] Ensure that HAVE_GETHOSTBYADDR is defined under Android too This is supposed to always be the same as HAVE_GETHOSTBYNAME, but wasn't, because the latter was explicitly defined for Android after defining the former as it. --- src/common/sckaddr.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/common/sckaddr.cpp b/src/common/sckaddr.cpp index 461c51f00f..3e252f0522 100644 --- a/src/common/sckaddr.cpp +++ b/src/common/sckaddr.cpp @@ -106,11 +106,6 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress, wxSockAddress); #endif #endif // __WINDOWS__ -// we assume that we have gethostbyaddr_r() if and only if we have -// gethostbyname_r() and that it uses the similar conventions to it (see -// comment in configure) -#define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME - #ifdef __ANDROID__ #ifndef HAVE_GETHOSTBYNAME #define HAVE_GETHOSTBYNAME @@ -125,7 +120,13 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress, wxSockAddress); #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6 #define HAVE_FUNC_GETHOSTBYADDR_R_6 #endif -#endif +#endif // __ANDROID__/!__ANDROID__ + +// we assume that we have gethostbyaddr_r() if and only if we have +// gethostbyname_r() and that it uses the similar conventions to it (see +// comment in configure) +#define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME + // the _r functions need the extra buffer parameter but unfortunately its type // differs between different systems and for the systems which use opaque // structs for it (at least AIX and OpenBSD) it must be zero-filled before From bb0f2f976885693952f4412d0740ea14542d3d1a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 27 Jan 2021 18:29:57 +0100 Subject: [PATCH 3/9] Fix endptr output value in android_wcstoxxx() These functions incorrectly multiplied an increment of wchar_t pointer by sizeof(wchar_t), which made the result quite wrong, so just don't do this. See 744ea8a618 (For Android (wxQT), add private wcstol, wcstoul and wcstod, 2015-02-11). --- src/common/wxcrt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/wxcrt.cpp b/src/common/wxcrt.cpp index c131cec80d..8437ce6ff6 100644 --- a/src/common/wxcrt.cpp +++ b/src/common/wxcrt.cpp @@ -1256,7 +1256,7 @@ int wxVsscanf(const wxCStrData& str, const wchar_t *format, va_list ap) #define ANDROID_WCSTO_END \ if(endptr) { \ if(dstendp) \ - *endptr = (wchar_t*)(nptr + (dstendp - dst) * sizeof(wchar_t)); \ + *endptr = (wchar_t*)(nptr + (dstendp - dst)); \ else \ *endptr = NULL; \ } \ From b692dd8aefd5c786be1ff4fec04536e626084b5b Mon Sep 17 00:00:00 2001 From: dsr Date: Mon, 25 Jan 2021 21:44:17 -0500 Subject: [PATCH 4/9] Implement wxMenuItem::SetFont() for wxQt --- include/wx/qt/menuitem.h | 1 + src/qt/menuitem.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/wx/qt/menuitem.h b/include/wx/qt/menuitem.h index 5f507f01f9..f5219cd1a9 100644 --- a/include/wx/qt/menuitem.h +++ b/include/wx/qt/menuitem.h @@ -40,6 +40,7 @@ public: virtual QAction *GetHandle() const; + virtual void SetFont(const wxFont& font); private: // Qt is using an action instead of a menu item. wxQtAction *m_qtAction; diff --git a/src/qt/menuitem.cpp b/src/qt/menuitem.cpp index a2f84822d6..97a85fdb37 100644 --- a/src/qt/menuitem.cpp +++ b/src/qt/menuitem.cpp @@ -128,6 +128,11 @@ void wxMenuItem::SetBitmap(const wxBitmap& bitmap) } } +void wxMenuItem::SetFont(const wxFont& font) +{ + m_qtAction->setFont(font.GetHandle()); +} + QAction *wxMenuItem::GetHandle() const { return m_qtAction; From 98e4f910a5ac692eea8f63d1f08d0d2ed4d84f85 Mon Sep 17 00:00:00 2001 From: dsr Date: Mon, 25 Jan 2021 21:44:17 -0500 Subject: [PATCH 5/9] Implement setting wxGLCanvas attributes in wxQt Simply remove the premature "return true" which was somehow added back in df13791078 (Merge wxQT branch into the trunk., 2014-08-24) and add WX_GL_MAJOR_VERSION support. --- src/qt/glcanvas.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qt/glcanvas.cpp b/src/qt/glcanvas.cpp index 4361b344a3..3ee0275868 100644 --- a/src/qt/glcanvas.cpp +++ b/src/qt/glcanvas.cpp @@ -425,7 +425,6 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format) { if (!wxattrs) return true; - return true; // set default parameters to false format.setDoubleBuffer(false); @@ -513,6 +512,10 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format) // can we somehow indicate if it's not supported? break; + case WX_GL_MAJOR_VERSION: + format.setVersion ( v,0 ); + break; + default: wxLogDebug(wxT("Unsupported OpenGL attribute %d"), wxattrs[arg]); From d046a8fbc69b36f9ab42ebfe5f9414894d70ea8a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 27 Jan 2021 18:41:06 +0100 Subject: [PATCH 6/9] Remove currently unused wxGLContext::m_glContext No real changes, just remove unused private field. --- include/wx/qt/glcanvas.h | 3 --- src/qt/glcanvas.cpp | 1 - 2 files changed, 4 deletions(-) diff --git a/include/wx/qt/glcanvas.h b/include/wx/qt/glcanvas.h index 08fc13b887..c08889e125 100644 --- a/include/wx/qt/glcanvas.h +++ b/include/wx/qt/glcanvas.h @@ -24,9 +24,6 @@ public: virtual bool SetCurrent(const wxGLCanvas& win) const wxOVERRIDE; -private: - QGLContext *m_glContext; - wxDECLARE_CLASS(wxGLContext); }; diff --git a/src/qt/glcanvas.cpp b/src/qt/glcanvas.cpp index 3ee0275868..5713a57f8a 100644 --- a/src/qt/glcanvas.cpp +++ b/src/qt/glcanvas.cpp @@ -338,7 +338,6 @@ wxIMPLEMENT_CLASS(wxGLContext, wxWindow); wxGLContext::wxGLContext(wxGLCanvas *WXUNUSED(win), const wxGLContext* WXUNUSED(other), const wxGLContextAttrs *WXUNUSED(ctxAttrs)) { -// m_glContext = win->GetHandle()->context(); } bool wxGLContext::SetCurrent(const wxGLCanvas&) const From 2cf57fda36bd287f9b385dcb77dfa83fc2c68422 Mon Sep 17 00:00:00 2001 From: dsr Date: Mon, 25 Jan 2021 21:44:17 -0500 Subject: [PATCH 7/9] Avoid crashes when destroying wxGLCanvas Block signals that are not safe to process any more. --- include/wx/qt/glcanvas.h | 2 ++ src/qt/glcanvas.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/wx/qt/glcanvas.h b/include/wx/qt/glcanvas.h index c08889e125..743ef5901a 100644 --- a/include/wx/qt/glcanvas.h +++ b/include/wx/qt/glcanvas.h @@ -54,6 +54,8 @@ public: const wxString& name = wxGLCanvasName, const wxPalette& palette = wxNullPalette); + ~wxGLCanvas(); + bool Create(wxWindow *parent, const wxGLAttributes& dispAttrs, wxWindowID id = wxID_ANY, diff --git a/src/qt/glcanvas.cpp b/src/qt/glcanvas.cpp index 5713a57f8a..29e6c09dd7 100644 --- a/src/qt/glcanvas.cpp +++ b/src/qt/glcanvas.cpp @@ -377,6 +377,12 @@ wxGLCanvas::wxGLCanvas(wxWindow *parent, Create(parent, id, pos, size, style, name, attribList, palette); } +wxGLCanvas::~wxGLCanvas() +{ + // Avoid sending further signals (i.e. if deleting the current page) + m_qtWindow->blockSignals(true); +} + bool wxGLCanvas::Create(wxWindow *parent, const wxGLAttributes& dispAttrs, wxWindowID id, From 7cd90e5b825b100a1a53b33eadc6797130395b86 Mon Sep 17 00:00:00 2001 From: dsr Date: Mon, 25 Jan 2021 21:44:17 -0500 Subject: [PATCH 8/9] Reset stored window pointer in wxWindow dtor This protects against orphan Qt events and signals. --- src/qt/window.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/window.cpp b/src/qt/window.cpp index 9020a7fc1c..d07dfcc221 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -309,6 +309,9 @@ wxWindowQt::~wxWindowQt() DestroyChildren(); // This also destroys scrollbars + if (m_qtWindow) + QtStoreWindowPointer( GetHandle(), NULL ); + #if wxUSE_DRAG_AND_DROP SetDropTarget(NULL); #endif From a3d58dadd97685941c061e7e5aa6c6b8f13de82d Mon Sep 17 00:00:00 2001 From: dsr Date: Mon, 25 Jan 2021 21:44:17 -0500 Subject: [PATCH 9/9] Implement wxGestureEvent support for wxQt Do it generically in wxWindow and also provide a special version for wxGLCanvas for which the standard implementation doesn't work well. --- include/wx/qt/private/winevent.h | 129 +++++++++++++++++++++++++++ include/wx/qt/window.h | 1 + src/qt/glcanvas.cpp | 148 +++++++++++++++++++++++++++++++ src/qt/window.cpp | 52 +++++++++++ 4 files changed, 330 insertions(+) diff --git a/include/wx/qt/private/winevent.h b/include/wx/qt/private/winevent.h index 21f0e505b6..54db552c44 100644 --- a/include/wx/qt/private/winevent.h +++ b/include/wx/qt/private/winevent.h @@ -19,6 +19,9 @@ #include "wx/qt/private/converter.h" #include "wx/qt/private/utils.h" +#include +#include + class QPaintEvent; template< typename Handler > @@ -327,6 +330,132 @@ protected: virtual bool winEvent ( MSG * message, long * result ) { } virtual bool x11Event ( XEvent * event ) { } */ + virtual bool event(QEvent *event) + { + if (event->type() == QEvent::Gesture) + { + return gestureEvent(static_cast(event), event); + } + + return Widget::event(event); + } + + bool gestureEvent(QGestureEvent *gesture, QEvent *event) + { + if (QGesture *tah = gesture->gesture(Qt::TapAndHoldGesture)) + { + // Set the policy so that accepted gestures are taken by the first window that gets them + tah->setGestureCancelPolicy ( QGesture::CancelAllInContext ); + tapandholdTriggered(static_cast(tah), event); + } + + if (QGesture *pan = gesture->gesture(Qt::PanGesture)) + { + panTriggered(static_cast(pan), event); + } + + if (QGesture *pinch = gesture->gesture(Qt::PinchGesture)) + { + pinchTriggered(static_cast(pinch), event); + } + + return true; + } + + void tapandholdTriggered(QTapAndHoldGesture *gesture, QEvent *event) + { + wxWindow *win = wxWindow::QtRetrieveWindowPointer( this ); + + if (gesture->state() == Qt::GestureFinished) + { + if ( win ) + { + wxLongPressEvent ev(win->GetId()); + ev.SetPosition( wxQtConvertPoint( gesture->position().toPoint() ) ); + + ev.SetGestureEnd(); + win->ProcessWindowEvent( ev ); + event->accept(); + } + + } + else if (gesture->state() == Qt::GestureStarted) + { + event->accept(); + } + else + { + event->accept(); + } + } + + void panTriggered(QPanGesture *gesture, QEvent *event) + { + wxWindow *win = wxWindow::QtRetrieveWindowPointer( this ); + + if (win) + { + wxPanGestureEvent evp(win->GetId()); + QPoint pos = QCursor::pos(); + evp.SetPosition( wxQtConvertPoint( pos ) ); + + QPoint offset = gesture->offset().toPoint(); + QPoint offset_last = gesture->lastOffset().toPoint(); + QPoint delta(offset.x() - offset_last.x(), offset.y() - offset_last.y()); + + evp.SetDelta( wxQtConvertPoint( delta ) ); + + switch(gesture->state()) + { + case Qt::GestureStarted: + evp.SetGestureStart(); + break; + case Qt::GestureFinished: + case Qt::GestureCanceled: + evp.SetGestureEnd(); + break; + default: + break; + } + + win->ProcessWindowEvent( evp ); + + event->accept(); + } + } + + void pinchTriggered(QPinchGesture *gesture, QEvent *event) + { + wxWindow *win = wxWindow::QtRetrieveWindowPointer( this ); + if (win) + { + + qreal this_sf = gesture->scaleFactor(); + QPoint center_point = gesture->centerPoint().toPoint(); + + wxZoomGestureEvent evp(win->GetId()); + evp.SetPosition( wxQtConvertPoint( center_point ) ); + evp.SetZoomFactor( this_sf); + + switch(gesture->state()) + { + case Qt::GestureStarted: + evp.SetGestureStart(); + break; + case Qt::GestureFinished: + case Qt::GestureCanceled: + evp.SetGestureEnd(); + break; + default: + break; + } + + win->ProcessWindowEvent( evp ); + + event->accept(); + + } + } }; #endif diff --git a/include/wx/qt/window.h b/include/wx/qt/window.h index a426af9f67..2f4d26aa28 100644 --- a/include/wx/qt/window.h +++ b/include/wx/qt/window.h @@ -221,6 +221,7 @@ protected: // itself. virtual QWidget* QtGetParentWidget() const { return GetHandle(); } + virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE; QWidget *m_qtWindow; diff --git a/src/qt/glcanvas.cpp b/src/qt/glcanvas.cpp index 29e6c09dd7..2fea936c55 100644 --- a/src/qt/glcanvas.cpp +++ b/src/qt/glcanvas.cpp @@ -13,6 +13,8 @@ #include "wx/glcanvas.h" #include +#include +#include #if defined(__VISUALC__) #pragma message("OpenGL support is not implemented in wxQt") @@ -347,6 +349,29 @@ bool wxGLContext::SetCurrent(const wxGLCanvas&) const return false; } +//--------------------------------------------------------------------------- +// PanGestureRecognizer - helper class for wxGLCanvas +//--------------------------------------------------------------------------- + +class PanGestureRecognizer : public QGestureRecognizer +{ +private: + static const int MINIMUM_DISTANCE = 10; + + typedef QGestureRecognizer parent; + + bool IsValidMove(int dx, int dy); + + virtual QGesture* create(QObject* pTarget); + + virtual QGestureRecognizer::Result recognize(QGesture* pGesture, QObject *pWatched, QEvent *pEvent); + + void reset (QGesture *pGesture); + + QPointF m_startPoint; + QPointF m_lastPoint; +}; + //--------------------------------------------------------------------------- // wxGlCanvas //--------------------------------------------------------------------------- @@ -416,6 +441,10 @@ bool wxGLCanvas::Create(wxWindow *parent, m_qtWindow = new wxQtGLWidget(parent, this, format); + // Create and register a custom pan recognizer, available to all instances of this class. + QGestureRecognizer* pPanRecognizer = new PanGestureRecognizer(); + QGestureRecognizer::registerRecognizer(pPanRecognizer); + return wxWindow::Create( parent, id, pos, size, style, name ); } @@ -567,4 +596,123 @@ bool wxGLApp::InitGLVisual(const int *attribList) return false; } +// ----------------------------------------------------------------------------------------- +// We want a private pan gesture recognizer for GL canvas, +// since the Qt standard recognizers do not function well for this window. +// ----------------------------------------------------------------------------------------- + +bool +PanGestureRecognizer::IsValidMove(int dx, int dy) +{ + // The moved distance is to small to count as not just a glitch. + if ((qAbs(dx) < MINIMUM_DISTANCE) && (qAbs(dy) < MINIMUM_DISTANCE)) + return false; + + return true; +} + + +// virtual +QGesture* +PanGestureRecognizer::create(QObject* pTarget) +{ + return new QPanGesture(pTarget); +} + + +// virtual +QGestureRecognizer::Result +PanGestureRecognizer::recognize(QGesture* pGesture, QObject *pWatched, QEvent *pEvent) +{ + wxUnusedVar(pWatched); + QGestureRecognizer::Result result = QGestureRecognizer::Ignore; + QPanGesture *pPan = static_cast(pGesture); + + const QTouchEvent *ev = static_cast(pEvent); + + switch (pEvent->type()) + { + case QEvent::TouchBegin: + { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + m_startPoint = p1.startScreenPos().toPoint(); + m_lastPoint = m_startPoint; + + pPan->setLastOffset(QPointF(0,0)); + pPan->setOffset(QPointF(0,0)); + + result = QGestureRecognizer::MayBeGesture; + } + break; + + case QEvent::TouchEnd: + { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QPointF endPoint = p1.screenPos().toPoint(); + + pPan->setLastOffset(pPan->offset()); + pPan->setOffset(QPointF(p1.pos().x() - p1.startPos().x(), + p1.pos().y() - p1.startPos().y())); + + pPan->setHotSpot(p1.startScreenPos()); + + // process distance and direction + int dx = endPoint.x() - m_startPoint.x(); + int dy = endPoint.y() - m_startPoint.y(); + + if (!IsValidMove(dx, dy)) + { + // Just a click, so no gesture. + result = QGestureRecognizer::Ignore; + } + else + { + result = QGestureRecognizer::FinishGesture; + } + + } + break; + + case QEvent::TouchUpdate: + { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QPointF upPoint = p1.screenPos().toPoint(); + + pPan->setLastOffset(pPan->offset()); + pPan->setOffset(QPointF(p1.pos().x() - p1.startPos().x(), + p1.pos().y() - p1.startPos().y())); + + pPan->setHotSpot(p1.startScreenPos()); + + int dx = upPoint.x() - m_lastPoint.x(); + int dy = upPoint.y() - m_lastPoint.y(); + + if( (dx > 2) || (dx < -2) || (dy > 2) || (dy < -2)) + { + result = QGestureRecognizer::TriggerGesture; + + } + else + { + result = QGestureRecognizer::Ignore; + } + + m_lastPoint = upPoint; + } + break; + + default: + break; + } + + return result; +} + +void +PanGestureRecognizer::reset(QGesture *pGesture) +{ + pGesture->setProperty("startPoint", QVariant(QVariant::Invalid)); + parent::reset(pGesture); +} + #endif // wxUSE_GLCANVAS diff --git a/src/qt/window.cpp b/src/qt/window.cpp index d07dfcc221..3474337f99 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -85,6 +85,28 @@ bool wxQtScrollArea::event(QEvent *e) break; } } + // QGesture events arrive without mouse capture + else if ( handler ) + { + switch ( e->type() ) + { + case QEvent::Gesture: + { + QScrollArea::event(e); + + if ( QScrollBar *vBar = verticalScrollBar() ) + vBar->triggerAction( QAbstractSlider::SliderMove ); + if ( QScrollBar *hBar = horizontalScrollBar() ) + hBar->triggerAction( QAbstractSlider::SliderMove ); + + return true; + } + + default: + break; + } + } + return QScrollArea::event(e); } @@ -1683,3 +1705,33 @@ QPainter *wxWindowQt::QtGetPainter() { return m_qtPainter.get(); } + +bool wxWindowQt::EnableTouchEvents(int eventsMask) +{ + wxCHECK_MSG( GetHandle(), false, "can't be called before creating the window" ); + + if ( eventsMask == wxTOUCH_NONE ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, false); + return true; + } + + if ( eventsMask & wxTOUCH_PRESS_GESTURES ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, true); + m_qtWindow->grabGesture(Qt::TapAndHoldGesture); + QTapAndHoldGesture::setTimeout ( 1000 ); + } + if ( eventsMask & wxTOUCH_PAN_GESTURES ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, true); + m_qtWindow->grabGesture(Qt::PanGesture); + } + if ( eventsMask & wxTOUCH_ZOOM_GESTURE ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, true); + m_qtWindow->grabGesture(Qt::PinchGesture); + } + + return true; +}