diff --git a/3rdparty/ext_qt/0027-Fetch-tablet-mapping-from-Wintab-instead-virtual-scr.patch b/3rdparty/ext_qt/0026-Fetch-mapped-screen-size-from-the-Wintab-driver.patch similarity index 53% rename from 3rdparty/ext_qt/0027-Fetch-tablet-mapping-from-Wintab-instead-virtual-scr.patch rename to 3rdparty/ext_qt/0026-Fetch-mapped-screen-size-from-the-Wintab-driver.patch index 43c58539ec..41da7dd0fa 100644 --- a/3rdparty/ext_qt/0027-Fetch-tablet-mapping-from-Wintab-instead-virtual-scr.patch +++ b/3rdparty/ext_qt/0026-Fetch-mapped-screen-size-from-the-Wintab-driver.patch @@ -1,171 +1,217 @@ -From 8a1dc023446ee4c114646b7cb5f9d6265d29877a Mon Sep 17 00:00:00 2001 +From 087561675d1c1922265c3c52faeac61ab1bc2ecf Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov -Date: Mon, 15 Apr 2019 13:48:16 +0300 -Subject: [PATCH] Fetch tablet mapping from Wintab instead virtual screen - geometry +Date: Sat, 13 Apr 2019 23:24:01 +0300 +Subject: [PATCH] Fetch mapped screen size from the Wintab driver Some devices, like Microsoft Surface Pro 5, don't map tablet's input range to the entire virtual screen area, but map it to the primary display that has actual built-in tablet sensor. In such cases we should fetch actualy mapped aread from Wintab's lcSys{Org,Ext}{X,Y} fields and use it for cursor mapping. -The patch also introduces an environment variable switch that -falls back to the old method of mapping: +If one wants to fall back to the old screen size detection method, +then an environment variable can be set: QT_IGNORE_WINTAB_MAPPING=1 When the variable is set, the scaling is done via virtual desktop area only. + +If the tablet driver is broken (e.g. Microsoft SP5, when primary +display is set to an external monitor) the user might want to override +mapping completely. Then the following variable can be used: + +QT_WINTAB_DESKTOP_RECT=x;y;width;height --- - .../windows/qwindowstabletsupport.cpp | 55 ++++++++++++++++++- - .../platforms/windows/qwindowstabletsupport.h | 11 +++- - 2 files changed, 64 insertions(+), 2 deletions(-) + .../windows/qwindowstabletsupport.cpp | 89 ++++++++++++++++++- + .../platforms/windows/qwindowstabletsupport.h | 13 ++- + 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp -index 43c6130f..e5aab523 100644 +index 18ec05e4..6a1bf02b 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp -@@ -217,6 +217,10 @@ QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context) +@@ -53,6 +53,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -216,6 +217,10 @@ QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context) // Some tablets don't support tilt, check if it is possible, if (QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_ORIENTATION, &orientation)) m_tiltSupport = orientation[0].axResolution && orientation[1].axResolution; + + connect(qGuiApp, &QGuiApplication::primaryScreenChanged, + this, QWindowsTabletSupport::slotPrimaryScreenChanged); + slotScreenGeometryChanged(); } QWindowsTabletSupport::~QWindowsTabletSupport() -@@ -395,6 +399,43 @@ QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(qint64 uniqueId, UINT +@@ -394,6 +399,84 @@ QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(qint64 uniqueId, UINT return result; } +void QWindowsTabletSupport::slotPrimaryScreenChanged(QScreen *screen) +{ + if (m_connectedScreen) + disconnect(m_connectedScreen, 0, this, 0); + + m_connectedScreen = screen; + + if (m_connectedScreen) + connect(m_connectedScreen, &QScreen::virtualGeometryChanged, + this, &QWindowsTabletSupport::slotScreenGeometryChanged); + + slotScreenGeometryChanged(); +} + +void QWindowsTabletSupport::slotScreenGeometryChanged() +{ + /** + * Some Wintab implementations map the tablet area to the entire + * virtual screen, but others (e.g. Microsoft SP5) don't. They + * may input range to a single (built-in) screen. The logic is + * quite obvious: when the screen has integrated tablet device, + * one cannot map this tablet device to another display. + * + * For such devices, we should always request mapped area from + * lcSys{Org,Ext}{X,Y} fields and use it accordingly. + */ + + LOGCONTEXT lc; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFSYSCTX, 0, &lc); -+ m_mappedScreenGeometry = QRect(lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY); ++ m_wintabScreenGeometry = QRect(lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY); + -+ qCDebug(lcQpaTablet) << "Updated tablet mapping: " << m_mappedScreenGeometry; ++ qCDebug(lcQpaTablet) << "Updated tablet mapping: " << m_wintabScreenGeometry; + if (QGuiApplication::primaryScreen()) { + qCDebug(lcQpaTablet) << " real desktop geometry: " << QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()); + } +} ++ ++void QWindowsTabletSupport::updateEffectiveScreenGeometry() ++{ ++ QRect customGeometry; ++ bool dontUseWintabDesktopRect = false; ++ ++ const QString geometry = qEnvironmentVariable("QT_WINTAB_DESKTOP_RECT"); ++ if (!geometry.isEmpty()) { ++ QString tmp = QString::fromLatin1("([+-]?\\d+);([+-]?\\d+);(\\d+);(\\d+)"); ++ ++ QRegularExpression rex(tmp); ++ QRegularExpressionMatch match = rex.match(geometry); ++ ++ if (match.hasMatch()) { ++ customGeometry.setRect(match.captured(1).toInt(), ++ match.captured(2).toInt(), ++ match.captured(3).toInt(), ++ match.captured(4).toInt()); ++ ++ qCDebug(lcQpaTablet) << "apply QT_WINTAB_DESKTOP_RECT:" << customGeometry; ++ } else { ++ qCWarning(lcQpaTablet) << "failed to parse QT_WINTAB_DESKTOP_RECT:" << geometry; ++ } ++ } ++ ++ if (qEnvironmentVariableIsSet("QT_IGNORE_WINTAB_MAPPING")) { ++ if (!customGeometry.isValid()) { ++ qCDebug(lcQpaTablet) << "fallback mapping is requested via QT_IGNORE_WINTAB_MAPPING"; ++ } else { ++ qCWarning(lcQpaTablet) << "ignoring QT_IGNORE_WINTAB_MAPPING, because QT_WINTAB_DESKTOP_RECT is set"; ++ } ++ dontUseWintabDesktopRect = true; ++ } ++ ++ m_effectiveScreenGeometry = ++ !customGeometry.isValid() ? ++ (dontUseWintabDesktopRect ? ++ QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) : ++ m_wintabScreenGeometry) : ++ customGeometry; ++} + bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam) { PACKET proximityBuffer[1]; // we are only interested in the first packet in this case -@@ -538,6 +579,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() - - static bool customGeometryIsInitialized = false; - static QRect customGeometry; -+ static bool dontUseWintabDesktopRect = false; - - if (!customGeometryIsInitialized) { - const QString geometry = qEnvironmentVariable("QT_WINTAB_DESKTOP_RECT"); -@@ -559,12 +601,23 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() - } - } +@@ -421,6 +504,8 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L + if (!totalPacks) + return false; -+ if (qEnvironmentVariableIsSet("QT_IGNORE_WINTAB_MAPPING")) { -+ if (!customGeometry.isValid()) { -+ qInfo() << "INFO: fallback mapping is requested via QT_IGNORE_WINTAB_MAPPING"; -+ } else { -+ qInfo() << "INFO: ignoring QT_IGNORE_WINTAB_MAPPING, because QT_WINTAB_DESKTOP_RECT is set"; -+ } -+ dontUseWintabDesktopRect = true; -+ } ++ updateEffectiveScreenGeometry(); + - customGeometryIsInitialized = true; - } - - const QRect virtualDesktopArea = - !customGeometry.isValid() ? -- QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) : -+ (dontUseWintabDesktopRect ? -+ QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) : -+ m_mappedScreenGeometry) : - customGeometry; + const UINT currentCursor = proximityBuffer[0].pkCursor; + UINT physicalCursorId; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId); +@@ -534,8 +619,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() + // in which case we snap the position to the mouse position. + // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext + // area is always the virtual desktop. +- const QRect virtualDesktopArea = +- QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()); ++ ++ const QRect virtualDesktopArea = m_effectiveScreenGeometry; if (QWindowsContext::verbose > 1) { + qCDebug(lcQpaTablet) << __FUNCTION__ << "processing" << packetCount diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h -index 5b1ddb52..e570f56d 100644 +index 5b1ddb52..e8b0c01b 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.h +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -45,7 +45,9 @@ #include #include +#include #include +#include #include @@ -56,6 +58,7 @@ QT_BEGIN_NAMESPACE class QDebug; class QWindow; class QRect; +class QScreen; struct QWindowsWinTab32DLL { @@ -108,7 +111,7 @@ struct QWindowsTabletDeviceData QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t); #endif -class QWindowsTabletSupport +class QWindowsTabletSupport : public QObject { Q_DISABLE_COPY(QWindowsTabletSupport) -@@ -141,6 +144,10 @@ public: +@@ -141,9 +144,14 @@ public: int absoluteRange() const { return m_absoluteRange; } void setAbsoluteRange(int a) { m_absoluteRange = a; } +private Q_SLOTS: + void slotPrimaryScreenChanged(QScreen *screen); + void slotScreenGeometryChanged(); + private: unsigned options() const; QWindowsTabletDeviceData tabletInit(qint64 uniqueId, UINT cursorType) const; -@@ -154,6 +161,8 @@ private: ++ void updateEffectiveScreenGeometry(); + + static QWindowsWinTab32DLL m_winTab32DLL; + const HWND m_window; +@@ -154,6 +162,9 @@ private: int m_currentDevice = -1; Mode m_mode = PenMode; State m_state = PenUp; + QScreen *m_connectedScreen = 0; -+ QRect m_mappedScreenGeometry; ++ QRect m_wintabScreenGeometry; ++ QRect m_effectiveScreenGeometry; }; QT_END_NAMESPACE -- 2.20.1.windows.1 diff --git a/3rdparty/ext_qt/0026-Implement-a-custom-variable-for-overriding-Wintab-s-.patch b/3rdparty/ext_qt/0026-Implement-a-custom-variable-for-overriding-Wintab-s-.patch deleted file mode 100644 index c71cb32985..0000000000 --- a/3rdparty/ext_qt/0026-Implement-a-custom-variable-for-overriding-Wintab-s-.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 73d1e5fac0d9f78a6ba23db2ac648ec52273a2dc Mon Sep 17 00:00:00 2001 -From: Dmitry Kazakov -Date: Sat, 13 Apr 2019 23:24:01 +0300 -Subject: [PATCH] Implement a custom variable for overriding Wintab's desktop - area - -If you think that Qt recognizes desktop area incorrectly, you can try -to override this choice by setting environment variable -QT_WINTAB_DESKTOP_RECT and running the application in this environment. -The value of the variable is a semicolon-separated list of integers: - -QT_WINTAB_DESKTOP_RECT=x;y;width;height ---- - .../windows/qwindowstabletsupport.cpp | 32 ++++++++++++++++++- - 1 file changed, 31 insertions(+), 1 deletion(-) - -diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp -index 18ec05e4..43c6130f 100644 ---- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp -+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp -@@ -53,6 +53,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -534,8 +535,37 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() - // in which case we snap the position to the mouse position. - // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext - // area is always the virtual desktop. -+ -+ static bool customGeometryIsInitialized = false; -+ static QRect customGeometry; -+ -+ if (!customGeometryIsInitialized) { -+ const QString geometry = qEnvironmentVariable("QT_WINTAB_DESKTOP_RECT"); -+ if (!geometry.isEmpty()) { -+ QString tmp = QString::fromLatin1("(\\d+);(\\d+);(\\d+);(\\d+)"); -+ -+ QRegularExpression rex(tmp); -+ QRegularExpressionMatch match = rex.match(geometry); -+ -+ if (match.hasMatch()) { -+ customGeometry.setRect(match.captured(1).toInt(), -+ match.captured(2).toInt(), -+ match.captured(3).toInt(), -+ match.captured(4).toInt()); -+ -+ qInfo() << "INFO: apply QT_WINTAB_DESKTOP_RECT:" << customGeometry; -+ } else { -+ qWarning() << "WARNING: failed to parse QT_WINTAB_DESKTOP_RECT:" << geometry; -+ } -+ } -+ -+ customGeometryIsInitialized = true; -+ } -+ - const QRect virtualDesktopArea = -- QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()); -+ !customGeometry.isValid() ? -+ QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) : -+ customGeometry; - - if (QWindowsContext::verbose > 1) { - qCDebug(lcQpaTablet) << __FUNCTION__ << "processing" << packetCount --- -2.20.1.windows.1 - diff --git a/3rdparty/ext_qt/CMakeLists.txt b/3rdparty/ext_qt/CMakeLists.txt index d905949ba4..061c2952b1 100644 --- a/3rdparty/ext_qt/CMakeLists.txt +++ b/3rdparty/ext_qt/CMakeLists.txt @@ -1,251 +1,250 @@ SET(EXTPREFIX_qt "${EXTPREFIX}") if (WIN32) list(APPEND _QT_conf -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtgraphicaleffects -skip qtlocation -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -no-sql-sqlite -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-qml-debug -no-libproxy -no-system-proxies -no-icu -no-mtdev -skip qtcharts -skip qtdatavis3d -skip qtgamepad -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscxml -skip qtserialbus -skip qtspeech -skip qtvirtualkeyboard # -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -openssl-linked -I ${EXTPREFIX_qt}/include -L ${EXTPREFIX_qt}/lib # -opensource -confirm-license # -release -platform win32-g++ -prefix ${EXTPREFIX_qt} QMAKE_LFLAGS_APP+=${SECURITY_EXE_LINKER_FLAGS} QMAKE_LFLAGS_SHLIB+=${SECURITY_SHARED_LINKER_FLAGS} QMAKE_LFLAGS_SONAME+=${SECURITY_SHARED_LINKER_FLAGS} ) if (QT_ENABLE_DEBUG_INFO) # Set the option to build Qt with debugging info enabled list(APPEND _QT_conf -force-debug-info) endif(QT_ENABLE_DEBUG_INFO) if (QT_ENABLE_DYNAMIC_OPENGL) list(APPEND _QT_conf -opengl dynamic -angle) else (QT_ENABLE_DYNAMIC_OPENGL) list(APPEND _QT_conf -opengl desktop -no-angle) endif (QT_ENABLE_DYNAMIC_OPENGL) if (NOT USE_QT_TABLET_WINDOWS) set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0001-disable-wintab.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/disable-winink.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0002-Don-t-request-the-MIME-image-every-time-Windows-asks.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0003-Hack-always-return-we-support-DIBV5.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0004-Fix-debug-on-openGL-ES.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0005-cumulative-patch-for-hdr.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0006-Fix-swizzling-when-rendering-QPainter-on-QOpenGLWidg.patch ) else() set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0002-Don-t-request-the-MIME-image-every-time-Windows-asks.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0003-Hack-always-return-we-support-DIBV5.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0004-Fix-debug-on-openGL-ES.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0005-cumulative-patch-for-hdr.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0006-Fix-swizzling-when-rendering-QPainter-on-QOpenGLWidg.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0020-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0021-Fix-QTabletEvent-uniqueId-when-Qt-uses-WinInk.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0022-Fix-generation-of-Leave-events-when-using-tablet-dev.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0023-Implement-a-switch-for-tablet-API-on-Windows.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0024-Fetch-stylus-button-remapping-from-WinTab-driver.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0025-Disable-tablet-relative-mode-in-Qt.patch - COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0026-Implement-a-custom-variable-for-overriding-Wintab-s-.patch - COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0027-Fetch-tablet-mapping-from-Wintab-instead-virtual-scr.patch + COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0026-Fetch-mapped-screen-size-from-the-Wintab-driver.patch ) endif() ExternalProject_Add( ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL https://download.qt.io/archive/qt/5.12/5.12.2/single/qt-everywhere-src-5.12.2.tar.xz URL_MD5 99c2eb46e533371798b4ca2d1458e065 PATCH_COMMAND ${ext_qt_PATCH_COMMAND} INSTALL_DIR ${EXTPREFIX_qt} CONFIGURE_COMMAND /configure.bat ${_QT_conf} BUILD_COMMAND mingw32-make -j${SUBMAKE_JOBS} INSTALL_COMMAND mingw32-make -j${SUBMAKE_JOBS} install UPDATE_COMMAND "" # Use a short name to reduce the chance of exceeding path length limit SOURCE_DIR s BINARY_DIR b DEPENDS ext_patch ext_openssl ) elseif (NOT APPLE) ExternalProject_Add( ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL https://download.qt.io/archive/qt/5.12/5.12.2/single/qt-everywhere-src-5.12.2.tar.xz URL_MD5 99c2eb46e533371798b4ca2d1458e065 PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0010-Fix-tablet-jitter-on-X11.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0011-Add-an-ID-for-recognition-of-UGEE-tablets.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0013-Poison-Qt-s-headers-with-a-mark-about-presence-of-En.patch CMAKE_ARGS -DOPENSSL_LIBS='-L${EXTPREFIX_qt}/lib -lssl -lcrypto' CONFIGURE_COMMAND /configure -prefix ${EXTPREFIX_qt} -opensource -confirm-license -openssl-linked -verbose -nomake examples -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtgraphicaleffects -skip qtlocation -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtandroidextras -skip qtserialport -skip qtdatavis3d -skip qtvirtualkeyboard -skip qtspeech -skip qtsensors -skip qtgamepad -skip qtscxml -skip qtremoteobjects -skip qtxmlpatterns -skip qtnetworkauth -skip qtcharts -skip qtdatavis3d -skip qtgamepad -skip qtpurchasing -skip qtscxml -skip qtserialbus -skip qtspeech -skip qtvirtualkeyboard -skip qtmultimedia INSTALL_DIR ${EXTPREFIX_qt} BUILD_COMMAND $(MAKE) INSTALL_COMMAND $(MAKE) install UPDATE_COMMAND "" BUILD_IN_SOURCE 1 ) else( APPLE ) # XCODE_VERSION is set by CMake when using the Xcode generator, otherwise we need # to detect it manually here. if (NOT XCODE_VERSION) execute_process( COMMAND xcodebuild -version OUTPUT_VARIABLE xcodebuild_version OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_FILE /dev/null ) string(REGEX MATCH "Xcode ([0-9]+([.][0-9]+)*)" version_match ${xcodebuild_version}) if (version_match) message(STATUS "${EXTPREFIX_qt}:Identified Xcode Version: ${CMAKE_MATCH_1}") set(XCODE_VERSION ${CMAKE_MATCH_1}) else() # If detecting Xcode version failed, set a crazy high version so we default # to the newest. set(XCODE_VERSION 99) message(WARNING "${EXTPREFIX_qt}:Failed to detect the version of an installed copy of Xcode, falling back to highest supported version. Set XCODE_VERSION to override.") endif(version_match) endif(NOT XCODE_VERSION) # ------------------------------------------------------------------------------- # Verify the Xcode installation on Mac OS like Qt5.7 does/will # If not stop now, the system isn't configured correctly for Qt. # No reason to even proceed. # ------------------------------------------------------------------------------- set(XCSELECT_OUTPUT) find_program(XCSELECT_PROGRAM "xcode-select") if(XCSELECT_PROGRAM) message(STATUS "${EXTPREFIX_qt}:Found XCSELECT_PROGRAM as ${XCSELECT_PROGRAM}") set(XCSELECT_COMMAND ${XCSELECT_PROGRAM} "--print-path") execute_process( COMMAND ${XCSELECT_COMMAND} RESULT_VARIABLE XCSELECT_COMMAND_RESULT OUTPUT_VARIABLE XCSELECT_COMMAND_OUTPUT ERROR_FILE /dev/null ) if(NOT XCSELECT_COMMAND_RESULT) # returned 0, we're ok. string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" XCSELECT_COMMAND_OUTPUT ${XCSELECT_COMMAND_OUTPUT}) else() string(REPLACE ";" " " XCSELECT_COMMAND_STR "${XCSELECT_COMMAND}") # message(STATUS "${XCSELECT_COMMAND_STR}") message(FATAL_ERROR "${EXTPREFIX_qt}:${XCSELECT_PROGRAM} test failed with status ${XCSELECT_COMMAND_RESULT}") endif() else() message(FATAL_ERROR "${EXTPREFIX_qt}:${XCSELECT_PROGRAM} not found. No Xcode is selected. Use xcode-select -switch to choose an Xcode version") endif() # Belts and suspenders # Beyond all the Xcode and Qt version checking, the proof of the pudding # lies in the success/failure of this command: xcrun --find xcrun. # On failure a patch is necessary, otherwise we're ok # So hard check xcrun now... set(XCRUN_OUTPUT) find_program(XCRUN_PROGRAM "xcrun") if(XCRUN_PROGRAM) message(STATUS "${EXTPREFIX_qt}:Found XCRUN_PROGRAM as ${XCRUN_PROGRAM}") set(XCRUN_COMMAND ${XCRUN_PROGRAM} "--find xcrun") execute_process( COMMAND ${XCRUN_COMMAND} RESULT_VARIABLE XCRUN_COMMAND_RESULT OUTPUT_VARIABLE XCRUN_COMMAND_OUTPUT ERROR_FILE /dev/null ) if(NOT XCRUN_COMMAND_RESULT) # returned 0, we're ok. string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" XCRUN_COMMAND_OUTPUT ${XCRUN_COMMAND_OUTPUT}) else() string(REPLACE ";" " " XCRUN_COMMAND_STR "${XCRUN_COMMAND}") # message(STATUS "${XCRUN_COMMAND_STR}") message(STATUS "${EXTPREFIX_qt}:xcrun test failed with status ${XCRUN_COMMAND_RESULT}") endif() else() message(STATUS "${EXTPREFIX_qt}:xcrun not found -- ${XCRUN_PROGRAM}") endif() # # Now configure ext_qt accordingly # if ((XCRUN_COMMAND_RESULT) AND (NOT (XCODE_VERSION VERSION_LESS 8.0.0))) # Fix Xcode xcrun related issue. # NOTE: This should be fixed by Qt 5.7.1 see here: http://code.qt.io/cgit/qt/qtbase.git/commit/?h=dev&id=77a71c32c9d19b87f79b208929e71282e8d8b5d9 # NOTE: but no one's holding their breath. set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND}} -p1 -b -d /qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/mac_standardpaths_qtbug-61159.diff COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0013-Poison-Qt-s-headers-with-a-mark-about-presence-of-En.patch #COMMAND ${PATCH_COMMAND} -p1 -b -d /qtbase/mkspecs/features/mac -i ${CMAKE_CURRENT_SOURCE_DIR}/mac-default.patch ) message(STATUS "${EXTPREFIX_qt}:Additional patches injected.") else() # No extra patches will be applied # NOTE: defaults for some untested scenarios like xcrun fails and xcode_version < 8. # NOTE: that is uncharted territory and (hopefully) a very unlikely scenario... set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch ) endif() # Qt is big - try and parallelize if at all possible include(ProcessorCount) ProcessorCount(NUM_CORES) if(NOT NUM_CORES EQUAL 0) if (NUM_CORES GREATER 2) # be nice... MATH( EXPR NUM_CORES "${NUM_CORES} - 2" ) endif() set(PARALLEL_MAKE "make;-j${NUM_CORES}") message(STATUS "${EXTPREFIX_qt}:Parallelized make: ${PARALLEL_MAKE}") else() set(PARALLEL_MAKE "make") endif() ExternalProject_Add(ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} LOG_DOWNLOAD ON LOG_UPDATE ON LOG_CONFIGURE ON LOG_BUILD ON LOG_TEST ON LOG_INSTALL ON BUILD_IN_SOURCE ON URL https://download.qt.io/archive/qt/5.12/5.12.2/single/qt-everywhere-src-5.12.2.tar.xz URL_MD5 99c2eb46e533371798b4ca2d1458e065 CMAKE_ARGS -DOPENSSL_LIBS='-L${EXTPREFIX_qt}/lib -lssl -lcrypto' INSTALL_DIR ${EXTPREFIX_qt} CONFIGURE_COMMAND /configure -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtgraphicaleffects -skip qtlocation -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebsockets -skip qtwebview -skip qtwebengine -skip qtxmlpatterns -no-sql-sqlite -skip qtcharts -skip qtdatavis3d -skip qtgamepad -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscxml -skip qtserialbus -skip qtspeech -skip qtvirtualkeyboard -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-qml-debug -no-libproxy -no-system-proxies -no-icu -no-mtdev -system-zlib -qt-pcre -opensource -confirm-license -openssl-linked -prefix ${EXTPREFIX_qt} BUILD_COMMAND ${PARALLEL_MAKE} INSTALL_COMMAND make install UPDATE_COMMAND "" BUILD_IN_SOURCE 1 ) endif() diff --git a/krita/main.cc b/krita/main.cc index e32a30ab6e..b0312fd37b 100644 --- a/krita/main.cc +++ b/krita/main.cc @@ -1,529 +1,518 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2015 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050900 #include #endif #include #include #include #include #include #include "data/splash/splash_screen.xpm" #include "data/splash/splash_holidays.xpm" #include "data/splash/splash_screen_x2.xpm" #include "data/splash/splash_holidays_x2.xpm" #include "KisDocument.h" #include "kis_splash_screen.h" #include "KisPart.h" #include "KisApplicationArguments.h" #include #include "input/KisQtWidgetsTweaker.h" #include #include #if defined Q_OS_WIN #include "config_use_qt_tablet_windows.h" #include #ifndef USE_QT_TABLET_WINDOWS #include #include #else #include #endif #include #endif #if defined HAVE_KCRASH #include #elif defined USE_DRMINGW namespace { void tryInitDrMingw() { wchar_t path[MAX_PATH]; QString pathStr = QCoreApplication::applicationDirPath().replace(L'/', L'\\') + QStringLiteral("\\exchndl.dll"); if (pathStr.size() > MAX_PATH - 1) { return; } int pathLen = pathStr.toWCharArray(path); path[pathLen] = L'\0'; // toWCharArray doesn't add NULL terminator HMODULE hMod = LoadLibraryW(path); if (!hMod) { return; } // No need to call ExcHndlInit since the crash handler is installed on DllMain auto myExcHndlSetLogFileNameA = reinterpret_cast(GetProcAddress(hMod, "ExcHndlSetLogFileNameA")); if (!myExcHndlSetLogFileNameA) { return; } // Set the log file path to %LocalAppData%\kritacrash.log QString logFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation).replace(L'/', L'\\') + QStringLiteral("\\kritacrash.log"); myExcHndlSetLogFileNameA(logFile.toLocal8Bit()); } typedef enum ORIENTATION_PREFERENCE { ORIENTATION_PREFERENCE_NONE = 0x0, ORIENTATION_PREFERENCE_LANDSCAPE = 0x1, ORIENTATION_PREFERENCE_PORTRAIT = 0x2, ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4, ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8 } ORIENTATION_PREFERENCE; typedef BOOL WINAPI (*pSetDisplayAutoRotationPreferences_t)( ORIENTATION_PREFERENCE orientation ); void resetRotation() { QLibrary user32Lib("user32"); if (!user32Lib.load()) { qWarning() << "Failed to load user32.dll! This really should not happen."; return; } pSetDisplayAutoRotationPreferences_t pSetDisplayAutoRotationPreferences = reinterpret_cast(user32Lib.resolve("SetDisplayAutoRotationPreferences")); if (!pSetDisplayAutoRotationPreferences) { dbgKrita << "Failed to load function SetDisplayAutoRotationPreferences"; return; } bool result = pSetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE); dbgKrita << "SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE) returned" << result; } } // namespace #endif extern "C" int main(int argc, char **argv) { // The global initialization of the random generator qsrand(time(0)); bool runningInKDE = !qgetenv("KDE_FULL_SESSION").isEmpty(); #if defined HAVE_X11 qputenv("QT_QPA_PLATFORM", "xcb"); #endif // Workaround a bug in QNetworkManager qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1)); // A per-user unique string, without /, because QLocalServer cannot use names with a / in it QString key = "Krita4" + QStandardPaths::writableLocation(QStandardPaths::HomeLocation).replace("/", "_"); key = key.replace(":", "_").replace("\\","_"); QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); #if QT_VERSION >= 0x050900 QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache, true); #endif const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); bool singleApplication = true; bool enableOpenGLDebug = false; bool openGLDebugSynchronous = false; bool logUsage = true; { singleApplication = kritarc.value("EnableSingleApplication", true).toBool(); if (kritarc.value("EnableHiDPI", true).toBool()) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); } if (!qgetenv("KRITA_HIDPI").isEmpty()) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); } if (!qgetenv("KRITA_OPENGL_DEBUG").isEmpty()) { enableOpenGLDebug = true; } else { enableOpenGLDebug = kritarc.value("EnableOpenGLDebug", false).toBool(); } if (enableOpenGLDebug && (qgetenv("KRITA_OPENGL_DEBUG") == "sync" || kritarc.value("OpenGLDebugSynchronous", false).toBool())) { openGLDebugSynchronous = true; } KisConfig::RootSurfaceFormat rootSurfaceFormat = KisConfig::rootSurfaceFormat(&kritarc); KisOpenGL::OpenGLRenderer preferredRenderer = KisOpenGL::RendererAuto; logUsage = kritarc.value("LogUsage", true).toBool(); const QString preferredRendererString = kritarc.value("OpenGLRenderer", "auto").toString(); preferredRenderer = KisOpenGL::convertConfigToOpenGLRenderer(preferredRendererString); #ifdef Q_OS_WIN // Force ANGLE to use Direct3D11. D3D9 doesn't support OpenGL ES 3 and WARP // might get weird crashes atm. qputenv("QT_ANGLE_PLATFORM", "d3d11"); #endif const QSurfaceFormat format = KisOpenGL::selectSurfaceFormat(preferredRenderer, rootSurfaceFormat, enableOpenGLDebug); if (format.renderableType() == QSurfaceFormat::OpenGLES) { QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); } else { QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true); } KisOpenGL::setDefaultSurfaceFormat(format); KisOpenGL::setDebugSynchronous(openGLDebugSynchronous); #ifdef Q_OS_WIN // HACK: https://bugs.kde.org/show_bug.cgi?id=390651 resetRotation(); #endif } if (logUsage) { KisUsageLogger::initialize(); } QString root; QString language; { // Create a temporary application to get the root QCoreApplication app(argc, argv); Q_UNUSED(app); root = KoResourcePaths::getApplicationRoot(); QSettings languageoverride(configPath + QStringLiteral("/klanguageoverridesrc"), QSettings::IniFormat); languageoverride.beginGroup(QStringLiteral("Language")); language = languageoverride.value(qAppName(), "").toString(); } #ifdef Q_OS_LINUX { QByteArray originalXdgDataDirs = qgetenv("XDG_DATA_DIRS"); if (originalXdgDataDirs.isEmpty()) { // We don't want to completely override the default originalXdgDataDirs = "/usr/local/share/:/usr/share/"; } qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share") + ":" + originalXdgDataDirs); } #else qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share")); #endif dbgKrita << "Setting XDG_DATA_DIRS" << qgetenv("XDG_DATA_DIRS"); // Now that the paths are set, set the language. First check the override from the language // selection dialog. dbgKrita << "Override language:" << language; bool rightToLeft = false; if (!language.isEmpty()) { KLocalizedString::setLanguages(language.split(":")); // And override Qt's locale, too qputenv("LANG", language.split(":").first().toLocal8Bit()); QLocale locale(language.split(":").first()); QLocale::setDefault(locale); const QStringList rtlLanguages = QStringList() << "ar" << "dv" << "he" << "ha" << "ku" << "fa" << "ps" << "ur" << "yi"; if (rtlLanguages.contains(language.split(':').first())) { rightToLeft = true; } } else { dbgKrita << "Qt UI languages:" << QLocale::system().uiLanguages() << qgetenv("LANG"); // And if there isn't one, check the one set by the system. QLocale locale = QLocale::system(); if (locale.name() != QStringLiteral("en")) { QStringList uiLanguages = locale.uiLanguages(); for (QString &uiLanguage : uiLanguages) { // This list of language codes that can have a specifier should // be extended whenever we have translations that need it; right // now, only en, pt, zh are in this situation. if (uiLanguage.startsWith("en") || uiLanguage.startsWith("pt")) { uiLanguage.replace(QChar('-'), QChar('_')); } else if (uiLanguage.startsWith("zh-Hant") || uiLanguage.startsWith("zh-TW")) { uiLanguage = "zh_TW"; } else if (uiLanguage.startsWith("zh-Hans") || uiLanguage.startsWith("zh-CN")) { uiLanguage = "zh_CN"; } } for (int i = 0; i < uiLanguages.size(); i++) { QString uiLanguage = uiLanguages[i]; // Strip the country code int idx = uiLanguage.indexOf(QChar('-')); if (idx != -1) { uiLanguage = uiLanguage.left(idx); uiLanguages.replace(i, uiLanguage); } } dbgKrita << "Converted ui languages:" << uiLanguages; qputenv("LANG", uiLanguages.first().toLocal8Bit()); #ifdef Q_OS_MAC // See https://bugs.kde.org/show_bug.cgi?id=396370 KLocalizedString::setLanguages(QStringList() << uiLanguages.first()); #else KLocalizedString::setLanguages(QStringList() << uiLanguages); #endif } } #if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS && defined QT_HAS_WINTAB_SWITCH const bool forceWinTab = !KisConfig::useWin8PointerInputNoApp(&kritarc); QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI, forceWinTab); if (qEnvironmentVariableIsEmpty("QT_WINTAB_DESKTOP_RECT") && qEnvironmentVariableIsEmpty("QT_IGNORE_WINTAB_MAPPING")) { QRect customTabletRect; KisDlgCustomTabletResolution::Mode tabletMode = KisDlgCustomTabletResolution::getTabletMode(&customTabletRect); - - if (tabletMode == KisDlgCustomTabletResolution::USE_CUSTOM) { - qputenv("QT_WINTAB_DESKTOP_RECT", - QString("%1;%2;%3;%4") - .arg(customTabletRect.x()) - .arg(customTabletRect.y()) - .arg(customTabletRect.width()) - .arg(customTabletRect.height()).toLatin1()); - } else if (tabletMode == KisDlgCustomTabletResolution::USE_VIRTUAL_SCREEN) { - qputenv("QT_IGNORE_WINTAB_MAPPING", "1"); - } + KisDlgCustomTabletResolution::applyConfiguration(tabletMode, customTabletRect); } - #endif // first create the application so we can create a pixmap KisApplication app(key, argc, argv); KisUsageLogger::writeHeader(); if (!language.isEmpty()) { if (rightToLeft) { app.setLayoutDirection(Qt::RightToLeft); } else { app.setLayoutDirection(Qt::LeftToRight); } } KLocalizedString::setApplicationDomain("krita"); dbgKrita << "Available translations" << KLocalizedString::availableApplicationTranslations(); dbgKrita << "Available domain translations" << KLocalizedString::availableDomainTranslations("krita"); #ifdef Q_OS_WIN QDir appdir(KoResourcePaths::getApplicationRoot()); QString path = qgetenv("PATH"); qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";" + appdir.absolutePath() + "/lib" + ";" + appdir.absolutePath() + "/Frameworks" + ";" + appdir.absolutePath() + ";" + path)); dbgKrita << "PATH" << qgetenv("PATH"); #endif if (qApp->applicationDirPath().contains(KRITA_BUILD_DIR)) { qFatal("FATAL: You're trying to run krita from the build location. You can only run Krita from the installation location."); } #if defined HAVE_KCRASH KCrash::initialize(); #elif defined USE_DRMINGW tryInitDrMingw(); #endif // If we should clear the config, it has to be done as soon as possible after // KisApplication has been created. Otherwise the config file may have been read // and stored in a KConfig object we have no control over. app.askClearConfig(); KisApplicationArguments args(app); if (singleApplication && app.isRunning()) { // only pass arguments to main instance if they are not for batch processing // any batch processing would be done in this separate instance const bool batchRun = args.exportAs(); if (!batchRun) { QByteArray ba = args.serialize(); if (app.sendMessage(ba)) { return 0; } } } if (!runningInKDE) { // Icons in menus are ugly and distracting app.setAttribute(Qt::AA_DontShowIconsInMenus); } app.installEventFilter(KisQtWidgetsTweaker::instance()); if (!args.noSplash()) { // then create the pixmap from an xpm: we cannot get the // location of our datadir before we've started our components, // so use an xpm. QDate currentDate = QDate::currentDate(); QWidget *splash = 0; if (currentDate > QDate(currentDate.year(), 12, 4) || currentDate < QDate(currentDate.year(), 1, 9)) { splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_holidays_xpm), QPixmap(splash_holidays_x2_xpm)); } else { splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_screen_xpm), QPixmap(splash_screen_x2_xpm)); } app.setSplashScreen(splash); } #if defined Q_OS_WIN KisConfig cfg(false); bool supportedWindowsVersion = true; #if QT_VERSION >= 0x050900 QOperatingSystemVersion osVersion = QOperatingSystemVersion::current(); if (osVersion.type() == QOperatingSystemVersion::Windows) { if (osVersion.majorVersion() >= QOperatingSystemVersion::Windows7.majorVersion()) { supportedWindowsVersion = true; } else { supportedWindowsVersion = false; if (cfg.readEntry("WarnedAboutUnsupportedWindows", false)) { QMessageBox::information(0, i18nc("@title:window", "Krita: Warning"), i18n("You are running an unsupported version of Windows: %1.\n" "This is not recommended. Do not report any bugs.\n" "Please update to a supported version of Windows: Windows 7, 8, 8.1 or 10.", osVersion.name())); cfg.writeEntry("WarnedAboutUnsupportedWindows", true); } } } #endif #ifndef USE_QT_TABLET_WINDOWS { if (cfg.useWin8PointerInput() && !KisTabletSupportWin8::isAvailable()) { cfg.setUseWin8PointerInput(false); } if (!cfg.useWin8PointerInput()) { bool hasWinTab = KisTabletSupportWin::init(); if (!hasWinTab && supportedWindowsVersion) { if (KisTabletSupportWin8::isPenDeviceAvailable()) { // Use WinInk automatically cfg.setUseWin8PointerInput(true); } else if (!cfg.readEntry("WarnedAboutMissingWinTab", false)) { if (KisTabletSupportWin8::isAvailable()) { QMessageBox::information(nullptr, i18n("Krita Tablet Support"), i18n("Cannot load WinTab driver and no Windows Ink pen devices are found. If you have a drawing tablet, please make sure the tablet driver is properly installed."), QMessageBox::Ok, QMessageBox::Ok); } else { QMessageBox::information(nullptr, i18n("Krita Tablet Support"), i18n("Cannot load WinTab driver. If you have a drawing tablet, please make sure the tablet driver is properly installed."), QMessageBox::Ok, QMessageBox::Ok); } cfg.writeEntry("WarnedAboutMissingWinTab", true); } } } if (cfg.useWin8PointerInput()) { KisTabletSupportWin8 *penFilter = new KisTabletSupportWin8(); if (penFilter->init()) { // penFilter.registerPointerDeviceNotifications(); app.installNativeEventFilter(penFilter); dbgKrita << "Using Win8 Pointer Input for tablet support"; } else { dbgKrita << "No Win8 Pointer Input available"; delete penFilter; } } } #elif defined QT_HAS_WINTAB_SWITCH // Check if WinTab/WinInk has actually activated const bool useWinTabAPI = app.testAttribute(Qt::AA_MSWindowsUseWinTabAPI); if (useWinTabAPI != !cfg.useWin8PointerInput()) { cfg.setUseWin8PointerInput(useWinTabAPI); } #endif #endif if (!app.start(args)) { return 1; } #if QT_VERSION >= 0x050700 app.setAttribute(Qt::AA_CompressHighFrequencyEvents, false); #endif // Set up remote arguments. QObject::connect(&app, SIGNAL(messageReceived(QByteArray,QObject*)), &app, SLOT(remoteArguments(QByteArray,QObject*))); QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), &app, SLOT(fileOpenRequested(QString))); // Hardware information KisUsageLogger::write("\nHardware Information\n"); KisUsageLogger::write(QString(" GPU Acceleration: %1").arg(kritarc.value("OpenGLRenderer", "auto").toString())); KisUsageLogger::write(QString(" Memory: %1 Mb").arg(KisImageConfig(true).totalRAM())); KisUsageLogger::write(QString(" Number of Cores: %1").arg(QThread::idealThreadCount())); KisUsageLogger::write(QString(" Swap Location: %1\n").arg(KisImageConfig(true).swapDir())); int state = app.exec(); { QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); kritarc.setValue("canvasState", "OPENGL_SUCCESS"); } if (logUsage) { KisUsageLogger::close(); } return state; } diff --git a/libs/ui/dialogs/KisDlgCustomTabletResolution.cpp b/libs/ui/dialogs/KisDlgCustomTabletResolution.cpp index 9a3c791ded..fa561dbbff 100644 --- a/libs/ui/dialogs/KisDlgCustomTabletResolution.cpp +++ b/libs/ui/dialogs/KisDlgCustomTabletResolution.cpp @@ -1,137 +1,171 @@ /* * Copyright (c) 2019 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisDlgCustomTabletResolution.h" #include "ui_KisDlgCustomTabletResolution.h" #include #include "kis_debug.h" #include #include #include #include +namespace { +QString rectToString(const QRect &rc) { + return QString("%1, %2 %3 x %4") + .arg(rc.x()) + .arg(rc.y()) + .arg(rc.width()) + .arg(rc.height()); +} +} KisDlgCustomTabletResolution::KisDlgCustomTabletResolution(QWidget *parent) : QDialog(parent), ui(new Ui::KisDlgCustomTabletResolution) { ui->setupUi(this); connect(ui->btnBox, SIGNAL(rejected()), this, SLOT(reject())); connect(ui->btnBox, SIGNAL(accepted()), this, SLOT(accept())); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->lblXOffset, SLOT(setEnabled(bool))); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->lblYOffset, SLOT(setEnabled(bool))); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->lblWidth, SLOT(setEnabled(bool))); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->lblHeight, SLOT(setEnabled(bool))); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->intXOffset, SLOT(setEnabled(bool))); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->intYOffset, SLOT(setEnabled(bool))); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->intWidth, SLOT(setEnabled(bool))); connect(ui->radioCustomMapping, SIGNAL(toggled(bool)), ui->intHeight, SLOT(setEnabled(bool))); const QRect virtualScreenRect = calcNativeScreenRect(); - const QString rectToString = - QString("%1, %2 %3 x %4") - .arg(virtualScreenRect.x()) - .arg(virtualScreenRect.y()) - .arg(virtualScreenRect.width()) - .arg(virtualScreenRect.height()); + ui->radioMapToEntireScreen->setText(i18nc("@option:radio", "Map to entire virtual screen (%1)", rectToString(virtualScreenRect))); - ui->radioMapToEntireScreen->setText(i18nc("@option:radio", "Map to entire virtual screen (%1)", rectToString)); + QRect nativeScreenRect; + QPlatformScreen *screen = qGuiApp->primaryScreen()->handle(); + Q_FOREACH (QPlatformScreen *scr, screen->virtualSiblings()) { + nativeScreenRect |= scr->geometry(); + } QRect customScreenRect = virtualScreenRect; Mode mode = getTabletMode(&customScreenRect); if (mode == USE_CUSTOM) { ui->radioCustomMapping->setChecked(true); } else if (mode == USE_VIRTUAL_SCREEN) { ui->radioMapToEntireScreen->setChecked(true); } else { ui->radioMapAsWintab->setChecked(true); } ui->intXOffset->setValue(customScreenRect.x()); ui->intYOffset->setValue(customScreenRect.y()); ui->intWidth->setValue(customScreenRect.width()); ui->intHeight->setValue(customScreenRect.height()); } void KisDlgCustomTabletResolution::accept() { const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings cfg(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); if (ui->radioMapAsWintab->isChecked()) { cfg.setValue("wintabResolutionMode", "wintab"); } else if (ui->radioMapToEntireScreen->isChecked()) { cfg.setValue("wintabResolutionMode", "virtual-screen"); } else if (ui->radioCustomMapping->isChecked()) { cfg.setValue("wintabResolutionMode", "custom"); cfg.setValue("wintabCustomResolutionX", ui->intXOffset->value()); cfg.setValue("wintabCustomResolutionY", ui->intYOffset->value()); cfg.setValue("wintabCustomResolutionWidth", ui->intWidth->value()); cfg.setValue("wintabCustomResolutionHeight", ui->intHeight->value()); } + // apply the mode right now + { + QRect customTabletRect; + const Mode tabletMode = getTabletMode(&customTabletRect); + applyConfiguration(tabletMode, customTabletRect); + } + QDialog::accept(); } KisDlgCustomTabletResolution::~KisDlgCustomTabletResolution() { delete ui; } QRect KisDlgCustomTabletResolution::calcNativeScreenRect() { QRect nativeScreenRect; QPlatformScreen *screen = qGuiApp->primaryScreen()->handle(); Q_FOREACH (QPlatformScreen *scr, screen->virtualSiblings()) { nativeScreenRect |= scr->geometry(); } return nativeScreenRect; } KisDlgCustomTabletResolution::Mode KisDlgCustomTabletResolution::getTabletMode(QRect *customRect) { const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings cfg(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); const QString mode = cfg.value("wintabResolutionMode", QString("wintab")).toString(); Mode modeValue = USE_WINTAB; if (mode == "custom") { modeValue = USE_CUSTOM; } else if (mode == "virtual-screen") { modeValue = USE_VIRTUAL_SCREEN; } else { modeValue = USE_WINTAB; } if (mode == "custom") { customRect->setX(cfg.value("wintabCustomResolutionX", customRect->x()).toInt()); customRect->setY(cfg.value("wintabCustomResolutionY", customRect->y()).toInt()); customRect->setWidth(cfg.value("wintabCustomResolutionWidth", customRect->width()).toInt()); customRect->setHeight(cfg.value("wintabCustomResolutionHeight", customRect->height()).toInt()); } return modeValue; } + +void KisDlgCustomTabletResolution::applyConfiguration(KisDlgCustomTabletResolution::Mode tabletMode, const QRect &customTabletRect) +{ + if (tabletMode == KisDlgCustomTabletResolution::USE_CUSTOM) { + qputenv("QT_WINTAB_DESKTOP_RECT", + QString("%1;%2;%3;%4") + .arg(customTabletRect.x()) + .arg(customTabletRect.y()) + .arg(customTabletRect.width()) + .arg(customTabletRect.height()).toLatin1()); + qunsetenv("QT_IGNORE_WINTAB_MAPPING"); + } else if (tabletMode == KisDlgCustomTabletResolution::USE_VIRTUAL_SCREEN) { + qputenv("QT_IGNORE_WINTAB_MAPPING", "1"); + qunsetenv("QT_WINTAB_DESKTOP_RECT"); + } else { + qunsetenv("QT_WINTAB_DESKTOP_RECT"); + qunsetenv("QT_IGNORE_WINTAB_MAPPING"); + } +} diff --git a/libs/ui/dialogs/KisDlgCustomTabletResolution.h b/libs/ui/dialogs/KisDlgCustomTabletResolution.h index 81bbab9467..164a8bd610 100644 --- a/libs/ui/dialogs/KisDlgCustomTabletResolution.h +++ b/libs/ui/dialogs/KisDlgCustomTabletResolution.h @@ -1,53 +1,55 @@ /* * Copyright (c) 2019 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISDLGCUSTOMTABLETRESOLUTION_H #define KISDLGCUSTOMTABLETRESOLUTION_H #include #include "kritaui_export.h" namespace Ui { class KisDlgCustomTabletResolution; } class KRITAUI_EXPORT KisDlgCustomTabletResolution : public QDialog { Q_OBJECT public: enum Mode { USE_WINTAB = 0, USE_VIRTUAL_SCREEN, USE_CUSTOM }; void accept(); public: explicit KisDlgCustomTabletResolution(QWidget *parent = 0); ~KisDlgCustomTabletResolution(); static QRect calcNativeScreenRect(); static Mode getTabletMode(QRect *customRect); + static void applyConfiguration(Mode mode, const QRect &customRect); + private: Ui::KisDlgCustomTabletResolution *ui; }; #endif // KISDLGCUSTOMTABLETRESOLUTION_H diff --git a/libs/ui/dialogs/KisDlgCustomTabletResolution.ui b/libs/ui/dialogs/KisDlgCustomTabletResolution.ui index 992c600c2e..c42d2af358 100644 --- a/libs/ui/dialogs/KisDlgCustomTabletResolution.ui +++ b/libs/ui/dialogs/KisDlgCustomTabletResolution.ui @@ -1,175 +1,198 @@ KisDlgCustomTabletResolution 0 0 321 - 237 + 255 Advanced Tablet Setting - Select area your tablet is mappet to (needs restart): + Select area your tablet is mappet to: Use information provided by tablet Map to entire virtual screen NO_I18N Map to custom area Qt::Horizontal QSizePolicy::Fixed 40 20 Width: px 10000 X offset: px -10000 10000 Height: px 10000 Y offset: px -10000 10000 + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + + Qt::Vertical QSizePolicy::MinimumExpanding 20 - 29 + 15 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok