diff options
author | Tobias Hunger <tobias.hunger@qt.io> | 2019-04-16 16:32:08 +0200 |
---|---|---|
committer | Tobias Hunger <tobias.hunger@qt.io> | 2019-04-16 16:32:08 +0200 |
commit | 6630937e63ae5797487b86743a7733c8ae5cc42c (patch) | |
tree | 3d53dacf6430f9099e1fb20835881205de674961 /src/platformsupport | |
parent | 37ed6dae00640f9cc980ffda05347c12a7eb5d7e (diff) | |
parent | c7af193d2e49e9f10b86262e63d8d13abf72b5cf (diff) |
Merge commit 'dev' into 'wip/cmake-merge'
Change-Id: I176c40d031be26a1dd1cf08843e448a660598783
Diffstat (limited to 'src/platformsupport')
70 files changed, 1980 insertions, 995 deletions
diff --git a/src/platformsupport/clipboard/qmacmime.mm b/src/platformsupport/clipboard/qmacmime.mm index caa2ccc6e5..f425e34b39 100644 --- a/src/platformsupport/clipboard/qmacmime.mm +++ b/src/platformsupport/clipboard/qmacmime.mm @@ -418,8 +418,10 @@ QVariant QMacPasteboardMimeUnicodeText::convertToMime(const QString &mimetype, Q QVariant ret; if (flavor == QLatin1String("public.utf8-plain-text")) { ret = QString::fromUtf8(firstData); +#if QT_CONFIG(textcodec) } else if (flavor == QLatin1String("public.utf16-plain-text")) { ret = QTextCodec::codecForName("UTF-16")->toUnicode(firstData); +#endif } else { qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); } @@ -432,8 +434,10 @@ QList<QByteArray> QMacPasteboardMimeUnicodeText::convertFromMime(const QString & QString string = data.toString(); if (flavor == QLatin1String("public.utf8-plain-text")) ret.append(string.toUtf8()); +#if QT_CONFIG(textcodec) else if (flavor == QLatin1String("public.utf16-plain-text")) ret.append(QTextCodec::codecForName("UTF-16")->fromUnicode(string)); +#endif return ret; } diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_p.h b/src/platformsupport/devicediscovery/qdevicediscovery_p.h index e3c22b0b37..f1f50e9708 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_p.h +++ b/src/platformsupport/devicediscovery/qdevicediscovery_p.h @@ -86,7 +86,7 @@ public: Q_ENUM(QDeviceType) Q_DECLARE_FLAGS(QDeviceTypes, QDeviceType) - static QDeviceDiscovery *create(QDeviceTypes type, QObject *parent = 0); + static QDeviceDiscovery *create(QDeviceTypes type, QObject *parent = nullptr); virtual QStringList scanConnectedDevices() = 0; @@ -96,7 +96,7 @@ signals: protected: QDeviceDiscovery(QDeviceTypes types, QObject *parent) : QObject(parent), m_types(types) { } - Q_DISABLE_COPY(QDeviceDiscovery) + Q_DISABLE_COPY_MOVE(QDeviceDiscovery) QDeviceTypes m_types; }; diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_udev_p.h b/src/platformsupport/devicediscovery/qdevicediscovery_udev_p.h index 28618d0b21..82b475776d 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_udev_p.h +++ b/src/platformsupport/devicediscovery/qdevicediscovery_udev_p.h @@ -61,7 +61,7 @@ class QDeviceDiscoveryUDev : public QDeviceDiscovery Q_OBJECT public: - QDeviceDiscoveryUDev(QDeviceTypes types, struct udev *udev, QObject *parent = 0); + QDeviceDiscoveryUDev(QDeviceTypes types, struct udev *udev, QObject *parent = nullptr); ~QDeviceDiscoveryUDev(); QStringList scanConnectedDevices() override; diff --git a/src/platformsupport/edid/qedidparser.cpp b/src/platformsupport/edid/qedidparser.cpp index ccaa50704c..06c8852825 100644 --- a/src/platformsupport/edid/qedidparser.cpp +++ b/src/platformsupport/edid/qedidparser.cpp @@ -166,7 +166,7 @@ QString QEdidParser::parseEdidString(const quint8 *data) // Replace non-printable characters with dash for (int i = 0; i < buffer.count(); ++i) { - if (buffer[i] < '\040' && buffer[i] > '\176') + if (buffer[i] < '\040' || buffer[i] > '\176') buffer[i] = '-'; } diff --git a/src/platformsupport/eglconvenience/eglconvenience.pro b/src/platformsupport/eglconvenience/eglconvenience.pro index 4301d63574..df21f14697 100644 --- a/src/platformsupport/eglconvenience/eglconvenience.pro +++ b/src/platformsupport/eglconvenience/eglconvenience.pro @@ -26,15 +26,15 @@ qtConfig(opengl) { qeglpbuffer.cpp } -# Avoid X11 header collision, use generic EGL native types -DEFINES += QT_EGL_NO_X11 - -qtConfig(xlib) { +qtConfig(egl_x11) { HEADERS += \ qxlibeglintegration_p.h SOURCES += \ qxlibeglintegration.cpp - LIBS_PRIVATE += $$QMAKE_LIBS_X11 + QMAKE_USE_PRIVATE += xlib +} else { + # Avoid X11 header collision, use generic EGL native types + DEFINES += QT_EGL_NO_X11 } CONFIG += egl diff --git a/src/platformsupport/eglconvenience/qeglpbuffer_p.h b/src/platformsupport/eglconvenience/qeglpbuffer_p.h index 0285e067a6..8ad2eb7248 100644 --- a/src/platformsupport/eglconvenience/qeglpbuffer_p.h +++ b/src/platformsupport/eglconvenience/qeglpbuffer_p.h @@ -60,7 +60,7 @@ class QEGLPbuffer : public QPlatformOffscreenSurface { public: QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface, - QEGLPlatformContext::Flags flags = 0); + QEGLPlatformContext::Flags flags = nullptr); ~QEGLPbuffer(); QSurfaceFormat format() const override { return m_format; } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 9d8bf07af8..c0e528f922 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -332,14 +332,6 @@ void QEGLPlatformContext::updateFormatFromGL() QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); int major, minor; if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) - // Some Android 4.2.2 devices report OpenGL ES 3.0 without the functions being available. - static int apiLevel = QtAndroidPrivate::androidSdkVersion(); - if (apiLevel <= 17 && major >= 3) { - major = 2; - minor = 0; - } -#endif m_format.setMajorVersion(major); m_format.setMinorVersion(minor); } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h index d6cbbe4131..ed77c57df5 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h @@ -68,8 +68,8 @@ public: Q_DECLARE_FLAGS(Flags, Flag) QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig *config = 0, const QVariant &nativeHandle = QVariant(), - Flags flags = 0); + EGLConfig *config = nullptr, const QVariant &nativeHandle = QVariant(), + Flags flags = nullptr); ~QEGLPlatformContext(); void initialize() override; diff --git a/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h b/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h index c3d3070210..31a79dbc6c 100644 --- a/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h +++ b/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h @@ -131,6 +131,12 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer); #endif +#ifndef EGL_EXT_stream_acquire_mode +#define EGL_EXT_stream_acquire_mode 1 +#define EGL_CONSUMER_AUTO_ACQUIRE_EXT 0x332B +#define EGL_RESOURCE_BUSY_EXT 0x3353 +#endif + #ifndef EGL_EXT_platform_device #define EGL_PLATFORM_DEVICE_EXT 0x313F #endif @@ -156,6 +162,11 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC) (EGLDi typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); #endif +#ifndef EGL_NV_output_drm_flip_event +#define EGL_NV_output_drm_flip_event 1 +#define EGL_DRM_FLIP_EVENT_DATA_NV 0x333E +#endif + QT_BEGIN_NAMESPACE class QEGLStreamConvenience diff --git a/src/platformsupport/eglconvenience/qt_egl_p.h b/src/platformsupport/eglconvenience/qt_egl_p.h index e2c6b0ceb6..ea554927de 100644 --- a/src/platformsupport/eglconvenience/qt_egl_p.h +++ b/src/platformsupport/eglconvenience/qt_egl_p.h @@ -52,7 +52,9 @@ // #ifdef QT_EGL_NO_X11 -# define MESA_EGL_NO_X11_HEADERS // MESA +# ifndef MESA_EGL_NO_X11_HEADERS +# define MESA_EGL_NO_X11_HEADERS // MESA +# endif # if !defined(Q_OS_INTEGRITY) # define WIN_INTERFACE_CUSTOM // NV # endif // Q_OS_INTEGRITY diff --git a/src/platformsupport/eglconvenience/qxlibeglintegration.cpp b/src/platformsupport/eglconvenience/qxlibeglintegration.cpp index 565dbfb11b..ac743e1e38 100644 --- a/src/platformsupport/eglconvenience/qxlibeglintegration.cpp +++ b/src/platformsupport/eglconvenience/qxlibeglintegration.cpp @@ -91,21 +91,21 @@ VisualID QXlibEglIntegration::getCompatibleVisualId(Display *display, EGLDisplay int visualRedSize = qPopulationCount(chosenVisualInfo->red_mask); int visualGreenSize = qPopulationCount(chosenVisualInfo->green_mask); int visualBlueSize = qPopulationCount(chosenVisualInfo->blue_mask); - int visualAlphaSize = chosenVisualInfo->depth == 32 ? 8 : 0; + int visualAlphaSize = chosenVisualInfo->depth - visualRedSize - visualBlueSize - visualGreenSize; - const bool visualMatchesConfig = visualRedSize == configRedSize - && visualGreenSize == configGreenSize - && visualBlueSize == configBlueSize - && visualAlphaSize == configAlphaSize; + const bool visualMatchesConfig = visualRedSize >= configRedSize + && visualGreenSize >= configGreenSize + && visualBlueSize >= configBlueSize + && visualAlphaSize >= configAlphaSize; // In some cases EGL tends to suggest a 24-bit visual for 8888 // configs. In such a case we have to fall back to XGetVisualInfo. if (!visualMatchesConfig) { visualId = 0; qCDebug(lcXlibEglDebug, - "EGL suggested using X Visual ID %d (%d %d %d depth %d) for EGL config %d" + "EGL suggested using X Visual ID %d (%d %d %d %d depth %d) for EGL config %d" "(%d %d %d %d), but this is incompatible", - (int)visualId, visualRedSize, visualGreenSize, visualBlueSize, chosenVisualInfo->depth, + (int)visualId, visualRedSize, visualGreenSize, visualBlueSize, visualAlphaSize, chosenVisualInfo->depth, configId, configRedSize, configGreenSize, configBlueSize, configAlphaSize); } } else { diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp index dc4785071f..0ccbf01e80 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp @@ -52,17 +52,14 @@ struct GUserEventSource { GSource source; QPAEventDispatcherGlib *q; + QPAEventDispatcherGlibPrivate *d; }; static gboolean userEventSourcePrepare(GSource *source, gint *timeout) { Q_UNUSED(timeout) GUserEventSource *userEventSource = reinterpret_cast<GUserEventSource *>(source); - QPAEventDispatcherGlib *dispatcher = userEventSource->q; - if (dispatcher->m_flags & QEventLoop::ExcludeUserInputEvents) - return QWindowSystemInterface::nonUserInputEventsQueued(); - else - return QWindowSystemInterface::windowSystemEventsQueued() > 0; + return userEventSource->d->wakeUpCalled; } static gboolean userEventSourceCheck(GSource *source) @@ -94,6 +91,7 @@ QPAEventDispatcherGlibPrivate::QPAEventDispatcherGlibPrivate(GMainContext *conte userEventSource = reinterpret_cast<GUserEventSource *>(g_source_new(&userEventSourceFuncs, sizeof(GUserEventSource))); userEventSource->q = q; + userEventSource->d = this; g_source_set_can_recurse(&userEventSource->source, true); g_source_attach(&userEventSource->source, mainContext); } diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h index 085a1c52f3..b9254d3071 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h @@ -64,7 +64,7 @@ class QPAEventDispatcherGlib : public QEventDispatcherGlib Q_DECLARE_PRIVATE(QPAEventDispatcherGlib) public: - explicit QPAEventDispatcherGlib(QObject *parent = 0); + explicit QPAEventDispatcherGlib(QObject *parent = nullptr); ~QPAEventDispatcherGlib(); bool processEvents(QEventLoop::ProcessEventsFlags flags) override; @@ -77,7 +77,7 @@ class QPAEventDispatcherGlibPrivate : public QEventDispatcherGlibPrivate { Q_DECLARE_PUBLIC(QPAEventDispatcherGlib) public: - QPAEventDispatcherGlibPrivate(GMainContext *context = 0); + QPAEventDispatcherGlibPrivate(GMainContext *context = nullptr); GUserEventSource *userEventSource; }; diff --git a/src/platformsupport/eventdispatchers/qunixeventdispatcher_qpa_p.h b/src/platformsupport/eventdispatchers/qunixeventdispatcher_qpa_p.h index 7f775b73ee..8157b8793d 100644 --- a/src/platformsupport/eventdispatchers/qunixeventdispatcher_qpa_p.h +++ b/src/platformsupport/eventdispatchers/qunixeventdispatcher_qpa_p.h @@ -61,7 +61,7 @@ class QUnixEventDispatcherQPA : public QEventDispatcherUNIX Q_OBJECT public: - explicit QUnixEventDispatcherQPA(QObject *parent = 0); + explicit QUnixEventDispatcherQPA(QObject *parent = nullptr); ~QUnixEventDispatcherQPA(); bool processEvents(QEventLoop::ProcessEventsFlags flags); diff --git a/src/platformsupport/fbconvenience/qfbcursor.cpp b/src/platformsupport/fbconvenience/qfbcursor.cpp index 7daf3f4d0c..e0f6b69e77 100644 --- a/src/platformsupport/fbconvenience/qfbcursor.cpp +++ b/src/platformsupport/fbconvenience/qfbcursor.cpp @@ -63,9 +63,9 @@ QFbCursor::QFbCursor(QFbScreen *screen) mCursorImage(nullptr), mDeviceListener(nullptr) { - QByteArray hideCursorVal = qgetenv("QT_QPA_FB_HIDECURSOR"); - if (!hideCursorVal.isEmpty()) - mVisible = hideCursorVal.toInt() == 0; + const char *envVar = "QT_QPA_FB_HIDECURSOR"; + if (qEnvironmentVariableIsSet(envVar)) + mVisible = qEnvironmentVariableIntValue(envVar) == 0; if (!mVisible) return; @@ -83,7 +83,7 @@ QFbCursor::~QFbCursor() delete mDeviceListener; } -QRect QFbCursor::getCurrentRect() +QRect QFbCursor::getCurrentRect() const { QRect rect = mCursorImage->image()->rect().translated(-mCursorImage->hotspot().x(), -mCursorImage->hotspot().y()); @@ -102,6 +102,8 @@ void QFbCursor::setPos(const QPoint &pos) { QGuiApplicationPrivate::inputDeviceManager()->setCursorPos(pos); m_pos = pos; + if (!mVisible) + return; mCurrentRect = getCurrentRect(); if (mOnScreen || mScreen->geometry().intersects(mCurrentRect.translated(mScreen->geometry().topLeft()))) setDirty(); @@ -112,6 +114,8 @@ void QFbCursor::pointerEvent(const QMouseEvent &e) if (e.type() != QEvent::MouseMove) return; m_pos = e.screenPos().toPoint(); + if (!mVisible) + return; mCurrentRect = getCurrentRect(); if (mOnScreen || mScreen->geometry().intersects(mCurrentRect.translated(mScreen->geometry().topLeft()))) setDirty(); @@ -149,23 +153,28 @@ QRect QFbCursor::dirtyRect() void QFbCursor::setCursor(Qt::CursorShape shape) { - mCursorImage->set(shape); + if (mCursorImage) + mCursorImage->set(shape); } void QFbCursor::setCursor(const QImage &image, int hotx, int hoty) { - mCursorImage->set(image, hotx, hoty); + if (mCursorImage) + mCursorImage->set(image, hotx, hoty); } void QFbCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY) { - mCursorImage->set(data, mask, width, height, hotX, hotY); + if (mCursorImage) + mCursorImage->set(data, mask, width, height, hotX, hotY); } #ifndef QT_NO_CURSOR void QFbCursor::changeCursor(QCursor * widgetCursor, QWindow *window) { Q_UNUSED(window); + if (!mVisible) + return; const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor; if (shape == Qt::BitmapCursor) { @@ -196,7 +205,7 @@ void QFbCursor::setDirty() void QFbCursor::updateMouseStatus() { - mVisible = mDeviceListener->hasMouse(); + mVisible = mDeviceListener ? mDeviceListener->hasMouse() : false; mScreen->setDirty(mVisible ? getCurrentRect() : lastPainted()); } diff --git a/src/platformsupport/fbconvenience/qfbcursor_p.h b/src/platformsupport/fbconvenience/qfbcursor_p.h index beda10a5f3..cc36a2411b 100644 --- a/src/platformsupport/fbconvenience/qfbcursor_p.h +++ b/src/platformsupport/fbconvenience/qfbcursor_p.h @@ -105,7 +105,7 @@ private: void setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY); void setCursor(Qt::CursorShape shape); void setCursor(const QImage &image, int hotx, int hoty); - QRect getCurrentRect(); + QRect getCurrentRect() const; bool mVisible; QFbScreen *mScreen; diff --git a/src/platformsupport/fbconvenience/qfbvthandler_p.h b/src/platformsupport/fbconvenience/qfbvthandler_p.h index 17d07317b2..d565ec3632 100644 --- a/src/platformsupport/fbconvenience/qfbvthandler_p.h +++ b/src/platformsupport/fbconvenience/qfbvthandler_p.h @@ -63,7 +63,7 @@ class QFbVtHandler : public QObject Q_OBJECT public: - QFbVtHandler(QObject *parent = 0); + QFbVtHandler(QObject *parent = nullptr); ~QFbVtHandler(); signals: diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index aa8f9a892a..e545d54ec2 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -908,7 +908,7 @@ QFont QFontconfigDatabase::defaultFont() const void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const { bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - bool forcedAntialiasSetting = !antialias; + bool forcedAntialiasSetting = !antialias || QHighDpiScaling::isActive(); const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services(); bool useXftConf = false; diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index 7b4f6aa107..40db7dbac7 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp @@ -121,13 +121,12 @@ class QtFreetypeData { public: QtFreetypeData() - : library(0), hasPatentFreeLcdRendering(false) + : library(0) { } ~QtFreetypeData(); FT_Library library; QHash<QFontEngine::FaceId, QFreetypeFace *> faces; - bool hasPatentFreeLcdRendering; }; QtFreetypeData::~QtFreetypeData() @@ -153,11 +152,6 @@ QtFreetypeData *qt_getFreetypeData() FT_Bool no_darkening = false; FT_Property_Set(freetypeData->library, "cff", "no-stem-darkening", &no_darkening); #endif - // FreeType has since 2.8.1 a patent free alternative to LCD-filtering. - FT_Int amajor, aminor = 0, apatch = 0; - FT_Library_Version(freetypeData->library, &amajor, &aminor, &apatch); - if (QT_VERSION_CHECK(amajor, aminor, apatch) >= QT_VERSION_CHECK(2, 8, 1)) - freetypeData->hasPatentFreeLcdRendering = true; } return freetypeData; } @@ -561,26 +555,7 @@ QFontEngineFT::Glyph::~Glyph() delete [] data; } -struct LcdFilterDummy -{ - static inline void filterPixel(uchar &, uchar &, uchar &) - {} -}; - -struct LcdFilterLegacy -{ - static inline void filterPixel(uchar &red, uchar &green, uchar &blue) - { - uint r = red, g = green, b = blue; - // intra-pixel filter used by the legacy filter (adopted from _ft_lcd_filter_legacy) - red = (r * uint(65538 * 9/13) + g * uint(65538 * 1/6) + b * uint(65538 * 1/13)) / 65536; - green = (r * uint(65538 * 3/13) + g * uint(65538 * 4/6) + b * uint(65538 * 3/13)) / 65536; - blue = (r * uint(65538 * 1/13) + g * uint(65538 * 1/6) + b * uint(65538 * 9/13)) / 65536; - } -}; - -template <typename LcdFilter> -static void convertRGBToARGB_helper(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr) +static inline void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr) { const int offs = bgr ? -1 : 1; const int w = width * 3; @@ -590,24 +565,14 @@ static void convertRGBToARGB_helper(const uchar *src, uint *dst, int width, int uchar red = src[x + 1 - offs]; uchar green = src[x + 1]; uchar blue = src[x + 1 + offs]; - LcdFilter::filterPixel(red, green, blue); - *dd++ = (0xFF << 24) | (red << 16) | (green << 8) | blue; + *dd++ = (0xFFU << 24) | (red << 16) | (green << 8) | blue; } dst += width; src += src_pitch; } } -static inline void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter) -{ - if (!legacyFilter) - convertRGBToARGB_helper<LcdFilterDummy>(src, dst, width, height, src_pitch, bgr); - else - convertRGBToARGB_helper<LcdFilterLegacy>(src, dst, width, height, src_pitch, bgr); -} - -template <typename LcdFilter> -static void convertRGBToARGB_V_helper(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr) +static inline void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr) { const int offs = bgr ? -src_pitch : src_pitch; while (height--) { @@ -615,54 +580,12 @@ static void convertRGBToARGB_V_helper(const uchar *src, uint *dst, int width, in uchar red = src[x + src_pitch - offs]; uchar green = src[x + src_pitch]; uchar blue = src[x + src_pitch + offs]; - LcdFilter::filterPixel(red, green, blue); - *dst++ = (0XFF << 24) | (red << 16) | (green << 8) | blue; + *dst++ = (0XFFU << 24) | (red << 16) | (green << 8) | blue; } src += 3*src_pitch; } } -static inline void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter) -{ - if (!legacyFilter) - convertRGBToARGB_V_helper<LcdFilterDummy>(src, dst, width, height, src_pitch, bgr); - else - convertRGBToARGB_V_helper<LcdFilterLegacy>(src, dst, width, height, src_pitch, bgr); -} - -static inline void convertGRAYToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch) -{ - while (height--) { - const uchar *p = src; - const uchar * const e = p + width; - while (p < e) { - uchar gray = *p++; - *dst++ = (0xFF << 24) | (gray << 16) | (gray << 8) | gray; - } - src += src_pitch; - } -} - -static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch) -{ - // convolute the bitmap with a triangle filter to get rid of color fringes - // If we take account for a gamma value of 2, we end up with - // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here, - // as this nicely sums up to 16 :) - int h = height; - while (h--) { - dst[0] = dst[1] = 0; - // - for (int x = 2; x < width - 2; ++x) { - uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2]; - dst[x] = (uchar) (sum >> 4); - } - dst[width - 2] = dst[width - 1] = 0; - src += pitch; - dst += pitch; - } -} - static QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint() { static int type = -1; @@ -1153,196 +1076,97 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, int glyph_buffer_size = 0; QScopedArrayPointer<uchar> glyph_buffer; - bool useFreetypeRenderGlyph = false; - if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) { - err = FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)lcdFilterType); - // We use FT_Render_Glyph if freetype has support for lcd-filtering - // or is version 2.8.1 or higher and can do without. - if (err == FT_Err_Ok || qt_getFreetypeData()->hasPatentFreeLcdRendering) - useFreetypeRenderGlyph = true; + FT_Render_Mode renderMode = (default_hint_style == HintLight) ? FT_RENDER_MODE_LIGHT : FT_RENDER_MODE_NORMAL; + switch (format) { + case Format_Mono: + renderMode = FT_RENDER_MODE_MONO; + break; + case Format_A32: + Q_ASSERT(hsubpixel || vfactor != 1); + renderMode = hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V; + break; + case Format_A8: + case Format_ARGB: + break; + default: + Q_UNREACHABLE(); } - if (useFreetypeRenderGlyph) { - err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V); - - if (err != FT_Err_Ok) - qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph); - - FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE); + FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)lcdFilterType); - info.height = slot->bitmap.rows / vfactor; - info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width; - info.x = slot->bitmap_left; - info.y = slot->bitmap_top; + err = FT_Render_Glyph(slot, renderMode); + if (err != FT_Err_Ok) + qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph); - glyph_buffer_size = info.width * info.height * 4; - glyph_buffer.reset(new uchar[glyph_buffer_size]); + FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE); - if (hsubpixel) - convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_RGB, false); - else if (vfactor != 1) - convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_VRGB, false); - } else { - int left = slot->metrics.horiBearingX; - int right = slot->metrics.horiBearingX + slot->metrics.width; - int top = slot->metrics.horiBearingY; - int bottom = slot->metrics.horiBearingY - slot->metrics.height; - if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP) - transformBoundingBox(&left, &top, &right, &bottom, &matrix); - left = FLOOR(left); - right = CEIL(right); - bottom = FLOOR(bottom); - top = CEIL(top); - - int hpixels = TRUNC(right - left); - // subpixel position requires one more pixel - if (subPixelPosition > 0 && format != Format_Mono) - hpixels++; - - if (hsubpixel) - hpixels = hpixels*3 + 8; - info.width = hpixels; - info.height = TRUNC(top - bottom); - info.x = TRUNC(left); - info.y = TRUNC(top); - if (hsubpixel) { - info.width /= 3; - info.x -= 1; - } - - // If any of the metrics are too large to fit, don't cache them - if (areMetricsTooLarge(info)) - return 0; + info.height = slot->bitmap.rows; + info.width = slot->bitmap.width; + info.x = slot->bitmap_left; + info.y = slot->bitmap_top; + if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) + info.width = info.width / 3; + if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) + info.height = info.height / vfactor; int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 : (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4)); - if (glyph_buffer_size < pitch * info.height) { - glyph_buffer_size = pitch * info.height; - glyph_buffer.reset(new uchar[glyph_buffer_size]); - memset(glyph_buffer.data(), 0, glyph_buffer_size); - } - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - FT_Bitmap bitmap; - bitmap.rows = info.height*vfactor; - bitmap.width = hpixels; - bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3); - int bitmap_buffer_size = bitmap.rows * bitmap.pitch; - if (!hsubpixel && vfactor == 1 && format != Format_A32) { - Q_ASSERT(glyph_buffer_size <= bitmap_buffer_size); - bitmap.buffer = glyph_buffer.data(); - } else { - bitmap.buffer = new uchar[bitmap_buffer_size]; - memset(bitmap.buffer, 0, bitmap_buffer_size); - } - bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY; - FT_Matrix matrix; - matrix.xx = (hsubpixel ? 3 : 1) << 16; - matrix.yy = vfactor << 16; - matrix.yx = matrix.xy = 0; - - FT_Outline_Transform(&slot->outline, &matrix); - FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor); - FT_Outline_Get_Bitmap(slot->library, &slot->outline, &bitmap); - if (hsubpixel) { - Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); - Q_ASSERT(antialias); - uchar *convoluted = new uchar[bitmap_buffer_size]; - bool useLegacyLcdFilter = false; - useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY); - uchar *buffer = bitmap.buffer; - if (!useLegacyLcdFilter) { - convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch); - buffer = convoluted; - } - convertRGBToARGB(buffer + 1, (uint *)glyph_buffer.data(), info.width, info.height, bitmap.pitch, subpixelType != Subpixel_RGB, useLegacyLcdFilter); - delete [] convoluted; - } else if (vfactor != 1) { - convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, bitmap.pitch, subpixelType != Subpixel_VRGB, true); - } else if (format == Format_A32 && bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { - convertGRAYToARGB(bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, bitmap.pitch); - } + glyph_buffer_size = info.height * pitch; + glyph_buffer.reset(new uchar[glyph_buffer_size]); - if (bitmap.buffer != glyph_buffer.data()) - delete [] bitmap.buffer; - } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) { -#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100) >= 20500) - Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO || slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA); -#else - Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO); -#endif + if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { + Q_ASSERT(format == Format_Mono); uchar *src = slot->bitmap.buffer; uchar *dst = glyph_buffer.data(); int h = slot->bitmap.rows; - if (format == Format_Mono) { - int bytes = ((info.width + 7) & ~7) >> 3; - while (h--) { - memcpy (dst, src, bytes); - dst += pitch; - src += slot->bitmap.pitch; - } - } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { - if (hsubpixel) { - while (h--) { - uint *dd = (uint *)dst; - *dd++ = 0; - for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++) { - uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000); - *dd++ = a; - } - *dd++ = 0; - dst += pitch; - src += slot->bitmap.pitch; - } - } else if (vfactor != 1) { - while (h--) { - uint *dd = (uint *)dst; - for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++) { - uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000); - *dd++ = a; - } - dst += pitch; - src += slot->bitmap.pitch; - } - } else { - while (h--) { - for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++) { - unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00); - dst[x] = a; - } - dst += pitch; - src += slot->bitmap.pitch; - } - } + + int bytes = ((info.width + 7) & ~7) >> 3; + while (h--) { + memcpy (dst, src, bytes); + dst += pitch; + src += slot->bitmap.pitch; } -#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100) >= 20500) - else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) - { - while (h--) { + } else if (slot->bitmap.pixel_mode == 7 /*FT_PIXEL_MODE_BGRA*/) { + Q_ASSERT(format == Format_ARGB); + uchar *src = slot->bitmap.buffer; + uchar *dst = glyph_buffer.data(); + int h = slot->bitmap.rows; + while (h--) { #if Q_BYTE_ORDER == Q_BIG_ENDIAN - const quint32 *srcPixel = (const quint32 *)src; - quint32 *dstPixel = (quint32 *)dst; - for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++, srcPixel++, dstPixel++) { - const quint32 pixel = *srcPixel; - *dstPixel = qbswap(pixel); - } + const quint32 *srcPixel = (const quint32 *)src; + quint32 *dstPixel = (quint32 *)dst; + for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++, srcPixel++, dstPixel++) { + const quint32 pixel = *srcPixel; + *dstPixel = qbswap(pixel); + } #else - memcpy(dst, src, slot->bitmap.width * 4); + memcpy(dst, src, slot->bitmap.width * 4); #endif - dst += slot->bitmap.pitch; - src += slot->bitmap.pitch; - } - info.width = info.linearAdvance = info.xOff = slot->bitmap.width; - info.height = slot->bitmap.rows; - info.x = slot->bitmap_left; - info.y = slot->bitmap_top; + dst += slot->bitmap.pitch; + src += slot->bitmap.pitch; } -#endif + info.linearAdvance = info.xOff = slot->bitmap.width; + } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { + Q_ASSERT(format == Format_A8); + uchar *src = slot->bitmap.buffer; + uchar *dst = glyph_buffer.data(); + int h = slot->bitmap.rows; + int bytes = info.width; + while (h--) { + memcpy (dst, src, bytes); + dst += pitch; + src += slot->bitmap.pitch; + } + } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { + Q_ASSERT(format == Format_A32); + convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_RGB); + } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) { + Q_ASSERT(format == Format_A32); + convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_VRGB); } else { - qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format); + qWarning("QFontEngine: Glyph rendered in unknown pixel_mode=%d", slot->bitmap.pixel_mode); return 0; } - } - if (!g) { g = new Glyph; @@ -1556,7 +1380,7 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadGlyphSet(const QTransform &matrix) gs = &transformedGlyphSets[0]; gs->clear(); gs->transformationMatrix = m; - gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.det()) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; + gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.determinant()) > QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; } Q_ASSERT(gs != 0); diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h index d498b0ac8b..2d1d5e6572 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h @@ -268,7 +268,7 @@ private: inline bool isScalableBitmap() const { return freetype->isScalableBitmap(); } inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const - { return loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); } + { return loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); } Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const; Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format, const QTransform &t, bool fetchBoundingBox = false, bool disableOutlineDrawing = false); diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri index af75aa3281..95b9926e65 100644 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ b/src/platformsupport/fontdatabases/mac/coretext.pri @@ -1,12 +1,6 @@ HEADERS += $$PWD/qcoretextfontdatabase_p.h $$PWD/qfontengine_coretext_p.h OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.mm -qtConfig(freetype) { - QMAKE_USE_PRIVATE += freetype - HEADERS += freetype/qfontengine_ft_p.h - SOURCES += freetype/qfontengine_ft.cpp -} - LIBS_PRIVATE += \ -framework CoreFoundation \ -framework CoreGraphics \ diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 5ac28ce798..047773d8e3 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -50,7 +50,9 @@ #include "qcoretextfontdatabase_p.h" #include "qfontengine_coretext_p.h" +#if QT_CONFIG(settings) #include <QtCore/QSettings> +#endif #include <QtCore/QtEndian> #ifndef QT_NO_FREETYPE #include <QtFontDatabaseSupport/private/qfontengine_ft_p.h> @@ -115,67 +117,6 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context) QCoreTextFontDatabase::QCoreTextFontDatabase() : m_hasPopulatedAliases(false) { -#ifdef Q_OS_MACX - QSettings appleSettings(QLatin1String("apple.com")); - QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); - if (appleValue.isValid()) - QCoreTextFontEngine::antialiasingThreshold = appleValue.toInt(); - - /* - font_smoothing = 0 means no smoothing, while 1-3 means subpixel - antialiasing with different hinting styles (but we don't care about the - exact value, only if subpixel rendering is available or not) - */ - int font_smoothing = 0; - appleValue = appleSettings.value(QLatin1String("AppleFontSmoothing")); - if (appleValue.isValid()) { - font_smoothing = appleValue.toInt(); - } else { - // non-Apple displays do not provide enough information about subpixel rendering so - // draw text with cocoa and compare pixel colors to see if subpixel rendering is enabled - int w = 10; - int h = 10; - NSRect rect = NSMakeRect(0.0, 0.0, w, h); - NSImage *fontImage = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; - - [fontImage lockFocus]; - - [[NSColor whiteColor] setFill]; - NSRectFill(rect); - - NSString *str = @"X\\"; - NSFont *font = [NSFont fontWithName:@"Helvetica" size:10.0]; - NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; - [attrs setObject:font forKey:NSFontAttributeName]; - [attrs setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName]; - - [str drawInRect:rect withAttributes:attrs]; - - NSBitmapImageRep *nsBitmapImage = [[NSBitmapImageRep alloc] initWithFocusedViewRect:rect]; - - [fontImage unlockFocus]; - - float red, green, blue; - for (int x = 0; x < w; x++) { - for (int y = 0; y < h; y++) { - NSColor *pixelColor = [nsBitmapImage colorAtX:x y:y]; - red = [pixelColor redComponent]; - green = [pixelColor greenComponent]; - blue = [pixelColor blueComponent]; - if (red != green || red != blue) - font_smoothing = 1; - } - } - - [nsBitmapImage release]; - [fontImage release]; - } - QCoreTextFontEngine::defaultGlyphFormat = (font_smoothing > 0 - ? QFontEngine::Format_A32 - : QFontEngine::Format_A8); -#else - QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A8; -#endif } QCoreTextFontDatabase::~QCoreTextFontDatabase() @@ -253,7 +194,7 @@ struct FontDescription { QFont::Weight weight; QFont::Style style; QFont::Stretch stretch; - int pixelSize; + qreal pointSize; bool fixedPitch; QSupportedWritingSystems writingSystems; }; @@ -269,7 +210,7 @@ Q_DECL_UNUSED static inline QDebug operator<<(QDebug debug, const FontDescriptio << ", weight=" << fd.weight << ", style=" << fd.style << ", stretch=" << fd.stretch - << ", pixelSize=" << fd.pixelSize + << ", pointSize=" << fd.pointSize << ", fixedPitch=" << fd.fixedPitch << ", writingSystems=" << fd.writingSystems << ")"; @@ -345,9 +286,11 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) if (CFNumberIsFloatType(size)) { double d; CFNumberGetValue(size, kCFNumberDoubleType, &d); - fd->pixelSize = d; + fd->pointSize = d; } else { - CFNumberGetValue(size, kCFNumberIntType, &fd->pixelSize); + int i; + CFNumberGetValue(size, kCFNumberIntType, &i); + fd->pointSize = i; } } @@ -375,8 +318,8 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font, con CFRetain(font); QPlatformFontDatabase::registerFont(family, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch, - true /* antialiased */, true /* scalable */, - fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font); + true /* antialiased */, true /* scalable */, 0 /* pixelSize, ignored as font is scalable */, + fd.fixedPitch, fd.writingSystems, (void *)font); } static NSString * const kQtFontDataAttribute = @"QtFontDataAttribute"; @@ -786,7 +729,7 @@ QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const else CFRelease(fontDesc); - QFont *font = new QFont(fd.familyName, fd.pixelSize, fd.weight, fd.style == QFont::StyleItalic); + QFont *font = new QFont(fd.familyName, fd.pointSize, fd.weight, fd.style == QFont::StyleItalic); return font; } diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 6543759a3d..25e7c6df72 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -41,9 +41,11 @@ #include <qpa/qplatformfontdatabase.h> #include <QtCore/qendian.h> +#if QT_CONFIG(settings) #include <QtCore/qsettings.h> +#endif #include <QtCore/qoperatingsystemversion.h> - +#include <private/qcoregraphics_p.h> #include <private/qimage_p.h> #include <cmath> @@ -83,6 +85,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") + static float SYNTHETIC_ITALIC_SKEW = std::tan(14.f * std::acos(0.f) / 90.f); bool QCoreTextFontEngine::ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length) @@ -131,42 +135,6 @@ QFont::Weight QCoreTextFontEngine::qtWeightFromCFWeight(float value) return ret; } -static void loadAdvancesForGlyphs(CTFontRef ctfont, - QVarLengthArray<CGGlyph> &cgGlyphs, - QGlyphLayout *glyphs, int len, - QFontEngine::ShaperFlags flags, - const QFontDef &fontDef) -{ - Q_UNUSED(flags); - QVarLengthArray<CGSize> advances(len); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), len); - - for (int i = 0; i < len; ++i) { - if (glyphs->glyphs[i] & 0xff000000) - continue; - glyphs->advances[i] = QFixed::fromReal(advances[i].width); - } - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < len; ++i) - glyphs->advances[i] = glyphs->advances[i].round(); - } -} - -static float getTraitValue(CFDictionaryRef allTraits, CFStringRef trait) -{ - if (CFDictionaryContainsKey(allTraits, trait)) { - CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait); - float v = 0; - CFNumberGetValue(traitNum, kCFNumberFloatType, &v); - return v; - } - return 0; -} - -int QCoreTextFontEngine::antialiasingThreshold = 0; -QFontEngine::GlyphFormat QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A32; - CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef) { CGAffineTransform transform = CGAffineTransformIdentity; @@ -221,38 +189,36 @@ QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qre } QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) - : QFontEngine(Mac) + : QCoreTextFontEngine(def) { - fontDef = def; - transform = qt_transform_from_fontdef(fontDef); - ctfont = font; - CFRetain(ctfont); - cgFont = CTFontCopyGraphicsFont(font, NULL); + ctfont = QCFType<CTFontRef>::constructFromGet(font); + cgFont = CTFontCopyGraphicsFont(font, nullptr); init(); } QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) + : QCoreTextFontEngine(def) +{ + cgFont = QCFType<CGFontRef>::constructFromGet(font); + ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, nullptr); + init(); +} + +QCoreTextFontEngine::QCoreTextFontEngine(const QFontDef &def) : QFontEngine(Mac) { fontDef = def; transform = qt_transform_from_fontdef(fontDef); - cgFont = font; - // Keep reference count balanced - CFRetain(cgFont); - ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL); - init(); } QCoreTextFontEngine::~QCoreTextFontEngine() { - CFRelease(cgFont); - CFRelease(ctfont); } void QCoreTextFontEngine::init() { - Q_ASSERT(ctfont != NULL); - Q_ASSERT(cgFont != NULL); + Q_ASSERT(ctfont); + Q_ASSERT(cgFont); face_id.index = 0; QCFString name = CTFontCopyName(ctfont, kCTFontUniqueNameKey); @@ -269,18 +235,29 @@ void QCoreTextFontEngine::init() if (traits & kCTFontColorGlyphsTrait) glyphFormat = QFontEngine::Format_ARGB; + else if (shouldSmoothFont() && fontSmoothing() == FontSmoothing::Subpixel) + glyphFormat = QFontEngine::Format_A32; else - glyphFormat = defaultGlyphFormat; + glyphFormat = QFontEngine::Format_A8; if (traits & kCTFontItalicTrait) fontDef.style = QFont::StyleItalic; - CFDictionaryRef allTraits = CTFontCopyTraits(ctfont); + static const auto getTraitValue = [](CFDictionaryRef allTraits, CFStringRef trait) -> float { + if (CFDictionaryContainsKey(allTraits, trait)) { + CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait); + float v = 0; + CFNumberGetValue(traitNum, kCFNumberFloatType, &v); + return v; + } + return 0; + }; + + QCFType<CFDictionaryRef> allTraits = CTFontCopyTraits(ctfont); fontDef.weight = QCoreTextFontEngine::qtWeightFromCFWeight(getTraitValue(allTraits, kCTFontWeightTrait)); int slant = static_cast<int>(getTraitValue(allTraits, kCTFontSlantTrait) * 500 + 500); if (slant > 500 && !(traits & kCTFontItalicTrait)) fontDef.style = QFont::StyleOblique; - CFRelease(allTraits); if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) synthesisFlags |= SynthesizedBold; @@ -359,22 +336,9 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout * *nglyphs = glyph_pos; glyphs->numGlyphs = glyph_pos; - if (flags & GlyphIndicesOnly) - return true; - - QVarLengthArray<CGSize> advances(glyph_pos); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), glyph_pos); - - for (int i = 0; i < glyph_pos; ++i) { - if (glyphs->glyphs[i] & 0xff000000) - continue; - glyphs->advances[i] = QFixed::fromReal(advances[i].width); - } + if (!(flags & GlyphIndicesOnly)) + loadAdvancesForGlyphs(cgGlyphs, glyphs); - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < glyph_pos; ++i) - glyphs->advances[i] = glyphs->advances[i].round(); - } return true; } @@ -469,6 +433,11 @@ qreal QCoreTextFontEngine::maxCharWidth() const return bb.xoff.toReal(); } +bool QCoreTextFontEngine::hasColorGlyphs() const +{ + return glyphFormat == QFontEngine::Format_ARGB; +} + void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) { QVarLengthArray<QFixedPoint> positions; @@ -522,9 +491,11 @@ void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextIt struct ConvertPathInfo { - ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos) : path(newPath), pos(newPos) {} + ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos, qreal newStretch = 1.0) : + path(newPath), pos(newPos), stretch(newStretch) {} QPainterPath *path; QPointF pos; + qreal stretch; }; static void convertCGPathToQPainterPath(void *info, const CGPathElement *element) @@ -532,32 +503,32 @@ static void convertCGPathToQPainterPath(void *info, const CGPathElement *element ConvertPathInfo *myInfo = static_cast<ConvertPathInfo *>(info); switch(element->type) { case kCGPathElementMoveToPoint: - myInfo->path->moveTo(element->points[0].x + myInfo->pos.x(), + myInfo->path->moveTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), element->points[0].y + myInfo->pos.y()); break; case kCGPathElementAddLineToPoint: - myInfo->path->lineTo(element->points[0].x + myInfo->pos.x(), + myInfo->path->lineTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), element->points[0].y + myInfo->pos.y()); break; case kCGPathElementAddQuadCurveToPoint: - myInfo->path->quadTo(element->points[0].x + myInfo->pos.x(), + myInfo->path->quadTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), element->points[0].y + myInfo->pos.y(), - element->points[1].x + myInfo->pos.x(), + (element->points[1].x * myInfo->stretch) + myInfo->pos.x(), element->points[1].y + myInfo->pos.y()); break; case kCGPathElementAddCurveToPoint: - myInfo->path->cubicTo(element->points[0].x + myInfo->pos.x(), + myInfo->path->cubicTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), element->points[0].y + myInfo->pos.y(), - element->points[1].x + myInfo->pos.x(), + (element->points[1].x * myInfo->stretch) + myInfo->pos.x(), element->points[1].y + myInfo->pos.y(), - element->points[2].x + myInfo->pos.x(), + (element->points[2].x * myInfo->stretch) + myInfo->pos.x(), element->points[2].y + myInfo->pos.y()); break; case kCGPathElementCloseSubpath: myInfo->path->closeSubpath(); break; default: - qDebug() << "Unhandled path transform type: " << element->type; + qCWarning(lcQpaFonts) << "Unhandled path transform type: " << element->type; } } @@ -565,7 +536,7 @@ static void convertCGPathToQPainterPath(void *info, const CGPathElement *element void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs, QPainterPath *path, QTextItem::RenderFlags) { - if (glyphFormat == QFontEngine::Format_ARGB) + if (hasColorGlyphs()) return; // We can't convert color-glyphs to path CGAffineTransform cgMatrix = CGAffineTransformIdentity; @@ -574,9 +545,10 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position if (synthesisFlags & QFontEngine::SynthesizedItalic) cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); + qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0; for (int i = 0; i < nGlyphs; ++i) { QCFType<CGPathRef> cgpath = CTFontCreatePathForGlyph(ctfont, glyphs[i], &cgMatrix); - ConvertPathInfo info(path, positions[i].toPointF()); + ConvertPathInfo info(path, positions[i].toPointF(), stretch); CGPathApply(cgpath, &info, convertCGPathToQPainterPath); } } @@ -645,66 +617,190 @@ glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed s return br; } +/* + Apple has gone through many iterations of its font smoothing algorithms, + and there are many ways to enable or disable certain aspects of it. As + keeping up with all the different toggles and behavior differences between + macOS versions is tricky, we resort to rendering a single glyph in a few + configurations, picking up the font smoothing algorithm from the observed + result. + + The possible values are: + + - Disabled: No font smoothing is applied. + + Possibly triggered by the user unchecking the "Use font smoothing when + available" checkbox in the system preferences or setting AppleFontSmoothing + to 0. Also controlled by the CGContextSetAllowsFontSmoothing() API, + which gets its default from the settings above. This API overrides + the more granular CGContextSetShouldSmoothFonts(), which we use to + enable (request) or disable font smoothing. + + Note that this does not exclude normal antialiasing, controlled by + the CGContextSetShouldAntialias() API. + + - Subpixel: Font smoothing is applied, and affects subpixels. + + This was the default mode on macOS versions prior to 10.14 (Mojave). + The font dilation (stem darkening) parameters were controlled by the + AppleFontSmoothing setting, ranging from 1 to 3 (light to strong). + + On Mojave it is no longer supported, but can be triggered by a legacy + override (CGFontRenderingFontSmoothingDisabled=NO), so we need to + still account for it, otherwise users will have a bad time. + + - Grayscale: Font smoothing is applied, but does not affect subpixels. + + This is the default mode on macOS 10.14 (Mojave). The font dilation + (stem darkening) parameters are not affected by the AppleFontSmoothing + setting, but are instead computed based on the fill color used when + drawing the glyphs (white fill gives a lighter dilation than black + fill). This affects how we build our glyph cache, since we produce + alpha maps by drawing white on black. +*/ +QCoreTextFontEngine::FontSmoothing QCoreTextFontEngine::fontSmoothing() +{ + static const FontSmoothing cachedFontSmoothing = [] { + static const int kSize = 10; + QCFType<CTFontRef> font = CTFontCreateWithName(CFSTR("Helvetica"), kSize, nullptr); + + UniChar character('X'); CGGlyph glyph; + CTFontGetGlyphsForCharacters(font, &character, &glyph, 1); + + auto drawGlyph = [&](bool smooth) -> QImage { + QImage image(kSize, kSize, QImage::Format_RGB32); + image.fill(0); + + QMacCGContext ctx(&image); + CGContextSetTextDrawingMode(ctx, kCGTextFill); + CGContextSetGrayFillColor(ctx, 1, 1); + + // Will be ignored if CGContextSetAllowsFontSmoothing() has been + // set to false by CoreGraphics based on user defaults. + CGContextSetShouldSmoothFonts(ctx, smooth); + + CTFontDrawGlyphs(font, &glyph, &CGPointZero, 1, ctx); + return image; + }; + + QImage nonSmoothed = drawGlyph(false); + QImage smoothed = drawGlyph(true); + + FontSmoothing fontSmoothing = FontSmoothing::Disabled; + [&] { + for (int x = 0; x < kSize; ++x) { + for (int y = 0; y < kSize; ++y) { + QRgb sp = smoothed.pixel(x, y); + if (qRed(sp) != qGreen(sp) || qRed(sp) != qBlue(sp)) { + fontSmoothing = FontSmoothing::Subpixel; + return; + } + + if (sp != nonSmoothed.pixel(x, y)) + fontSmoothing = FontSmoothing::Grayscale; + } + } + }(); + + auto defaults = [NSUserDefaults standardUserDefaults]; + qCDebug(lcQpaFonts) << "Resolved font smoothing algorithm. Defaults =" + << [[defaults dictionaryRepresentation] dictionaryWithValuesForKeys:@[ + @"AppleFontSmoothing", + @"CGFontRenderingFontSmoothingDisabled" + ]] << "Result =" << fontSmoothing; + + return fontSmoothing; + }(); + + return cachedFontSmoothing; +} + +bool QCoreTextFontEngine::shouldAntialias() const +{ + return !(fontDef.styleStrategy & QFont::NoAntialias); +} + +bool QCoreTextFontEngine::shouldSmoothFont() const +{ + if (hasColorGlyphs()) + return false; + + if (!shouldAntialias()) + return false; + + switch (fontSmoothing()) { + case Disabled: return false; + case Subpixel: return !(fontDef.styleStrategy & QFont::NoSubpixelAntialias); + case Grayscale: return true; + } + + Q_UNREACHABLE(); +} + bool QCoreTextFontEngine::expectsGammaCorrectedBlending() const { - // Only works well when font-smoothing is enabled - return (glyphFormat == Format_A32) && !(fontDef.styleStrategy & (QFont::NoAntialias | QFont::NoSubpixelAntialias)); + return shouldSmoothFont() && fontSmoothing() == Subpixel; } -QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool aa, const QTransform &matrix) +qreal QCoreTextFontEngine::fontSmoothingGamma() +{ + return 2.0; +} + +QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix) { glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat); - bool isColorGlyph = glyphFormat == QFontEngine::Format_ARGB; - QImage::Format imageFormat = isColorGlyph ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + QImage::Format imageFormat = hasColorGlyphs() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; QImage im(br.width.ceil().toInt(), br.height.ceil().toInt(), imageFormat); if (!im.width() || !im.height()) return im; + QCFType<CGColorSpaceRef> colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + QCFType<CGContextRef> ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(), + 8, im.bytesPerLine(), colorspace, + qt_mac_bitmapInfoForImage(im)); + Q_ASSERT(ctx); + + CGContextSetShouldAntialias(ctx, shouldAntialias()); + + const bool shouldSmooth = shouldSmoothFont(); + CGContextSetShouldSmoothFonts(ctx, shouldSmooth); + #if defined(Q_OS_MACOS) - CGColorRef glyphColor = CGColorGetConstantColor(kCGColorWhite); - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) { - // macOS 10.14 uses a new font smoothing algorithm that takes the fill color into - // account. This means our default approach of drawing white on black to produce - // the alpha map will result in non-native looking text when then drawn as black - // on white during the final blit. As a workaround we use the application's current - // appearance to decide whether to draw with white or black fill, and then invert - // the glyph image in the latter case, producing an alpha map. This covers the - // most common use-cases, but longer term we should propagate the fill color all - // the way from the paint engine, and include it in the key for the glyph cache. - if (!qt_mac_applicationIsInDarkMode()) - glyphColor = CGColorGetConstantColor(kCGColorBlack); - } - const bool blackOnWhiteGlyphs = !isColorGlyph - && CGColorEqualToColor(glyphColor, CGColorGetConstantColor(kCGColorBlack)); + auto glyphColor = [&] { + if (shouldSmooth && fontSmoothing() == Grayscale) { + // The grayscale font smoothing algorithm introduced in macOS Mojave (10.14) adjusts + // its dilation (stem darkening) parameters based on the fill color. This means our + // default approach of drawing white on black to produce the alpha map will result + // in non-native looking text when then drawn as black on white during the final blit. + // As a workaround we use the application's current appearance to decide whether to + // draw with white or black fill, and then invert the glyph image in the latter case, + // producing an alpha map. This covers the most common use-cases, but longer term we + // should propagate the fill color all the way from the paint engine, and include it + //in the key for the glyph cache. + + if (!qt_mac_applicationIsInDarkMode()) + return kCGColorBlack; + } + return kCGColorWhite; + }(); + + const bool blackOnWhiteGlyphs = glyphColor == kCGColorBlack; if (blackOnWhiteGlyphs) im.fill(Qt::white); else #endif - im.fill(0); // Faster than Qt::black - - CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - uint cgflags = isColorGlyph ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; -#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version - cgflags |= kCGBitmapByteOrder32Host; -#endif + im.fill(0); - CGContextRef ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(), - 8, im.bytesPerLine(), colorspace, - cgflags); - Q_ASSERT(ctx); CGContextSetFontSize(ctx, fontDef.pixelSize); - const bool antialias = (aa || fontDef.pointSize > antialiasingThreshold) && !(fontDef.styleStrategy & QFont::NoAntialias); - CGContextSetShouldAntialias(ctx, antialias); - const bool smoothing = antialias && !(fontDef.styleStrategy & QFont::NoSubpixelAntialias); - CGContextSetShouldSmoothFonts(ctx, smoothing); CGAffineTransform cgMatrix = CGAffineTransformIdentity; if (synthesisFlags & QFontEngine::SynthesizedItalic) cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); - if (!isColorGlyph) // CTFontDrawGlyphs incorporates the font's matrix already + if (!hasColorGlyphs()) // CTFontDrawGlyphs incorporates the font's matrix already cgMatrix = CGAffineTransformConcat(cgMatrix, transform); if (matrix.isScaling()) @@ -714,10 +810,10 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition qreal pos_x = -br.x.truncate() + subPixelPosition.toReal(); qreal pos_y = im.height() + br.y.toReal(); - if (!isColorGlyph) { + if (!hasColorGlyphs()) { CGContextSetTextMatrix(ctx, cgMatrix); #if defined(Q_OS_MACOS) - CGContextSetFillColorWithColor(ctx, glyphColor); + CGContextSetFillColorWithColor(ctx, CGColorGetConstantColor(glyphColor)); #else CGContextSetRGBFillColor(ctx, 1, 1, 1, 1); #endif @@ -742,8 +838,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); } - CGContextRelease(ctx); - CGColorSpaceRelease(colorspace); + if (expectsGammaCorrectedBlending()) + qGamma_correct_back_to_linear_cs(&im); #if defined(Q_OS_MACOS) if (blackOnWhiteGlyphs) @@ -763,7 +859,7 @@ QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosit if (x.type() > QTransform::TxScale) return QFontEngine::alphaMapForGlyph(glyph, subPixelPosition, x); - QImage im = imageForGlyph(glyph, subPixelPosition, false, x); + QImage im = imageForGlyph(glyph, subPixelPosition, x); QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); @@ -785,9 +881,7 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo if (x.type() > QTransform::TxScale) return QFontEngine::alphaRGBMapForGlyph(glyph, subPixelPosition, x); - QImage im = imageForGlyph(glyph, subPixelPosition, true, x); - qGamma_correct_back_to_linear_cs(&im); - return im; + return imageForGlyph(glyph, subPixelPosition, x); } QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) @@ -795,22 +889,35 @@ QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPositio if (t.type() > QTransform::TxScale) return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t); - return imageForGlyph(glyph, subPixelPosition, true, t); + return imageForGlyph(glyph, subPixelPosition, t); } void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const { - int i, numGlyphs = glyphs->numGlyphs; + Q_UNUSED(flags); + + const int numGlyphs = glyphs->numGlyphs; QVarLengthArray<CGGlyph> cgGlyphs(numGlyphs); - for (i = 0; i < numGlyphs; ++i) { - if (glyphs->glyphs[i] & 0xff000000) - cgGlyphs[i] = 0; - else - cgGlyphs[i] = glyphs->glyphs[i]; + for (int i = 0; i < numGlyphs; ++i) { + Q_ASSERT(!QFontEngineMulti::highByte(glyphs->glyphs[i])); + cgGlyphs[i] = glyphs->glyphs[i]; } - loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef); + loadAdvancesForGlyphs(cgGlyphs, glyphs); +} + +void QCoreTextFontEngine::loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const +{ + const int numGlyphs = glyphs->numGlyphs; + QVarLengthArray<CGSize> advances(numGlyphs); + CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), numGlyphs); + + for (int i = 0; i < numGlyphs; ++i) { + QFixed advance = QFixed::fromReal(advances[i].width); + glyphs->advances[i] = fontDef.styleStrategy & QFont::ForceIntegerMetrics + ? advance.round() : advance; + } } QFontEngine::FaceId QCoreTextFontEngine::faceId() const @@ -867,7 +974,7 @@ QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const Qt::HANDLE QCoreTextFontEngine::handle() const { - return (Qt::HANDLE)ctfont; + return (Qt::HANDLE)(static_cast<CTFontRef>(ctfont)); } bool QCoreTextFontEngine::supportsTransformation(const QTransform &transform) const diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index b77aaa27c1..4064507058 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -53,6 +53,7 @@ #include <private/qfontengine_p.h> #include <private/qcore_mac_p.h> +#include <QtCore/qloggingcategory.h> #ifdef Q_OS_OSX #include <ApplicationServices/ApplicationServices.h> @@ -63,8 +64,12 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) + class QCoreTextFontEngine : public QFontEngine { + Q_GADGET + public: QCoreTextFontEngine(CTFontRef font, const QFontDef &def); QCoreTextFontEngine(CGFontRef font, const QFontDef &def); @@ -118,18 +123,28 @@ public: QFontEngine::Properties properties() const override; + enum FontSmoothing { Disabled, Subpixel, Grayscale }; + Q_ENUM(FontSmoothing); + + static FontSmoothing fontSmoothing(); + static qreal fontSmoothingGamma(); + static bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length); static QFont::Weight qtWeightFromCFWeight(float value); - static int antialiasingThreshold; - static QFontEngine::GlyphFormat defaultGlyphFormat; - static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); + protected: + QCoreTextFontEngine(const QFontDef &def); void init(); - QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool colorful, const QTransform &m); - CTFontRef ctfont; - CGFontRef cgFont; + QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &m); + void loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const; + bool hasColorGlyphs() const; + bool shouldAntialias() const; + bool shouldSmoothFont() const; + + QCFType<CTFontRef> ctfont; + QCFType<CGFontRef> cgFont; int synthesisFlags; CGAffineTransform transform; QFixed avgCharWidth; diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index 00a0643dd1..b1ba84fe14 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -1264,11 +1264,6 @@ QWindowsFontDatabase::~QWindowsFontDatabase() removeApplicationFonts(); } -QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) -{ - return new QWindowsMultiFontEngine(fontEngine, script); -} - QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { const QString faceName(static_cast<const QChar*>(handle)); @@ -1434,8 +1429,8 @@ QT_WARNING_POP reinterpret_cast<const OS2Table *>(fontData.constData() + qFromBigEndian<quint32>(os2TableEntry->offset)); - bool italic = qFromBigEndian<quint16>(os2Table->selection) & 1; - bool oblique = qFromBigEndian<quint16>(os2Table->selection) & 128; + bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0); + bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9); if (italic) fontEngine->fontDef.style = QFont::StyleItalic; @@ -1490,7 +1485,8 @@ static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, static void getFamiliesAndSignatures(const QByteArray &fontData, QList<QFontNames> *families, - QVector<FONTSIGNATURE> *signatures) + QVector<FONTSIGNATURE> *signatures, + QVector<QFontValues> *values) { const uchar *data = reinterpret_cast<const uchar *>(fontData.constData()); @@ -1509,11 +1505,27 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, if (names.name.isEmpty()) continue; - families->append(qMove(names)); + families->append(std::move(names)); + + if (values || signatures) + getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); + + if (values) { + QFontValues fontValues; + if (table && length >= 64) { + // Read in some details about the font, offset calculated based on the specification + fontValues.weight = qFromBigEndian<quint16>(table + 4); + + quint16 fsSelection = qFromBigEndian<quint16>(table + 62); + fontValues.isItalic = (fsSelection & 1) != 0; + fontValues.isUnderlined = (fsSelection & (1 << 1)) != 0; + fontValues.isOverstruck = (fsSelection & (1 << 4)) != 0; + } + values->append(std::move(fontValues)); + } if (signatures) { FONTSIGNATURE signature; - getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); if (table && length >= 86) { // Offsets taken from OS/2 table in the TrueType spec signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42); @@ -1536,11 +1548,12 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, WinApplicationFont font; font.fileName = fileName; QVector<FONTSIGNATURE> signatures; + QVector<QFontValues> fontValues; QList<QFontNames> families; QStringList familyNames; if (!fontData.isEmpty()) { - getFamiliesAndSignatures(fontData, &families, &signatures); + getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues); if (families.isEmpty()) return familyNames; @@ -1553,14 +1566,23 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, // Memory fonts won't show up in enumeration, so do add them the hard way. for (int j = 0; j < families.count(); ++j) { - const QString familyName = families.at(j).name; - const QString styleName = families.at(j).style; + const auto &family = families.at(j); + const QString &familyName = family.name; + const QString &styleName = family.style; familyNames << familyName; HDC hdc = GetDC(0); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size())); lf.lfCharSet = DEFAULT_CHARSET; + const QFontValues &values = fontValues.at(j); + lf.lfWeight = values.weight; + if (values.isItalic) + lf.lfItalic = TRUE; + if (values.isOverstruck) + lf.lfStrikeOut = TRUE; + if (values.isUnderlined) + lf.lfUnderline = TRUE; HFONT hfont = CreateFontIndirect(&lf); HGDIOBJ oldobj = SelectObject(hdc, hfont); @@ -1581,7 +1603,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, QByteArray data = f.readAll(); f.close(); - getFamiliesAndSignatures(data, &families, 0); + getFamiliesAndSignatures(data, &families, nullptr, nullptr); if (families.isEmpty()) return QStringList(); diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp index f68ea54dcf..db2186644b 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp @@ -115,30 +115,33 @@ static FontKeys &fontKeys() { static FontKeys result; if (result.isEmpty()) { - const QSettings fontRegistry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), - QSettings::NativeFormat); - const QStringList allKeys = fontRegistry.allKeys(); - const QString trueType = QStringLiteral("(TrueType)"); + const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), + QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") }; + for (const auto key : keys) { + const QSettings fontRegistry(key, QSettings::NativeFormat); + const QStringList allKeys = fontRegistry.allKeys(); + const QString trueType = QStringLiteral("(TrueType)"); #if QT_CONFIG(regularexpression) - const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+")); + const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+")); #else - const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+")); + const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+")); #endif - Q_ASSERT(sizeListMatch.isValid()); - const int size = allKeys.size(); - result.reserve(size); - for (int i = 0; i < size; ++i) { - FontKey fontKey; - const QString ®istryFontKey = allKeys.at(i); - fontKey.fileName = fontRegistry.value(registryFontKey).toString(); - QString realKey = registryFontKey; - realKey.remove(trueType); - realKey.remove(sizeListMatch); - const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&')); - fontKey.fontNames.reserve(fontNames.size()); - for (const QStringRef &fontName : fontNames) - fontKey.fontNames.append(fontName.trimmed().toString()); - result.append(fontKey); + Q_ASSERT(sizeListMatch.isValid()); + const int size = allKeys.size(); + result.reserve(result.size() + size); + for (int i = 0; i < size; ++i) { + FontKey fontKey; + const QString ®istryFontKey = allKeys.at(i); + fontKey.fileName = fontRegistry.value(registryFontKey).toString(); + QString realKey = registryFontKey; + realKey.remove(trueType); + realKey.remove(sizeListMatch); + const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&')); + fontKey.fontNames.reserve(fontNames.size()); + for (const QStringRef &fontName : fontNames) + fontKey.fontNames.append(fontName.trimmed().toString()); + result.append(fontKey); + } } } return result; diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h index ab6d6307c7..b85a2dceee 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h @@ -67,7 +67,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) class QWindowsFontEngineData { - Q_DISABLE_COPY(QWindowsFontEngineData) + Q_DISABLE_COPY_MOVE(QWindowsFontEngineData) public: QWindowsFontEngineData(); ~QWindowsFontEngineData(); @@ -85,7 +85,7 @@ public: class QWindowsFontDatabase : public QPlatformFontDatabase { - Q_DISABLE_COPY(QWindowsFontDatabase) + Q_DISABLE_COPY_MOVE(QWindowsFontDatabase) public: enum FontOptions { // Relevant bits from QWindowsIntegration::Options @@ -98,7 +98,6 @@ public: void populateFontDatabase() override; void populateFamily(const QString &familyName) override; - QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) override; QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override; @@ -177,6 +176,14 @@ struct QFontNames QString preferredStyle; // e.g. "Condensed Italic" }; +struct QFontValues +{ + quint16 weight = 0; + bool isItalic = false; + bool isOverstruck = false; + bool isUnderlined = false; +}; + bool qt_localizedName(const QString &name); QString qt_getEnglishName(const QString &familyName, bool includeStyle = false); QFontNames qt_getCanonicalFontNames(const LOGFONT &lf); diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp index 2a41209225..2ae378c558 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp @@ -702,8 +702,8 @@ static inline double qt_fixed_to_double(const FIXED &p) { return ((p.value << 16) + p.fract) / 65536.0; } -static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) { - return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale); +static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch) { + return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale); } #ifndef GGO_UNHINTED @@ -711,7 +711,8 @@ static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) { #endif static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, - QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1) + QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, + qreal scale = 1.0, qreal stretch = 1.0) { MAT2 mat; mat.eM11.value = mat.eM22.value = 1; @@ -761,7 +762,7 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, while (headerOffset < bufferSize) { const TTPOLYGONHEADER *ttph = reinterpret_cast<const TTPOLYGONHEADER *>(dataBuffer + headerOffset); - QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale)); + QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch)); path->moveTo(lastPoint + oset); offset += sizeof(TTPOLYGONHEADER); while (offset < headerOffset + ttph->cb) { @@ -769,7 +770,7 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, switch (curve->wType) { case TT_PRIM_LINE: { for (int i=0; i<curve->cpfx; ++i) { - QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset; + QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; path->lineTo(p); } break; @@ -779,8 +780,8 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, QPointF prev(elm.x, elm.y); QPointF endPoint; for (int i=0; i<curve->cpfx - 1; ++i) { - QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset; - QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset; + QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; + QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset; if (i < curve->cpfx - 2) { endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2); } else { @@ -795,9 +796,9 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, } case TT_PRIM_CSPLINE: { for (int i=0; i<curve->cpfx; ) { - QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset; - QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset; - QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset; + QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; + QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; + QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; path->cubicTo(p2, p3, p4); } break; @@ -829,9 +830,11 @@ void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions HDC hdc = m_fontEngineData->hdc; HGDIOBJ oldfont = SelectObject(hdc, hf); + qreal scale = qreal(fontDef.pixelSize) / unitsPerEm; + qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0; for(int i = 0; i < nglyphs; ++i) { if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0, - qreal(fontDef.pixelSize) / unitsPerEm)) { + scale, stretch)) { // Some windows fonts, like "Modern", are vector stroke // fonts, which are reported as TMPF_VECTOR but do not // support GetGlyphOutline, and thus we set this bit so @@ -1199,120 +1202,6 @@ void QWindowsFontEngine::initFontInfo(const QFontDef &request, } } -/*! - \class QWindowsMultiFontEngine - \brief Standard Windows Multi font engine. - \internal - \ingroup qt-lighthouse-win - - "Merges" several font engines that have gaps in the - supported writing systems. - - Will probably be superseded by a common Free Type font engine in Qt 5.X. -*/ -QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *fe, int script) - : QFontEngineMulti(fe, script) -{ -} - -#ifndef QT_NO_DIRECTWRITE -static QString msgDirectWriteFunctionFailed(HRESULT hr, const char *function, - const QString &fam, const QString &substitute) -{ - _com_error error(hr); - QString result; - QTextStream str(&result); - str << function << " failed for \"" << fam << '"'; - if (substitute != fam) - str << " (substitute: \"" << substitute << "\")"; - str << ": error " << hex << showbase << ulong(hr) << ' ' << noshowbase << dec - << ": " << QString::fromWCharArray(error.ErrorMessage()); - return result; -} -#endif // !QT_NO_DIRECTWRITE - -QFontEngine *QWindowsMultiFontEngine::loadEngine(int at) -{ - QFontEngine *fontEngine = engine(0); - QSharedPointer<QWindowsFontEngineData> data; - LOGFONT lf; - -#ifndef QT_NO_DIRECTWRITE - if (fontEngine->type() == QFontEngine::DirectWrite) { - QWindowsFontEngineDirectWrite *fe = static_cast<QWindowsFontEngineDirectWrite *>(fontEngine); - lf = QWindowsFontDatabase::fontDefToLOGFONT(fe->fontDef, QString()); - - data = fe->fontEngineData(); - } else -#endif - { - QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(fontEngine); - lf = fe->m_logfont; - - data = fe->fontEngineData(); - } - - const QString fam = fallbackFamilyAt(at - 1); - const int faceNameLength = qMin(fam.length(), LF_FACESIZE - 1); - memcpy(lf.lfFaceName, fam.utf16(), faceNameLength * sizeof(wchar_t)); - lf.lfFaceName[faceNameLength] = 0; - -#ifndef QT_NO_DIRECTWRITE - if (fontEngine->type() == QFontEngine::DirectWrite) { - const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); - if (nameSubstitute != fam) { - const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); - memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); - lf.lfFaceName[nameSubstituteLength] = 0; - } - - HFONT hfont = CreateFontIndirect(&lf); - if (hfont == nullptr) { - qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); - } else { - HGDIOBJ oldFont = SelectObject(data->hdc, hfont); - - IDWriteFontFace *directWriteFontFace = nullptr; - QWindowsFontEngineDirectWrite *fedw = nullptr; - HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace); - if (SUCCEEDED(hr)) { - Q_ASSERT(directWriteFontFace); - fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, - fontEngine->fontDef.pixelSize, - data); - fedw->fontDef.weight = fontEngine->fontDef.weight; - if (fontEngine->fontDef.style > QFont::StyleNormal) - fedw->fontDef.style = fontEngine->fontDef.style; - fedw->fontDef.family = fam; - fedw->fontDef.hintingPreference = fontEngine->fontDef.hintingPreference; - fedw->fontDef.stretch = fontEngine->fontDef.stretch; - } else { - qWarning("%s: %s", __FUNCTION__, - qPrintable(msgDirectWriteFunctionFailed(hr, "CreateFontFace", fam, nameSubstitute))); - } - - SelectObject(data->hdc, oldFont); - DeleteObject(hfont); - - if (fedw != nullptr) - return fedw; - } - } -#endif - - // Get here if original font is not DirectWrite or DirectWrite creation failed for some - // reason - - QFontEngine *fe = new QWindowsFontEngine(fam, lf, data); - fe->fontDef.weight = fontEngine->fontDef.weight; - if (fontEngine->fontDef.style > QFont::StyleNormal) - fe->fontDef.style = fontEngine->fontDef.style; - fe->fontDef.family = fam; - fe->fontDef.hintingPreference = fontEngine->fontDef.hintingPreference; - fe->fontDef.stretch = fontEngine->fontDef.stretch; - return fe; -} - bool QWindowsFontEngine::supportsTransformation(const QTransform &transform) const { // Support all transformations for ttf files, and translations for raster fonts diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h index a151cf7343..b1b9d828ac 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h @@ -66,9 +66,7 @@ class QWindowsFontEngineData; class QWindowsFontEngine : public QFontEngine { - Q_DISABLE_COPY(QWindowsFontEngine) - friend class QWindowsMultiFontEngine; - + Q_DISABLE_COPY_MOVE(QWindowsFontEngine) public: QWindowsFontEngine(const QString &name, LOGFONT lf, const QSharedPointer<QWindowsFontEngineData> &fontEngineData); @@ -169,14 +167,6 @@ private: mutable int designAdvancesSize = 0; }; -class QWindowsMultiFontEngine : public QFontEngineMulti -{ -public: - explicit QWindowsMultiFontEngine(QFontEngine *fe, int script); - - QFontEngine *loadEngine(int at) override; -}; - QT_END_NAMESPACE Q_DECLARE_METATYPE(HFONT) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp index 57c41938bc..60a5896e7b 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp @@ -69,7 +69,7 @@ namespace { class GeometrySink: public IDWriteGeometrySink { - Q_DISABLE_COPY(GeometrySink) + Q_DISABLE_COPY_MOVE(GeometrySink) public: GeometrySink(QPainterPath *path) : m_refCount(0), m_path(path) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h index 9326f5aece..3eaf8cf3d8 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h @@ -72,7 +72,7 @@ class QWindowsFontEngineData; class QWindowsFontEngineDirectWrite : public QFontEngine { - Q_DISABLE_COPY(QWindowsFontEngineDirectWrite) + Q_DISABLE_COPY_MOVE(QWindowsFontEngineDirectWrite) public: explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, qreal pixelSize, diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h index 6c47a527d2..ed68ac2644 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE class QWindowsNativeImage { - Q_DISABLE_COPY(QWindowsNativeImage) + Q_DISABLE_COPY_MOVE(QWindowsNativeImage) public: QWindowsNativeImage(int width, int height, QImage::Format format); diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri index 0e64084cf1..9c529f55ea 100644 --- a/src/platformsupport/fontdatabases/windows/windows.pri +++ b/src/platformsupport/fontdatabases/windows/windows.pri @@ -15,9 +15,14 @@ qtConfig(freetype) { HEADERS += $$PWD/qwindowsfontdatabase_ft_p.h } -qtConfig(directwrite) { - qtConfig(directwrite2): \ +qtConfig(directwrite):qtConfig(direct2d) { + qtConfig(directwrite2) { + QMAKE_USE_PRIVATE += dwrite_2 DEFINES *= QT_USE_DIRECTWRITE2 + } else { + QMAKE_USE_PRIVATE += dwrite + } + QMAKE_USE_PRIVATE += d2d1 SOURCES += $$PWD/qwindowsfontenginedirectwrite.cpp HEADERS += $$PWD/qwindowsfontenginedirectwrite_p.h diff --git a/src/platformsupport/fontdatabases/winrt/winrt.pri b/src/platformsupport/fontdatabases/winrt/winrt.pri index 291ada220f..7617df2e7a 100644 --- a/src/platformsupport/fontdatabases/winrt/winrt.pri +++ b/src/platformsupport/fontdatabases/winrt/winrt.pri @@ -8,4 +8,6 @@ HEADERS += \ DEFINES += __WRL_NO_DEFAULT_LIB__ -LIBS += -lws2_32 -ldwrite +LIBS += -lws2_32 + +QMAKE_USE_PRIVATE += dwrite_1 diff --git a/src/platformsupport/glxconvenience/glxconvenience.pro b/src/platformsupport/glxconvenience/glxconvenience.pro index 58fa9fc479..8367dc5e31 100644 --- a/src/platformsupport/glxconvenience/glxconvenience.pro +++ b/src/platformsupport/glxconvenience/glxconvenience.pro @@ -6,7 +6,7 @@ CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII -LIBS_PRIVATE += $$QMAKE_LIBS_X11 +QMAKE_USE_PRIVATE += xlib HEADERS += qglxconvenience_p.h SOURCES += qglxconvenience.cpp diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 8d2e58b57b..6458454336 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -42,13 +42,18 @@ #include <QtCore/QByteArray> #include <QtCore/QScopedPointer> +#include <QtCore/qmetatype.h> +#include <QtCore/qtextstream.h> #include "qglxconvenience_p.h" +#include <QtCore/QLoggingCategory> #include <QtCore/QVector> #include <QtCore/QVarLengthArray> #include <GL/glxext.h> +Q_LOGGING_CATEGORY(lcGlx, "qt.glx") + enum { XFocusOut = FocusOut, XFocusIn = FocusIn, @@ -207,6 +212,7 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format const int requestedBlue = qMax(0, format.blueBufferSize()); const int requestedAlpha = qMax(0, format.alphaBufferSize()); + GLXFBConfig compatibleCandidate = nullptr; for (int i = 0; i < confcount; i++) { GLXFBConfig candidate = configs[i]; @@ -218,13 +224,27 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format } QXlibPointer<XVisualInfo> visual(glXGetVisualFromFBConfig(display, candidate)); - if (visual.isNull()) + int actualRed; + int actualGreen; + int actualBlue; + int actualAlpha; + glXGetFBConfigAttrib(display, candidate, GLX_RED_SIZE, &actualRed); + glXGetFBConfigAttrib(display, candidate, GLX_GREEN_SIZE, &actualGreen); + glXGetFBConfigAttrib(display, candidate, GLX_BLUE_SIZE, &actualBlue); + glXGetFBConfigAttrib(display, candidate, GLX_ALPHA_SIZE, &actualAlpha); + // Sometimes the visuals don't have a depth that includes the alpha channel. + actualAlpha = qMin(actualAlpha, visual->depth - actualRed - actualGreen - actualBlue); + + if (requestedRed && actualRed < requestedRed) continue; - - const int actualRed = qPopulationCount(visual->red_mask); - const int actualGreen = qPopulationCount(visual->green_mask); - const int actualBlue = qPopulationCount(visual->blue_mask); - const int actualAlpha = visual->depth - actualRed - actualGreen - actualBlue; + if (requestedGreen && actualGreen < requestedGreen) + continue; + if (requestedBlue && actualBlue < requestedBlue) + continue; + if (requestedAlpha && actualAlpha < requestedAlpha) + continue; + if (!compatibleCandidate) // Only pick up the first compatible one offered by the server + compatibleCandidate = candidate; if (requestedRed && actualRed != requestedRed) continue; @@ -237,6 +257,11 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format return candidate; } + if (compatibleCandidate) { + qCDebug(lcGlx) << "qglx_findConfig: Found non-matching but compatible FBConfig"; + return compatibleCandidate; + } + qCWarning(lcGlx, "qglx_findConfig: Failed to finding matching FBConfig (%d %d %d %d)", requestedRed, requestedGreen, requestedBlue, requestedAlpha); } while (qglx_reduceFormat(&format)); return config; @@ -352,6 +377,18 @@ void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, bool qglx_reduceFormat(QSurfaceFormat *format) { Q_ASSERT(format); + if (std::max(std::max(format->redBufferSize(), format->greenBufferSize()), format->blueBufferSize()) > 8) { + if (format->alphaBufferSize() > 2) { + // First try to match 10 10 10 2 + format->setAlphaBufferSize(2); + return true; + } + + format->setRedBufferSize(std::min(format->redBufferSize(), 8)); + format->setGreenBufferSize(std::min(format->greenBufferSize(), 8)); + format->setBlueBufferSize(std::min(format->blueBufferSize(), 8)); + return true; + } if (format->redBufferSize() > 1) { format->setRedBufferSize(1); diff --git a/src/platformsupport/input/CMakeLists.txt b/src/platformsupport/input/CMakeLists.txt index bcd96a9cdb..1ab85ce239 100644 --- a/src/platformsupport/input/CMakeLists.txt +++ b/src/platformsupport/input/CMakeLists.txt @@ -1,3 +1,5 @@ +# Generated from input.pro. + find_package(Libinput) # special case find_package(XKB) # special case find_package(Tslib) # special case @@ -15,9 +17,13 @@ add_qt_module(InputSupport Qt::CorePrivate Qt::DeviceDiscoverySupportPrivate Qt::GuiPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::DeviceDiscoverySupport + Qt::Gui ) -#### Keys ignored in scope 1:.:input.pro:<NONE>: +#### Keys ignored in scope 3:.:.:input-support.pro:<TRUE>: # CONFIG = "static" "internal_module" # MODULE = "input_support" # PRECOMPILED_HEADER = "../../corelib/global/qt_pch.h" @@ -63,7 +69,7 @@ extend_target(InputSupport CONDITION QT_FEATURE_evdev AND QT_FEATURE_mtdev extend_target(InputSupport CONDITION QT_FEATURE_tslib SOURCES tslib/qtslib.cpp tslib/qtslib_p.h - LIBRARIES + PUBLIC_LIBRARIES PkgConfig::Tslib ) @@ -80,14 +86,12 @@ extend_target(InputSupport CONDITION QT_FEATURE_libinput PkgConfig::Libudev ) -extend_target(InputSupport CONDITION QT_FEATURE_libinput AND QT_FEATURE_xkbcommon_evdev +extend_target(InputSupport CONDITION QT_FEATURE_libinput AND QT_FEATURE_xkbcommon LIBRARIES + Qt::XkbCommonSupportPrivate XKB::XKB -) - -extend_target(InputSupport CONDITION QT_FEATURE_libinput AND NOT QT_FEATURE_xkbcommon_evdev - DEFINES - QT_NO_XKBCOMMON_EVDEV + PUBLIC_LIBRARIES + Qt::XkbCommonSupport ) extend_target(InputSupport CONDITION QT_FEATURE_evdev OR QT_FEATURE_libinput @@ -101,3 +105,7 @@ extend_target(InputSupport CONDITION QT_FEATURE_integrityhid LIBRARIES integrityhid ) + +if(QT_FEATURE_xkbcommon) + add_subdirectory(xkbcommon) +endif() diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp index b21d5d9ef5..02d6586fe8 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp @@ -66,7 +66,7 @@ Q_LOGGING_CATEGORY(qLcEvdevKeyMap, "qt.qpa.input.keymap") // simple builtin US keymap #include "qevdevkeyboard_defaultmap_p.h" -void QFdContainer::reset() Q_DECL_NOTHROW +void QFdContainer::reset() noexcept { if (m_fd >= 0) qt_safe_close(m_fd); @@ -76,7 +76,7 @@ void QFdContainer::reset() Q_DECL_NOTHROW QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, QFdContainer &fd, bool disableZap, bool enableCompose, const QString &keymapFile) : m_device(device), m_fd(fd.release()), m_notify(nullptr), m_modifiers(0), m_composing(0), m_dead_unicode(0xffff), - m_no_zap(disableZap), m_do_compose(enableCompose), + m_langLock(0), m_no_zap(disableZap), m_do_compose(enableCompose), m_keymap(0), m_keymap_size(0), m_keycompose(0), m_keycompose_size(0) { qCDebug(qLcEvdevKey) << "Create keyboard handler with for device" << device; @@ -253,6 +253,8 @@ QEvdevKeyboardHandler::KeycodeAction QEvdevKeyboardHandler::processKeycode(quint quint8 testmods = m_modifiers; if (m_locks[0] /*CapsLock*/ && (m->flags & QEvdevKeyboardMap::IsLetter)) testmods ^= QEvdevKeyboardMap::ModShift; + if (m_langLock) + testmods ^= QEvdevKeyboardMap::ModAltGr; if (m->modifiers == testmods) map_withmod = m; } @@ -509,6 +511,8 @@ void QEvdevKeyboardHandler::unloadKeymap() m_locks[2] = 1; qCDebug(qLcEvdevKey, "numlock=%d , capslock=%d, scrolllock=%d", m_locks[1], m_locks[0], m_locks[2]); } + + m_langLock = 0; } bool QEvdevKeyboardHandler::loadKeymap(const QString &file) @@ -553,7 +557,7 @@ bool QEvdevKeyboardHandler::loadKeymap(const QString &file) delete [] qmap_keymap; delete [] qmap_keycompose; - qWarning("Keymap file '%s' can not be loaded.", qPrintable(file)); + qWarning("Keymap file '%s' cannot be loaded.", qPrintable(file)); return false; } @@ -570,4 +574,9 @@ bool QEvdevKeyboardHandler::loadKeymap(const QString &file) return true; } +void QEvdevKeyboardHandler::switchLang() +{ + m_langLock ^= 1; +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h index 7c64c4febb..d154c30ed5 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h @@ -132,15 +132,15 @@ inline QDataStream &operator<<(QDataStream &ds, const QEvdevKeyboardMap::Composi class QFdContainer { int m_fd; - Q_DISABLE_COPY(QFdContainer); + Q_DISABLE_COPY_MOVE(QFdContainer); public: - explicit QFdContainer(int fd = -1) Q_DECL_NOTHROW : m_fd(fd) {} + explicit QFdContainer(int fd = -1) noexcept : m_fd(fd) {} ~QFdContainer() { reset(); } - int get() const Q_DECL_NOTHROW { return m_fd; } + int get() const noexcept { return m_fd; } - int release() Q_DECL_NOTHROW { int result = m_fd; m_fd = -1; return result; } - void reset() Q_DECL_NOTHROW; + int release() noexcept { int result = m_fd; m_fd = -1; return result; } + void reset() noexcept; }; class QEvdevKeyboardHandler : public QObject @@ -192,6 +192,8 @@ public: void readKeycode(); KeycodeAction processKeycode(quint16 keycode, bool pressed, bool autorepeat); + void switchLang(); + private: void processKeyEvent(int nativecode, int unicode, int qtcode, Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat); @@ -206,6 +208,7 @@ private: quint8 m_locks[3]; int m_composing; quint16 m_dead_unicode; + quint8 m_langLock; bool m_no_zap; bool m_do_compose; diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp index 85e6a80879..e1659bc0d9 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp @@ -153,4 +153,10 @@ void QEvdevKeyboardManager::loadKeymap(const QString &file) } } +void QEvdevKeyboardManager::switchLang() +{ + foreach (QEvdevKeyboardHandler *handler, m_keyboards) + handler->switchLang(); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h index 27ea7e468e..01b7e9fc0e 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h @@ -64,10 +64,11 @@ QT_BEGIN_NAMESPACE class QEvdevKeyboardManager : public QObject { public: - QEvdevKeyboardManager(const QString &key, const QString &specification, QObject *parent = 0); + QEvdevKeyboardManager(const QString &key, const QString &specification, QObject *parent = nullptr); ~QEvdevKeyboardManager(); void loadKeymap(const QString &file); + void switchLang(); void addKeyboard(const QString &deviceNode = QString()); void removeKeyboard(const QString &deviceNode); diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h index 13a8e3dec5..c63ca29a71 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h @@ -65,7 +65,7 @@ class QDeviceDiscovery; class QEvdevMouseManager : public QObject { public: - QEvdevMouseManager(const QString &key, const QString &specification, QObject *parent = 0); + QEvdevMouseManager(const QString &key, const QString &specification, QObject *parent = nullptr); ~QEvdevMouseManager(); void handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons, diff --git a/src/platformsupport/input/evdevtablet/qevdevtablethandler_p.h b/src/platformsupport/input/evdevtablet/qevdevtablethandler_p.h index 66e821117a..b83bb21258 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtablethandler_p.h +++ b/src/platformsupport/input/evdevtablet/qevdevtablethandler_p.h @@ -64,7 +64,7 @@ class QEvdevTabletData; class QEvdevTabletHandler : public QObject { public: - explicit QEvdevTabletHandler(const QString &device, const QString &spec = QString(), QObject *parent = 0); + explicit QEvdevTabletHandler(const QString &device, const QString &spec = QString(), QObject *parent = nullptr); ~QEvdevTabletHandler(); qint64 deviceId() const; @@ -83,7 +83,7 @@ private: class QEvdevTabletHandlerThread : public QDaemonThread { public: - explicit QEvdevTabletHandlerThread(const QString &device, const QString &spec, QObject *parent = 0); + explicit QEvdevTabletHandlerThread(const QString &device, const QString &spec, QObject *parent = nullptr); ~QEvdevTabletHandlerThread(); void run() override; QEvdevTabletHandler *handler() { return m_handler; } diff --git a/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h b/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h index cde91c55aa..b598156e52 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h +++ b/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h @@ -63,7 +63,7 @@ class QEvdevTabletHandlerThread; class QEvdevTabletManager : public QObject { public: - QEvdevTabletManager(const QString &key, const QString &spec, QObject *parent = 0); + QEvdevTabletManager(const QString &key, const QString &spec, QObject *parent = nullptr); ~QEvdevTabletManager(); void addDevice(const QString &deviceNode); diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h index e524c516f1..b9b772fb3a 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h @@ -63,7 +63,7 @@ class QEvdevTouchScreenHandlerThread; class QEvdevTouchManager : public QObject { public: - QEvdevTouchManager(const QString &key, const QString &spec, QObject *parent = 0); + QEvdevTouchManager(const QString &key, const QString &spec, QObject *parent = nullptr); ~QEvdevTouchManager(); void addDevice(const QString &deviceNode); diff --git a/src/platformsupport/input/input-support.pro b/src/platformsupport/input/input-support.pro new file mode 100644 index 0000000000..3d39210b9e --- /dev/null +++ b/src/platformsupport/input/input-support.pro @@ -0,0 +1,35 @@ +TARGET = QtInputSupport +MODULE = input_support + +QT = core-private gui-private devicediscovery_support-private +CONFIG += static internal_module + +DEFINES += QT_NO_CAST_FROM_ASCII +PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h + +qtConfig(evdev) { + include($$PWD/evdevmouse/evdevmouse.pri) + include($$PWD/evdevkeyboard/evdevkeyboard.pri) + include($$PWD/evdevtouch/evdevtouch.pri) + qtConfig(tabletevent) { + include($$PWD/evdevtablet/evdevtablet.pri) + } +} + +qtConfig(tslib) { + include($$PWD/tslib/tslib.pri) +} + +qtConfig(libinput) { + include($$PWD/libinput/libinput.pri) +} + +qtConfig(evdev)|qtConfig(libinput) { + include($$PWD/shared/shared.pri) +} + +qtConfig(integrityhid) { + include($$PWD/integrityhid/integrityhid.pri) +} + +load(qt_module) diff --git a/src/platformsupport/input/input.pro b/src/platformsupport/input/input.pro index 3d39210b9e..138c04dea3 100644 --- a/src/platformsupport/input/input.pro +++ b/src/platformsupport/input/input.pro @@ -1,35 +1,8 @@ -TARGET = QtInputSupport -MODULE = input_support +TEMPLATE = subdirs +QT_FOR_CONFIG += gui-private -QT = core-private gui-private devicediscovery_support-private -CONFIG += static internal_module +qtConfig(xkbcommon): SUBDIRS += xkbcommon -DEFINES += QT_NO_CAST_FROM_ASCII -PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h +SUBDIRS += input-support.pro ### FIXME - QTBUG-52657 -qtConfig(evdev) { - include($$PWD/evdevmouse/evdevmouse.pri) - include($$PWD/evdevkeyboard/evdevkeyboard.pri) - include($$PWD/evdevtouch/evdevtouch.pri) - qtConfig(tabletevent) { - include($$PWD/evdevtablet/evdevtablet.pri) - } -} - -qtConfig(tslib) { - include($$PWD/tslib/tslib.pri) -} - -qtConfig(libinput) { - include($$PWD/libinput/libinput.pri) -} - -qtConfig(evdev)|qtConfig(libinput) { - include($$PWD/shared/shared.pri) -} - -qtConfig(integrityhid) { - include($$PWD/integrityhid/integrityhid.pri) -} - -load(qt_module) +CONFIG += ordered diff --git a/src/platformsupport/input/libinput/libinput.pri b/src/platformsupport/input/libinput/libinput.pri index f922769a37..f80b5f41d9 100644 --- a/src/platformsupport/input/libinput/libinput.pri +++ b/src/platformsupport/input/libinput/libinput.pri @@ -14,7 +14,7 @@ QMAKE_USE_PRIVATE += libudev libinput INCLUDEPATH += $$PWD/../shared -qtConfig(xkbcommon-evdev): \ - QMAKE_USE_PRIVATE += xkbcommon_evdev -else: \ - DEFINES += QT_NO_XKBCOMMON_EVDEV +qtConfig(xkbcommon): { + QMAKE_USE_PRIVATE += xkbcommon + QT += xkbcommon_support-private +} diff --git a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp index 5152725468..6586b084f1 100644 --- a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp +++ b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp @@ -44,9 +44,10 @@ #include <QtGui/private/qinputdevicemanager_p.h> #include <qpa/qwindowsysteminterface.h> #include <libinput.h> -#ifndef QT_NO_XKBCOMMON_EVDEV +#if QT_CONFIG(xkbcommon) #include <xkbcommon/xkbcommon-keysyms.h> #include <xkbcommon/xkbcommon-names.h> +#include <QtXkbCommonSupport/private/qxkbcommon_p.h> #endif QT_BEGIN_NAMESPACE @@ -56,90 +57,9 @@ Q_DECLARE_LOGGING_CATEGORY(qLcLibInput) const int REPEAT_DELAY = 500; const int REPEAT_RATE = 100; -#ifndef QT_NO_XKBCOMMON_EVDEV -struct KeyTabEntry { - int xkbkey; - int qtkey; -}; - -static inline bool operator==(const KeyTabEntry &a, const KeyTabEntry &b) -{ - return a.xkbkey == b.xkbkey; -} - -static const KeyTabEntry keyTab[] = { - { XKB_KEY_Escape, Qt::Key_Escape }, - { XKB_KEY_Tab, Qt::Key_Tab }, - { XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab }, - { XKB_KEY_BackSpace, Qt::Key_Backspace }, - { XKB_KEY_Return, Qt::Key_Return }, - { XKB_KEY_Insert, Qt::Key_Insert }, - { XKB_KEY_Delete, Qt::Key_Delete }, - { XKB_KEY_Clear, Qt::Key_Delete }, - { XKB_KEY_Pause, Qt::Key_Pause }, - { XKB_KEY_Print, Qt::Key_Print }, - - { XKB_KEY_Home, Qt::Key_Home }, - { XKB_KEY_End, Qt::Key_End }, - { XKB_KEY_Left, Qt::Key_Left }, - { XKB_KEY_Up, Qt::Key_Up }, - { XKB_KEY_Right, Qt::Key_Right }, - { XKB_KEY_Down, Qt::Key_Down }, - { XKB_KEY_Prior, Qt::Key_PageUp }, - { XKB_KEY_Next, Qt::Key_PageDown }, - - { XKB_KEY_Shift_L, Qt::Key_Shift }, - { XKB_KEY_Shift_R, Qt::Key_Shift }, - { XKB_KEY_Shift_Lock, Qt::Key_Shift }, - { XKB_KEY_Control_L, Qt::Key_Control }, - { XKB_KEY_Control_R, Qt::Key_Control }, - { XKB_KEY_Meta_L, Qt::Key_Meta }, - { XKB_KEY_Meta_R, Qt::Key_Meta }, - { XKB_KEY_Alt_L, Qt::Key_Alt }, - { XKB_KEY_Alt_R, Qt::Key_Alt }, - { XKB_KEY_Caps_Lock, Qt::Key_CapsLock }, - { XKB_KEY_Num_Lock, Qt::Key_NumLock }, - { XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock }, - { XKB_KEY_Super_L, Qt::Key_Super_L }, - { XKB_KEY_Super_R, Qt::Key_Super_R }, - { XKB_KEY_Menu, Qt::Key_Menu }, - { XKB_KEY_Hyper_L, Qt::Key_Hyper_L }, - { XKB_KEY_Hyper_R, Qt::Key_Hyper_R }, - { XKB_KEY_Help, Qt::Key_Help }, - - { XKB_KEY_KP_Space, Qt::Key_Space }, - { XKB_KEY_KP_Tab, Qt::Key_Tab }, - { XKB_KEY_KP_Enter, Qt::Key_Enter }, - { XKB_KEY_KP_Home, Qt::Key_Home }, - { XKB_KEY_KP_Left, Qt::Key_Left }, - { XKB_KEY_KP_Up, Qt::Key_Up }, - { XKB_KEY_KP_Right, Qt::Key_Right }, - { XKB_KEY_KP_Down, Qt::Key_Down }, - { XKB_KEY_KP_Prior, Qt::Key_PageUp }, - { XKB_KEY_KP_Next, Qt::Key_PageDown }, - { XKB_KEY_KP_End, Qt::Key_End }, - { XKB_KEY_KP_Begin, Qt::Key_Clear }, - { XKB_KEY_KP_Insert, Qt::Key_Insert }, - { XKB_KEY_KP_Delete, Qt::Key_Delete }, - { XKB_KEY_KP_Equal, Qt::Key_Equal }, - { XKB_KEY_KP_Multiply, Qt::Key_Asterisk }, - { XKB_KEY_KP_Add, Qt::Key_Plus }, - { XKB_KEY_KP_Separator, Qt::Key_Comma }, - { XKB_KEY_KP_Subtract, Qt::Key_Minus }, - { XKB_KEY_KP_Decimal, Qt::Key_Period }, - { XKB_KEY_KP_Divide, Qt::Key_Slash }, -}; -#endif - QLibInputKeyboard::QLibInputKeyboard() -#ifndef QT_NO_XKBCOMMON_EVDEV - : m_ctx(0), - m_keymap(0), - m_state(0), - m_mods(Qt::NoModifier) -#endif { -#ifndef QT_NO_XKBCOMMON_EVDEV +#if QT_CONFIG(xkbcommon) qCDebug(qLcLibInput) << "Using xkbcommon for key mapping"; m_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!m_ctx) { @@ -148,29 +68,25 @@ QLibInputKeyboard::QLibInputKeyboard() } m_keymap = xkb_keymap_new_from_names(m_ctx, nullptr, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!m_keymap) { - qWarning("Failed to compile keymap"); + qCWarning(qLcLibInput, "Failed to compile keymap"); return; } m_state = xkb_state_new(m_keymap); if (!m_state) { - qWarning("Failed to create xkb state"); + qCWarning(qLcLibInput, "Failed to create xkb state"); return; } - m_modindex[0] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CTRL); - m_modindex[1] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_ALT); - m_modindex[2] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_SHIFT); - m_modindex[3] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_LOGO); m_repeatTimer.setSingleShot(true); connect(&m_repeatTimer, &QTimer::timeout, this, &QLibInputKeyboard::handleRepeat); #else - qCWarning(qLcLibInput) << "X-less xkbcommon not available, not performing key mapping"; + qCWarning(qLcLibInput) << "xkbcommon not available, not performing key mapping"; #endif } QLibInputKeyboard::~QLibInputKeyboard() { -#ifndef QT_NO_XKBCOMMON_EVDEV +#if QT_CONFIG(xkbcommon) if (m_state) xkb_state_unref(m_state); if (m_keymap) @@ -182,56 +98,37 @@ QLibInputKeyboard::~QLibInputKeyboard() void QLibInputKeyboard::processKey(libinput_event_keyboard *e) { -#ifndef QT_NO_XKBCOMMON_EVDEV +#if QT_CONFIG(xkbcommon) if (!m_ctx || !m_keymap || !m_state) return; - const uint32_t k = libinput_event_keyboard_get_key(e) + 8; + const uint32_t keycode = libinput_event_keyboard_get_key(e) + 8; + const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, keycode); const bool pressed = libinput_event_keyboard_get_key_state(e) == LIBINPUT_KEY_STATE_PRESSED; - QVarLengthArray<char, 32> chars(32); - const int size = xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size()); - if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL - chars.resize(size + 1); - xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size()); - } - const QString text = QString::fromUtf8(chars.constData(), size); - - const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, k); + // Modifiers here is the modifier state before the event, i.e. not + // including the current key in case it is a modifier. See the XOR + // logic in QKeyEvent::modifiers(). ### QTBUG-73826 + Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(m_state); - // mods here is the modifier state before the event, i.e. not - // including the current key in case it is a modifier. - Qt::KeyboardModifiers mods = Qt::NoModifier; - const int qtkey = keysymToQtKey(sym, &mods, text); + const QString text = QXkbCommon::lookupString(m_state, keycode); + const int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, m_state, keycode); - if (qtkey == Qt::Key_Control) - mods |= Qt::ControlModifier; - if (qtkey == Qt::Key_Alt) - mods |= Qt::AltModifier; - if (qtkey == Qt::Key_Shift) - mods |= Qt::ShiftModifier; - if (qtkey == Qt::Key_Meta) - mods |= Qt::MetaModifier; - xkb_state_update_key(m_state, k, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); + xkb_state_update_key(m_state, keycode, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); - if (mods != Qt::NoModifier) { - if (pressed) - m_mods |= mods; - else - m_mods &= ~mods; + Qt::KeyboardModifiers modifiersAfterStateChange = QXkbCommon::modifiers(m_state); + QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiersAfterStateChange); - QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(m_mods); - } QWindowSystemInterface::handleExtendedKeyEvent(nullptr, pressed ? QEvent::KeyPress : QEvent::KeyRelease, - qtkey, m_mods, k, sym, m_mods, text); + qtkey, modifiers, keycode, sym, modifiers, text); - if (pressed && xkb_keymap_key_repeats(m_keymap, k)) { + if (pressed && xkb_keymap_key_repeats(m_keymap, keycode)) { m_repeatData.qtkey = qtkey; - m_repeatData.mods = mods; - m_repeatData.nativeScanCode = k; + m_repeatData.mods = modifiers; + m_repeatData.nativeScanCode = keycode; m_repeatData.virtualKey = sym; - m_repeatData.nativeMods = mods; + m_repeatData.nativeMods = modifiers; m_repeatData.unicodeText = text; m_repeatData.repeatCount = 1; m_repeatTimer.setInterval(REPEAT_DELAY); @@ -245,7 +142,7 @@ void QLibInputKeyboard::processKey(libinput_event_keyboard *e) #endif } -#ifndef QT_NO_XKBCOMMON_EVDEV +#if QT_CONFIG(xkbcommon) void QLibInputKeyboard::handleRepeat() { QWindowSystemInterface::handleExtendedKeyEvent(nullptr, QEvent::KeyPress, @@ -256,50 +153,6 @@ void QLibInputKeyboard::handleRepeat() m_repeatTimer.setInterval(REPEAT_RATE); m_repeatTimer.start(); } - -int QLibInputKeyboard::keysymToQtKey(xkb_keysym_t key) const -{ - const size_t elemCount = sizeof(keyTab) / sizeof(KeyTabEntry); - KeyTabEntry e; - e.xkbkey = key; - const KeyTabEntry *result = std::find(keyTab, keyTab + elemCount, e); - return result != keyTab + elemCount ? result->qtkey : 0; -} - -int QLibInputKeyboard::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers *modifiers, const QString &text) const -{ - int code = 0; -#ifndef QT_NO_TEXTCODEC - QTextCodec *systemCodec = QTextCodec::codecForLocale(); -#endif - if (keysym < 128 || (keysym < 256 -#ifndef QT_NO_TEXTCODEC - && systemCodec->mibEnum() == 4 -#endif - )) { - // upper-case key, if known - code = isprint((int)keysym) ? toupper((int)keysym) : 0; - } else if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) { - // function keys - code = Qt::Key_F1 + ((int)keysym - XKB_KEY_F1); - } else if (keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_9) { - if (keysym >= XKB_KEY_KP_0) { - // numeric keypad keys - code = Qt::Key_0 + ((int)keysym - XKB_KEY_KP_0); - } else { - code = keysymToQtKey(keysym); - } - *modifiers |= Qt::KeypadModifier; - } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f - && text.unicode()->unicode() != 0x7f - && !(keysym >= XKB_KEY_dead_grave && keysym <= XKB_KEY_dead_longsolidusoverlay)) { - code = text.unicode()->toUpper().unicode(); - } else { - // any other keys - code = keysymToQtKey(keysym); - } - return code; -} #endif QT_END_NAMESPACE diff --git a/src/platformsupport/input/libinput/qlibinputkeyboard_p.h b/src/platformsupport/input/libinput/qlibinputkeyboard_p.h index 9e09bccd79..7521902e02 100644 --- a/src/platformsupport/input/libinput/qlibinputkeyboard_p.h +++ b/src/platformsupport/input/libinput/qlibinputkeyboard_p.h @@ -43,7 +43,9 @@ #include <QtCore/QPoint> #include <QtCore/QTimer> -#ifndef QT_NO_XKBCOMMON_EVDEV +#include <QtGui/private/qtguiglobal_p.h> + +#if QT_CONFIG(xkbcommon) #include <xkbcommon/xkbcommon.h> #endif @@ -70,17 +72,16 @@ public: void processKey(libinput_event_keyboard *e); -#ifndef QT_NO_XKBCOMMON_EVDEV +#if QT_CONFIG(xkbcommon) void handleRepeat(); private: int keysymToQtKey(xkb_keysym_t key) const; int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers *modifiers, const QString &text) const; - xkb_context *m_ctx; - xkb_keymap *m_keymap; - xkb_state *m_state; - xkb_mod_index_t m_modindex[4]; + xkb_context *m_ctx = nullptr; + xkb_keymap *m_keymap = nullptr; + xkb_state *m_state = nullptr; QTimer m_repeatTimer; @@ -93,7 +94,6 @@ private: QString unicodeText; int repeatCount; } m_repeatData; - Qt::KeyboardModifiers m_mods; #endif }; diff --git a/src/platformsupport/input/libinput/qlibinputtouch_p.h b/src/platformsupport/input/libinput/qlibinputtouch_p.h index 6f88001d19..51304e6a21 100644 --- a/src/platformsupport/input/libinput/qlibinputtouch_p.h +++ b/src/platformsupport/input/libinput/qlibinputtouch_p.h @@ -73,7 +73,7 @@ public: private: struct DeviceState { - DeviceState() : m_touchDevice(0) { } + DeviceState() : m_touchDevice(nullptr) { } QWindowSystemInterface::TouchPoint *point(int32_t slot); QList<QWindowSystemInterface::TouchPoint> m_points; QTouchDevice *m_touchDevice; diff --git a/src/platformsupport/input/tslib/qtslib.cpp b/src/platformsupport/input/tslib/qtslib.cpp index 75ac3c50e0..f8fdc151ec 100644 --- a/src/platformsupport/input/tslib/qtslib.cpp +++ b/src/platformsupport/input/tslib/qtslib.cpp @@ -57,7 +57,7 @@ QTsLibMouseHandler::QTsLibMouseHandler(const QString &key, const QString &specification, QObject *parent) : QObject(parent), - m_notify(0), m_x(0), m_y(0), m_pressed(0), m_rawMode(false) + m_rawMode(!key.compare(QLatin1String("TslibRaw"), Qt::CaseInsensitive)) { qCDebug(qLcTsLib) << "Initializing tslib plugin" << key << specification; setObjectName(QLatin1String("TSLib Mouse Handler")); @@ -79,13 +79,11 @@ QTsLibMouseHandler::QTsLibMouseHandler(const QString &key, if (ts_config(m_dev)) qErrnoWarning(errno, "ts_config() failed"); - m_rawMode = !key.compare(QLatin1String("TslibRaw"), Qt::CaseInsensitive); - int fd = ts_fd(m_dev); if (fd >= 0) { qCDebug(qLcTsLib) << "tslib device is" << device; m_notify = new QSocketNotifier(fd, QSocketNotifier::Read, this); - connect(m_notify, SIGNAL(activated(int)), this, SLOT(readMouseData())); + connect(m_notify, &QSocketNotifier::activated, this, &QTsLibMouseHandler::readMouseData); } else { qErrnoWarning(errno, "tslib: Cannot open input device %s", device.constData()); } @@ -129,7 +127,9 @@ void QTsLibMouseHandler::readMouseData() } QPoint pos(x, y); - QWindowSystemInterface::handleMouseEvent(0, pos, pos, pressed ? Qt::LeftButton : Qt::NoButton); + QWindowSystemInterface::handleMouseEvent(nullptr, pos, pos, + pressed ? Qt::LeftButton : Qt::NoButton, + Qt::NoButton, QEvent::None); m_x = x; m_y = y; diff --git a/src/platformsupport/input/tslib/qtslib_p.h b/src/platformsupport/input/tslib/qtslib_p.h index 0c08fb6a3d..ffd60cd0e3 100644 --- a/src/platformsupport/input/tslib/qtslib_p.h +++ b/src/platformsupport/input/tslib/qtslib_p.h @@ -71,11 +71,12 @@ private slots: void readMouseData(); private: - QSocketNotifier * m_notify; + QSocketNotifier * m_notify = nullptr; tsdev *m_dev; - int m_x, m_y; - bool m_pressed; - bool m_rawMode; + int m_x = 0; + int m_y = 0; + bool m_pressed = false; + const bool m_rawMode; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/xkbcommon/CMakeLists.txt b/src/platformsupport/input/xkbcommon/CMakeLists.txt new file mode 100644 index 0000000000..2797966fc4 --- /dev/null +++ b/src/platformsupport/input/xkbcommon/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from xkbcommon.pro. + +##################################################################### +## XkbCommonSupport Module: +##################################################################### + +add_qt_module(XkbCommonSupport + STATIC + SOURCES + qxkbcommon.cpp qxkbcommon_p.h + qxkbcommon_3rdparty.cpp + DEFINES + QT_NO_CAST_FROM_ASCII + LIBRARIES + Qt::CorePrivate + Qt::GuiPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + XKB::XKB +) + +#### Keys ignored in scope 1:.:.:xkbcommon.pro:<TRUE>: +# CONFIG = "static" "internal_module" +# MODULE = "xkbcommon_support" +# PRECOMPILED_HEADER = "../../../corelib/global/qt_pch.h" +# _LOADED = "qt_module" + +## Scopes: +##################################################################### + +extend_target(XkbCommonSupport CONDITION CLANG AND NOT ICC + COMPILE_OPTIONS + "-ftemplate-depth=1024" +) diff --git a/src/platformsupport/input/xkbcommon/qxkbcommon.cpp b/src/platformsupport/input/xkbcommon/qxkbcommon.cpp new file mode 100644 index 0000000000..877c5d848f --- /dev/null +++ b/src/platformsupport/input/xkbcommon/qxkbcommon.cpp @@ -0,0 +1,828 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxkbcommon_p.h" + +#include <private/qmakearray_p.h> + +#include <QtCore/QMetaMethod> +#include <QtGui/QKeyEvent> +#include <QtGui/private/qguiapplication_p.h> + +#include <qpa/qplatforminputcontext.h> +#include <qpa/qplatformintegration.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcXkbcommon, "qt.xkbcommon") + +static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers, + xkb_state *state, xkb_keycode_t code, + bool superAsMeta, bool hyperAsMeta); + +typedef struct xkb2qt +{ + unsigned int xkb; + unsigned int qt; + + constexpr bool operator <=(const xkb2qt &that) const noexcept + { + return xkb <= that.xkb; + } + + constexpr bool operator <(const xkb2qt &that) const noexcept + { + return xkb < that.xkb; + } +} xkb2qt_t; + +template<std::size_t Xkb, std::size_t Qt> +struct Xkb2Qt +{ + using Type = xkb2qt_t; + static constexpr Type data() noexcept { return Type{Xkb, Qt}; } +}; + +static constexpr const auto KeyTbl = qMakeArray( + QSortedData< + // misc keys + + Xkb2Qt<XKB_KEY_Escape, Qt::Key_Escape>, + Xkb2Qt<XKB_KEY_Tab, Qt::Key_Tab>, + Xkb2Qt<XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab>, + Xkb2Qt<XKB_KEY_BackSpace, Qt::Key_Backspace>, + Xkb2Qt<XKB_KEY_Return, Qt::Key_Return>, + Xkb2Qt<XKB_KEY_Insert, Qt::Key_Insert>, + Xkb2Qt<XKB_KEY_Delete, Qt::Key_Delete>, + Xkb2Qt<XKB_KEY_Clear, Qt::Key_Delete>, + Xkb2Qt<XKB_KEY_Pause, Qt::Key_Pause>, + Xkb2Qt<XKB_KEY_Print, Qt::Key_Print>, + Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq + Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq + + // cursor movement + + Xkb2Qt<XKB_KEY_Home, Qt::Key_Home>, + Xkb2Qt<XKB_KEY_End, Qt::Key_End>, + Xkb2Qt<XKB_KEY_Left, Qt::Key_Left>, + Xkb2Qt<XKB_KEY_Up, Qt::Key_Up>, + Xkb2Qt<XKB_KEY_Right, Qt::Key_Right>, + Xkb2Qt<XKB_KEY_Down, Qt::Key_Down>, + Xkb2Qt<XKB_KEY_Prior, Qt::Key_PageUp>, + Xkb2Qt<XKB_KEY_Next, Qt::Key_PageDown>, + + // modifiers + + Xkb2Qt<XKB_KEY_Shift_L, Qt::Key_Shift>, + Xkb2Qt<XKB_KEY_Shift_R, Qt::Key_Shift>, + Xkb2Qt<XKB_KEY_Shift_Lock, Qt::Key_Shift>, + Xkb2Qt<XKB_KEY_Control_L, Qt::Key_Control>, + Xkb2Qt<XKB_KEY_Control_R, Qt::Key_Control>, + Xkb2Qt<XKB_KEY_Meta_L, Qt::Key_Meta>, + Xkb2Qt<XKB_KEY_Meta_R, Qt::Key_Meta>, + Xkb2Qt<XKB_KEY_Alt_L, Qt::Key_Alt>, + Xkb2Qt<XKB_KEY_Alt_R, Qt::Key_Alt>, + Xkb2Qt<XKB_KEY_Caps_Lock, Qt::Key_CapsLock>, + Xkb2Qt<XKB_KEY_Num_Lock, Qt::Key_NumLock>, + Xkb2Qt<XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock>, + Xkb2Qt<XKB_KEY_Super_L, Qt::Key_Super_L>, + Xkb2Qt<XKB_KEY_Super_R, Qt::Key_Super_R>, + Xkb2Qt<XKB_KEY_Menu, Qt::Key_Menu>, + Xkb2Qt<XKB_KEY_Hyper_L, Qt::Key_Hyper_L>, + Xkb2Qt<XKB_KEY_Hyper_R, Qt::Key_Hyper_R>, + Xkb2Qt<XKB_KEY_Help, Qt::Key_Help>, + Xkb2Qt<0x1000FF74, Qt::Key_Backtab>, // hardcoded HP backtab + Xkb2Qt<0x1005FF10, Qt::Key_F11>, // hardcoded Sun F36 (labeled F11) + Xkb2Qt<0x1005FF11, Qt::Key_F12>, // hardcoded Sun F37 (labeled F12) + + // numeric and function keypad keys + + Xkb2Qt<XKB_KEY_KP_Space, Qt::Key_Space>, + Xkb2Qt<XKB_KEY_KP_Tab, Qt::Key_Tab>, + Xkb2Qt<XKB_KEY_KP_Enter, Qt::Key_Enter>, + Xkb2Qt<XKB_KEY_KP_Home, Qt::Key_Home>, + Xkb2Qt<XKB_KEY_KP_Left, Qt::Key_Left>, + Xkb2Qt<XKB_KEY_KP_Up, Qt::Key_Up>, + Xkb2Qt<XKB_KEY_KP_Right, Qt::Key_Right>, + Xkb2Qt<XKB_KEY_KP_Down, Qt::Key_Down>, + Xkb2Qt<XKB_KEY_KP_Prior, Qt::Key_PageUp>, + Xkb2Qt<XKB_KEY_KP_Next, Qt::Key_PageDown>, + Xkb2Qt<XKB_KEY_KP_End, Qt::Key_End>, + Xkb2Qt<XKB_KEY_KP_Begin, Qt::Key_Clear>, + Xkb2Qt<XKB_KEY_KP_Insert, Qt::Key_Insert>, + Xkb2Qt<XKB_KEY_KP_Delete, Qt::Key_Delete>, + Xkb2Qt<XKB_KEY_KP_Equal, Qt::Key_Equal>, + Xkb2Qt<XKB_KEY_KP_Multiply, Qt::Key_Asterisk>, + Xkb2Qt<XKB_KEY_KP_Add, Qt::Key_Plus>, + Xkb2Qt<XKB_KEY_KP_Separator, Qt::Key_Comma>, + Xkb2Qt<XKB_KEY_KP_Subtract, Qt::Key_Minus>, + Xkb2Qt<XKB_KEY_KP_Decimal, Qt::Key_Period>, + Xkb2Qt<XKB_KEY_KP_Divide, Qt::Key_Slash>, + + // special non-XF86 function keys + + Xkb2Qt<XKB_KEY_Undo, Qt::Key_Undo>, + Xkb2Qt<XKB_KEY_Redo, Qt::Key_Redo>, + Xkb2Qt<XKB_KEY_Find, Qt::Key_Find>, + Xkb2Qt<XKB_KEY_Cancel, Qt::Key_Cancel>, + + // International input method support keys + + // International & multi-key character composition + Xkb2Qt<XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr>, + Xkb2Qt<XKB_KEY_Multi_key, Qt::Key_Multi_key>, + Xkb2Qt<XKB_KEY_Codeinput, Qt::Key_Codeinput>, + Xkb2Qt<XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate>, + Xkb2Qt<XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate>, + Xkb2Qt<XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate>, + + // Misc Functions + Xkb2Qt<XKB_KEY_Mode_switch, Qt::Key_Mode_switch>, + Xkb2Qt<XKB_KEY_script_switch, Qt::Key_Mode_switch>, + + // Japanese keyboard support + Xkb2Qt<XKB_KEY_Kanji, Qt::Key_Kanji>, + Xkb2Qt<XKB_KEY_Muhenkan, Qt::Key_Muhenkan>, + //Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode>, + Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan>, + Xkb2Qt<XKB_KEY_Henkan, Qt::Key_Henkan>, + Xkb2Qt<XKB_KEY_Romaji, Qt::Key_Romaji>, + Xkb2Qt<XKB_KEY_Hiragana, Qt::Key_Hiragana>, + Xkb2Qt<XKB_KEY_Katakana, Qt::Key_Katakana>, + Xkb2Qt<XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana>, + Xkb2Qt<XKB_KEY_Zenkaku, Qt::Key_Zenkaku>, + Xkb2Qt<XKB_KEY_Hankaku, Qt::Key_Hankaku>, + Xkb2Qt<XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku>, + Xkb2Qt<XKB_KEY_Touroku, Qt::Key_Touroku>, + Xkb2Qt<XKB_KEY_Massyo, Qt::Key_Massyo>, + Xkb2Qt<XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock>, + Xkb2Qt<XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift>, + Xkb2Qt<XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift>, + Xkb2Qt<XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle>, + //Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou>, + //Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho>, + //Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho>, + Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput>, + Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate>, + Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate>, + + // Korean keyboard support + Xkb2Qt<XKB_KEY_Hangul, Qt::Key_Hangul>, + Xkb2Qt<XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start>, + Xkb2Qt<XKB_KEY_Hangul_End, Qt::Key_Hangul_End>, + Xkb2Qt<XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja>, + Xkb2Qt<XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo>, + Xkb2Qt<XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja>, + //Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput>, + Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput>, + Xkb2Qt<XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja>, + Xkb2Qt<XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja>, + Xkb2Qt<XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja>, + Xkb2Qt<XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja>, + //Xkb2Qt<XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate>, + //Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate>, + //Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate>, + Xkb2Qt<XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate>, + Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate>, + Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate>, + Xkb2Qt<XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special>, + //Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch>, + Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Mode_switch>, + + // dead keys + Xkb2Qt<XKB_KEY_dead_grave, Qt::Key_Dead_Grave>, + Xkb2Qt<XKB_KEY_dead_acute, Qt::Key_Dead_Acute>, + Xkb2Qt<XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex>, + Xkb2Qt<XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde>, + Xkb2Qt<XKB_KEY_dead_macron, Qt::Key_Dead_Macron>, + Xkb2Qt<XKB_KEY_dead_breve, Qt::Key_Dead_Breve>, + Xkb2Qt<XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot>, + Xkb2Qt<XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis>, + Xkb2Qt<XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering>, + Xkb2Qt<XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute>, + Xkb2Qt<XKB_KEY_dead_caron, Qt::Key_Dead_Caron>, + Xkb2Qt<XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla>, + Xkb2Qt<XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek>, + Xkb2Qt<XKB_KEY_dead_iota, Qt::Key_Dead_Iota>, + Xkb2Qt<XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound>, + Xkb2Qt<XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound>, + Xkb2Qt<XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot>, + Xkb2Qt<XKB_KEY_dead_hook, Qt::Key_Dead_Hook>, + Xkb2Qt<XKB_KEY_dead_horn, Qt::Key_Dead_Horn>, + Xkb2Qt<XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke>, + Xkb2Qt<XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma>, + Xkb2Qt<XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma>, + Xkb2Qt<XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave>, + Xkb2Qt<XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring>, + Xkb2Qt<XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron>, + Xkb2Qt<XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex>, + Xkb2Qt<XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde>, + Xkb2Qt<XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve>, + Xkb2Qt<XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis>, + Xkb2Qt<XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve>, + Xkb2Qt<XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma>, + Xkb2Qt<XKB_KEY_dead_currency, Qt::Key_Dead_Currency>, + Xkb2Qt<XKB_KEY_dead_a, Qt::Key_Dead_a>, + Xkb2Qt<XKB_KEY_dead_A, Qt::Key_Dead_A>, + Xkb2Qt<XKB_KEY_dead_e, Qt::Key_Dead_e>, + Xkb2Qt<XKB_KEY_dead_E, Qt::Key_Dead_E>, + Xkb2Qt<XKB_KEY_dead_i, Qt::Key_Dead_i>, + Xkb2Qt<XKB_KEY_dead_I, Qt::Key_Dead_I>, + Xkb2Qt<XKB_KEY_dead_o, Qt::Key_Dead_o>, + Xkb2Qt<XKB_KEY_dead_O, Qt::Key_Dead_O>, + Xkb2Qt<XKB_KEY_dead_u, Qt::Key_Dead_u>, + Xkb2Qt<XKB_KEY_dead_U, Qt::Key_Dead_U>, + Xkb2Qt<XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa>, + Xkb2Qt<XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa>, + Xkb2Qt<XKB_KEY_dead_greek, Qt::Key_Dead_Greek>, + Xkb2Qt<XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline>, + Xkb2Qt<XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline>, + Xkb2Qt<XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline>, + Xkb2Qt<XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay>, + + // Special keys from X.org - This include multimedia keys, + // wireless/bluetooth/uwb keys, special launcher keys, etc. + Xkb2Qt<XKB_KEY_XF86Back, Qt::Key_Back>, + Xkb2Qt<XKB_KEY_XF86Forward, Qt::Key_Forward>, + Xkb2Qt<XKB_KEY_XF86Stop, Qt::Key_Stop>, + Xkb2Qt<XKB_KEY_XF86Refresh, Qt::Key_Refresh>, + Xkb2Qt<XKB_KEY_XF86Favorites, Qt::Key_Favorites>, + Xkb2Qt<XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia>, + Xkb2Qt<XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl>, + Xkb2Qt<XKB_KEY_XF86HomePage, Qt::Key_HomePage>, + Xkb2Qt<XKB_KEY_XF86Search, Qt::Key_Search>, + Xkb2Qt<XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown>, + Xkb2Qt<XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute>, + Xkb2Qt<XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp>, + Xkb2Qt<XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay>, + Xkb2Qt<XKB_KEY_XF86AudioStop, Qt::Key_MediaStop>, + Xkb2Qt<XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious>, + Xkb2Qt<XKB_KEY_XF86AudioNext, Qt::Key_MediaNext>, + Xkb2Qt<XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord>, + Xkb2Qt<XKB_KEY_XF86AudioPause, Qt::Key_MediaPause>, + Xkb2Qt<XKB_KEY_XF86Mail, Qt::Key_LaunchMail>, + Xkb2Qt<XKB_KEY_XF86MyComputer, Qt::Key_Launch0>, // ### Qt 6: remap properly + Xkb2Qt<XKB_KEY_XF86Calculator, Qt::Key_Launch1>, + Xkb2Qt<XKB_KEY_XF86Memo, Qt::Key_Memo>, + Xkb2Qt<XKB_KEY_XF86ToDoList, Qt::Key_ToDoList>, + Xkb2Qt<XKB_KEY_XF86Calendar, Qt::Key_Calendar>, + Xkb2Qt<XKB_KEY_XF86PowerDown, Qt::Key_PowerDown>, + Xkb2Qt<XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust>, + Xkb2Qt<XKB_KEY_XF86Standby, Qt::Key_Standby>, + Xkb2Qt<XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp>, + Xkb2Qt<XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown>, + Xkb2Qt<XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff>, + Xkb2Qt<XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp>, + Xkb2Qt<XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown>, + Xkb2Qt<XKB_KEY_XF86PowerOff, Qt::Key_PowerOff>, + Xkb2Qt<XKB_KEY_XF86WakeUp, Qt::Key_WakeUp>, + Xkb2Qt<XKB_KEY_XF86Eject, Qt::Key_Eject>, + Xkb2Qt<XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver>, + Xkb2Qt<XKB_KEY_XF86WWW, Qt::Key_WWW>, + Xkb2Qt<XKB_KEY_XF86Sleep, Qt::Key_Sleep>, + Xkb2Qt<XKB_KEY_XF86LightBulb, Qt::Key_LightBulb>, + Xkb2Qt<XKB_KEY_XF86Shop, Qt::Key_Shop>, + Xkb2Qt<XKB_KEY_XF86History, Qt::Key_History>, + Xkb2Qt<XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite>, + Xkb2Qt<XKB_KEY_XF86HotLinks, Qt::Key_HotLinks>, + Xkb2Qt<XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust>, + Xkb2Qt<XKB_KEY_XF86Finance, Qt::Key_Finance>, + Xkb2Qt<XKB_KEY_XF86Community, Qt::Key_Community>, + Xkb2Qt<XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind>, + Xkb2Qt<XKB_KEY_XF86BackForward, Qt::Key_BackForward>, + Xkb2Qt<XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft>, + Xkb2Qt<XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight>, + Xkb2Qt<XKB_KEY_XF86Book, Qt::Key_Book>, + Xkb2Qt<XKB_KEY_XF86CD, Qt::Key_CD>, + Xkb2Qt<XKB_KEY_XF86Calculater, Qt::Key_Calculator>, + Xkb2Qt<XKB_KEY_XF86Clear, Qt::Key_Clear>, + Xkb2Qt<XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab>, + Xkb2Qt<XKB_KEY_XF86Close, Qt::Key_Close>, + Xkb2Qt<XKB_KEY_XF86Copy, Qt::Key_Copy>, + Xkb2Qt<XKB_KEY_XF86Cut, Qt::Key_Cut>, + Xkb2Qt<XKB_KEY_XF86Display, Qt::Key_Display>, + Xkb2Qt<XKB_KEY_XF86DOS, Qt::Key_DOS>, + Xkb2Qt<XKB_KEY_XF86Documents, Qt::Key_Documents>, + Xkb2Qt<XKB_KEY_XF86Excel, Qt::Key_Excel>, + Xkb2Qt<XKB_KEY_XF86Explorer, Qt::Key_Explorer>, + Xkb2Qt<XKB_KEY_XF86Game, Qt::Key_Game>, + Xkb2Qt<XKB_KEY_XF86Go, Qt::Key_Go>, + Xkb2Qt<XKB_KEY_XF86iTouch, Qt::Key_iTouch>, + Xkb2Qt<XKB_KEY_XF86LogOff, Qt::Key_LogOff>, + Xkb2Qt<XKB_KEY_XF86Market, Qt::Key_Market>, + Xkb2Qt<XKB_KEY_XF86Meeting, Qt::Key_Meeting>, + Xkb2Qt<XKB_KEY_XF86MenuKB, Qt::Key_MenuKB>, + Xkb2Qt<XKB_KEY_XF86MenuPB, Qt::Key_MenuPB>, + Xkb2Qt<XKB_KEY_XF86MySites, Qt::Key_MySites>, + Xkb2Qt<XKB_KEY_XF86New, Qt::Key_New>, + Xkb2Qt<XKB_KEY_XF86News, Qt::Key_News>, + Xkb2Qt<XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome>, + Xkb2Qt<XKB_KEY_XF86Open, Qt::Key_Open>, + Xkb2Qt<XKB_KEY_XF86Option, Qt::Key_Option>, + Xkb2Qt<XKB_KEY_XF86Paste, Qt::Key_Paste>, + Xkb2Qt<XKB_KEY_XF86Phone, Qt::Key_Phone>, + Xkb2Qt<XKB_KEY_XF86Reply, Qt::Key_Reply>, + Xkb2Qt<XKB_KEY_XF86Reload, Qt::Key_Reload>, + Xkb2Qt<XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows>, + Xkb2Qt<XKB_KEY_XF86RotationPB, Qt::Key_RotationPB>, + Xkb2Qt<XKB_KEY_XF86RotationKB, Qt::Key_RotationKB>, + Xkb2Qt<XKB_KEY_XF86Save, Qt::Key_Save>, + Xkb2Qt<XKB_KEY_XF86Send, Qt::Key_Send>, + Xkb2Qt<XKB_KEY_XF86Spell, Qt::Key_Spell>, + Xkb2Qt<XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen>, + Xkb2Qt<XKB_KEY_XF86Support, Qt::Key_Support>, + Xkb2Qt<XKB_KEY_XF86TaskPane, Qt::Key_TaskPane>, + Xkb2Qt<XKB_KEY_XF86Terminal, Qt::Key_Terminal>, + Xkb2Qt<XKB_KEY_XF86Tools, Qt::Key_Tools>, + Xkb2Qt<XKB_KEY_XF86Travel, Qt::Key_Travel>, + Xkb2Qt<XKB_KEY_XF86Video, Qt::Key_Video>, + Xkb2Qt<XKB_KEY_XF86Word, Qt::Key_Word>, + Xkb2Qt<XKB_KEY_XF86Xfer, Qt::Key_Xfer>, + Xkb2Qt<XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn>, + Xkb2Qt<XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut>, + Xkb2Qt<XKB_KEY_XF86Away, Qt::Key_Away>, + Xkb2Qt<XKB_KEY_XF86Messenger, Qt::Key_Messenger>, + Xkb2Qt<XKB_KEY_XF86WebCam, Qt::Key_WebCam>, + Xkb2Qt<XKB_KEY_XF86MailForward, Qt::Key_MailForward>, + Xkb2Qt<XKB_KEY_XF86Pictures, Qt::Key_Pictures>, + Xkb2Qt<XKB_KEY_XF86Music, Qt::Key_Music>, + Xkb2Qt<XKB_KEY_XF86Battery, Qt::Key_Battery>, + Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>, + Xkb2Qt<XKB_KEY_XF86WLAN, Qt::Key_WLAN>, + Xkb2Qt<XKB_KEY_XF86UWB, Qt::Key_UWB>, + Xkb2Qt<XKB_KEY_XF86AudioForward, Qt::Key_AudioForward>, + Xkb2Qt<XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat>, + Xkb2Qt<XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay>, + Xkb2Qt<XKB_KEY_XF86Subtitle, Qt::Key_Subtitle>, + Xkb2Qt<XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack>, + Xkb2Qt<XKB_KEY_XF86Time, Qt::Key_Time>, + Xkb2Qt<XKB_KEY_XF86Select, Qt::Key_Select>, + Xkb2Qt<XKB_KEY_XF86View, Qt::Key_View>, + Xkb2Qt<XKB_KEY_XF86TopMenu, Qt::Key_TopMenu>, + Xkb2Qt<XKB_KEY_XF86Red, Qt::Key_Red>, + Xkb2Qt<XKB_KEY_XF86Green, Qt::Key_Green>, + Xkb2Qt<XKB_KEY_XF86Yellow, Qt::Key_Yellow>, + Xkb2Qt<XKB_KEY_XF86Blue, Qt::Key_Blue>, + Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>, + Xkb2Qt<XKB_KEY_XF86Suspend, Qt::Key_Suspend>, + Xkb2Qt<XKB_KEY_XF86Hibernate, Qt::Key_Hibernate>, + Xkb2Qt<XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle>, + Xkb2Qt<XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn>, + Xkb2Qt<XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff>, + Xkb2Qt<XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute>, + Xkb2Qt<XKB_KEY_XF86Launch0, Qt::Key_Launch2>, // ### Qt 6: remap properly + Xkb2Qt<XKB_KEY_XF86Launch1, Qt::Key_Launch3>, + Xkb2Qt<XKB_KEY_XF86Launch2, Qt::Key_Launch4>, + Xkb2Qt<XKB_KEY_XF86Launch3, Qt::Key_Launch5>, + Xkb2Qt<XKB_KEY_XF86Launch4, Qt::Key_Launch6>, + Xkb2Qt<XKB_KEY_XF86Launch5, Qt::Key_Launch7>, + Xkb2Qt<XKB_KEY_XF86Launch6, Qt::Key_Launch8>, + Xkb2Qt<XKB_KEY_XF86Launch7, Qt::Key_Launch9>, + Xkb2Qt<XKB_KEY_XF86Launch8, Qt::Key_LaunchA>, + Xkb2Qt<XKB_KEY_XF86Launch9, Qt::Key_LaunchB>, + Xkb2Qt<XKB_KEY_XF86LaunchA, Qt::Key_LaunchC>, + Xkb2Qt<XKB_KEY_XF86LaunchB, Qt::Key_LaunchD>, + Xkb2Qt<XKB_KEY_XF86LaunchC, Qt::Key_LaunchE>, + Xkb2Qt<XKB_KEY_XF86LaunchD, Qt::Key_LaunchF>, + Xkb2Qt<XKB_KEY_XF86LaunchE, Qt::Key_LaunchG>, + Xkb2Qt<XKB_KEY_XF86LaunchF, Qt::Key_LaunchH> + >::Data{} +); + +xkb_keysym_t QXkbCommon::qxkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks) +{ + xkb_keysym_t lower, upper; + + xkbcommon_XConvertCase(ks, &lower, &upper); + + return upper; +} + +QString QXkbCommon::lookupString(struct xkb_state *state, xkb_keycode_t code) +{ + QVarLengthArray<char, 32> chars(32); + const int size = xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); + if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL + chars.resize(size + 1); + xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); + } + return QString::fromUtf8(chars.constData(), size); +} + +QString QXkbCommon::lookupStringNoKeysymTransformations(xkb_keysym_t keysym) +{ + QVarLengthArray<char, 32> chars(32); + const int size = xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); + if (size == 0) + return QString(); // the keysym does not have a Unicode representation + + if (Q_UNLIKELY(size > chars.size())) { + chars.resize(size); + xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); + } + return QString::fromUtf8(chars.constData(), size - 1); +} + +QVector<xkb_keysym_t> QXkbCommon::toKeysym(QKeyEvent *event) +{ + QVector<xkb_keysym_t> keysyms; + int qtKey = event->key(); + + if (qtKey >= Qt::Key_F1 && qtKey <= Qt::Key_F35) { + keysyms.append(XKB_KEY_F1 + (qtKey - Qt::Key_F1)); + } else if (event->modifiers() & Qt::KeypadModifier) { + if (qtKey >= Qt::Key_0 && qtKey <= Qt::Key_9) + keysyms.append(XKB_KEY_KP_0 + (qtKey - Qt::Key_0)); + } else if (isLatin(qtKey) && event->text().isUpper()) { + keysyms.append(qtKey); + } + + if (!keysyms.isEmpty()) + return keysyms; + + // check if we have a direct mapping + auto it = std::find_if(KeyTbl.cbegin(), KeyTbl.cend(), [&qtKey](xkb2qt_t elem) { + return elem.qt == static_cast<uint>(qtKey); + }); + if (it != KeyTbl.end()) { + keysyms.append(it->xkb); + return keysyms; + } + + QVector<uint> ucs4; + if (event->text().isEmpty()) + ucs4.append(qtKey); + else + ucs4 = event->text().toUcs4(); + + // From libxkbcommon keysym-utf.c: + // "We allow to represent any UCS character in the range U-00000000 to + // U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff." + for (uint utf32 : qAsConst(ucs4)) + keysyms.append(utf32 | 0x01000000); + + return keysyms; +} + +int QXkbCommon::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers) +{ + return keysymToQtKey(keysym, modifiers, nullptr, 0); +} + +int QXkbCommon::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers, + xkb_state *state, xkb_keycode_t code, + bool superAsMeta, bool hyperAsMeta) +{ + // Note 1: All standard key sequences on linux (as defined in platform theme) + // that use a latin character also contain a control modifier, which is why + // checking for Qt::ControlModifier is sufficient here. It is possible to + // override QPlatformTheme::keyBindings() and provide custom sequences for + // QKeySequence::StandardKey. Custom sequences probably should respect this + // convention (alternatively, we could test against other modifiers here). + // Note 2: The possibleKeys() shorcut mechanism is not affected by this value + // adjustment and does its own thing. + if (modifiers & Qt::ControlModifier) { + // With standard shortcuts we should prefer a latin character, this is + // for checks like "some qkeyevent == QKeySequence::Copy" to work even + // when using for example 'russian' keyboard layout. + if (!QXkbCommon::isLatin(keysym)) { + xkb_keysym_t latinKeysym = QXkbCommon::lookupLatinKeysym(state, code); + if (latinKeysym != XKB_KEY_NoSymbol) + keysym = latinKeysym; + } + } + + return keysymToQtKey_internal(keysym, modifiers, state, code, superAsMeta, hyperAsMeta); +} + +static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers, + xkb_state *state, xkb_keycode_t code, + bool superAsMeta, bool hyperAsMeta) +{ + int qtKey = 0; + + // lookup from direct mapping + if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) { + // function keys + qtKey = Qt::Key_F1 + (keysym - XKB_KEY_F1); + } else if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) { + // numeric keypad keys + qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0); + } else if (QXkbCommon::isLatin(keysym)) { + qtKey = QXkbCommon::qxkbcommon_xkb_keysym_to_upper(keysym); + } else { + // check if we have a direct mapping + xkb2qt_t searchKey{keysym, 0}; + auto it = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); + if (it != KeyTbl.end() && !(searchKey < *it)) + qtKey = it->qt; + } + + if (qtKey) + return qtKey; + + // lookup from unicode + QString text; + if (!state || modifiers & Qt::ControlModifier) { + // Control modifier changes the text to ASCII control character, therefore we + // can't use this text to map keysym to a qt key. We can use the same keysym + // (it is not affectd by transformation) to obtain untransformed text. For details + // see "Appendix A. Default Symbol Transformations" in the XKB specification. + text = QXkbCommon::lookupStringNoKeysymTransformations(keysym); + } else { + text = QXkbCommon::lookupString(state, code); + } + if (!text.isEmpty()) { + if (text.unicode()->isDigit()) { + // Ensures that also non-latin digits are mapped to corresponding qt keys, + // e.g CTRL + ۲ (arabic two), is mapped to CTRL + Qt::Key_2. + qtKey = Qt::Key_0 + text.unicode()->digitValue(); + } else { + qtKey = text.unicode()->toUpper().unicode(); + } + } + + // translate Super/Hyper keys to Meta if we're using them as the MetaModifier + if (superAsMeta && (qtKey == Qt::Key_Super_L || qtKey == Qt::Key_Super_R)) + qtKey = Qt::Key_Meta; + if (hyperAsMeta && (qtKey == Qt::Key_Hyper_L || qtKey == Qt::Key_Hyper_R)) + qtKey = Qt::Key_Meta; + + return qtKey; +} + +Qt::KeyboardModifiers QXkbCommon::modifiers(struct xkb_state *state) +{ + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE) > 0) + modifiers |= Qt::ControlModifier; + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE) > 0) + modifiers |= Qt::AltModifier; + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE) > 0) + modifiers |= Qt::ShiftModifier; + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE) > 0) + modifiers |= Qt::MetaModifier; + + return modifiers; +} + +// Possible modifier states. +static const Qt::KeyboardModifiers ModsTbl[] = { + Qt::NoModifier, // 0 + Qt::ShiftModifier, // 1 + Qt::ControlModifier, // 2 + Qt::ControlModifier | Qt::ShiftModifier, // 3 + Qt::AltModifier, // 4 + Qt::AltModifier | Qt::ShiftModifier, // 5 + Qt::AltModifier | Qt::ControlModifier, // 6 + Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 + Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts +}; + +QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event, + bool superAsMeta, bool hyperAsMeta) +{ + QList<int> result; + quint32 keycode = event->nativeScanCode(); + Qt::KeyboardModifiers modifiers = event->modifiers(); + xkb_keymap *keymap = xkb_state_get_keymap(state); + // turn off the modifier bits which doesn't participate in shortcuts + Qt::KeyboardModifiers notNeeded = Qt::KeypadModifier | Qt::GroupSwitchModifier; + modifiers &= ~notNeeded; + // create a fresh kb state and test against the relevant modifier combinations + ScopedXKBState scopedXkbQueryState(xkb_state_new(keymap)); + xkb_state *queryState = scopedXkbQueryState.get(); + if (!queryState) { + qCWarning(lcXkbcommon) << Q_FUNC_INFO << "failed to compile xkb keymap"; + return result; + } + // get kb state from the master state and update the temporary state + xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LOCKED); + xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED); + xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED); + xkb_state_update_mask(queryState, depressedMods, latchedMods, lockedMods, 0, 0, lockedLayout); + // handle shortcuts for level three and above + xkb_layout_index_t layoutIndex = xkb_state_key_get_layout(queryState, keycode); + xkb_level_index_t levelIndex = 0; + if (layoutIndex != XKB_LAYOUT_INVALID) { + levelIndex = xkb_state_key_get_level(queryState, keycode, layoutIndex); + if (levelIndex == XKB_LEVEL_INVALID) + levelIndex = 0; + } + if (levelIndex <= 1) + xkb_state_update_mask(queryState, 0, latchedMods, lockedMods, 0, 0, lockedLayout); + + xkb_keysym_t sym = xkb_state_key_get_one_sym(queryState, keycode); + if (sym == XKB_KEY_NoSymbol) + return result; + + int baseQtKey = keysymToQtKey_internal(sym, modifiers, queryState, keycode, superAsMeta, hyperAsMeta); + if (baseQtKey) + result += (baseQtKey + modifiers); + + xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(keymap, "Shift"); + xkb_mod_index_t altMod = xkb_keymap_mod_get_index(keymap, "Alt"); + xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(keymap, "Control"); + xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(keymap, "Meta"); + + Q_ASSERT(shiftMod < 32); + Q_ASSERT(altMod < 32); + Q_ASSERT(controlMod < 32); + + xkb_mod_mask_t depressed; + int qtKey = 0; + // obtain a list of possible shortcuts for the given key event + for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) { + Qt::KeyboardModifiers neededMods = ModsTbl[i]; + if ((modifiers & neededMods) == neededMods) { + if (i == 8) { + if (isLatin(baseQtKey)) + continue; + // add a latin key as a fall back key + sym = lookupLatinKeysym(state, keycode); + } else { + depressed = 0; + if (neededMods & Qt::AltModifier) + depressed |= (1 << altMod); + if (neededMods & Qt::ShiftModifier) + depressed |= (1 << shiftMod); + if (neededMods & Qt::ControlModifier) + depressed |= (1 << controlMod); + if (metaMod < 32 && neededMods & Qt::MetaModifier) + depressed |= (1 << metaMod); + xkb_state_update_mask(queryState, depressed, latchedMods, lockedMods, 0, 0, lockedLayout); + sym = xkb_state_key_get_one_sym(queryState, keycode); + } + if (sym == XKB_KEY_NoSymbol) + continue; + + Qt::KeyboardModifiers mods = modifiers & ~neededMods; + qtKey = keysymToQtKey_internal(sym, mods, queryState, keycode, superAsMeta, hyperAsMeta); + if (!qtKey || qtKey == baseQtKey) + continue; + + // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, + // but Ctrl++ is more specific than +, so we should skip the last one + bool ambiguous = false; + for (int shortcut : qAsConst(result)) { + if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) { + ambiguous = true; + break; + } + } + if (ambiguous) + continue; + + result += (qtKey + mods); + } + } + + return result; +} + +void QXkbCommon::verifyHasLatinLayout(xkb_keymap *keymap) +{ + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(keymap); + const xkb_keycode_t minKeycode = xkb_keymap_min_keycode(keymap); + const xkb_keycode_t maxKeycode = xkb_keymap_max_keycode(keymap); + + const xkb_keysym_t *keysyms = nullptr; + int nrLatinKeys = 0; + for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) { + for (xkb_keycode_t code = minKeycode; code < maxKeycode; ++code) { + xkb_keymap_key_get_syms_by_level(keymap, code, layout, 0, &keysyms); + if (keysyms && isLatin(keysyms[0])) + nrLatinKeys++; + if (nrLatinKeys > 10) // arbitrarily chosen threshold + return; + } + } + // This means that lookupLatinKeysym() will not find anything and latin + // key shortcuts might not work. This is a bug in the affected desktop + // environment. Usually can be solved via system settings by adding e.g. 'us' + // layout to the list of seleced layouts, or by using command line, "setxkbmap + // -layout rus,en". The position of latin key based layout in the list of the + // selected layouts is irrelevant. Properly functioning desktop environments + // handle this behind the scenes, even if no latin key based layout has been + // explicitly listed in the selected layouts. + qCDebug(lcXkbcommon, "no keyboard layouts with latin keys present"); +} + +xkb_keysym_t QXkbCommon::lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode) +{ + xkb_layout_index_t layout; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + xkb_keymap *keymap = xkb_state_get_keymap(state); + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(keymap, keycode); + const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(state, keycode); + // Look at user layouts in the order in which they are defined in system + // settings to find a latin keysym. + for (layout = 0; layout < layoutCount; ++layout) { + if (layout == currentLayout) + continue; + const xkb_keysym_t *syms = nullptr; + xkb_level_index_t level = xkb_state_key_get_level(state, keycode, layout); + if (xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, level, &syms) != 1) + continue; + if (isLatin(syms[0])) { + sym = syms[0]; + break; + } + } + + if (sym == XKB_KEY_NoSymbol) + return sym; + + xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED); + + // Check for uniqueness, consider the following setup: + // setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active). + // In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+<physical x key>, + // because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained + // 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired + // then the obtained key is not unique. This prevents ctrl+<physical q key> from generating a ctrl+q + // shortcut in the above described setup. We don't want ctrl+<physical x key> and ctrl+<physical q key> to + // generate the same shortcut event in this case. + const xkb_keycode_t minKeycode = xkb_keymap_min_keycode(keymap); + const xkb_keycode_t maxKeycode = xkb_keymap_max_keycode(keymap); + ScopedXKBState queryState(xkb_state_new(keymap)); + for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) { + xkb_state_update_mask(queryState.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout); + for (xkb_keycode_t code = minKeycode; code < maxKeycode; ++code) { + xkb_keysym_t prevSym = xkb_state_key_get_one_sym(queryState.get(), code); + if (prevSym == sym) { + sym = XKB_KEY_NoSymbol; + break; + } + } + } + + return sym; +} + +void QXkbCommon::setXkbContext(QPlatformInputContext *inputContext, struct xkb_context *context) +{ + if (!inputContext || !context) + return; + + const char *const inputContextClassName = "QComposeInputContext"; + const char *const normalizedSignature = "setXkbContext(xkb_context*)"; + + if (inputContext->objectName() != QLatin1String(inputContextClassName)) + return; + + static const QMetaMethod setXkbContext = [&]() { + int methodIndex = inputContext->metaObject()->indexOfMethod(normalizedSignature); + QMetaMethod method = inputContext->metaObject()->method(methodIndex); + Q_ASSERT(method.isValid()); + if (!method.isValid()) + qCWarning(lcXkbcommon) << normalizedSignature << "not found on" << inputContextClassName; + return method; + }(); + + if (!setXkbContext.isValid()) + return; + + setXkbContext.invoke(inputContext, Qt::DirectConnection, Q_ARG(struct xkb_context*, context)); +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/input/xkbcommon/qxkbcommon_3rdparty.cpp b/src/platformsupport/input/xkbcommon/qxkbcommon_3rdparty.cpp new file mode 100644 index 0000000000..08f43b3b72 --- /dev/null +++ b/src/platformsupport/input/xkbcommon/qxkbcommon_3rdparty.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* Copyright 1985, 1987, 1990, 1998 The Open Group + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the authors or their + institutions shall not be used in advertising or otherwise to promote the + sale, use or other dealings in this Software without prior written + authorization from the authors. + + + + Copyright © 2009 Dan Nicholson + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/* + XConvertCase was copied from src/3rdparty/xkbcommon/src/keysym.c + The following code modifications were applied: + + XConvertCase() was renamed to xkbcommon_XConvertCase(), to not confuse it + with Xlib's XConvertCase(). + + UCSConvertCase() was renamed to qt_UCSConvertCase() and function's body was + replaced to use Qt APIs for doing case conversion, which should give us better + results instead of using the less complete version from keysym.c +*/ + +#include "qxkbcommon_p.h" + +#include <QtCore/QChar> + +static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper) +{ + *lower = QChar::toLower(code); + *upper = QChar::toUpper(code); +} + +void QXkbCommon::xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper) +{ + /* Latin 1 keysym */ + if (sym < 0x100) { + qt_UCSConvertCase(sym, lower, upper); + return; + } + + /* Unicode keysym */ + if ((sym & 0xff000000) == 0x01000000) { + qt_UCSConvertCase((sym & 0x00ffffff), lower, upper); + *upper |= 0x01000000; + *lower |= 0x01000000; + return; + } + + /* Legacy keysym */ + + *lower = sym; + *upper = sym; + + switch (sym >> 8) { + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XKB_KEY_Aogonek) + *lower = XKB_KEY_aogonek; + else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute) + *lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke); + else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute) + *lower += (XKB_KEY_scaron - XKB_KEY_Scaron); + else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot) + *lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron); + else if (sym == XKB_KEY_aogonek) + *upper = XKB_KEY_Aogonek; + else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute) + *upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke); + else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute) + *upper -= (XKB_KEY_scaron - XKB_KEY_Scaron); + else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot) + *upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron); + else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla) + *lower += (XKB_KEY_racute - XKB_KEY_Racute); + else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla) + *upper -= (XKB_KEY_racute - XKB_KEY_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex) + *lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke); + else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex) + *lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve); + else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex) + *upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke); + else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex) + *upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve); + else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex) + *lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); + else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex) + *upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash) + *lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); + else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash) + *upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); + else if (sym == XKB_KEY_ENG) + *lower = XKB_KEY_eng; + else if (sym == XKB_KEY_eng) + *upper = XKB_KEY_ENG; + else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron) + *lower += (XKB_KEY_amacron - XKB_KEY_Amacron); + else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron) + *upper -= (XKB_KEY_amacron - XKB_KEY_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE) + *lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); + else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze) + *upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); + else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN) + *lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); + else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign) + *upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent) + *lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); + else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent && + sym != XKB_KEY_Greek_iotaaccentdieresis && + sym != XKB_KEY_Greek_upsilonaccentdieresis) + *upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); + else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA) + *lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); + else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega && + sym != XKB_KEY_Greek_finalsmallsigma) + *upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); + break; + case 0x13: /* Latin 9 */ + if (sym == XKB_KEY_OE) + *lower = XKB_KEY_oe; + else if (sym == XKB_KEY_oe) + *upper = XKB_KEY_OE; + else if (sym == XKB_KEY_Ydiaeresis) + *lower = XKB_KEY_ydiaeresis; + break; + } +} diff --git a/src/platformsupport/input/xkbcommon/qxkbcommon_p.h b/src/platformsupport/input/xkbcommon/qxkbcommon_p.h new file mode 100644 index 0000000000..561eae03db --- /dev/null +++ b/src/platformsupport/input/xkbcommon/qxkbcommon_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXKBCOMMON_P_H +#define QXKBCOMMON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtCore/QVector> +#include <QtCore/QLoggingCategory> +#include <QtCore/QList> + +#include <xkbcommon/xkbcommon.h> + +#include <memory> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcXkbcommon) + +class QEvent; +class QKeyEvent; +class QPlatformInputContext; + +class QXkbCommon +{ +public: + static QString lookupString(struct xkb_state *state, xkb_keycode_t code); + static QString lookupStringNoKeysymTransformations(xkb_keysym_t keysym); + + static QVector<xkb_keysym_t> toKeysym(QKeyEvent *event); + + static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers); + static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers, + xkb_state *state, xkb_keycode_t code, + bool superAsMeta = false, bool hyperAsMeta = false); + + // xkbcommon_* API is part of libxkbcommon internals, with modifications as + // desribed in the header of the implementation file. + static void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper); + static xkb_keysym_t qxkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks); + + static Qt::KeyboardModifiers modifiers(struct xkb_state *state); + + static QList<int> possibleKeys(xkb_state *state, const QKeyEvent *event, + bool superAsMeta = false, bool hyperAsMeta = false); + + static void verifyHasLatinLayout(xkb_keymap *keymap); + static xkb_keysym_t lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode); + + static bool isLatin(xkb_keysym_t sym) { + return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z')); + } + static bool isKeypad(xkb_keysym_t sym) { + return sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9; + } + + static void setXkbContext(QPlatformInputContext *inputContext, struct xkb_context *context); + + struct XKBStateDeleter { + void operator()(struct xkb_state *state) const { return xkb_state_unref(state); } + }; + struct XKBKeymapDeleter { + void operator()(struct xkb_keymap *keymap) const { return xkb_keymap_unref(keymap); } + }; + struct XKBContextDeleter { + void operator()(struct xkb_context *context) const { return xkb_context_unref(context); } + }; + using ScopedXKBState = std::unique_ptr<struct xkb_state, XKBStateDeleter>; + using ScopedXKBKeymap = std::unique_ptr<struct xkb_keymap, XKBKeymapDeleter>; + using ScopedXKBContext = std::unique_ptr<struct xkb_context, XKBContextDeleter>; +}; + +QT_END_NAMESPACE + +#endif // QXKBCOMMON_P_H diff --git a/src/platformsupport/input/xkbcommon/xkbcommon.pro b/src/platformsupport/input/xkbcommon/xkbcommon.pro new file mode 100644 index 0000000000..22b16ae44a --- /dev/null +++ b/src/platformsupport/input/xkbcommon/xkbcommon.pro @@ -0,0 +1,23 @@ +TARGET = QtXkbCommonSupport +MODULE = xkbcommon_support + +QT = core-private gui-private +CONFIG += static internal_module + +DEFINES += QT_NO_CAST_FROM_ASCII +PRECOMPILED_HEADER = ../../../corelib/global/qt_pch.h + +QMAKE_USE += xkbcommon + +HEADERS += \ + qxkbcommon_p.h + +SOURCES += \ + qxkbcommon.cpp \ + qxkbcommon_3rdparty.cpp + +# qxkbcommon.cpp::KeyTbl has more than 256 levels of expansion and older +# Clang uses that as a limit (it's 1024 in current versions). +clang:!intel_icc: QMAKE_CXXFLAGS += -ftemplate-depth=1024 + +load(qt_module) diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index ef81f6162d..4b27522976 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -777,9 +777,7 @@ void QKmsDevice::discoverPlanes() for (int i = 0; i < countFormats; ++i) { uint32_t f = drmplane->formats[i]; plane.supportedFormats.append(f); - QString s; - s.sprintf("%c%c%c%c ", f, f >> 8, f >> 16, f >> 24); - formatStr += s; + formatStr += QString::asprintf("%c%c%c%c ", f, f >> 8, f >> 16, f >> 24); } qCDebug(qLcKmsDebug, "plane %d: id = %u countFormats = %d possibleCrtcs = 0x%x supported formats = %s", diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h index b5704f53ad..0b624389a3 100644 --- a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h +++ b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h @@ -76,7 +76,7 @@ class AtSpiAdaptor :public QDBusVirtualObject Q_OBJECT public: - explicit AtSpiAdaptor(DBusConnection *connection, QObject *parent = 0); + explicit AtSpiAdaptor(DBusConnection *connection, QObject *parent = nullptr); ~AtSpiAdaptor(); void registerApplication(); diff --git a/src/platformsupport/linuxaccessibility/cache_p.h b/src/platformsupport/linuxaccessibility/cache_p.h index e8529b779b..cc55acc6f8 100644 --- a/src/platformsupport/linuxaccessibility/cache_p.h +++ b/src/platformsupport/linuxaccessibility/cache_p.h @@ -65,7 +65,7 @@ class QSpiDBusCache : public QObject Q_OBJECT public: - explicit QSpiDBusCache(QDBusConnection c, QObject* parent = 0); + explicit QSpiDBusCache(QDBusConnection c, QObject* parent = nullptr); void emitAddAccessible(const QSpiAccessibleCacheItem& item); void emitRemoveAccessible(const QSpiObjectReference& item); diff --git a/src/platformsupport/linuxaccessibility/constant_mappings.cpp b/src/platformsupport/linuxaccessibility/constant_mappings.cpp index de4a68dc5b..ef2b3429d2 100644 --- a/src/platformsupport/linuxaccessibility/constant_mappings.cpp +++ b/src/platformsupport/linuxaccessibility/constant_mappings.cpp @@ -83,6 +83,8 @@ quint64 spiStatesFromQState(QAccessible::State state) // if (state.HotTracked) if (state.defaultButton) setSpiStateBit(&spiState, ATSPI_STATE_IS_DEFAULT); + if (state.expandable) + setSpiStateBit(&spiState, ATSPI_STATE_EXPANDABLE); if (state.expanded) setSpiStateBit(&spiState, ATSPI_STATE_EXPANDED); if (state.collapsed) diff --git a/src/platformsupport/linuxaccessibility/dbusconnection_p.h b/src/platformsupport/linuxaccessibility/dbusconnection_p.h index 4030fabc22..860c18ca05 100644 --- a/src/platformsupport/linuxaccessibility/dbusconnection_p.h +++ b/src/platformsupport/linuxaccessibility/dbusconnection_p.h @@ -65,7 +65,7 @@ class DBusConnection : public QObject Q_OBJECT public: - DBusConnection(QObject *parent = 0); + DBusConnection(QObject *parent = nullptr); QDBusConnection connection() const; bool isEnabled() const { return m_enabled; } diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp index 67884cef92..734bdcaf75 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp +++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp @@ -45,7 +45,9 @@ #if QT_CONFIG(process) # include <QtCore/QProcess> #endif +#if QT_CONFIG(settings) #include <QtCore/QSettings> +#endif #include <QtCore/QStandardPaths> #include <QtCore/QUrl> @@ -93,7 +95,7 @@ static inline QByteArray detectDesktopEnvironment() // This can be a path in /usr/share/xsessions int slash = desktopSession.lastIndexOf('/'); if (slash != -1) { -#ifndef QT_NO_SETTINGS +#if QT_CONFIG(settings) QSettings desktopFile(QFile::decodeName(desktopSession + ".desktop"), QSettings::IniFormat); desktopFile.beginGroup(QStringLiteral("Desktop Entry")); QByteArray desktopName = desktopFile.value(QStringLiteral("DesktopNames")).toByteArray(); @@ -177,7 +179,15 @@ static inline bool checkNeedPortalSupport() return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty() || qEnvironmentVariableIsSet("SNAP"); } -static inline bool xdgDesktopPortalOpenFile(const QUrl &url) +static inline bool isPortalReturnPermanent(const QDBusError &error) +{ + // A service unknown error isn't permanent, it just indicates that we + // should fall back to the regular way. This check includes + // QDBusError::NoError. + return error.type() != QDBusError::ServiceUnknown; +} + +static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url) { // DBus signature: // OpenFile (IN s parent_window, @@ -196,23 +206,22 @@ static inline bool xdgDesktopPortalOpenFile(const QUrl &url) QLatin1String("org.freedesktop.portal.OpenURI"), QLatin1String("OpenFile")); - QDBusUnixFileDescriptor descriptor(fd); - qt_safe_close(fd); + QDBusUnixFileDescriptor descriptor; + descriptor.giveFileDescriptor(fd); // FIXME parent_window_id and handle writable option message << QString() << QVariant::fromValue(descriptor) << QVariantMap(); - QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message); - return !reply.isError(); + return QDBusConnection::sessionBus().call(message); } #else Q_UNUSED(url) #endif - return false; + return QDBusMessage::createError(QDBusError::InternalError, qt_error_string()); } -static inline bool xdgDesktopPortalOpenUrl(const QUrl &url) +static inline QDBusMessage xdgDesktopPortalOpenUrl(const QUrl &url) { // DBus signature: // OpenURI (IN s parent_window, @@ -232,11 +241,10 @@ static inline bool xdgDesktopPortalOpenUrl(const QUrl &url) // FIXME parent_window_id and handle writable option message << QString() << url.toString() << QVariantMap(); - QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message); - return !reply.isError(); + return QDBusConnection::sessionBus().call(message); } -static inline bool xdgDesktopPortalSendEmail(const QUrl &url) +static inline QDBusMessage xdgDesktopPortalSendEmail(const QUrl &url) { // DBus signature: // ComposeEmail (IN s parent_window, @@ -279,8 +287,7 @@ static inline bool xdgDesktopPortalSendEmail(const QUrl &url) // FIXME parent_window_id message << QString() << options; - QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message); - return !reply.isError(); + return QDBusConnection::sessionBus().call(message); } #endif // QT_CONFIG(dbus) @@ -294,15 +301,23 @@ bool QGenericUnixServices::openUrl(const QUrl &url) { if (url.scheme() == QLatin1String("mailto")) { #if QT_CONFIG(dbus) - if (checkNeedPortalSupport()) - return xdgDesktopPortalSendEmail(url); + if (checkNeedPortalSupport()) { + QDBusError error = xdgDesktopPortalSendEmail(url); + if (isPortalReturnPermanent(error)) + return !error.isValid(); + + // service not running, fall back + } #endif return openDocument(url); } #if QT_CONFIG(dbus) - if (checkNeedPortalSupport()) - return xdgDesktopPortalOpenUrl(url); + if (checkNeedPortalSupport()) { + QDBusError error = xdgDesktopPortalOpenUrl(url); + if (isPortalReturnPermanent(error)) + return !error.isValid(); + } #endif if (m_webBrowser.isEmpty() && !detectWebBrowser(desktopEnvironment(), true, &m_webBrowser)) { @@ -315,8 +330,11 @@ bool QGenericUnixServices::openUrl(const QUrl &url) bool QGenericUnixServices::openDocument(const QUrl &url) { #if QT_CONFIG(dbus) - if (checkNeedPortalSupport()) - return xdgDesktopPortalOpenFile(url); + if (checkNeedPortalSupport()) { + QDBusError error = xdgDesktopPortalOpenFile(url); + if (isPortalReturnPermanent(error)) + return !error.isValid(); + } #endif if (m_documentLauncher.isEmpty() && !detectWebBrowser(desktopEnvironment(), false, &m_documentLauncher)) { diff --git a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h index c7c3f4bc5b..565af6c947 100644 --- a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h +++ b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h @@ -67,7 +67,7 @@ class QDBusMenuConnection : public QObject Q_OBJECT public: - QDBusMenuConnection(QObject *parent = 0, const QString &serviceName = QString()); + QDBusMenuConnection(QObject *parent = nullptr, const QString &serviceName = QString()); QDBusConnection connection() const { return m_connection; } QDBusServiceWatcher *dbusWatcher() const { return m_dbusWatcher; } bool isStatusNotifierHostRegistered() const { return m_statusNotifierHostRegistered; } diff --git a/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h b/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h index 352b4aa5d6..ab99ea65dd 100644 --- a/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h +++ b/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h @@ -88,7 +88,7 @@ public: public: QXdgNotificationInterface(const QString &service, const QString &path, - const QDBusConnection &connection, QObject *parent = 0); + const QDBusConnection &connection, QObject *parent = nullptr); ~QXdgNotificationInterface(); diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index 63a860f251..7b3f9b624a 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -49,9 +49,13 @@ #include <QtCore/QFile> #include <QtCore/QDebug> #include <QtCore/QHash> +#if QT_CONFIG(mimetype) #include <QtCore/QMimeDatabase> +#endif #include <QtCore/QLoggingCategory> +#if QT_CONFIG(settings) #include <QtCore/QSettings> +#endif #include <QtCore/QVariant> #include <QtCore/QStandardPaths> #include <QtCore/QStringList> @@ -168,15 +172,9 @@ QStringList QGenericUnixTheme::xdgIconThemePaths() if (homeIconDir.isDir()) paths.prepend(homeIconDir.absoluteFilePath()); - QString xdgDirString = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); - if (xdgDirString.isEmpty()) - xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); - const auto xdgDirs = xdgDirString.splitRef(QLatin1Char(':')); - for (const QStringRef &xdgDir : xdgDirs) { - const QFileInfo xdgIconsDir(xdgDir + QLatin1String("/icons")); - if (xdgIconsDir.isDir()) - paths.append(xdgIconsDir.absoluteFilePath()); - } + paths.append(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, + QStringLiteral("icons"), + QStandardPaths::LocateDirectory)); return paths; } @@ -259,7 +257,7 @@ static QIcon xdgFileIcon(const QFileInfo &fileInfo) } #endif -#ifndef QT_NO_SETTINGS +#if QT_CONFIG(settings) class QKdeThemePrivate : public QPlatformThemePrivate { public: @@ -686,7 +684,7 @@ QPlatformSystemTrayIcon *QKdeTheme::createPlatformSystemTrayIcon() const } #endif -#endif // QT_NO_SETTINGS +#endif // settings /*! \class QGnomeTheme @@ -832,7 +830,7 @@ QPlatformTheme *QGenericUnixTheme::createUnixTheme(const QString &name) { if (name == QLatin1String(QGenericUnixTheme::name)) return new QGenericUnixTheme; -#ifndef QT_NO_SETTINGS +#if QT_CONFIG(settings) if (name == QLatin1String(QKdeTheme::name)) if (QPlatformTheme *kdeTheme = QKdeTheme::createKdeTheme()) return kdeTheme; @@ -857,7 +855,7 @@ QStringList QGenericUnixTheme::themeNames() const QList<QByteArray> desktopNames = desktopEnvironment.split(':'); for (const QByteArray &desktopName : desktopNames) { if (desktopEnvironment == "KDE") { -#ifndef QT_NO_SETTINGS +#if QT_CONFIG(settings) result.push_back(QLatin1String(QKdeTheme::name)); #endif } else if (gtkBasedEnvironments.contains(desktopName)) { diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h index 865a624694..c0da9d8370 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h @@ -96,7 +96,7 @@ public: static const char *name; }; -#ifndef QT_NO_SETTINGS +#if QT_CONFIG(settings) class QKdeThemePrivate; class QKdeTheme : public QPlatformTheme @@ -109,7 +109,7 @@ public: QVariant themeHint(ThemeHint hint) const override; QIcon fileIcon(const QFileInfo &fileInfo, - QPlatformTheme::IconOptions iconOptions = 0) const override; + QPlatformTheme::IconOptions iconOptions = nullptr) const override; const QPalette *palette(Palette type = SystemPalette) const override; @@ -123,7 +123,7 @@ public: static const char *name; }; -#endif // QT_NO_SETTINGS +#endif // settings class QGnomeThemePrivate; @@ -134,7 +134,7 @@ public: QGnomeTheme(); QVariant themeHint(ThemeHint hint) const override; QIcon fileIcon(const QFileInfo &fileInfo, - QPlatformTheme::IconOptions = 0) const override; + QPlatformTheme::IconOptions = nullptr) const override; const QFont *font(Font type) const override; QString standardButtonText(int button) const override; diff --git a/src/platformsupport/themes/qabstractfileiconengine.cpp b/src/platformsupport/themes/qabstractfileiconengine.cpp index 192ed00510..c5800d9119 100644 --- a/src/platformsupport/themes/qabstractfileiconengine.cpp +++ b/src/platformsupport/themes/qabstractfileiconengine.cpp @@ -76,7 +76,7 @@ QPixmap QAbstractFileIconEngine::pixmap(const QSize &size, QIcon::Mode mode, key += QLatin1Char('_') + QString::number(size.width()); QPixmap result; - if (!QPixmapCache::find(key, result)) { + if (!QPixmapCache::find(key, &result)) { result = filePixmap(size, mode, state); if (!result.isNull()) QPixmapCache::insert(key, result); diff --git a/src/platformsupport/vkconvenience/CMakeLists.txt b/src/platformsupport/vkconvenience/CMakeLists.txt index 23d7c6ffec..106f78fb3d 100644 --- a/src/platformsupport/vkconvenience/CMakeLists.txt +++ b/src/platformsupport/vkconvenience/CMakeLists.txt @@ -13,7 +13,6 @@ add_qt_module(VulkanSupport LIBRARIES Qt::CorePrivate Qt::GuiPrivate - Vulkan::Vulkan # special case ) #### Keys ignored in scope 1:.:vkconvenience.pro:<NONE>: |