diff options
Diffstat (limited to 'src')
19 files changed, 328 insertions, 91 deletions
diff --git a/src/3rdparty/xkbcommon/qt_attribution.json b/src/3rdparty/xkbcommon/qt_attribution.json index 8ee0df1b22..4be9b42917 100644 --- a/src/3rdparty/xkbcommon/qt_attribution.json +++ b/src/3rdparty/xkbcommon/qt_attribution.json @@ -6,6 +6,7 @@ "Description": "xkbcommon is a keymap compiler and support library which processes a reduced subset of keymaps as defined by the XKB specification.", "Homepage": "http://xkbcommon.org/", + "Version": "0.4.1", "License": "MIT Licenses (with no-advertisement clause)", "LicenseId": "MIT", "LicenseFile": "COPYING", diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index 0564683f48..b8b064d43b 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -98,11 +98,19 @@ #define QT_NO_QOBJECT #define QT_FEATURE_process -1 #define QT_FEATURE_regularexpression -1 -#define QT_FEATURE_renameat2 -1 +#ifdef __GLIBC_PREREQ +# define QT_FEATURE_renameat2 (__GLIBC_PREREQ(2, 28) ? 1 : -1) +#else +# define QT_FEATURE_renameat2 -1 +#endif #define QT_FEATURE_settings -1 #define QT_FEATURE_sharedmemory -1 #define QT_FEATURE_slog2 -1 -#define QT_FEATURE_statx -1 +#ifdef __GLIBC_PREREQ +# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1) +#else +# define QT_FEATURE_statx -1 +#endif #define QT_FEATURE_syslog -1 #define QT_NO_SYSTEMLOCALE #define QT_FEATURE_systemsemaphore -1 diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index d197688316..37cc40f577 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -2212,10 +2212,19 @@ static bool readEtcFile(QUnixOSVersion &v, const char *filename, return true; } -static bool readEtcOsRelease(QUnixOSVersion &v) +static bool readOsRelease(QUnixOSVersion &v) { - return readEtcFile(v, "/etc/os-release", QByteArrayLiteral("ID="), - QByteArrayLiteral("VERSION_ID="), QByteArrayLiteral("PRETTY_NAME=")); + QByteArray id = QByteArrayLiteral("ID="); + QByteArray versionId = QByteArrayLiteral("VERSION_ID="); + QByteArray prettyName = QByteArrayLiteral("PRETTY_NAME="); + + // man os-release(5) says: + // The file /etc/os-release takes precedence over /usr/lib/os-release. + // Applications should check for the former, and exclusively use its data + // if it exists, and only fall back to /usr/lib/os-release if it is + // missing. + return readEtcFile(v, "/etc/os-release", id, versionId, prettyName) || + readEtcFile(v, "/usr/lib/os-release", id, versionId, prettyName); } static bool readEtcLsbRelease(QUnixOSVersion &v) @@ -2297,7 +2306,7 @@ static bool readEtcDebianVersion(QUnixOSVersion &v) static bool findUnixOsVersion(QUnixOSVersion &v) { - if (readEtcOsRelease(v)) + if (readOsRelease(v)) return true; if (readEtcLsbRelease(v)) return true; diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 9d20ef5088..d0cd5449f0 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -91,7 +91,6 @@ extern "C" NSString *NSTemporaryDirectory(); # include <sys/syscall.h> # include <sys/sendfile.h> # include <linux/fs.h> -# include <linux/stat.h> // in case linux/fs.h is too old and doesn't define it: #ifndef FICLONE @@ -112,6 +111,7 @@ static int renameat2(int oldfd, const char *oldpath, int newfd, const char *newp # endif # if !QT_CONFIG(statx) && defined(SYS_statx) +# include <linux/stat.h> static int statx(int dirfd, const char *pathname, int flag, unsigned mask, struct statx *statxbuf) { return syscall(SYS_statx, dirfd, pathname, flag, mask, statxbuf); } # elif !QT_CONFIG(statx) && !defined(SYS_statx) diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp index 8cefa7a118..4c780a9294 100644 --- a/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -345,7 +345,6 @@ QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context) sizeof(GIdleTimerSource))); idleTimerSource->timerSource = timerSource; g_source_set_can_recurse(&idleTimerSource->source, true); - g_source_set_priority(&idleTimerSource->source, G_PRIORITY_DEFAULT_IDLE); g_source_attach(&idleTimerSource->source, mainContext); } diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h index 4157fbbd0e..f8b1ede943 100644 --- a/src/corelib/serialization/qxmlstream_p.h +++ b/src/corelib/serialization/qxmlstream_p.h @@ -1250,7 +1250,7 @@ bool QXmlStreamReaderPrivate::parse() state_stack[tos] = 0; return true; } else if (act > 0) { - if (++tos == stack_size-1) + if (++tos >= stack_size-1) reallocateStack(); Value &val = sym_stack[tos]; diff --git a/src/corelib/tools/qtimezoneprivate_mac.mm b/src/corelib/tools/qtimezoneprivate_mac.mm index fa0dd87cfc..d3c4fbe5da 100644 --- a/src/corelib/tools/qtimezoneprivate_mac.mm +++ b/src/corelib/tools/qtimezoneprivate_mac.mm @@ -227,7 +227,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinc QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const { // The native API only lets us search forward, so we need to find an early-enough start: - const NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::min(); + const NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::lowest(); const qint64 endSecs = beforeMSecsSinceEpoch / 1000; const int year = 366 * 24 * 3600; // a (long) year, in seconds NSTimeInterval prevSecs = endSecs; // sentinel for later check diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 2d1f0fa823..5d582551a7 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2053,7 +2053,7 @@ void QTextEngine::itemize() const layoutData->string.detach(); string = reinterpret_cast<const ushort *>(layoutData->string.unicode()); uc = string + offset; - e = uc + length; + e = string + length; *const_cast<ushort*>(uc) = 0x21B5; // visual line separator } break; diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index cf4be3df95..8de9760710 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -133,6 +133,8 @@ QByteArray QHttpNetworkRequest::uri(bool throughProxy) const QUrl copy = d->url; if (copy.path().isEmpty()) copy.setPath(QStringLiteral("/")); + else + format |= QUrl::NormalizePathSegments; QByteArray uri = copy.toEncoded(format); return uri; } diff --git a/src/plugins/platforminputcontexts/ibus/ibus.pro b/src/plugins/platforminputcontexts/ibus/ibus.pro index 9f6c848e6a..52836bb8b6 100644 --- a/src/plugins/platforminputcontexts/ibus/ibus.pro +++ b/src/plugins/platforminputcontexts/ibus/ibus.pro @@ -3,12 +3,14 @@ TARGET = ibusplatforminputcontextplugin QT += dbus gui-private SOURCES += $$PWD/qibusplatforminputcontext.cpp \ $$PWD/qibusproxy.cpp \ + $$PWD/qibusproxyportal.cpp \ $$PWD/qibusinputcontextproxy.cpp \ $$PWD/qibustypes.cpp \ $$PWD/main.cpp HEADERS += $$PWD/qibusplatforminputcontext.h \ $$PWD/qibusproxy.h \ + $$PWD/qibusproxyportal.h \ $$PWD/qibusinputcontextproxy.h \ $$PWD/qibustypes.h diff --git a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.Portal.xml b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.Portal.xml new file mode 100644 index 0000000000..1a5414d0ae --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.Portal.xml @@ -0,0 +1,10 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.IBus.Portal"> + <method name="CreateInputContext"> + <arg name="name" direction="in" type="s"/> + <arg name="context" direction="out" type="o"/> + </method> + </interface> +</node> diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index f339938f86..0e587965ca 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -50,6 +50,7 @@ #include <qpa/qwindowsysteminterface.h> #include "qibusproxy.h" +#include "qibusproxyportal.h" #include "qibusinputcontextproxy.h" #include "qibustypes.h" @@ -78,19 +79,23 @@ public: { delete context; delete bus; + delete portalBus; delete connection; } static QString getSocketPath(); - static QDBusConnection *createConnection(); + QDBusConnection *createConnection(); void initBus(); void createBusProxy(); QDBusConnection *connection; QIBusProxy *bus; + QIBusProxyPortal *portalBus; // bus and portalBus are alternative. QIBusInputContextProxy *context; + QDBusServiceWatcher serviceWatcher; + bool usePortal; // return value of shouldConnectIbusPortal bool valid; bool busConnected; QString predit; @@ -103,20 +108,25 @@ public: QIBusPlatformInputContext::QIBusPlatformInputContext () : d(new QIBusPlatformInputContextPrivate()) { - QString socketPath = QIBusPlatformInputContextPrivate::getSocketPath(); - QFile file(socketPath); - if (file.open(QFile::ReadOnly)) { + if (!d->usePortal) { + QString socketPath = QIBusPlatformInputContextPrivate::getSocketPath(); + QFile file(socketPath); + if (file.open(QFile::ReadOnly)) { #ifndef QT_NO_FILESYSTEMWATCHER - // If KDE session save is used or restart ibus-daemon, - // the applications could run before ibus-daemon runs. - // We watch the getSocketPath() to get the launching ibus-daemon. - m_socketWatcher.addPath(socketPath); - connect(&m_socketWatcher, SIGNAL(fileChanged(QString)), this, SLOT(socketChanged(QString))); + qCDebug(qtQpaInputMethods) << "socketWatcher.addPath" << socketPath; + // If KDE session save is used or restart ibus-daemon, + // the applications could run before ibus-daemon runs. + // We watch the getSocketPath() to get the launching ibus-daemon. + m_socketWatcher.addPath(socketPath); + connect(&m_socketWatcher, SIGNAL(fileChanged(QString)), this, SLOT(socketChanged(QString))); #endif + } + m_timer.setSingleShot(true); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(connectToBus())); } - m_timer.setSingleShot(true); - connect(&m_timer, SIGNAL(timeout()), this, SLOT(connectToBus())); + QObject::connect(&d->serviceWatcher, SIGNAL(serviceRegistered(QString)), this, SLOT(busRegistered(QString))); + QObject::connect(&d->serviceWatcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(busUnregistered(QString))); connectToContextSignals(); @@ -507,6 +517,9 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal QLocale QIBusPlatformInputContext::locale() const { + // d->locale is not updated when IBus portal is used + if (d->usePortal) + return QPlatformInputContext::locale(); return d->locale; } @@ -527,6 +540,22 @@ void QIBusPlatformInputContext::socketChanged(const QString &str) m_timer.start(100); } +void QIBusPlatformInputContext::busRegistered(const QString &str) +{ + qCDebug(qtQpaInputMethods) << "busRegistered"; + Q_UNUSED (str); + if (d->usePortal) { + connectToBus(); + } +} + +void QIBusPlatformInputContext::busUnregistered(const QString &str) +{ + qCDebug(qtQpaInputMethods) << "busUnregistered"; + Q_UNUSED (str); + d->busConnected = false; +} + // When getSocketPath() is modified, the bus is not established yet // so use m_timer. void QIBusPlatformInputContext::connectToBus() @@ -536,7 +565,7 @@ void QIBusPlatformInputContext::connectToBus() connectToContextSignals(); #ifndef QT_NO_FILESYSTEMWATCHER - if (m_socketWatcher.files().size() == 0) + if (!d->usePortal && m_socketWatcher.files().size() == 0) m_socketWatcher.addPath(QIBusPlatformInputContextPrivate::getSocketPath()); #endif } @@ -572,15 +601,34 @@ void QIBusPlatformInputContext::connectToContextSignals() } } +static inline bool checkRunningUnderFlatpak() +{ + return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty(); +} + +static bool shouldConnectIbusPortal() +{ + // honor the same env as ibus-gtk + return (checkRunningUnderFlatpak() || !qgetenv("IBUS_USE_PORTAL").isNull()); +} + QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate() : connection(0), bus(0), + portalBus(0), context(0), + usePortal(shouldConnectIbusPortal()), valid(false), busConnected(false), needsSurroundingText(false) { - valid = !QStandardPaths::findExecutable(QString::fromLocal8Bit("ibus-daemon"), QStringList()).isEmpty(); + if (usePortal) { + valid = true; + if (debug) + qDebug() << "use IBus portal"; + } else { + valid = !QStandardPaths::findExecutable(QString::fromLocal8Bit("ibus-daemon"), QStringList()).isEmpty(); + } if (!valid) return; initBus(); @@ -603,21 +651,40 @@ void QIBusPlatformInputContextPrivate::createBusProxy() if (!connection || !connection->isConnected()) return; - bus = new QIBusProxy(QLatin1String("org.freedesktop.IBus"), - QLatin1String("/org/freedesktop/IBus"), - *connection); - if (!bus->isValid()) { - qWarning("QIBusPlatformInputContext: invalid bus."); - return; + const char* ibusService = usePortal ? "org.freedesktop.portal.IBus" : "org.freedesktop.IBus"; + QDBusReply<QDBusObjectPath> ic; + if (usePortal) { + portalBus = new QIBusProxyPortal(QLatin1String(ibusService), + QLatin1String("/org/freedesktop/IBus"), + *connection); + if (!portalBus->isValid()) { + qWarning("QIBusPlatformInputContext: invalid portal bus."); + return; + } + + ic = portalBus->CreateInputContext(QLatin1String("QIBusInputContext")); + } else { + bus = new QIBusProxy(QLatin1String(ibusService), + QLatin1String("/org/freedesktop/IBus"), + *connection); + if (!bus->isValid()) { + qWarning("QIBusPlatformInputContext: invalid bus."); + return; + } + + ic = bus->CreateInputContext(QLatin1String("QIBusInputContext")); } - QDBusReply<QDBusObjectPath> ic = bus->CreateInputContext(QLatin1String("QIBusInputContext")); + serviceWatcher.removeWatchedService(ibusService); + serviceWatcher.setConnection(*connection); + serviceWatcher.addWatchedService(ibusService); + if (!ic.isValid()) { qWarning("QIBusPlatformInputContext: CreateInputContext failed."); return; } - context = new QIBusInputContextProxy(QLatin1String("org.freedesktop.IBus"), ic.value().path(), *connection); + context = new QIBusInputContextProxy(QLatin1String(ibusService), ic.value().path(), *connection); if (!context->isValid()) { qWarning("QIBusPlatformInputContext: invalid input context."); @@ -665,6 +732,8 @@ QString QIBusPlatformInputContextPrivate::getSocketPath() QDBusConnection *QIBusPlatformInputContextPrivate::createConnection() { + if (usePortal) + return new QDBusConnection(QDBusConnection::connectToBus(QDBusConnection::SessionBus, QLatin1String("QIBusProxy"))); QFile file(getSocketPath()); if (!file.open(QFile::ReadOnly)) diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h index 9b92b2e1f9..f37552b937 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h @@ -108,6 +108,8 @@ public Q_SLOTS: void showPreeditText(); void filterEventFinished(QDBusPendingCallWatcher *call); void socketChanged(const QString &str); + void busRegistered(const QString &str); + void busUnregistered(const QString &str); void connectToBus(); void globalEngineChanged(const QString &engine_name); diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp new file mode 100644 index 0000000000..50482e2d9a --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -N -p qibusproxyportal -c QIBusProxyPortal interfaces/org.freedesktop.IBus.Portal.xml + * + * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "qibusproxyportal.h" + +/* + * Implementation of interface class QIBusProxyPortal + */ + +QIBusProxyPortal::QIBusProxyPortal(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +QIBusProxyPortal::~QIBusProxyPortal() +{ +} + diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h new file mode 100644 index 0000000000..bdd1d9c395 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h @@ -0,0 +1,49 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -N -p qibusproxyportal -c QIBusProxyPortal interfaces/org.freedesktop.IBus.Portal.xml + * + * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef QIBUSPROXYPORTAL_H +#define QIBUSPROXYPORTAL_H + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface org.freedesktop.IBus.Portal + */ +class QIBusProxyPortal: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.freedesktop.IBus.Portal"; } + +public: + QIBusProxyPortal(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); + + ~QIBusProxyPortal(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<QDBusObjectPath> CreateInputContext(const QString &name) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(name); + return asyncCallWithArgumentList(QStringLiteral("CreateInputContext"), argumentList); + } + +Q_SIGNALS: // SIGNALS +}; + +#endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 612290c9bd..0f87109ada 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -72,6 +72,12 @@ #include <IOKit/graphics/IOGraphicsLib.h> +#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) +@interface NSApplication (MojaveForwardDeclarations) +@property (strong) NSAppearance *appearance NS_AVAILABLE_MAC(10_14); +@end +#endif + static void initResources() { Q_INIT_RESOURCE(qcocoaresources); @@ -133,6 +139,21 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) NSApplication *cocoaApplication = [QNSApplication sharedApplication]; qt_redirectNSApplicationSendEvent(); + if (__builtin_available(macOS 10.14, *)) { + // Disable dark appearance, unless the Info.plist or environment requests that it should be enabled + bool plistEnablesDarkAppearance = [[[NSBundle mainBundle] objectForInfoDictionaryKey: + @"NSRequiresAquaSystemAppearance"] boolValue]; + + bool hasEnvironmentRequiresAquaAppearance; + int environmentRequiresAquaAppearance = qEnvironmentVariableIntValue( + "QT_MAC_REQUIRES_AQUA_SYSTEM_APPEARANCE", &hasEnvironmentRequiresAquaAppearance); + bool environmentEnablesDarkAppearance = hasEnvironmentRequiresAquaAppearance + && environmentRequiresAquaAppearance == 0; + + if (!(plistEnablesDarkAppearance || environmentEnablesDarkAppearance)) + NSApp.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; + } + if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { // Applications launched from plain executables (without an app // bundle) are "background" applications that does not take keybaord diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index e73e6f3e61..c29eb29b7e 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -85,7 +85,8 @@ class QXcbBackingStore; class QXcbBackingStoreImage : public QXcbObject { public: - QXcbBackingStoreImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format); + QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size); + QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size, uint depth, QImage::Format format); ~QXcbBackingStoreImage() { destroy(true); } void resize(const QSize &size); @@ -109,10 +110,10 @@ public: xcb_shm_segment_info_t *shm_info = nullptr); private: - void createShmSegment(size_t segmentSize); - void destroyShmSegment(size_t segmentSize); + void init(const QSize &size, uint depth, QImage::Format format); - void create(const QSize &size, const xcb_format_t *fmt, QImage::Format format); + void createShmSegment(size_t segmentSize); + void destroyShmSegment(); void destroy(bool destroyShm); void ensureGC(xcb_drawable_t dst); @@ -120,10 +121,9 @@ private: void flushPixmap(const QRegion ®ion, bool fullRegion = false); void setClip(const QRegion ®ion); - xcb_window_t m_screen_root; - xcb_shm_segment_info_t m_shm_info; size_t m_segmentSize = 0; + QXcbBackingStore *m_backingStore = nullptr; xcb_image_t *m_xcb_image = nullptr; @@ -153,6 +153,9 @@ private: bool m_hasAlpha = false; bool m_clientSideScroll = false; + + const xcb_format_t *m_xcb_format = nullptr; + QImage::Format m_qimage_format = QImage::Format_Invalid; }; class QXcbGraphicsBuffer : public QPlatformGraphicsBuffer @@ -190,83 +193,108 @@ static inline size_t imageDataSize(const xcb_image_t *image) return static_cast<size_t>(image->stride) * image->height; } -QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) - : QXcbObject(screen->connection()) - , m_screen_root(screen->screen()->root) +QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size) + : QXcbObject(backingStore->connection()) + , m_backingStore(backingStore) { - const xcb_format_t *fmt = connection()->formatForDepth(depth); - Q_ASSERT(fmt); + auto window = static_cast<QXcbWindow *>(m_backingStore->window()->handle()); + init(size, window->depth(), window->imageFormat()); +} - memset(&m_shm_info, 0, sizeof m_shm_info); +QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size, + uint depth, QImage::Format format) + : QXcbObject(backingStore->connection()) + , m_backingStore(backingStore) +{ + init(size, depth, format); +} - m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha; +void QXcbBackingStoreImage::init(const QSize &size, uint depth, QImage::Format format) +{ + m_xcb_format = connection()->formatForDepth(depth); + Q_ASSERT(m_xcb_format); + + m_qimage_format = format; + m_hasAlpha = QImage::toPixelFormat(m_qimage_format).alphaUsage() == QPixelFormat::UsesAlpha; if (!m_hasAlpha) - create(size, fmt, qt_maybeAlphaVersionWithSameDepth(format)); - else - create(size, fmt, format); + m_qimage_format = qt_maybeAlphaVersionWithSameDepth(m_qimage_format); + + memset(&m_shm_info, 0, sizeof m_shm_info); + + resize(size); } void QXcbBackingStoreImage::resize(const QSize &size) { - xcb_format_t fmt; - fmt.depth = m_xcb_image->depth; - fmt.bits_per_pixel = m_xcb_image->bpp; - fmt.scanline_pad = m_xcb_image->scanline_pad; - memset(fmt.pad0, 0, sizeof(fmt.pad0)); destroy(false); - create(size, &fmt, m_qimage.format()); -} -void QXcbBackingStoreImage::create(const QSize &size, const xcb_format_t *fmt, QImage::Format format) -{ + auto byteOrder = QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST + : XCB_IMAGE_ORDER_LSB_FIRST; m_xcb_image = xcb_image_create(size.width(), size.height(), XCB_IMAGE_FORMAT_Z_PIXMAP, - fmt->scanline_pad, - fmt->depth, fmt->bits_per_pixel, 0, - QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST, + m_xcb_format->scanline_pad, + m_xcb_format->depth, + m_xcb_format->bits_per_pixel, + 0, byteOrder, XCB_IMAGE_ORDER_MSB_FIRST, 0, ~0, 0); const size_t segmentSize = imageDataSize(m_xcb_image); - if (!segmentSize) - return; if (connection()->hasShm()) { - if (m_shm_info.shmaddr && (m_segmentSize < segmentSize || m_segmentSize / 2 >= segmentSize)) - destroyShmSegment(m_segmentSize); - if (!m_shm_info.shmaddr) { - qCDebug(lcQpaXcb) << "creating shared memory" << segmentSize << "for" - << size << "depth" << fmt->depth << "bits" << fmt->bits_per_pixel; - createShmSegment(segmentSize); + if (segmentSize == 0) { + if (m_segmentSize > 0) { + destroyShmSegment(); + qCDebug(lcQpaXcb) << "[" << m_backingStore->window() + << "] destroyed SHM segment due to resize to" << size; + } + } else { + // Destroy shared memory segment if it is double (or more) of what we actually + // need with new window size. Or if the new size is bigger than what we currently + // have allocated. + if (m_shm_info.shmaddr && (m_segmentSize < segmentSize || m_segmentSize / 2 >= segmentSize)) + destroyShmSegment(); + if (!m_shm_info.shmaddr) { + qCDebug(lcQpaXcb) << "[" << m_backingStore->window() + << "] creating shared memory" << segmentSize << "bytes for" + << size << "depth" << m_xcb_format->depth << "bits" + << m_xcb_format->bits_per_pixel; + createShmSegment(segmentSize); + } } } - m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize); + if (segmentSize == 0) + return; - m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); + m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize); + m_qimage = QImage(static_cast<uchar *>(m_xcb_image->data), m_xcb_image->width, + m_xcb_image->height, m_xcb_image->stride, m_qimage_format); m_graphics_buffer = new QXcbGraphicsBuffer(&m_qimage); m_xcb_pixmap = xcb_generate_id(xcb_connection()); + auto xcbScreen = static_cast<QXcbScreen *>(m_backingStore->window()->screen()->handle()); xcb_create_pixmap(xcb_connection(), m_xcb_image->depth, m_xcb_pixmap, - m_screen_root, + xcbScreen->root(), m_xcb_image->width, m_xcb_image->height); } void QXcbBackingStoreImage::destroy(bool destroyShm) { - if (m_xcb_image->data) { - if (m_shm_info.shmaddr) { - if (destroyShm) - destroyShmSegment(m_segmentSize); - } else { - free(m_xcb_image->data); + if (m_xcb_image) { + if (m_xcb_image->data) { + if (m_shm_info.shmaddr) { + if (destroyShm) + destroyShmSegment(); + } else { + free(m_xcb_image->data); + } } + xcb_image_destroy(m_xcb_image); } - xcb_image_destroy(m_xcb_image); - if (m_gc) { xcb_free_gc(xcb_connection(), m_gc); m_gc = 0; @@ -276,8 +304,12 @@ void QXcbBackingStoreImage::destroy(bool destroyShm) delete m_graphics_buffer; m_graphics_buffer = nullptr; - xcb_free_pixmap(xcb_connection(), m_xcb_pixmap); - m_xcb_pixmap = 0; + if (m_xcb_pixmap) { + xcb_free_pixmap(xcb_connection(), m_xcb_pixmap); + m_xcb_pixmap = 0; + } + + m_qimage = QImage(); } void QXcbBackingStoreImage::flushScrolledRegion(bool clientSideScroll) @@ -420,11 +452,8 @@ bool QXcbBackingStoreImage::createSystemVShmSegment(QXcbConnection *c, size_t se return true; } -void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) +void QXcbBackingStoreImage::destroyShmSegment() { -#ifndef XCB_USE_SHM_FD - Q_UNUSED(segmentSize) -#endif auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) @@ -433,9 +462,9 @@ void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) #ifdef XCB_USE_SHM_FD if (connection()->hasShmFd()) { - if (munmap(m_shm_info.shmaddr, segmentSize) == -1) { + if (munmap(m_shm_info.shmaddr, m_segmentSize) == -1) { qCWarning(lcQpaXcb, "munmap() failed (%d: %s) for %p with size %zu", - errno, strerror(errno), m_shm_info.shmaddr, segmentSize); + errno, strerror(errno), m_shm_info.shmaddr, m_segmentSize); } } else #endif @@ -894,7 +923,7 @@ void QXcbBackingStore::recreateImage(QXcbWindow *win, const QSize &size) if (m_image) m_image->resize(size); else - m_image = new QXcbBackingStoreImage(win->xcbScreen(), size, win->depth(), win->imageFormat()); + m_image = new QXcbBackingStoreImage(this, size); // Slow path for bgr888 VNC: Create an additional image, paint into that and // swap R and B while copying to m_image after each paint. @@ -1024,7 +1053,7 @@ void QXcbSystemTrayBackingStore::recreateImage(QXcbWindow *win, const QSize &siz if (m_image) m_image->resize(size); else - m_image = new QXcbBackingStoreImage(screen, size, 32, QImage::Format_ARGB32_Premultiplied); + m_image = new QXcbBackingStoreImage(this, size, 32, QImage::Format_ARGB32_Premultiplied); #endif // QT_CONFIG(xcb_render) } diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index e18a08755b..44c7d22344 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -69,7 +69,7 @@ QImage::Format imageFormatForMasks(int depth, int bits_per_pixel, int red_mask, if (red_mask == 0xff && blue_mask == 0xff0000) return QImage::Format_RGBA8888_Premultiplied; #else - if (red_mask == 0xff000000 && blue_mask == 0xff00) + if (unsigned(red_mask) == unsigned(0xff000000) && blue_mask == 0xff00) return QImage::Format_RGBA8888_Premultiplied; #endif if (red_mask == 0x3ff && blue_mask == 0x3ff00000) @@ -90,7 +90,7 @@ QImage::Format imageFormatForMasks(int depth, int bits_per_pixel, int red_mask, if (red_mask == 0xff && blue_mask == 0xff0000) return QImage::Format_RGBX8888; #else - if (red_mask == 0xff000000 && blue_mask == 0xff00) + if (unsigned(red_mask) == unsigned(0xff000000) && blue_mask == 0xff00) return QImage::Format_RGBX8888; #endif break; diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index 52ca88891e..6de952a1d3 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -1022,6 +1022,16 @@ void QMessageBoxPrivate::detectEscapeButton() return; } + // If there are two buttons and one of them is the "Show Details..." + // button, then make the other one the escape button + if (buttons.count() == 2 && detailsButton) { + auto idx = buttons.indexOf(detailsButton); + if (idx != -1) { + detectedEscapeButton = buttons.at(1 - idx); + return; + } + } + // if the message box has one RejectRole button, make it the escape button for (auto *button : buttons) { if (buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) { |