diff options
Diffstat (limited to 'src/platformsupport')
62 files changed, 912 insertions, 838 deletions
diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_p.h b/src/platformsupport/devicediscovery/qdevicediscovery_p.h index b1ce14b5c3..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; 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 06c8852825..6bf1f1db96 100644 --- a/src/platformsupport/edid/qedidparser.cpp +++ b/src/platformsupport/edid/qedidparser.cpp @@ -42,8 +42,6 @@ #include "qedidparser_p.h" #include "qedidvendortable_p.h" -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) - #define EDID_DESCRIPTOR_ALPHANUMERIC_STRING 0xfe #define EDID_DESCRIPTOR_PRODUCT_NAME 0xfc #define EDID_DESCRIPTOR_SERIAL_NUMBER 0xff @@ -139,9 +137,9 @@ bool QEdidParser::parse(const QByteArray &blob) manufacturer = m_vendorCache.value(pnpIdString); if (manufacturer.isEmpty()) { // Find the manufacturer from the vendor lookup table - for (size_t i = 0; i < ARRAY_LENGTH(q_edidVendorTable); i++) { - if (strncmp(q_edidVendorTable[i].id, pnpId, 3) == 0) { - manufacturer = QString::fromUtf8(q_edidVendorTable[i].name); + for (const auto &vendor : q_edidVendorTable) { + if (strncmp(vendor.id, pnpId, 3) == 0) { + manufacturer = QString::fromUtf8(vendor.name); break; } } 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_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/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/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/fbconvenience/qfbwindow.cpp b/src/platformsupport/fbconvenience/qfbwindow.cpp index 36f92b8cea..9f5f87d9d6 100644 --- a/src/platformsupport/fbconvenience/qfbwindow.cpp +++ b/src/platformsupport/fbconvenience/qfbwindow.cpp @@ -45,11 +45,12 @@ QT_BEGIN_NAMESPACE +static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0); + QFbWindow::QFbWindow(QWindow *window) : QPlatformWindow(window), mBackingStore(0), mWindowState(Qt::WindowNoState) { - static QAtomicInt winIdGenerator(1); - mWindowId = winIdGenerator.fetchAndAddRelaxed(1); + mWindowId = winIdGenerator.fetchAndAddRelaxed(1) + 1; } QFbWindow::~QFbWindow() diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index e545d54ec2..7abf295782 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -721,7 +721,7 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont FcValue value; value.type = FcTypeString; - QByteArray cs = family.toUtf8(); + const QByteArray cs = family.toUtf8(); value.u.s = (const FcChar8 *)cs.data(); FcPatternAdd(pattern,FC_FAMILY,value,true); @@ -863,7 +863,7 @@ QString QFontconfigDatabase::resolveFontFamilyAlias(const QString &family) const return family; if (!family.isEmpty()) { - QByteArray cs = family.toUtf8(); + const QByteArray cs = family.toUtf8(); FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData()); } FcConfigSubstitute(0, pattern, FcMatchPattern); diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index 08e652b2a0..8c6cc8fbc1 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; } @@ -260,7 +254,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, } newFreetype->face = face; - newFreetype->ref.store(1); + newFreetype->ref.storeRelaxed(1); newFreetype->xsize = 0; newFreetype->ysize = 0; newFreetype->matrix.xx = 0x10000; @@ -556,26 +550,7 @@ void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path); } -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; @@ -585,7 +560,6 @@ 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++ = (0xFFU << 24) | (red << 16) | (green << 8) | blue; } dst += width; @@ -593,16 +567,7 @@ static void convertRGBToARGB_helper(const uchar *src, uint *dst, int width, int } } -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--) { @@ -610,54 +575,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++ = (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++ = (0xFFU << 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; @@ -1148,126 +1071,49 @@ 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) { uchar *src = slot->bitmap.buffer; uchar *dst = glyph_buffer.data(); int h = slot->bitmap.rows; + // Some fonts return bitmaps even when we requested something else: if (format == Format_Mono) { int bytes = ((info.width + 7) & ~7) >> 3; while (h--) { @@ -1275,69 +1121,63 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, 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; - } + } else if (format == Format_A8) { + while (h--) { + for (int x = 0; x < int{info.width}; x++) + dst[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00); + dst += pitch; + src += slot->bitmap.pitch; } - } -#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100) >= 20500) - else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) - { + } else { 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); - } -#else - memcpy(dst, src, slot->bitmap.width * 4); -#endif - dst += slot->bitmap.pitch; + uint *dd = reinterpret_cast<uint *>(dst); + for (int x = 0; x < int{info.width}; x++) + dd[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffffff : 0x00000000); + dst += 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; } + } 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); + } +#else + memcpy(dst, src, slot->bitmap.width * 4); #endif + dst += slot->bitmap.pitch; + src += slot->bitmap.pitch; + } + 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; diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h index 2863d206d2..2e3aef6979 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h @@ -116,11 +116,11 @@ private: friend class QFontEngineFT; friend class QtFreetypeData; friend struct QScopedPointerDeleter<QFreetypeFace>; - QFreetypeFace() : _lock(QMutex::Recursive) {} + QFreetypeFace() = default; ~QFreetypeFace() {} void cleanup(); QAtomicInt ref; - QMutex _lock; + QRecursiveMutex _lock; QByteArray fontData; QFontEngine::Holder hbFace; @@ -252,7 +252,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/freetype/qfreetypefontdatabase.cpp b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp index adc2f6c1fe..25c10fbd3c 100644 --- a/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp +++ b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp @@ -127,7 +127,7 @@ QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const Q error = FT_New_Face(library, file.constData(), index, &face); } if (error != FT_Err_Ok) { - qDebug() << "FT_New_Face failed with index" << index << ':' << hex << error; + qDebug() << "FT_New_Face failed with index" << index << ':' << Qt::hex << error; break; } numFaces = face->num_faces; diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index c450e91d49..daa3dc94ea 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -48,6 +48,8 @@ #import <UIKit/UIFont.h> #endif +#include <QtCore/qelapsedtimer.h> + #include "qcoretextfontdatabase_p.h" #include "qfontengine_coretext_p.h" #if QT_CONFIG(settings) @@ -100,20 +102,6 @@ static const char *languageForWritingSystem[] = { }; enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; -#ifdef Q_OS_OSX -static NSInteger languageMapSort(id obj1, id obj2, void *context) -{ - NSArray<NSString *> *map1 = reinterpret_cast<NSArray<NSString *> *>(obj1); - NSArray<NSString *> *map2 = reinterpret_cast<NSArray<NSString *> *>(obj2); - NSArray<NSString *> *languages = reinterpret_cast<NSArray<NSString *> *>(context); - - NSString *lang1 = [map1 objectAtIndex:0]; - NSString *lang2 = [map2 objectAtIndex:0]; - - return [languages indexOfObject:lang1] - [languages indexOfObject:lang2]; -} -#endif - QCoreTextFontDatabase::QCoreTextFontDatabase() : m_hasPopulatedAliases(false) { @@ -127,39 +115,77 @@ QCoreTextFontDatabase::~QCoreTextFontDatabase() void QCoreTextFontDatabase::populateFontDatabase() { + qCDebug(lcQpaFonts) << "Populating font database..."; + QElapsedTimer elapsed; + if (lcQpaFonts().isDebugEnabled()) + elapsed.start(); + QCFType<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames(); for (NSString *familyName in familyNames.as<const NSArray *>()) QPlatformFontDatabase::registerFontFamily(QString::fromNSString(familyName)); + qCDebug(lcQpaFonts) << "Populating available families took" << elapsed.restart() << "ms"; + // Force creating the theme fonts to get the descriptors in m_systemFontDescriptors if (m_themeFonts.isEmpty()) (void)themeFonts(); + qCDebug(lcQpaFonts) << "Resolving theme fonts took" << elapsed.restart() << "ms"; + Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors) populateFromDescriptor(fontDesc); + qCDebug(lcQpaFonts) << "Populating system descriptors took" << elapsed.restart() << "ms"; + Q_ASSERT(!m_hasPopulatedAliases); } -bool QCoreTextFontDatabase::populateFamilyAliases() +bool QCoreTextFontDatabase::populateFamilyAliases(const QString &missingFamily) { #if defined(Q_OS_MACOS) if (m_hasPopulatedAliases) return false; + // There's no API to go from a localized family name to its non-localized + // name, so we have to resort to enumerating all the available fonts and + // doing a reverse lookup. + + qCDebug(lcQpaFonts) << "Populating family aliases..."; + QElapsedTimer elapsed; + elapsed.start(); + + QString nonLocalizedMatch; QCFType<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames(); + NSFontManager *fontManager = NSFontManager.sharedFontManager; for (NSString *familyName in familyNames.as<const NSArray *>()) { - NSFontManager *fontManager = [NSFontManager sharedFontManager]; NSString *localizedFamilyName = [fontManager localizedNameForFamily:familyName face:nil]; if (![localizedFamilyName isEqual:familyName]) { - QPlatformFontDatabase::registerAliasToFontFamily( - QString::fromNSString(familyName), - QString::fromNSString(localizedFamilyName)); + QString nonLocalizedFamily = QString::fromNSString(familyName); + QString localizedFamily = QString::fromNSString(localizedFamilyName); + QPlatformFontDatabase::registerAliasToFontFamily(nonLocalizedFamily, localizedFamily); + if (localizedFamily == missingFamily) + nonLocalizedMatch = nonLocalizedFamily; } } m_hasPopulatedAliases = true; + + if (lcQpaFonts().isWarningEnabled()) { + QString warningMessage; + QDebug msg(&warningMessage); + + msg << "Populating font family aliases took" << elapsed.restart() << "ms."; + if (!nonLocalizedMatch.isNull()) + msg << "Replace uses of" << missingFamily << "with its non-localized name" << nonLocalizedMatch; + else + msg << "Replace uses of missing font family" << missingFamily << "with one that exists"; + msg << "to avoid this cost."; + + qCWarning(lcQpaFonts) << qPrintable(warningMessage); + } + return true; #else + Q_UNUSED(missingFamily); return false; #endif } @@ -173,7 +199,7 @@ void QCoreTextFontDatabase::populateFamily(const QString &familyName) // A single family might match several different fonts with different styles eg. QCFType<CFArrayRef> matchingFonts = (CFArrayRef) CTFontDescriptorCreateMatchingFontDescriptors(nameOnlyDescriptor, 0); if (!matchingFonts) { - qWarning() << "QCoreTextFontDatabase: Found no matching fonts for family" << familyName; + qCWarning(lcQpaFonts) << "QCoreTextFontDatabase: Found no matching fonts for family" << familyName; return; } @@ -406,175 +432,163 @@ template class QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>; template class QCoreTextFontDatabaseEngineFactory<QFontEngineFT>; #endif -QFont::StyleHint styleHintFromNSString(NSString *style) +CTFontDescriptorRef descriptorForFamily(const QString &familyName) +{ + return CTFontDescriptorCreateWithAttributes(CFDictionaryRef(@{ + (id)kCTFontFamilyNameAttribute: familyName.toNSString() + })); +} + +CTFontDescriptorRef descriptorForFamily(const char *familyName) { - if ([style isEqual: @"sans-serif"]) - return QFont::SansSerif; - else if ([style isEqual: @"monospace"]) - return QFont::Monospace; - else if ([style isEqual: @"cursive"]) - return QFont::Cursive; - else if ([style isEqual: @"serif"]) - return QFont::Serif; - else if ([style isEqual: @"fantasy"]) - return QFont::Fantasy; - else // if ([style isEqual: @"default"]) - return QFont::AnyStyle; + return descriptorForFamily(QString::fromLatin1(familyName)); } -#ifdef Q_OS_OSX -static QString familyNameFromPostScriptName(NSString *psName) +CFArrayRef fallbacksForDescriptor(CTFontDescriptorRef descriptor) { - QCFType<CTFontDescriptorRef> fontDescriptor = (CTFontDescriptorRef) CTFontDescriptorCreateWithNameAndSize((CFStringRef)psName, 12.0); - QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute); - QString name = QString::fromCFString(familyName); - if (name.isEmpty()) - qWarning() << "QCoreTextFontDatabase: Failed to resolve family name for PostScript name " << QString::fromCFString((CFStringRef)psName); + QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr); + if (!font) { + qCWarning(lcQpaFonts) << "Failed to create fallback font for" << descriptor; + return nullptr; + } + + CFArrayRef cascadeList = CFArrayRef(CTFontCopyDefaultCascadeListForLanguages(font, + (CFArrayRef)[NSUserDefaults.standardUserDefaults stringArrayForKey:@"AppleLanguages"])); + + if (!cascadeList) { + qCWarning(lcQpaFonts) << "Failed to create fallback cascade list for" << descriptor; + return nullptr; + } - return name; + return cascadeList; } -#endif -static void addExtraFallbacks(QStringList *fallbackList) +CFArrayRef QCoreTextFontDatabase::fallbacksForFamily(const QString &family) { -#if defined(Q_OS_MACOS) - // Since we are only returning a list of default fonts for the current language, we do not - // cover all unicode completely. This was especially an issue for some of the common script - // symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk - // of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most - // of Unicode 2.1. - if (!fallbackList->contains(QStringLiteral("Arial Unicode MS"))) - fallbackList->append(QStringLiteral("Arial Unicode MS")); - // Since some symbols (specifically Braille) are not in Arial Unicode MS, we - // add Apple Symbols to cover those too. - if (!fallbackList->contains(QStringLiteral("Apple Symbols"))) - fallbackList->append(QStringLiteral("Apple Symbols")); -#else - Q_UNUSED(fallbackList) -#endif + if (family.isEmpty()) + return nullptr; + + QCFType<CTFontDescriptorRef> fontDescriptor = descriptorForFamily(family); + if (!fontDescriptor) { + qCWarning(lcQpaFonts) << "Failed to create fallback font descriptor for" << family; + return nullptr; + } + + // If the font is not available we want to fall back to the style hint. + // By creating a matching font descriptor we can verify whether the font + // is available or not, and avoid CTFontCreateWithFontDescriptor picking + // a default font for us based on incomplete information. + fontDescriptor = CTFontDescriptorCreateMatchingFontDescriptor(fontDescriptor, 0); + if (!fontDescriptor) + return nullptr; + + return fallbacksForDescriptor(fontDescriptor); } -// ### Replace this with QPlatformFontDatabase::isFamilyPopulated() in Qt 5.14 -Q_GUI_EXPORT extern bool qt_isFontFamilyPopulated(const QString &familyName); +CTFontDescriptorRef descriptorForFontType(CTFontUIFontType uiType) +{ + static const CGFloat kDefaultSizeForRequestedUIType = 0.0; + QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage( + uiType, kDefaultSizeForRequestedUIType, nullptr); + return CTFontCopyFontDescriptor(ctFont); +} + +CTFontDescriptorRef descriptorForStyle(QFont::StyleHint styleHint) +{ + switch (styleHint) { + case QFont::SansSerif: return descriptorForFamily("Helvetica"); + case QFont::Serif: return descriptorForFamily("Times New Roman"); + case QFont::Monospace: return descriptorForFamily("Menlo"); +#ifdef Q_OS_MACOS + case QFont::Cursive: return descriptorForFamily("Apple Chancery"); +#endif + case QFont::Fantasy: return descriptorForFamily("Zapfino"); + case QFont::TypeWriter: return descriptorForFamily("American Typewriter"); + case QFont::AnyStyle: Q_FALLTHROUGH(); + case QFont::System: return descriptorForFontType(kCTFontUIFontSystem); + default: return nullptr; // No matching font on this platform + } +} QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { Q_UNUSED(style); - Q_UNUSED(script); + + qCDebug(lcQpaFonts).nospace() << "Resolving fallbacks families for" + << (!family.isEmpty() ? qPrintable(QLatin1String(" family '%1' with").arg(family)) : "") + << " style hint " << styleHint; QMacAutoReleasePool pool; - static QHash<QString, QStringList> fallbackLists; - - if (!family.isEmpty()) { - QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(family)); - if (QCFType<CTFontDescriptorRef> fontDescriptor = CTFontDescriptorCreateWithAttributes(attributes)) { - if (QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(fontDescriptor, 12.0, 0)) { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; - - QCFType<CFArrayRef> cascadeList = (CFArrayRef) CTFontCopyDefaultCascadeListForLanguages(font, (CFArrayRef) languages); - if (cascadeList) { - QStringList fallbackList; - const int numCascades = CFArrayGetCount(cascadeList); - - int symbolIndex = -1; - int notoSansUniversalIndex = -1; - for (int i = 0; i < numCascades; ++i) { - CTFontDescriptorRef fontFallback = (CTFontDescriptorRef) CFArrayGetValueAtIndex(cascadeList, i); - QCFString fallbackFamilyName = (CFStringRef) CTFontDescriptorCopyAttribute(fontFallback, kCTFontFamilyNameAttribute); - - QString fallbackName = QString::fromCFString(fallbackFamilyName); - fallbackList.append(fallbackName); - - if (!qt_isFontFamilyPopulated(fallbackName)) - const_cast<QCoreTextFontDatabase *>(this)->populateFromDescriptor(fontFallback, fallbackName); - - if (fallbackName == QLatin1String(".Apple Symbols Fallback")) - symbolIndex = fallbackList.size() - 1; - else if (fallbackName == QLatin1String(".Noto Sans Universal")) - notoSansUniversalIndex = fallbackList.size() - 1; - } - - // .Apple Symbols Fallback will be at the beginning of the list and we will - // detect that this has glyphs for Arabic and other writing systems. - // Since it is a symbol font, it should be the last resort, so that - // the proper fonts for these writing systems are preferred. - if (symbolIndex >= 0) { - fallbackList.move(symbolIndex, fallbackList.size() - 1); - if (notoSansUniversalIndex > symbolIndex) - --notoSansUniversalIndex; - } - - // .Noto Sans Universal appears to have a bug when the application - // does not have a valid Info.plist, which causes it to return glyph #4 - // (a question mark) for any character. - if (notoSansUniversalIndex >= 0) - fallbackList.move(notoSansUniversalIndex, fallbackList.size() - 1); - - addExtraFallbacks(&fallbackList); - - extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &); - fallbackList = qt_sort_families_by_writing_system(script, fallbackList); - - return fallbackList; - } - } + QStringList fallbackList; + + QCFType<CFArrayRef> fallbackFonts = fallbacksForFamily(family); + if (!fallbackFonts || !CFArrayGetCount(fallbackFonts)) { + // We were not able to find a fallback for the specific family, + // or the family was empty, so we fall back to the style hint. + if (!family.isEmpty()) + qCDebug(lcQpaFonts) << "No fallbacks found. Using style hint instead"; + + if (QCFType<CTFontDescriptorRef> styleDescriptor = descriptorForStyle(styleHint)) { + CFMutableArrayRef tmp = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(tmp, styleDescriptor); + QCFType<CFArrayRef> styleFallbacks = fallbacksForDescriptor(styleDescriptor); + CFArrayAppendArray(tmp, styleFallbacks, CFRangeMake(0, CFArrayGetCount(styleFallbacks))); + fallbackFonts = tmp; } } - // We were not able to find a fallback for the specific family, - // so we fall back to the stylehint. - - static const QString styleLookupKey = QString::fromLatin1(".QFontStyleHint_%1"); - - static bool didPopulateStyleFallbacks = false; - if (!didPopulateStyleFallbacks) { -#if defined(Q_OS_MACX) - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSArray<NSString *> *languages = [defaults stringArrayForKey:@"AppleLanguages"]; - - NSDictionary<NSString *, id> *fallbackDict = [NSDictionary<NSString *, id> dictionaryWithContentsOfFile:@"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreText.framework/Resources/DefaultFontFallbacks.plist"]; - - for (NSString *style in [fallbackDict allKeys]) { - NSArray *list = [fallbackDict valueForKey:style]; - QFont::StyleHint fallbackStyleHint = styleHintFromNSString(style); - QStringList fallbackList; - for (id item in list) { - // sort the array based on system language preferences - if ([item isKindOfClass:[NSArray class]]) { - NSArray *langs = [reinterpret_cast<NSArray *>(item) - sortedArrayUsingFunction:languageMapSort context:languages]; - for (NSArray<NSString *> *map in langs) - fallbackList.append(familyNameFromPostScriptName([map objectAtIndex:1])); - } - else if ([item isKindOfClass: [NSString class]]) - fallbackList.append(familyNameFromPostScriptName(item)); - } + if (!fallbackFonts) + return fallbackList; + + const int numberOfFallbacks = CFArrayGetCount(fallbackFonts); + for (int i = 0; i < numberOfFallbacks; ++i) { + auto fallbackDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fallbackFonts, i)); + auto fallbackFamilyName = QCFString(CTFontDescriptorCopyAttribute(fallbackDescriptor, kCTFontFamilyNameAttribute)); + + if (!isFamilyPopulated(fallbackFamilyName)) { + // We need to populate, or at least register the fallback fonts, + // otherwise the Qt font database may not know they exist. + if (isPrivateFontFamily(fallbackFamilyName)) + const_cast<QCoreTextFontDatabase *>(this)->populateFromDescriptor(fallbackDescriptor); + else + registerFontFamily(fallbackFamilyName); + } - fallbackList.append(QLatin1String("Apple Color Emoji")); + fallbackList.append(fallbackFamilyName); + } - addExtraFallbacks(&fallbackList); - fallbackLists[styleLookupKey.arg(fallbackStyleHint)] = fallbackList; - } -#else - QStringList staticFallbackList; - staticFallbackList << QString::fromLatin1("Helvetica,Apple Color Emoji,Geeza Pro,Arial Hebrew,Thonburi,Kailasa" - "Hiragino Kaku Gothic ProN,.Heiti J,Apple SD Gothic Neo,.Heiti K,Heiti SC,Heiti TC" - "Bangla Sangam MN,Devanagari Sangam MN,Gujarati Sangam MN,Gurmukhi MN,Kannada Sangam MN" - "Malayalam Sangam MN,Oriya Sangam MN,Sinhala Sangam MN,Tamil Sangam MN,Telugu Sangam MN" - "Euphemia UCAS,.PhoneFallback").split(QLatin1String(",")); - - for (int i = QFont::Helvetica; i <= QFont::Fantasy; ++i) - fallbackLists[styleLookupKey.arg(i)] = staticFallbackList; + // Some fallback fonts will have have an order in the list returned + // by Core Text that would indicate they should be preferred for e.g. + // Arabic, or Emoji, while in reality only supporting a tiny subset + // of the required glyphs, or representing them by question marks. + // Move these to the end, so that the proper fonts are preferred. + for (const char *family : { ".Apple Symbols Fallback", ".Noto Sans Universal" }) { + int index = fallbackList.indexOf(QLatin1String(family)); + if (index >= 0) + fallbackList.move(index, fallbackList.size() - 1); + } + +#if defined(Q_OS_MACOS) + // Since we are only returning a list of default fonts for the current language, we do not + // cover all Unicode completely. This was especially an issue for some of the common script + // symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk + // of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most + // of Unicode 2.1. + if (!fallbackList.contains(QStringLiteral("Arial Unicode MS"))) + fallbackList.append(QStringLiteral("Arial Unicode MS")); + // Since some symbols (specifically Braille) are not in Arial Unicode MS, we + // add Apple Symbols to cover those too. + if (!fallbackList.contains(QStringLiteral("Apple Symbols"))) + fallbackList.append(QStringLiteral("Apple Symbols")); #endif - didPopulateStyleFallbacks = true; - } + extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &); + fallbackList = qt_sort_families_by_writing_system(script, fallbackList); - Q_ASSERT(!fallbackLists.isEmpty()); - return fallbackLists[styleLookupKey.arg(styleHint)]; + qCDebug(lcQpaFonts).nospace() << "Fallback families ordered by script " << script << ": " << fallbackList; + + return fallbackList; } QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) @@ -733,10 +747,8 @@ static CTFontDescriptorRef fontDescriptorFromTheme(QPlatformTheme::Font f) } #endif // Q_OS_IOS, Q_OS_TVOS, Q_OS_WATCHOS - // OSX default case and iOS fallback case - CTFontUIFontType fontType = fontTypeFromTheme(f); - QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage(fontType, 0.0, NULL); - return CTFontCopyFontDescriptor(ctFont); + // macOS default case and iOS fallback case + return descriptorForFontType(fontTypeFromTheme(f)); } const QHash<QPlatformTheme::Font, QFont *> &QCoreTextFontDatabase::themeFonts() const @@ -769,8 +781,8 @@ QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const QFont QCoreTextFontDatabase::defaultFont() const { if (defaultFontName.isEmpty()) { - QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, 12.0, NULL); - defaultFontName = (QString) QCFString(CTFontCopyFullName(font)); + QCFType<CTFontDescriptorRef> systemFont = descriptorForFontType(kCTFontUIFontSystem); + defaultFontName = QCFString(CTFontDescriptorCopyAttribute(systemFont, kCTFontFamilyNameAttribute)); } return QFont(defaultFontName); diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index 05f6ed641c..eebb3eb964 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -71,7 +71,7 @@ public: QCoreTextFontDatabase(); ~QCoreTextFontDatabase(); void populateFontDatabase() override; - bool populateFamilyAliases() override; + bool populateFamilyAliases(const QString &missingFamily) override; void populateFamily(const QString &familyName) override; void invalidate() override; @@ -92,6 +92,7 @@ protected: private: void populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName = QString()); + static CFArrayRef fallbacksForFamily(const QString &family); mutable QString defaultFontName; diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index c523e799e6..011476cf13 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -53,6 +53,7 @@ #include <QtCore/QtEndian> #include <QtCore/QThreadStorage> #include <QtCore/private/qsystemlibrary_p.h> +#include <QtCore/private/qwinregistry_p.h> #include <wchar.h> @@ -1007,12 +1008,27 @@ static QChar *createFontFile(const QString &faceName) return faceNamePtr; } +namespace { + struct StoreFontPayload { + StoreFontPayload(const QString &family, + QWindowsFontDatabase *fontDatabase) + : populatedFontFamily(family) + , windowsFontDatabase(fontDatabase) + {} + + QString populatedFontFamily; + QSet<QPair<QString,QString> > foundFontAndStyles; + QWindowsFontDatabase *windowsFontDatabase; + }; +} + static bool addFontToDatabase(QString familyName, QString styleName, const LOGFONT &logFont, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, - int type) + int type, + StoreFontPayload *sfp) { // the "@family" fonts are just the same as "family". Ignore them. if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) @@ -1092,6 +1108,16 @@ static bool addFontToDatabase(QString familyName, writingSystems.setSupported(ws); } + // We came here from populating a different font family, so we have + // to ensure the entire typographic family is populated before we + // mark it as such inside registerFont() + if (!subFamilyName.isEmpty() + && familyName != subFamilyName + && sfp->populatedFontFamily != familyName + && !QPlatformFontDatabase::isFamilyPopulated(familyName)) { + sfp->windowsFontDatabase->populateFamily(familyName); + } + QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); @@ -1128,17 +1154,18 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t // to the documentation is identical to a TEXTMETRIC except for the last four // members, which we don't use anyway const FONTSIGNATURE *signature = nullptr; + StoreFontPayload *sfp = reinterpret_cast<StoreFontPayload *>(lparam); + Q_ASSERT(sfp != nullptr); if (type & TRUETYPE_FONTTYPE) { signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig; // We get a callback for each script-type supported, but we register them all // at once using the signature, so we only need one call to addFontToDatabase(). - QSet<QPair<QString,QString>> *foundFontAndStyles = reinterpret_cast<QSet<QPair<QString,QString>> *>(lparam); QPair<QString,QString> fontAndStyle(familyName, styleName); - if (foundFontAndStyles->contains(fontAndStyle)) + if (sfp->foundFontAndStyles.contains(fontAndStyle)) return 1; - foundFontAndStyles->insert(fontAndStyle); + sfp->foundFontAndStyles.insert(fontAndStyle); } - addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type); + addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp); // keep on enumerating return 1; @@ -1157,8 +1184,8 @@ void QWindowsFontDatabase::populateFamily(const QString &familyName) familyName.toWCharArray(lf.lfFaceName); lf.lfFaceName[familyName.size()] = 0; lf.lfPitchAndFamily = 0; - QSet<QPair<QString,QString>> foundFontAndStyles; - EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&foundFontAndStyles), 0); + StoreFontPayload sfp(familyName, this); + EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&sfp), 0); ReleaseDC(0, dummy); } @@ -1184,33 +1211,8 @@ static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TE void QWindowsFontDatabase::addDefaultEUDCFont() { - QString path; - { - HKEY key; - if (RegOpenKeyEx(HKEY_CURRENT_USER, - L"EUDC\\1252", - 0, - KEY_READ, - &key) != ERROR_SUCCESS) { - return; - } - - WCHAR value[MAX_PATH]; - DWORD bufferSize = sizeof(value); - ZeroMemory(value, bufferSize); - - if (RegQueryValueEx(key, - L"SystemDefaultEUDCFont", - nullptr, - nullptr, - reinterpret_cast<LPBYTE>(value), - &bufferSize) == ERROR_SUCCESS) { - path = QString::fromWCharArray(value); - } - - RegCloseKey(key); - } - + const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)") + .stringValue(L"SystemDefaultEUDCFont"); if (!path.isEmpty()) { QFile file(path); if (!file.open(QIODevice::ReadOnly)) { @@ -1338,11 +1340,11 @@ QT_WARNING_POP if (request.family != fontEngine->fontDef.family) { qWarning("%s: Failed to load font. Got fallback instead: %s", __FUNCTION__, qPrintable(fontEngine->fontDef.family)); - if (fontEngine->ref.load() == 0) + if (fontEngine->ref.loadRelaxed() == 0) delete fontEngine; fontEngine = 0; } else { - Q_ASSERT(fontEngine->ref.load() == 0); + Q_ASSERT(fontEngine->ref.loadRelaxed() == 0); // Override the generated font name switch (fontEngine->type()) { @@ -1514,7 +1516,7 @@ 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); @@ -1598,8 +1600,9 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, TEXTMETRIC textMetrics; GetTextMetrics(hdc, &textMetrics); + StoreFontPayload sfp(familyName, this); addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j), - TRUETYPE_FONTTYPE); + TRUETYPE_FONTTYPE, &sfp); SelectObject(hdc, oldobj); DeleteObject(hfont); @@ -2078,28 +2081,6 @@ int QWindowsFontDatabase::defaultVerticalDPI() return vDPI; } -QString QWindowsFontDatabase::readRegistryString(HKEY parentHandle, const wchar_t *keyPath, const wchar_t *keyName) -{ - QString result; - HKEY handle = 0; - if (RegOpenKeyEx(parentHandle, keyPath, 0, KEY_READ, &handle) == ERROR_SUCCESS) { - // get the size and type of the value - DWORD dataType; - DWORD dataSize; - if (RegQueryValueEx(handle, keyName, 0, &dataType, 0, &dataSize) == ERROR_SUCCESS) { - if (dataType == REG_SZ || dataType == REG_EXPAND_SZ) { - dataSize += 2; // '\0' missing? - QVarLengthArray<unsigned char> data(dataSize); - data[dataSize - 2] = data[dataSize - 1] = '\0'; - if (RegQueryValueEx(handle, keyName, 0, 0, data.data(), &dataSize) == ERROR_SUCCESS) - result = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.data())); - } - } - RegCloseKey(handle); - } - return result; -} - bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const { return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family); diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp index fdef0f5ff1..a6b7fcf31e 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp @@ -48,7 +48,11 @@ #include <QtCore/QDir> #include <QtCore/QDirIterator> #include <QtCore/QSettings> +#if QT_CONFIG(regularexpression) #include <QtCore/QRegularExpression> +#else +#include <QtCore/QRegExp> +#endif #include <QtGui/QGuiApplication> #include <QtGui/QFontDatabase> diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h index b85a2dceee..f132e69d4d 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h @@ -96,6 +96,8 @@ public: QWindowsFontDatabase(); ~QWindowsFontDatabase() override; + void ensureFamilyPopulated(const QString &familyName); + void populateFontDatabase() override; void populateFamily(const QString &familyName) override; QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; @@ -131,8 +133,6 @@ public: static void setFontOptions(unsigned options); static unsigned fontOptions(); - static QString readRegistryString(HKEY parentHandle, const wchar_t *keyPath, const wchar_t *keyName); - private: void removeApplicationFonts(); void addDefaultEUDCFont(); diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp index a4490a6664..e796c18e79 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp @@ -47,6 +47,7 @@ #include <QtCore/QFile> #include <private/qstringiterator_p.h> #include <QtCore/private/qsystemlibrary_p.h> +#include <QtCore/private/qwinregistry_p.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> #include <QtGui/private/qhighdpiscaling_p.h> @@ -945,10 +946,10 @@ void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName) { - const wchar_t key[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"; const QString substitute = - QWindowsFontDatabase::readRegistryString(HKEY_LOCAL_MACHINE, key, - reinterpret_cast<const wchar_t *>(familyName.utf16())); + QWinRegistryKey(HKEY_LOCAL_MACHINE, + LR"(Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes)") + .stringValue(familyName); return substitute.isEmpty() ? familyName : substitute; } diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri index 9c529f55ea..7ddfb2c281 100644 --- a/src/platformsupport/fontdatabases/windows/windows.pri +++ b/src/platformsupport/fontdatabases/windows/windows.pri @@ -30,5 +30,5 @@ qtConfig(directwrite):qtConfig(direct2d) { DEFINES *= QT_NO_DIRECTWRITE } -LIBS += -lole32 -lgdi32 -luser32 -ladvapi32 -mingw: LIBS += -luuid +QMAKE_USE_PRIVATE += advapi32 ole32 user32 gdi32 +mingw: QMAKE_USE_PRIVATE += uuid diff --git a/src/platformsupport/fontdatabases/winrt/winrt.pri b/src/platformsupport/fontdatabases/winrt/winrt.pri index 7617df2e7a..1cd417c1fd 100644 --- a/src/platformsupport/fontdatabases/winrt/winrt.pri +++ b/src/platformsupport/fontdatabases/winrt/winrt.pri @@ -8,6 +8,4 @@ HEADERS += \ DEFINES += __WRL_NO_DEFAULT_LIB__ -LIBS += -lws2_32 - -QMAKE_USE_PRIVATE += dwrite_1 +QMAKE_USE_PRIVATE += dwrite_1 ws2_32 diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 5f16d00dad..81bccb1c25 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -317,7 +317,7 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, glXGetFBConfigAttrib(display, config, GLX_ALPHA_SIZE, &alphaSize); glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize); glXGetFBConfigAttrib(display, config, GLX_STENCIL_SIZE, &stencilSize); - glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleBuffers); + glXGetFBConfigAttrib(display, config, GLX_SAMPLE_BUFFERS_ARB, &sampleBuffers); glXGetFBConfigAttrib(display, config, GLX_STEREO, &stereo); if (flags & QGLX_SUPPORTS_SRGB) glXGetFBConfigAttrib(display, config, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable); @@ -356,7 +356,7 @@ void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, glXGetConfig(display, visualInfo, GLX_ALPHA_SIZE, &alphaSize); glXGetConfig(display, visualInfo, GLX_DEPTH_SIZE, &depthSize); glXGetConfig(display, visualInfo, GLX_STENCIL_SIZE, &stencilSize); - glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleBuffers); + glXGetConfig(display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &sampleBuffers); glXGetConfig(display, visualInfo, GLX_STEREO, &stereo); if (flags & QGLX_SUPPORTS_SRGB) glXGetConfig(display, visualInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable); diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp index 666613f09d..3555763b89 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); @@ -98,11 +98,12 @@ QEvdevKeyboardHandler::~QEvdevKeyboardHandler() unloadKeymap(); } -QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, +std::unique_ptr<QEvdevKeyboardHandler> QEvdevKeyboardHandler::create(const QString &device, const QString &specification, const QString &defaultKeymapFile) { - qCDebug(qLcEvdevKey) << "Try to create keyboard handler for" << device << specification; + qCDebug(qLcEvdevKey, "Try to create keyboard handler for \"%ls\" \"%ls\"", + qUtf16Printable(device), qUtf16Printable(specification)); QString keymapFile = defaultKeymapFile; int repeatDelay = 400; @@ -127,7 +128,7 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, grab = arg.mid(5).toInt(); } - qCDebug(qLcEvdevKey) << "Opening keyboard at" << device; + qCDebug(qLcEvdevKey, "Opening keyboard at %ls", qUtf16Printable(device)); QFdContainer fd(qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0)); if (fd.get() >= 0) { @@ -137,16 +138,16 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, ::ioctl(fd.get(), EVIOCSREP, kbdrep); } - return new QEvdevKeyboardHandler(device, fd, disableZap, enableCompose, keymapFile); + return std::unique_ptr<QEvdevKeyboardHandler>(new QEvdevKeyboardHandler(device, fd, disableZap, enableCompose, keymapFile)); } else { - qWarning("Cannot open keyboard input device '%s': %s", qPrintable(device), strerror(errno)); - return 0; + qErrnoWarning("Cannot open keyboard input device '%ls'", qUtf16Printable(device)); + return nullptr; } } void QEvdevKeyboardHandler::switchLed(int led, bool state) { - qCDebug(qLcEvdevKey) << "switchLed" << led << state; + qCDebug(qLcEvdevKey, "switchLed %d %d", led, int(state)); struct ::input_event led_ie; ::gettimeofday(&led_ie.time, 0); @@ -170,7 +171,7 @@ void QEvdevKeyboardHandler::readKeycode() return; } else if (result < 0) { if (errno != EINTR && errno != EAGAIN) { - qErrnoWarning(errno, "evdevkeyboard: Could not read from input device"); + qErrnoWarning("evdevkeyboard: Could not read from input device"); // If the device got disconnected, stop reading, otherwise we get flooded // by the above error over and over again. if (errno == ENODEV) { @@ -230,7 +231,7 @@ void QEvdevKeyboardHandler::processKeyEvent(int nativecode, int unicode, int qtc QWindowSystemInterface::handleExtendedKeyEvent(0, (isPress ? QEvent::KeyPress : QEvent::KeyRelease), qtcode, modifiers, nativecode + 8, 0, int(modifiers), - (unicode != 0xffff ) ? QString(unicode) : QString(), autoRepeat); + (unicode != 0xffff ) ? QString(QChar(unicode)) : QString(), autoRepeat); } QEvdevKeyboardHandler::KeycodeAction QEvdevKeyboardHandler::processKeycode(quint16 keycode, bool pressed, bool autorepeat) @@ -473,7 +474,7 @@ QEvdevKeyboardHandler::KeycodeAction QEvdevKeyboardHandler::processKeycode(quint void QEvdevKeyboardHandler::unloadKeymap() { - qCDebug(qLcEvdevKey) << "Unload current keymap and restore built-in"; + qCDebug(qLcEvdevKey, "Unload current keymap and restore built-in"); if (m_keymap && m_keymap != s_keymap_default) delete [] m_keymap; @@ -517,12 +518,12 @@ void QEvdevKeyboardHandler::unloadKeymap() bool QEvdevKeyboardHandler::loadKeymap(const QString &file) { - qCDebug(qLcEvdevKey) << "Loading keymap" << file; + qCDebug(qLcEvdevKey, "Loading keymap %ls", qUtf16Printable(file)); QFile f(file); if (!f.open(QIODevice::ReadOnly)) { - qWarning("Could not open keymap file '%s'", qPrintable(file)); + qWarning("Could not open keymap file '%ls'", qUtf16Printable(file)); return false; } @@ -541,7 +542,7 @@ bool QEvdevKeyboardHandler::loadKeymap(const QString &file) ds >> qmap_magic >> qmap_version >> qmap_keymap_size >> qmap_keycompose_size; if (ds.status() != QDataStream::Ok || qmap_magic != QEvdevKeyboardMap::FileMagic || qmap_version != 1 || qmap_keymap_size == 0) { - qWarning("'%s' is not a valid .qmap keymap file", qPrintable(file)); + qWarning("'%ls' is not a valid .qmap keymap file", qUtf16Printable(file)); return false; } @@ -557,7 +558,7 @@ bool QEvdevKeyboardHandler::loadKeymap(const QString &file) delete [] qmap_keymap; delete [] qmap_keycompose; - qWarning("Keymap file '%s' cannot be loaded.", qPrintable(file)); + qWarning("Keymap file '%ls' cannot be loaded.", qUtf16Printable(file)); return false; } diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h index 21e6d055a0..f92a2bf704 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h @@ -55,6 +55,8 @@ #include <QTimer> #include <QDataStream> +#include <memory> + QT_BEGIN_NAMESPACE class QSocketNotifier; @@ -134,13 +136,13 @@ class QFdContainer int m_fd; 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 @@ -168,7 +170,7 @@ public: SwitchConsoleMask = 0x0000007f }; - static QEvdevKeyboardHandler *create(const QString &device, + static std::unique_ptr<QEvdevKeyboardHandler> create(const QString &device, const QString &specification, const QString &defaultKeymapFile = QString()); diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp index e1659bc0d9..52d9c34b1c 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp @@ -39,6 +39,8 @@ #include "qevdevkeyboardmanager_p.h" +#include <QtInputSupport/private/qevdevutil_p.h> + #include <QStringList> #include <QCoreApplication> #include <QLoggingCategory> @@ -61,36 +63,24 @@ QEvdevKeyboardManager::QEvdevKeyboardManager(const QString &key, const QString & if (spec.isEmpty()) spec = specification; - QStringList args = spec.split(QLatin1Char(':')); - QStringList devices; - - foreach (const QString &arg, args) { - if (arg.startsWith(QLatin1String("/dev/"))) { - // if device is specified try to use it - devices.append(arg); - args.removeAll(arg); - } - } - - // build new specification without /dev/ elements - m_spec = args.join(QLatin1Char(':')); + auto parsed = QEvdevUtil::parseSpecification(spec); + m_spec = std::move(parsed.spec); // add all keyboards for devices specified in the argument list - foreach (const QString &device, devices) + for (const QString &device : qAsConst(parsed.devices)) addKeyboard(device); - if (devices.isEmpty()) { - qCDebug(qLcEvdevKey) << "evdevkeyboard: Using device discovery"; - m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Keyboard, this); - if (m_deviceDiscovery) { + if (parsed.devices.isEmpty()) { + qCDebug(qLcEvdevKey, "evdevkeyboard: Using device discovery"); + if (auto deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Keyboard, this)) { // scan and add already connected keyboards - const QStringList devices = m_deviceDiscovery->scanConnectedDevices(); + const QStringList devices = deviceDiscovery->scanConnectedDevices(); for (const QString &device : devices) addKeyboard(device); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceDetected, + connect(deviceDiscovery, &QDeviceDiscovery::deviceDetected, this, &QEvdevKeyboardManager::addKeyboard); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceRemoved, + connect(deviceDiscovery, &QDeviceDiscovery::deviceRemoved, this, &QEvdevKeyboardManager::removeKeyboard); } } @@ -98,36 +88,34 @@ QEvdevKeyboardManager::QEvdevKeyboardManager(const QString &key, const QString & QEvdevKeyboardManager::~QEvdevKeyboardManager() { - qDeleteAll(m_keyboards); - m_keyboards.clear(); } void QEvdevKeyboardManager::addKeyboard(const QString &deviceNode) { - qCDebug(qLcEvdevKey) << "Adding keyboard at" << deviceNode; - QEvdevKeyboardHandler *keyboard; - keyboard = QEvdevKeyboardHandler::create(deviceNode, m_spec, m_defaultKeymapFile); + qCDebug(qLcEvdevKey, "Adding keyboard at %ls", qUtf16Printable(deviceNode)); + auto keyboard = QEvdevKeyboardHandler::create(deviceNode, m_spec, m_defaultKeymapFile); if (keyboard) { - m_keyboards.insert(deviceNode, keyboard); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeKeyboard, m_keyboards.count()); + m_keyboards.add(deviceNode, std::move(keyboard)); + updateDeviceCount(); } else { - qWarning("Failed to open keyboard device %s", qPrintable(deviceNode)); + qWarning("Failed to open keyboard device %ls", qUtf16Printable(deviceNode)); } } void QEvdevKeyboardManager::removeKeyboard(const QString &deviceNode) { - if (m_keyboards.contains(deviceNode)) { - qCDebug(qLcEvdevKey) << "Removing keyboard at" << deviceNode; - QEvdevKeyboardHandler *keyboard = m_keyboards.value(deviceNode); - m_keyboards.remove(deviceNode); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeKeyboard, m_keyboards.count()); - delete keyboard; + if (m_keyboards.remove(deviceNode)) { + qCDebug(qLcEvdevKey, "Removing keyboard at %ls", qUtf16Printable(deviceNode)); + updateDeviceCount(); } } +void QEvdevKeyboardManager::updateDeviceCount() +{ + QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( + QInputDeviceManager::DeviceTypeKeyboard, m_keyboards.count()); +} + void QEvdevKeyboardManager::loadKeymap(const QString &file) { m_defaultKeymapFile = file; @@ -141,22 +129,22 @@ void QEvdevKeyboardManager::loadKeymap(const QString &file) if (arg.startsWith(QLatin1String("keymap="))) keymapFromSpec = arg.mid(7).toString(); } - foreach (QEvdevKeyboardHandler *handler, m_keyboards) { + for (const auto &keyboard : m_keyboards) { if (keymapFromSpec.isEmpty()) - handler->unloadKeymap(); + keyboard.handler->unloadKeymap(); else - handler->loadKeymap(keymapFromSpec); + keyboard.handler->loadKeymap(keymapFromSpec); } } else { - foreach (QEvdevKeyboardHandler *handler, m_keyboards) - handler->loadKeymap(file); + for (const auto &keyboard : m_keyboards) + keyboard.handler->loadKeymap(file); } } void QEvdevKeyboardManager::switchLang() { - foreach (QEvdevKeyboardHandler *handler, m_keyboards) - handler->switchLang(); + for (const auto &keyboard : m_keyboards) + keyboard.handler->switchLang(); } QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h index 326e438a7c..d91da330c3 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h @@ -53,6 +53,7 @@ #include "qevdevkeyboardhandler_p.h" +#include <QtInputSupport/private/devicehandlerlist_p.h> #include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h> #include <QObject> @@ -64,7 +65,7 @@ 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); @@ -74,9 +75,10 @@ public: void removeKeyboard(const QString &deviceNode); private: + void updateDeviceCount(); + QString m_spec; - QHash<QString,QEvdevKeyboardHandler*> m_keyboards; - QDeviceDiscovery *m_deviceDiscovery; + QtInputSupport::DeviceHandlerList<QEvdevKeyboardHandler> m_keyboards; QString m_defaultKeymapFile; }; diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index 86a4cd0076..6a53ad2088 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcEvdevMouse, "qt.qpa.input") -QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QString &specification) +std::unique_ptr<QEvdevMouseHandler> QEvdevMouseHandler::create(const QString &device, const QString &specification) { qCDebug(qLcEvdevMouse) << "create mouse handler for" << device << specification; @@ -91,10 +91,10 @@ QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QStr fd = qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); if (fd >= 0) { ::ioctl(fd, EVIOCGRAB, grab); - return new QEvdevMouseHandler(device, fd, abs, compression, jitterLimit); + return std::unique_ptr<QEvdevMouseHandler>(new QEvdevMouseHandler(device, fd, abs, compression, jitterLimit)); } else { qErrnoWarning(errno, "Cannot open mouse input device %s", qPrintable(device)); - return 0; + return nullptr; } } diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h b/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h index c7f2b04eb2..727f1a02f9 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h @@ -56,6 +56,8 @@ #include <QPoint> #include <QEvent> +#include <memory> + QT_BEGIN_NAMESPACE class QSocketNotifier; @@ -64,7 +66,7 @@ class QEvdevMouseHandler : public QObject { Q_OBJECT public: - static QEvdevMouseHandler *create(const QString &device, const QString &specification); + static std::unique_ptr<QEvdevMouseHandler> create(const QString &device, const QString &specification); ~QEvdevMouseHandler(); void readMouseData(); diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp index 06025c016e..daa52d690e 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp @@ -39,6 +39,8 @@ #include "qevdevmousemanager_p.h" +#include <QtInputSupport/private/qevdevutil_p.h> + #include <QStringList> #include <QGuiApplication> #include <QScreen> @@ -63,40 +65,32 @@ QEvdevMouseManager::QEvdevMouseManager(const QString &key, const QString &specif if (spec.isEmpty()) spec = specification; - QStringList args = spec.split(QLatin1Char(':')); - QStringList devices; + auto parsed = QEvdevUtil::parseSpecification(spec); + m_spec = std::move(parsed.spec); - foreach (const QString &arg, args) { - if (arg.startsWith(QLatin1String("/dev/"))) { - // if device is specified try to use it - devices.append(arg); - args.removeAll(arg); - } else if (arg.startsWith(QLatin1String("xoffset="))) { + for (const QStringRef &arg : qAsConst(parsed.args)) { + if (arg.startsWith(QLatin1String("xoffset="))) { m_xoffset = arg.mid(8).toInt(); } else if (arg.startsWith(QLatin1String("yoffset="))) { m_yoffset = arg.mid(8).toInt(); } } - // build new specification without /dev/ elements - m_spec = args.join(QLatin1Char(':')); - // add all mice for devices specified in the argument list - foreach (const QString &device, devices) + for (const QString &device : qAsConst(parsed.devices)) addMouse(device); - if (devices.isEmpty()) { - qCDebug(qLcEvdevMouse) << "evdevmouse: Using device discovery"; - m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Mouse | QDeviceDiscovery::Device_Touchpad, this); - if (m_deviceDiscovery) { + if (parsed.devices.isEmpty()) { + qCDebug(qLcEvdevMouse, "evdevmouse: Using device discovery"); + if (auto deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Mouse | QDeviceDiscovery::Device_Touchpad, this)) { // scan and add already connected keyboards - const QStringList devices = m_deviceDiscovery->scanConnectedDevices(); + const QStringList devices = deviceDiscovery->scanConnectedDevices(); for (const QString &device : devices) addMouse(device); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceDetected, + connect(deviceDiscovery, &QDeviceDiscovery::deviceDetected, this, &QEvdevMouseManager::addMouse); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceRemoved, + connect(deviceDiscovery, &QDeviceDiscovery::deviceRemoved, this, &QEvdevMouseManager::removeMouse); } } @@ -111,8 +105,6 @@ QEvdevMouseManager::QEvdevMouseManager(const QString &key, const QString &specif QEvdevMouseManager::~QEvdevMouseManager() { - qDeleteAll(m_mice); - m_mice.clear(); } void QEvdevMouseManager::clampPosition() @@ -159,31 +151,32 @@ void QEvdevMouseManager::handleWheelEvent(QPoint delta) void QEvdevMouseManager::addMouse(const QString &deviceNode) { - qCDebug(qLcEvdevMouse) << "Adding mouse at" << deviceNode; - QEvdevMouseHandler *handler = QEvdevMouseHandler::create(deviceNode, m_spec); + qCDebug(qLcEvdevMouse, "Adding mouse at %ls", qUtf16Printable(deviceNode)); + auto handler = QEvdevMouseHandler::create(deviceNode, m_spec); if (handler) { - connect(handler, &QEvdevMouseHandler::handleMouseEvent, + connect(handler.get(), &QEvdevMouseHandler::handleMouseEvent, this, &QEvdevMouseManager::handleMouseEvent); - connect(handler, &QEvdevMouseHandler::handleWheelEvent, + connect(handler.get(), &QEvdevMouseHandler::handleWheelEvent, this, &QEvdevMouseManager::handleWheelEvent); - m_mice.insert(deviceNode, handler); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypePointer, m_mice.count()); + m_mice.add(deviceNode, std::move(handler)); + updateDeviceCount(); } else { - qWarning("evdevmouse: Failed to open mouse device %s", qPrintable(deviceNode)); + qWarning("evdevmouse: Failed to open mouse device %ls", qUtf16Printable(deviceNode)); } } void QEvdevMouseManager::removeMouse(const QString &deviceNode) { - if (m_mice.contains(deviceNode)) { - qCDebug(qLcEvdevMouse) << "Removing mouse at" << deviceNode; - QEvdevMouseHandler *handler = m_mice.value(deviceNode); - m_mice.remove(deviceNode); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypePointer, m_mice.count()); - delete handler; + if (m_mice.remove(deviceNode)) { + qCDebug(qLcEvdevMouse, "Removing mouse at %ls", qUtf16Printable(deviceNode)); + updateDeviceCount(); } } +void QEvdevMouseManager::updateDeviceCount() +{ + QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( + QInputDeviceManager::DeviceTypePointer, m_mice.count()); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h index 13a8e3dec5..f5c32ed8b5 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h @@ -53,6 +53,8 @@ #include "qevdevmousehandler_p.h" +#include <QtInputSupport/private/devicehandlerlist_p.h> + #include <QObject> #include <QHash> #include <QSocketNotifier> @@ -65,7 +67,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, @@ -77,10 +79,10 @@ public: private: void clampPosition(); + void updateDeviceCount(); QString m_spec; - QHash<QString,QEvdevMouseHandler*> m_mice; - QDeviceDiscovery *m_deviceDiscovery; + QtInputSupport::DeviceHandlerList<QEvdevMouseHandler> m_mice; int m_x; int m_y; int m_xoffset; diff --git a/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp b/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp index b6051aaf3c..c86840b76c 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp +++ b/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp @@ -172,11 +172,11 @@ QEvdevTabletHandler::QEvdevTabletHandler(const QString &device, const QString &s setObjectName(QLatin1String("Evdev Tablet Handler")); - qCDebug(qLcEvdevTablet, "evdevtablet: using %s", qPrintable(device)); + qCDebug(qLcEvdevTablet, "evdevtablet: using %ls", qUtf16Printable(device)); m_fd = QT_OPEN(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); if (m_fd < 0) { - qErrnoWarning(errno, "evdevtablet: Cannot open input device %s", qPrintable(device)); + qErrnoWarning("evdevtablet: Cannot open input device %ls", qUtf16Printable(device)); return; } @@ -184,11 +184,11 @@ QEvdevTabletHandler::QEvdevTabletHandler(const QString &device, const QString &s if (grabSuccess) ioctl(m_fd, EVIOCGRAB, (void *) 0); else - qWarning("evdevtablet: %s: The device is grabbed by another process. No events will be read.", qPrintable(device)); + qWarning("evdevtablet: %ls: The device is grabbed by another process. No events will be read.", qUtf16Printable(device)); d = new QEvdevTabletData(this); if (!queryLimits()) - qWarning("evdevtablet: %s: Unset or invalid ABS limits. Behavior will be unspecified.", qPrintable(device)); + qWarning("evdevtablet: %ls: Unset or invalid ABS limits. Behavior will be unspecified.", qUtf16Printable(device)); m_notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); connect(m_notifier, &QSocketNotifier::activated, this, &QEvdevTabletHandler::readData); @@ -216,32 +216,32 @@ bool QEvdevTabletHandler::queryLimits() if (ok) { d->minValues.x = absInfo.minimum; d->maxValues.x = absInfo.maximum; - qCDebug(qLcEvdevTablet, "evdevtablet: %s: min X: %d max X: %d", qPrintable(m_device), + qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min X: %d max X: %d", qUtf16Printable(m_device), d->minValues.x, d->maxValues.x); } ok &= ioctl(m_fd, EVIOCGABS(ABS_Y), &absInfo) >= 0; if (ok) { d->minValues.y = absInfo.minimum; d->maxValues.y = absInfo.maximum; - qCDebug(qLcEvdevTablet, "evdevtablet: %s: min Y: %d max Y: %d", qPrintable(m_device), + qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min Y: %d max Y: %d", qUtf16Printable(m_device), d->minValues.y, d->maxValues.y); } if (ioctl(m_fd, EVIOCGABS(ABS_PRESSURE), &absInfo) >= 0) { d->minValues.p = absInfo.minimum; d->maxValues.p = absInfo.maximum; - qCDebug(qLcEvdevTablet, "evdevtablet: %s: min pressure: %d max pressure: %d", qPrintable(m_device), + qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min pressure: %d max pressure: %d", qUtf16Printable(m_device), d->minValues.p, d->maxValues.p); } if (ioctl(m_fd, EVIOCGABS(ABS_DISTANCE), &absInfo) >= 0) { d->minValues.d = absInfo.minimum; d->maxValues.d = absInfo.maximum; - qCDebug(qLcEvdevTablet, "evdevtablet: %s: min distance: %d max distance: %d", qPrintable(m_device), + qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min distance: %d max distance: %d", qUtf16Printable(m_device), d->minValues.d, d->maxValues.d); } char name[128]; if (ioctl(m_fd, EVIOCGNAME(sizeof(name) - 1), name) >= 0) { d->devName = QString::fromLocal8Bit(name); - qCDebug(qLcEvdevTablet, "evdevtablet: %s: device name: %s", qPrintable(m_device), name); + qCDebug(qLcEvdevTablet, "evdevtablet: %ls: device name: %s", qUtf16Printable(m_device), name); } return ok; } @@ -253,11 +253,11 @@ void QEvdevTabletHandler::readData() for (; ;) { int result = QT_READ(m_fd, reinterpret_cast<char*>(buffer) + n, sizeof(buffer) - n); if (!result) { - qWarning("evdevtablet: %s: Got EOF from input device", qPrintable(m_device)); + qWarning("evdevtablet: %ls: Got EOF from input device", qUtf16Printable(m_device)); return; } else if (result < 0) { if (errno != EINTR && errno != EAGAIN) { - qErrnoWarning(errno, "evdevtablet: %s: Could not read from input device", qPrintable(m_device)); + qErrnoWarning("evdevtablet: %ls: Could not read from input device", qUtf16Printable(m_device)); if (errno == ENODEV) { // device got disconnected -> stop reading delete m_notifier; m_notifier = 0; 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.cpp b/src/platformsupport/input/evdevtablet/qevdevtabletmanager.cpp index 90949408ac..d9888c5b97 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtabletmanager.cpp +++ b/src/platformsupport/input/evdevtablet/qevdevtabletmanager.cpp @@ -40,12 +40,15 @@ #include "qevdevtabletmanager_p.h" #include "qevdevtablethandler_p.h" +#include <QtInputSupport/private/qevdevutil_p.h> + #include <QStringList> #include <QGuiApplication> #include <QLoggingCategory> #include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h> #include <private/qguiapplication_p.h> #include <private/qinputdevicemanager_p_p.h> +#include <private/qmemory_p.h> QT_BEGIN_NAMESPACE @@ -64,34 +67,23 @@ QEvdevTabletManager::QEvdevTabletManager(const QString &key, const QString &spec if (spec.isEmpty()) spec = specification; - QStringList args = spec.split(QLatin1Char(':')); - QStringList devices; - - foreach (const QString &arg, args) { - if (arg.startsWith(QLatin1String("/dev/"))) { - devices.append(arg); - args.removeAll(arg); - } - } - - // build new specification without /dev/ elements - m_spec = args.join(QLatin1Char(':')); + auto parsed = QEvdevUtil::parseSpecification(spec); + m_spec = std::move(parsed.spec); - foreach (const QString &device, devices) + for (const QString &device : qAsConst(parsed.devices)) addDevice(device); // when no devices specified, use device discovery to scan and monitor - if (devices.isEmpty()) { - qCDebug(qLcEvdevTablet) << "evdevtablet: Using device discovery"; - m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Tablet, this); - if (m_deviceDiscovery) { - const QStringList devices = m_deviceDiscovery->scanConnectedDevices(); + if (parsed.devices.isEmpty()) { + qCDebug(qLcEvdevTablet, "evdevtablet: Using device discovery"); + if (auto deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Tablet, this)) { + const QStringList devices = deviceDiscovery->scanConnectedDevices(); for (const QString &device : devices) addDevice(device); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceDetected, + connect(deviceDiscovery, &QDeviceDiscovery::deviceDetected, this, &QEvdevTabletManager::addDevice); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceRemoved, + connect(deviceDiscovery, &QDeviceDiscovery::deviceRemoved, this, &QEvdevTabletManager::removeDevice); } } @@ -99,33 +91,32 @@ QEvdevTabletManager::QEvdevTabletManager(const QString &key, const QString &spec QEvdevTabletManager::~QEvdevTabletManager() { - qDeleteAll(m_activeDevices); } void QEvdevTabletManager::addDevice(const QString &deviceNode) { - qCDebug(qLcEvdevTablet) << "Adding device at" << deviceNode; - QEvdevTabletHandlerThread *handler; - handler = new QEvdevTabletHandlerThread(deviceNode, m_spec); + qCDebug(qLcEvdevTablet, "Adding device at %ls", qUtf16Printable(deviceNode)); + auto handler = qt_make_unique<QEvdevTabletHandlerThread>(deviceNode, m_spec); if (handler) { - m_activeDevices.insert(deviceNode, handler); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeTablet, m_activeDevices.count()); + m_activeDevices.add(deviceNode, std::move(handler)); + updateDeviceCount(); } else { - qWarning("evdevtablet: Failed to open tablet device %s", qPrintable(deviceNode)); + qWarning("evdevtablet: Failed to open tablet device %ls", qUtf16Printable(deviceNode)); } } void QEvdevTabletManager::removeDevice(const QString &deviceNode) { - if (m_activeDevices.contains(deviceNode)) { - qCDebug(qLcEvdevTablet) << "Removing device at" << deviceNode; - QEvdevTabletHandlerThread *handler = m_activeDevices.value(deviceNode); - m_activeDevices.remove(deviceNode); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeTablet, m_activeDevices.count()); - delete handler; + if (m_activeDevices.remove(deviceNode)) { + qCDebug(qLcEvdevTablet, "Removing device at %ls", qUtf16Printable(deviceNode)); + updateDeviceCount(); } } +void QEvdevTabletManager::updateDeviceCount() +{ + QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( + QInputDeviceManager::DeviceTypeTablet, m_activeDevices.count()); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h b/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h index cde91c55aa..bb18ffba04 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h +++ b/src/platformsupport/input/evdevtablet/qevdevtabletmanager_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include <QtInputSupport/private/devicehandlerlist_p.h> + #include <QObject> #include <QHash> #include <QSocketNotifier> @@ -63,16 +65,17 @@ 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); void removeDevice(const QString &deviceNode); private: + void updateDeviceCount(); + QString m_spec; - QDeviceDiscovery *m_deviceDiscovery; - QHash<QString, QEvdevTabletHandlerThread *> m_activeDevices; + QtInputSupport::DeviceHandlerList<QEvdevTabletHandlerThread> m_activeDevices; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index f86f80785e..c51db59e1f 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -49,6 +49,9 @@ #include <QtCore/private/qcore_unix_p.h> #include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/private/qguiapplication_p.h> + +#include <mutex> + #ifdef Q_OS_FREEBSD #include <dev/evdev/input.h> #else @@ -66,6 +69,7 @@ extern "C" { QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcEvdevTouch, "qt.qpa.input") +Q_LOGGING_CATEGORY(qLcEvents, "qt.qpa.input.events") /* android (and perhaps some other linux-derived stuff) don't define everything * in linux/input.h, so we'll need to do that ourselves. @@ -228,7 +232,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const } } - qCDebug(qLcEvdevTouch, "evdevtouch: Using device %s", qPrintable(device)); + qCDebug(qLcEvdevTouch, "evdevtouch: Using device %ls", qUtf16Printable(device)); m_fd = QT_OPEN(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); @@ -236,7 +240,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); connect(m_notify, &QSocketNotifier::activated, this, &QEvdevTouchScreenHandler::readData); } else { - qErrnoWarning(errno, "evdevtouch: Cannot open input device %s", qPrintable(device)); + qErrnoWarning("evdevtouch: Cannot open input device %ls", qUtf16Printable(device)); return; } @@ -266,8 +270,8 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const d->deviceNode = device; qCDebug(qLcEvdevTouch, - "evdevtouch: %s: Protocol type %c %s (%s), filtered=%s", - qPrintable(d->deviceNode), + "evdevtouch: %ls: Protocol type %c %s (%s), filtered=%s", + qUtf16Printable(d->deviceNode), d->m_typeB ? 'B' : 'A', mtdevStr, d->m_singleTouch ? "single" : "multi", d->m_filtered ? "yes" : "no"); @@ -279,7 +283,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const bool has_x_range = false, has_y_range = false; if (ioctl(m_fd, EVIOCGABS((d->m_singleTouch ? ABS_X : ABS_MT_POSITION_X)), &absInfo) >= 0) { - qCDebug(qLcEvdevTouch, "evdevtouch: %s: min X: %d max X: %d", qPrintable(device), + qCDebug(qLcEvdevTouch, "evdevtouch: %ls: min X: %d max X: %d", qUtf16Printable(device), absInfo.minimum, absInfo.maximum); d->hw_range_x_min = absInfo.minimum; d->hw_range_x_max = absInfo.maximum; @@ -287,7 +291,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const } if (ioctl(m_fd, EVIOCGABS((d->m_singleTouch ? ABS_Y : ABS_MT_POSITION_Y)), &absInfo) >= 0) { - qCDebug(qLcEvdevTouch, "evdevtouch: %s: min Y: %d max Y: %d", qPrintable(device), + qCDebug(qLcEvdevTouch, "evdevtouch: %ls: min Y: %d max Y: %d", qUtf16Printable(device), absInfo.minimum, absInfo.maximum); d->hw_range_y_min = absInfo.minimum; d->hw_range_y_max = absInfo.maximum; @@ -295,10 +299,10 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const } if (!has_x_range || !has_y_range) - qWarning("evdevtouch: %s: Invalid ABS limits, behavior unspecified", qPrintable(device)); + qWarning("evdevtouch: %ls: Invalid ABS limits, behavior unspecified", qUtf16Printable(device)); if (ioctl(m_fd, EVIOCGABS(ABS_PRESSURE), &absInfo) >= 0) { - qCDebug(qLcEvdevTouch, "evdevtouch: %s: min pressure: %d max pressure: %d", qPrintable(device), + qCDebug(qLcEvdevTouch, "evdevtouch: %ls: min pressure: %d max pressure: %d", qUtf16Printable(device), absInfo.minimum, absInfo.maximum); if (absInfo.maximum > absInfo.minimum) { d->hw_pressure_min = absInfo.minimum; @@ -309,7 +313,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const char name[1024]; if (ioctl(m_fd, EVIOCGNAME(sizeof(name) - 1), name) >= 0) { d->hw_name = QString::fromLocal8Bit(name); - qCDebug(qLcEvdevTouch, "evdevtouch: %s: device name: %s", qPrintable(device), name); + qCDebug(qLcEvdevTouch, "evdevtouch: %ls: device name: %s", qUtf16Printable(device), name); } // Fix up the coordinate ranges for am335x in case the kernel driver does not have them fixed. @@ -345,8 +349,8 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const if (mapping.load()) { d->m_screenName = mapping.screenNameForDeviceNode(d->deviceNode); if (!d->m_screenName.isEmpty()) - qCDebug(qLcEvdevTouch, "evdevtouch: Mapping device %s to screen %s", - qPrintable(d->deviceNode), qPrintable(d->m_screenName)); + qCDebug(qLcEvdevTouch, "evdevtouch: Mapping device %ls to screen %ls", + qUtf16Printable(d->deviceNode), qUtf16Printable(d->m_screenName)); } registerTouchDevice(); @@ -427,7 +431,7 @@ err: return; } else if (events < 0) { if (errno != EINTR && errno != EAGAIN) { - qErrnoWarning(errno, "evdevtouch: Could not read from input device"); + qErrnoWarning("evdevtouch: Could not read from input device"); if (errno == ENODEV) { // device got disconnected -> stop reading delete m_notify; m_notify = nullptr; @@ -536,6 +540,9 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) if (m_typeB) m_contacts[m_currentSlot].maj = m_currentData.maj; } else if (data->code == ABS_PRESSURE || data->code == ABS_MT_PRESSURE) { + if (Q_UNLIKELY(qLcEvents().isDebugEnabled())) + qCDebug(qLcEvents, "EV_ABS code 0x%x: pressure %d; bounding to [%d,%d]", + data->code, data->value, hw_pressure_min, hw_pressure_max); m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max); if (m_typeB || m_singleTouch) m_contacts[m_currentSlot].pressure = m_currentData.pressure; @@ -563,8 +570,9 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) if (!m_contacts.isEmpty() && m_contacts.constBegin().value().trackingId == -1) assignIds(); + std::unique_lock<QMutex> locker; if (m_filtered) - m_mutex.lock(); + locker = std::unique_lock<QMutex>{m_mutex}; // update timestamps m_lastTimeStamp = m_timeStamp; @@ -573,10 +581,11 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) m_lastTouchPoints = m_touchPoints; m_touchPoints.clear(); Qt::TouchPointStates combinedStates; + bool hasPressure = false; + + for (auto i = m_contacts.begin(), end = m_contacts.end(); i != end; /*erasing*/) { + auto it = i++; - QMutableHashIterator<int, Contact> it(m_contacts); - while (it.hasNext()) { - it.next(); Contact &contact(it.value()); if (!contact.state) @@ -599,17 +608,18 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) // Avoid reporting a contact in released state more than once. if (!m_typeB && contact.state == Qt::TouchPointReleased && !m_lastContacts.contains(key)) { - it.remove(); + m_contacts.erase(it); continue; } + if (contact.pressure) + hasPressure = true; + addTouchPoint(contact, &combinedStates); } // Now look for contacts that have disappeared since the last sync. - it = m_lastContacts; - while (it.hasNext()) { - it.next(); + for (auto it = m_lastContacts.begin(), end = m_lastContacts.end(); it != end; ++it) { Contact &contact(it.value()); int key = m_typeB ? it.key() : contact.trackingId; if (m_typeB) { @@ -626,9 +636,9 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) } // Remove contacts that have just been reported as released. - it = m_contacts; - while (it.hasNext()) { - it.next(); + for (auto i = m_contacts.begin(), end = m_contacts.end(); i != end; /*erasing*/) { + auto it = i++; + Contact &contact(it.value()); if (!contact.state) @@ -638,7 +648,7 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) if (m_typeB) contact.state = static_cast<Qt::TouchPointState>(0); else - it.remove(); + m_contacts.erase(it); } else { contact.state = Qt::TouchPointStationary; } @@ -649,11 +659,8 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) m_contacts.clear(); - if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary) + if (!m_touchPoints.isEmpty() && (hasPressure || combinedStates != Qt::TouchPointStationary)) reportPoints(); - - if (m_filtered) - m_mutex.unlock(); } m_lastEventType = data->type; @@ -778,6 +785,9 @@ void QEvdevTouchScreenData::reportPoints() tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1; else tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min); + + if (Q_UNLIKELY(qLcEvents().isDebugEnabled())) + qCDebug(qLcEvents) << "reporting" << tp; } // Let qguiapp pick the target window. diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp index 4cacbf03e5..bf2df93d11 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp @@ -40,12 +40,15 @@ #include "qevdevtouchmanager_p.h" #include "qevdevtouchhandler_p.h" +#include <QtInputSupport/private/qevdevutil_p.h> + #include <QStringList> #include <QGuiApplication> #include <QLoggingCategory> #include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h> #include <private/qguiapplication_p.h> #include <private/qinputdevicemanager_p_p.h> +#include <private/qmemory_p.h> QT_BEGIN_NAMESPACE @@ -64,34 +67,23 @@ QEvdevTouchManager::QEvdevTouchManager(const QString &key, const QString &specif if (spec.isEmpty()) spec = specification; - QStringList args = spec.split(QLatin1Char(':')); - QStringList devices; - - foreach (const QString &arg, args) { - if (arg.startsWith(QLatin1String("/dev/"))) { - devices.append(arg); - args.removeAll(arg); - } - } - - // build new specification without /dev/ elements - m_spec = args.join(QLatin1Char(':')); + auto parsed = QEvdevUtil::parseSpecification(spec); + m_spec = std::move(parsed.spec); - foreach (const QString &device, devices) + for (const QString &device : qAsConst(parsed.devices)) addDevice(device); // when no devices specified, use device discovery to scan and monitor - if (devices.isEmpty()) { - qCDebug(qLcEvdevTouch) << "evdevtouch: Using device discovery"; - m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Touchpad | QDeviceDiscovery::Device_Touchscreen, this); - if (m_deviceDiscovery) { - const QStringList devices = m_deviceDiscovery->scanConnectedDevices(); + if (parsed.devices.isEmpty()) { + qCDebug(qLcEvdevTouch, "evdevtouch: Using device discovery"); + if (auto deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Touchpad | QDeviceDiscovery::Device_Touchscreen, this)) { + const QStringList devices = deviceDiscovery->scanConnectedDevices(); for (const QString &device : devices) addDevice(device); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceDetected, + connect(deviceDiscovery, &QDeviceDiscovery::deviceDetected, this, &QEvdevTouchManager::addDevice); - connect(m_deviceDiscovery, &QDeviceDiscovery::deviceRemoved, + connect(deviceDiscovery, &QDeviceDiscovery::deviceRemoved, this, &QEvdevTouchManager::removeDevice); } } @@ -99,30 +91,24 @@ QEvdevTouchManager::QEvdevTouchManager(const QString &key, const QString &specif QEvdevTouchManager::~QEvdevTouchManager() { - qDeleteAll(m_activeDevices); } void QEvdevTouchManager::addDevice(const QString &deviceNode) { - qCDebug(qLcEvdevTouch) << "evdevtouch: Adding device at" << deviceNode; - QEvdevTouchScreenHandlerThread *handler; - handler = new QEvdevTouchScreenHandlerThread(deviceNode, m_spec); + qCDebug(qLcEvdevTouch, "evdevtouch: Adding device at %ls", qUtf16Printable(deviceNode)); + auto handler = qt_make_unique<QEvdevTouchScreenHandlerThread>(deviceNode, m_spec); if (handler) { - m_activeDevices.insert(deviceNode, handler); - connect(handler, &QEvdevTouchScreenHandlerThread::touchDeviceRegistered, this, &QEvdevTouchManager::updateInputDeviceCount); + connect(handler.get(), &QEvdevTouchScreenHandlerThread::touchDeviceRegistered, this, &QEvdevTouchManager::updateInputDeviceCount); + m_activeDevices.add(deviceNode, std::move(handler)); } else { - qWarning("evdevtouch: Failed to open touch device %s", qPrintable(deviceNode)); + qWarning("evdevtouch: Failed to open touch device %ls", qUtf16Printable(deviceNode)); } } void QEvdevTouchManager::removeDevice(const QString &deviceNode) { - if (m_activeDevices.contains(deviceNode)) { - qCDebug(qLcEvdevTouch) << "evdevtouch: Removing device at" << deviceNode; - QEvdevTouchScreenHandlerThread *handler = m_activeDevices.value(deviceNode); - m_activeDevices.remove(deviceNode); - delete handler; - + if (m_activeDevices.remove(deviceNode)) { + qCDebug(qLcEvdevTouch, "evdevtouch: Removing device at %ls", qUtf16Printable(deviceNode)); updateInputDeviceCount(); } } @@ -130,13 +116,13 @@ void QEvdevTouchManager::removeDevice(const QString &deviceNode) void QEvdevTouchManager::updateInputDeviceCount() { int registeredTouchDevices = 0; - Q_FOREACH (QEvdevTouchScreenHandlerThread *handler, m_activeDevices) { - if (handler->isTouchDeviceRegistered()) + for (const auto &device : m_activeDevices) { + if (device.handler->isTouchDeviceRegistered()) ++registeredTouchDevices; } - qCDebug(qLcEvdevTouch) << "evdevtouch: Updating QInputDeviceManager device count:" << registeredTouchDevices << " touch devices," - << m_activeDevices.count() - registeredTouchDevices << "pending handler(s)" ; + qCDebug(qLcEvdevTouch, "evdevtouch: Updating QInputDeviceManager device count: %d touch devices, %d pending handler(s)", + registeredTouchDevices, m_activeDevices.count() - registeredTouchDevices); QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( QInputDeviceManager::DeviceTypeTouch, registeredTouchDevices); diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h index e524c516f1..94ee05d900 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include <QtInputSupport/private/devicehandlerlist_p.h> + #include <QObject> #include <QHash> #include <QSocketNotifier> @@ -63,7 +65,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); @@ -73,8 +75,7 @@ public: private: QString m_spec; - QDeviceDiscovery *m_deviceDiscovery; - QHash<QString, QEvdevTouchScreenHandlerThread *> m_activeDevices; + QtInputSupport::DeviceHandlerList<QEvdevTouchScreenHandlerThread> m_activeDevices; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/libinput/qlibinputhandler.cpp b/src/platformsupport/input/libinput/qlibinputhandler.cpp index e5dc182bec..95dfb46d16 100644 --- a/src/platformsupport/input/libinput/qlibinputhandler.cpp +++ b/src/platformsupport/input/libinput/qlibinputhandler.cpp @@ -205,6 +205,9 @@ void QLibInputHandler::processEvent(libinput_event *ev) case LIBINPUT_EVENT_POINTER_MOTION: m_pointer->processMotion(libinput_event_get_pointer_event(ev)); break; + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + m_pointer->processAbsMotion(libinput_event_get_pointer_event(ev)); + break; case LIBINPUT_EVENT_POINTER_AXIS: m_pointer->processAxis(libinput_event_get_pointer_event(ev)); break; diff --git a/src/platformsupport/input/libinput/qlibinputpointer.cpp b/src/platformsupport/input/libinput/qlibinputpointer.cpp index c54b61fc66..db9e81b5df 100644 --- a/src/platformsupport/input/libinput/qlibinputpointer.cpp +++ b/src/platformsupport/input/libinput/qlibinputpointer.cpp @@ -103,6 +103,24 @@ void QLibInputPointer::processMotion(libinput_event_pointer *e) Qt::NoButton, QEvent::MouseMove, mods); } +void QLibInputPointer::processAbsMotion(libinput_event_pointer *e) +{ + QScreen * const primaryScreen = QGuiApplication::primaryScreen(); + const QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); + + const double x = libinput_event_pointer_get_absolute_x_transformed(e, g.width()); + const double y = libinput_event_pointer_get_absolute_y_transformed(e, g.height()); + + m_pos.setX(qBound(g.left(), qRound(g.left() + x), g.right())); + m_pos.setY(qBound(g.top(), qRound(g.top() + y), g.bottom())); + + Qt::KeyboardModifiers mods = QGuiApplicationPrivate::inputDeviceManager()->keyboardModifiers(); + + QWindowSystemInterface::handleMouseEvent(nullptr, m_pos, m_pos, m_buttons, + Qt::NoButton, QEvent::MouseMove, mods); + +} + void QLibInputPointer::processAxis(libinput_event_pointer *e) { double value; // default axis value is 15 degrees per wheel click diff --git a/src/platformsupport/input/libinput/qlibinputpointer_p.h b/src/platformsupport/input/libinput/qlibinputpointer_p.h index a7a66337f1..55d4a5f919 100644 --- a/src/platformsupport/input/libinput/qlibinputpointer_p.h +++ b/src/platformsupport/input/libinput/qlibinputpointer_p.h @@ -64,6 +64,7 @@ public: void processButton(libinput_event_pointer *e); void processMotion(libinput_event_pointer *e); + void processAbsMotion(libinput_event_pointer *e); void processAxis(libinput_event_pointer *e); void setPos(const QPoint &pos); 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/shared/devicehandlerlist_p.h b/src/platformsupport/input/shared/devicehandlerlist_p.h new file mode 100644 index 0000000000..97794d4d7d --- /dev/null +++ b/src/platformsupport/input/shared/devicehandlerlist_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** 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 QTINPUTSUPPORT_DEVICEHANDLERLIST_P_H +#define QTINPUTSUPPORT_DEVICEHANDLERLIST_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 <QString> + +#include <vector> +#include <memory> + +namespace QtInputSupport { + +template <typename Handler> +class DeviceHandlerList { +public: + struct Device { + QString deviceNode; + std::unique_ptr<Handler> handler; + }; + + void add(const QString &deviceNode, std::unique_ptr<Handler> handler) + { + v.push_back({deviceNode, std::move(handler)}); + } + + bool remove(const QString &deviceNode) + { + const auto deviceNodeMatches = [&] (const Device &d) { return d.deviceNode == deviceNode; }; + const auto it = std::find_if(v.cbegin(), v.cend(), deviceNodeMatches); + if (it == v.cend()) + return false; + v.erase(it); + return true; + } + + int count() const noexcept { return static_cast<int>(v.size()); } + + typename std::vector<Device>::const_iterator begin() const noexcept { return v.begin(); } + typename std::vector<Device>::const_iterator end() const noexcept { return v.end(); } + +private: + std::vector<Device> v; +}; + +} // QtInputSupport + +#endif // QTINPUTSUPPORT_DEVICEHANDLERLIST_P_H diff --git a/src/platformsupport/input/shared/qevdevutil.cpp b/src/platformsupport/input/shared/qevdevutil.cpp new file mode 100644 index 0000000000..74f8bcdc2b --- /dev/null +++ b/src/platformsupport/input/shared/qevdevutil.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins 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 "qevdevutil_p.h" + +QT_BEGIN_NAMESPACE + +namespace QEvdevUtil { + +ParsedSpecification parseSpecification(const QString &specification) +{ + ParsedSpecification result; + + result.args = specification.splitRef(QLatin1Char(':')); + + for (const QStringRef &arg : qAsConst(result.args)) { + if (arg.startsWith(QLatin1String("/dev/"))) { + // if device is specified try to use it + result.devices.append(arg.toString()); + } else { + // build new specification without /dev/ elements + result.spec += arg + QLatin1Char(':'); + } + } + + if (!result.spec.isEmpty()) + result.spec.chop(1); // remove trailing ':' + + return result; +} + +} // namespace QEvdevUtil + +QT_END_NAMESPACE diff --git a/src/platformsupport/input/shared/qevdevutil_p.h b/src/platformsupport/input/shared/qevdevutil_p.h new file mode 100644 index 0000000000..7d0a5af130 --- /dev/null +++ b/src/platformsupport/input/shared/qevdevutil_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins 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 QEVDEVUTIL_P_H +#define QEVDEVUTIL_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 <QString> +#include <QStringList> +#include <QVector> +#include <QStringRef> + +QT_BEGIN_NAMESPACE + +namespace QEvdevUtil { + +struct ParsedSpecification +{ + QString spec; + QStringList devices; + QVector<QStringRef> args; +}; + +ParsedSpecification parseSpecification(const QString &specification); + +} + +QT_END_NAMESPACE + +#endif // QEVDEVUTIL_P_H diff --git a/src/platformsupport/input/shared/shared.pri b/src/platformsupport/input/shared/shared.pri index 1443235244..c29d11e7d6 100644 --- a/src/platformsupport/input/shared/shared.pri +++ b/src/platformsupport/input/shared/shared.pri @@ -1,5 +1,8 @@ HEADERS += \ + $$PWD/devicehandlerlist_p.h \ + $$PWD/qevdevutil_p.h \ $$PWD/qtouchoutputmapping_p.h SOURCES += \ + $$PWD/qevdevutil.cpp \ $$PWD/qtouchoutputmapping.cpp diff --git a/src/platformsupport/input/tslib/qtslib.cpp b/src/platformsupport/input/tslib/qtslib.cpp index 7609416fea..e105f5ea98 100644 --- a/src/platformsupport/input/tslib/qtslib.cpp +++ b/src/platformsupport/input/tslib/qtslib.cpp @@ -57,38 +57,22 @@ 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")); - QByteArray device = qgetenv("TSLIB_TSDEVICE"); - - if (specification.startsWith(QLatin1String("/dev/"))) - device = specification.toLocal8Bit(); - - if (device.isEmpty()) - device = QByteArrayLiteral("/dev/input/event1"); - - m_dev = ts_open(device.constData(), 1); + m_dev = ts_setup(nullptr, 1); if (!m_dev) { - qErrnoWarning(errno, "ts_open() failed"); + qErrnoWarning(errno, "ts_setup() failed"); return; } - 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, &QSocketNotifier::activated, this, &QTsLibMouseHandler::readMouseData); - } else { - qErrnoWarning(errno, "tslib: Cannot open input device %s", device.constData()); - } +#ifdef TSLIB_VERSION_EVENTPATH /* also introduced in 1.15 */ + qCDebug(qLcTsLib) << "tslib device is" << ts_get_eventpath(m_dev); +#endif + m_notify = new QSocketNotifier(ts_fd(m_dev), QSocketNotifier::Read, this); + connect(m_notify, &QSocketNotifier::activated, this, &QTsLibMouseHandler::readMouseData); } QTsLibMouseHandler::~QTsLibMouseHandler() 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/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index fec59cfc7b..6121faf362 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -66,6 +66,8 @@ enum OutputConfiguration { int QKmsDevice::crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector) { + int candidate = -1; + for (int i = 0; i < connector->count_encoders; i++) { drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->encoders[i]); if (!encoder) { @@ -73,19 +75,30 @@ int QKmsDevice::crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr co continue; } + quint32 encoderId = encoder->encoder_id; + quint32 crtcId = encoder->crtc_id; quint32 possibleCrtcs = encoder->possible_crtcs; drmModeFreeEncoder(encoder); for (int j = 0; j < resources->count_crtcs; j++) { bool isPossible = possibleCrtcs & (1 << j); bool isAvailable = !(m_crtc_allocator & (1 << j)); - - if (isPossible && isAvailable) + // Preserve the existing CRTC -> encoder -> connector routing if + // any. It makes the initialization faster, and may be better + // since we have a very dumb picking algorithm. + bool isBestChoice = (!connector->encoder_id || + (connector->encoder_id == encoderId && + resources->crtcs[j] == crtcId)); + + if (isPossible && isAvailable && isBestChoice) { return j; + } else if (isPossible && isAvailable) { + candidate = j; + } } } - return -1; + return candidate; } static const char * const connector_type_names[] = { // must match DRM_MODE_CONNECTOR_* @@ -381,23 +394,26 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, if (!cloneSource.isEmpty()) qCDebug(qLcKmsDebug) << "Output" << connectorName << " clones output " << cloneSource; - const QByteArray fbsize = userConnectorConfig.value(QStringLiteral("size")).toByteArray().toLower(); QSize framebufferSize; - framebufferSize.setWidth(modes[selected_mode].hdisplay); - framebufferSize.setHeight(modes[selected_mode].vdisplay); - + bool framebufferSizeSet = false; + const QByteArray fbsize = userConnectorConfig.value(QStringLiteral("size")).toByteArray().toLower(); + if (!fbsize.isEmpty()) { + if (sscanf(fbsize.constData(), "%dx%d", &framebufferSize.rwidth(), &framebufferSize.rheight()) == 2) { #if QT_CONFIG(drm_atomic) - if (hasAtomicSupport()) { - if (sscanf(fbsize.constData(), "%dx%d", &framebufferSize.rwidth(), &framebufferSize.rheight()) != 2) { - qWarning("Framebuffer size format is invalid."); + if (hasAtomicSupport()) + framebufferSizeSet = true; +#endif + if (!framebufferSizeSet) + qWarning("Setting framebuffer size is only available with DRM atomic API"); + } else { + qWarning("Invalid framebuffer size '%s'", fbsize.constData()); } - } else { - qWarning("Setting framebuffer size is only available with DRM atomic API"); } -#else - if (fbsize.size()) - qWarning("Setting framebuffer size is only available with DRM atomic API"); -#endif + if (!framebufferSizeSet) { + framebufferSize.setWidth(modes[selected_mode].hdisplay); + framebufferSize.setHeight(modes[selected_mode].vdisplay); + } + qCDebug(qLcKmsDebug) << "Output" << connectorName << "framebuffer size is " << framebufferSize; QKmsOutput output; @@ -799,9 +815,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", @@ -848,6 +862,8 @@ void QKmsDevice::discoverPlanes() plane.crtcYPropertyId = prop->prop_id; } else if (!strcasecmp(prop->name, "zpos")) { plane.zposPropertyId = prop->prop_id; + } else if (!strcasecmp(prop->name, "blend_op")) { + plane.blendOpPropertyId = prop->prop_id; } }); diff --git a/src/platformsupport/kmsconvenience/qkmsdevice_p.h b/src/platformsupport/kmsconvenience/qkmsdevice_p.h index 14da6bb947..b1150e2875 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice_p.h +++ b/src/platformsupport/kmsconvenience/qkmsdevice_p.h @@ -178,6 +178,7 @@ struct QKmsPlane uint32_t crtcwidthPropertyId = 0; uint32_t crtcheightPropertyId = 0; uint32_t zposPropertyId = 0; + uint32_t blendOpPropertyId = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QKmsPlane::Rotations) diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp index 6e8cab93a2..4a83c6eb80 100644 --- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp +++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp @@ -2050,8 +2050,8 @@ QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int of int endOffset; QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset); - QStringList attributes = joined.split (QLatin1Char(';'), QString::SkipEmptyParts, Qt::CaseSensitive); - foreach (const QString &attr, attributes) { + const QStringList attributes = joined.split (QLatin1Char(';'), QString::SkipEmptyParts, Qt::CaseSensitive); + for (const QString &attr : attributes) { QStringList items; items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive); AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]); @@ -2069,14 +2069,13 @@ QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, in { QString mapped; QString joined; - QStringList attributes; QSpiAttributeSet map; int startOffset; int endOffset; joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset); - attributes = joined.split (QLatin1Char(';'), QString::SkipEmptyParts, Qt::CaseSensitive); - foreach (const QString& attr, attributes) { + const QStringList attributes = joined.split (QLatin1Char(';'), QString::SkipEmptyParts, Qt::CaseSensitive); + for (const QString& attr : attributes) { QStringList items; items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive); AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]); 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/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/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h index 7959f0c28a..f484795fbb 100644 --- a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h +++ b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h @@ -69,7 +69,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/dbusmenu/qdbusmenuregistrarproxy_p.h b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuregistrarproxy_p.h index c92de0a140..cffc080f87 100644 --- a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuregistrarproxy_p.h +++ b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuregistrarproxy_p.h @@ -92,15 +92,11 @@ public: public Q_SLOTS: // METHODS QDBusPendingReply<QString, QDBusObjectPath> GetMenuForWindow(uint windowId) { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(windowId); - return asyncCallWithArgumentList(QStringLiteral("GetMenuForWindow"), argumentList); + return asyncCall(QStringLiteral("GetMenuForWindow"), windowId); } QDBusReply<QString> GetMenuForWindow(uint windowId, QDBusObjectPath &menuObjectPath) { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(windowId); - QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("GetMenuForWindow"), argumentList); + QDBusMessage reply = call(QDBus::Block, QStringLiteral("GetMenuForWindow"), windowId); QList<QVariant> arguments = reply.arguments(); if (reply.type() == QDBusMessage::ReplyMessage && arguments.count() == 2) menuObjectPath = qdbus_cast<QDBusObjectPath>(arguments.at(1)); @@ -109,16 +105,12 @@ public Q_SLOTS: // METHODS QDBusPendingReply<> RegisterWindow(uint windowId, const QDBusObjectPath &menuObjectPath) { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(windowId) << QVariant::fromValue(menuObjectPath); - return asyncCallWithArgumentList(QStringLiteral("RegisterWindow"), argumentList); + return asyncCall(QStringLiteral("RegisterWindow"), windowId, menuObjectPath); } QDBusPendingReply<> UnregisterWindow(uint windowId) { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(windowId); - return asyncCallWithArgumentList(QStringLiteral("UnregisterWindow"), argumentList); + return asyncCall(QStringLiteral("UnregisterWindow"), windowId); } }; diff --git a/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h b/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h index 352b4aa5d6..2194a787eb 100644 --- a/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h +++ b/src/platformsupport/themes/genericunix/dbustray/qxdgnotificationproxy_p.h @@ -88,33 +88,28 @@ public: public: QXdgNotificationInterface(const QString &service, const QString &path, - const QDBusConnection &connection, QObject *parent = 0); + const QDBusConnection &connection, QObject *parent = nullptr); ~QXdgNotificationInterface(); public Q_SLOTS: // METHODS inline QDBusPendingReply<> closeNotification(uint id) { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(id); - return asyncCallWithArgumentList(QStringLiteral("CloseNotification"), argumentList); + return asyncCall(QStringLiteral("CloseNotification"), id); } inline QDBusPendingReply<QStringList> getCapabilities() { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QStringLiteral("GetCapabilities"), argumentList); + return asyncCall(QStringLiteral("GetCapabilities")); } inline QDBusPendingReply<QString, QString, QString, QString> getServerInformation() { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QStringLiteral("GetServerInformation"), argumentList); + return asyncCall(QStringLiteral("GetServerInformation")); } inline QDBusReply<QString> getServerInformation(QString &vendor, QString &version, QString &specVersion) { - QList<QVariant> argumentList; - QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("GetServerInformation"), argumentList); + QDBusMessage reply = call(QDBus::Block, QStringLiteral("GetServerInformation")); if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 4) { vendor = qdbus_cast<QString>(reply.arguments().at(1)); version = qdbus_cast<QString>(reply.arguments().at(2)); @@ -129,12 +124,7 @@ public Q_SLOTS: // METHODS const QVariantMap &hints, int timeout) { qCDebug(qLcTray) << appName << replacesId << appIcon << summary << body << actions << hints << timeout; - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(appName) << QVariant::fromValue(replacesId) << - QVariant::fromValue(appIcon) << QVariant::fromValue(summary) << - QVariant::fromValue(body) << QVariant::fromValue(actions) << - QVariant::fromValue(hints) << QVariant::fromValue(timeout); - return asyncCallWithArgumentList(QStringLiteral("Notify"), argumentList); + return asyncCall(QStringLiteral("Notify"), appName, replacesId, appIcon, summary, body, actions, hints, timeout); } Q_SIGNALS: diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index 6db25a90da..70d5616075 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -175,15 +175,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; } diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h index a5963b79ea..c0da9d8370 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h @@ -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; @@ -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/vkconvenience/qbasicvulkanplatforminstance.cpp b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp index b9c5669b3f..68340a3173 100644 --- a/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp +++ b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp @@ -330,6 +330,11 @@ bool QBasicPlatformVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevi return supported; } +void QBasicPlatformVulkanInstance::setDebugFilters(const QVector<QVulkanInstance::DebugFilter> &filters) +{ + m_debugFilters = filters; +} + void QBasicPlatformVulkanInstance::destroySurface(VkSurfaceKHR surface) const { if (m_destroySurface && surface) @@ -345,11 +350,11 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL defaultDebugCallbackFunc(VkDebugReportFlag const char *pMessage, void *pUserData) { - Q_UNUSED(flags); - Q_UNUSED(objectType); - Q_UNUSED(object); - Q_UNUSED(location); - Q_UNUSED(pUserData); + QBasicPlatformVulkanInstance *self = static_cast<QBasicPlatformVulkanInstance *>(pUserData); + for (QVulkanInstance::DebugFilter filter : *self->debugFilters()) { + if (filter(flags, objectType, object, location, messageCode, pLayerPrefix, pMessage)) + return VK_FALSE; + } // not categorized, just route to plain old qDebug qDebug("vkDebug: %s: %d: %s", pLayerPrefix, messageCode, pMessage); @@ -374,6 +379,7 @@ void QBasicPlatformVulkanInstance::setupDebugOutput() | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; dbgCallbackInfo.pfnCallback = defaultDebugCallbackFunc; + dbgCallbackInfo.pUserData = this; VkResult err = createDebugReportCallback(m_vkInst, &dbgCallbackInfo, nullptr, &m_debugCallback); if (err != VK_SUCCESS) diff --git a/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h index 566140b032..e59d9219fb 100644 --- a/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h +++ b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h @@ -73,7 +73,10 @@ public: QByteArrayList enabledExtensions() const override; PFN_vkVoidFunction getInstanceProcAddr(const char *name) override; bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + void setDebugFilters(const QVector<QVulkanInstance::DebugFilter> &filters) override; + void destroySurface(VkSurfaceKHR surface) const; + const QVector<QVulkanInstance::DebugFilter> *debugFilters() const { return &m_debugFilters; } protected: void loadVulkanLibrary(const QString &defaultLibraryName); @@ -105,6 +108,7 @@ private: VkDebugReportCallbackEXT m_debugCallback; PFN_vkDestroyDebugReportCallbackEXT m_vkDestroyDebugReportCallbackEXT; + QVector<QVulkanInstance::DebugFilter> m_debugFilters; }; QT_END_NAMESPACE diff --git a/src/platformsupport/vkconvenience/qvkconvenience.cpp b/src/platformsupport/vkconvenience/qvkconvenience.cpp index 462cdc9e0d..acde1d1bda 100644 --- a/src/platformsupport/vkconvenience/qvkconvenience.cpp +++ b/src/platformsupport/vkconvenience/qvkconvenience.cpp @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE \ingroup qpa */ +#if QT_CONFIG(opengl) VkFormat QVkConvenience::vkFormatFromGlFormat(uint glFormat) { using GlFormat = QOpenGLTexture::TextureFormat; @@ -211,5 +212,6 @@ VkFormat QVkConvenience::vkFormatFromGlFormat(uint glFormat) default: return VK_FORMAT_UNDEFINED; } } +#endif QT_END_NAMESPACE diff --git a/src/platformsupport/vkconvenience/qvkconvenience_p.h b/src/platformsupport/vkconvenience/qvkconvenience_p.h index 1dd1dfc4a7..580271b593 100644 --- a/src/platformsupport/vkconvenience/qvkconvenience_p.h +++ b/src/platformsupport/vkconvenience/qvkconvenience_p.h @@ -59,7 +59,9 @@ QT_BEGIN_NAMESPACE class QVkConvenience { public: +#if QT_CONFIG(opengl) static VkFormat vkFormatFromGlFormat(uint glFormat); +#endif }; QT_END_NAMESPACE |