From 79d7487c89aead1a736f75a5fbf8c154c09924e0 Mon Sep 17 00:00:00 2001 From: Kari Hormi Date: Thu, 10 Oct 2019 17:49:43 +0300 Subject: Fix cursor not showing in empty block preceding a table When an empty text block precedes a table in QTextEdit, the cursor in the said text block is drawn twice (in order to make sure that the cursor is drawn on top of the table) with inverted colors, resulting in nothing showing up. This commit checks for an empty block before the table and skips the first drawing of the cursor if that's what it finds. Fixes: QTBUG-62919 Change-Id: I828d06e0645007ac42e3f308a35868b4f0db1380 Reviewed-by: Edward Welbourne Reviewed-by: Ville Voutilainen --- src/gui/text/qtextdocumentlayout.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index cf02e2f9c8..65cafc7bc2 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -1336,8 +1336,12 @@ void QTextDocumentLayoutPrivate::drawBlock(const QPointF &offset, QPainter *pain tl->draw(painter, offset, selections, context.clip.isValid() ? (context.clip & clipRect) : clipRect); - if ((context.cursorPosition >= blpos && context.cursorPosition < blpos + bllen) - || (context.cursorPosition < -1 && !tl->preeditAreaText().isEmpty())) { + // if the block is empty and it precedes a table, do not draw the cursor. + // the cursor is drawn later after the table has been drawn so no need + // to draw it here. + if (!isEmptyBlockBeforeTable(frameIteratorForTextPosition(blpos)) + && ((context.cursorPosition >= blpos && context.cursorPosition < blpos + bllen) + || (context.cursorPosition < -1 && !tl->preeditAreaText().isEmpty()))) { int cpos = context.cursorPosition; if (cpos < -1) cpos = tl->preeditAreaPosition() - (cpos + 2); -- cgit v1.2.3 From c5e9d7e504172707f7705d03ae27006c45eb5eac Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 28 Aug 2019 16:09:25 +0200 Subject: Generate metatypes.json for QtCore, QtGui, and QtWidgets These libraries contain types which are exposed to QML from qtdeclarative. Change-Id: Ie0edaef94fcb40074b6f6b2ea1a1c3a77ed3e9a9 Reviewed-by: Simon Hausmann --- src/gui/gui.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 45c8c05162..decfb364cf 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -35,7 +35,7 @@ testcocoon { osx: LIBS_PRIVATE += -framework AppKit darwin: LIBS_PRIVATE += -framework CoreGraphics -CONFIG += simd optimize_full +CONFIG += simd optimize_full metatypes install_metatypes include(accessible/accessible.pri) include(kernel/kernel.pri) -- cgit v1.2.3 From 19f29802bf7daafacd0fd824c2a1349e80eac536 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Thu, 17 Oct 2019 13:25:06 +0200 Subject: Fix: QPainter off-by-one clipping for some non-integer scalings For some scalings, setClipRect(QRect) would produce a clip one pixel different from setClipRect(QRectF) because of different rounding. Ditto for setClipRegion. Fix by making sure to transform QRectFs instead of QRects. Fixes: QTBUG-78962 Fixes: QTBUG-78963 Change-Id: I0be721133858c30769ec6d81e978962a3d6b70cf Reviewed-by: Christoph Cullmann Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qpaintengine_raster.cpp | 2 +- src/gui/painting/qtransform.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 8c51981120..40c822076b 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1319,7 +1319,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) QPaintEngineEx::clip(rect, op); return; - } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) { + } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(QRectF(rect)).toRect(), op)) { QPaintEngineEx::clip(rect, op); return; } diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 7696da7d45..d75b66c50b 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1529,12 +1529,12 @@ QRegion QTransform::map(const QRegion &r) const QRegion res; if (m11() < 0 || m22() < 0) { for (const QRect &rect : r) - res += mapRect(rect); + res += mapRect(QRectF(rect)).toRect(); } else { QVarLengthArray rects; rects.reserve(r.rectCount()); for (const QRect &rect : r) { - QRect nr = mapRect(rect); + QRect nr = mapRect(QRectF(rect)).toRect(); if (!nr.isEmpty()) rects.append(nr); } -- cgit v1.2.3 From 1b6db1849477be30ef0ca52c288d358b911ea1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 14 Oct 2019 15:58:50 +0200 Subject: Propagate application termination requests through QPA Instead of having each platform plugin deal with application termination in their own weird ways, we now have a QPA API to signal that the system requested the application to terminate. On the QGuiApplication side this results in a Quit event being sent to the application, which triggers the default behavior of closing all app windows, and then finally calling QCoreApplication::quit(). The quit event replaces the misuse of a close event being sent to the application. Close events are documented as being sent to windows. The close events that are sent to individual windows as part of the quit process can be ignored. This will skip the final quit() of the application, and also inform the platform that the quit was not accepted, in case that should be propagated further. In the future the logic for closing windows should be unified between the various approaches in closeAllWindows, shouldQuit, and friends. Change-Id: I0ed7f1c0d3f0bf1a755e1dd4066e1575fc3a28e1 Reviewed-by: Paul Olav Tvete --- src/gui/kernel/qguiapplication.cpp | 23 +++++++++++++++++++++++ src/gui/kernel/qguiapplication_p.h | 2 ++ src/gui/kernel/qwindowsysteminterface.cpp | 6 ++++++ src/gui/kernel/qwindowsysteminterface.h | 3 +++ src/gui/kernel/qwindowsysteminterface_p.h | 3 ++- 5 files changed, 36 insertions(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 13de8af8b5..54f3996b6e 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1863,7 +1863,20 @@ bool QGuiApplication::event(QEvent *e) { if(e->type() == QEvent::LanguageChange) { setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight); + } else if (e->type() == QEvent::Quit) { + // Close open windows. This is done in order to deliver de-expose + // events while the event loop is still running. + for (QWindow *topLevelWindow : QGuiApplication::topLevelWindows()) { + // Already closed windows will not have a platform window, skip those + if (!topLevelWindow->handle()) + continue; + if (!topLevelWindow->close()) { + e->ignore(); + return true; + } + } } + return QCoreApplication::event(e); } @@ -1940,6 +1953,9 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast(e); QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); } break; + case QWindowSystemInterfacePrivate::ApplicationTermination: + QGuiApplicationPrivate::processApplicationTermination(e); + break; case QWindowSystemInterfacePrivate::FlushEvents: { QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast(e); QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); } @@ -3489,6 +3505,13 @@ bool QGuiApplicationPrivate::tryCloseRemainingWindows(QWindowList processedWindo return true; } +void QGuiApplicationPrivate::processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *windowSystemEvent) +{ + QEvent event(QEvent::Quit); + QGuiApplication::sendSpontaneousEvent(QGuiApplication::instance(), &event); + windowSystemEvent->eventAccepted = event.isAccepted(); +} + /*! \since 5.2 \fn Qt::ApplicationState QGuiApplication::applicationState() diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index e28607bad6..26f65b2f16 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -141,6 +141,8 @@ public: static void processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e); + static void processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *e); + static void updateFilteredScreenOrientation(QScreen *screen); static void reportScreenOrientationChange(QScreen *screen); static void processScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent *e); diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 5f61853a6d..4f1056e906 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -285,6 +285,12 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleApplicationStateChanged, Qt::Application QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } +QT_DEFINE_QPA_EVENT_HANDLER(bool, handleApplicationTermination) +{ + auto *e = new QWindowSystemInterfacePrivate::WindowSystemEvent(QWindowSystemInterfacePrivate::ApplicationTermination); + return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); +} + QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow *window, const QRect &newGeometry) : WindowSystemEvent(GeometryChange) , window(window) diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 4a0bc858a9..d5a4ad30d8 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -215,6 +215,9 @@ public: template static void handleApplicationStateChanged(Qt::ApplicationState newState, bool forcePropagate = false); + template + static bool handleApplicationTermination(); + #if QT_CONFIG(draganddrop) #if QT_DEPRECATED_SINCE(5, 11) QT_DEPRECATED static QPlatformDragQtResponse handleDrag(QWindow *window, const QMimeData *dropData, diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 55fd181ef0..6e4bce607e 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -99,7 +99,8 @@ public: ApplicationStateChanged = 0x19, FlushEvents = 0x20, WindowScreenChanged = 0x21, - SafeAreaMarginsChanged = 0x22 + SafeAreaMarginsChanged = 0x22, + ApplicationTermination = 0x23 }; class WindowSystemEvent { -- cgit v1.2.3 From cc4087b18a488ffb02105d31da6f05acad65b728 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 16 Oct 2019 15:24:07 +0200 Subject: Remove mapping from CJK/Latin to Common script in Harfbuzz NG The original commit message says this is to ensure compatibility with the old Harfbuzz, but since OpenType features such as kerning are often matched based on the writing system of the glyphs, it will break kerning (and other OpenType features) for text in these languages in some fonts. Even font that were successfully kerned by the old Harfbuzz are broken. To avoid regressing on finding cursor positions inside ligatures, we need to amend 9f837af9458ea4825b9a8061de444f62d8a7a048. This would enable cursor positions inside ligatures for languages where they are only used for cosmetic purposes, and this was generalized to Common and Greek at the time. This now has to be expanded to include all the writing systems that were previously covered by "Common". [ChangeLog][Text] Fixed kerning error with certain fonts. Fixes: QTBUG-77908 Change-Id: Id261fef05f86841b1533b7d87207c3d17e01e96e Reviewed-by: Simon Hausmann --- src/gui/text/qtextengine.cpp | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index b37353bf2c..209433dac5 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2125,22 +2125,7 @@ void QTextEngine::itemize() const } #if QT_CONFIG(harfbuzz) analysis = scriptAnalysis.data(); - if (qt_useHarfbuzzNG()) { - // ### pretend HB-old behavior for now - for (int i = 0; i < length; ++i) { - switch (analysis[i].script) { - case QChar::Script_Latin: - case QChar::Script_Hiragana: - case QChar::Script_Katakana: - case QChar::Script_Bopomofo: - case QChar::Script_Han: - analysis[i].script = QChar::Script_Common; - break; - default: - break; - } - } - } else { + if (!qt_useHarfbuzzNG()) { for (int i = 0; i < length; ++i) analysis[i].script = hbscript_to_script(script_to_hbscript(analysis[i].script)); } @@ -3619,7 +3604,12 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end, int clusterLength = 0; if (si->analysis.script != QChar::Script_Common && - si->analysis.script != QChar::Script_Greek) { + si->analysis.script != QChar::Script_Greek && + si->analysis.script != QChar::Script_Latin && + si->analysis.script != QChar::Script_Hiragana && + si->analysis.script != QChar::Script_Katakana && + si->analysis.script != QChar::Script_Bopomofo && + si->analysis.script != QChar::Script_Han) { if (glyph_pos == -1) return si->position + end; else { -- cgit v1.2.3 From 5288c8dae34ae3a3883f12c8fabeb717e1c5a263 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sun, 20 Oct 2019 18:06:07 +0200 Subject: rhi: Enhance swapchain size query docs Inspired by a recent Qt Quick fix. Make sure we make it clear that QRhi-based rendering code should base output size calculations (e.g. for setViewport() and similar) on the pixel size reported from QRhiSwapChain, instead of going to the QWindow. Change-Id: I2fc22972162ccc6307ac07ceb7766c746d5f562a Reviewed-by: Paul Olav Tvete --- src/gui/rhi/qrhi.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index dabad35688..8ef98d2e42 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -3518,14 +3518,36 @@ QRhiResource::Type QRhiSwapChain::resourceType() const \c{currentPixelSize() != surfacePixelSize()} then the swapchain needs to be resized. + \note Typical rendering logic will call this function to get the output + size when starting to prepare a new frame, and base dependent calculations + (such as, the viewport) on the size returned from this function. + + While in many cases the value is the same as \c{QWindow::size() * + QWindow::devicePixelRatio()}, relying on the QWindow-reported size is not + guaranteed to be correct on all platforms and graphics API implementations. + Using this function is therefore strongly recommended whenever there is a + need to identify the dimensions, in pixels, of the output layer or surface. + + This also has the added benefit of avoiding potential data races when QRhi + is used on a dedicated rendering thread, because the need to call QWindow + functions, that may then access data updated on the main thread, is + avoided. + \sa surfacePixelSize() */ /*! \fn QSize QRhiSwapChain::surfacePixelSize() - \return The size of the window's associated surface or layer. Do not assume - this is the same as QWindow::size() * QWindow::devicePixelRatio(). + \return The size of the window's associated surface or layer. + + \warning Do not assume this is the same as \c{QWindow::size() * + QWindow::devicePixelRatio()}. With some graphics APIs and windowing system + interfaces (for example, Vulkan) there is a theoretical possibility for a + surface to assume a size different from the associated window. To support + these cases, rendering logic must always base size-derived calculations + (such as, viewports) on the size reported from QRhiSwapChain, and never on + the size queried from QWindow. \note Can also be called before buildOrResize(), if at least window() is already set) This in combination with currentPixelSize() allows to detect -- cgit v1.2.3 From b61c6164c100defc519b178d73858df59cffc48d Mon Sep 17 00:00:00 2001 From: Hernan Martinez Date: Sat, 12 Oct 2019 02:40:29 -0400 Subject: QtGui: Disable Windows on ARM64 preprocessor conflict in QtOpenGL The Windows API MemoryBarrier function is actually a macro when _M_ARM64 is defined and it conflicts with the MemoryBarrier method when it's declared and used. Task-number: QTBUG-77388 Change-Id: I762edfc4ca1a44cbe095724de708c7cdad34ae65 Reviewed-by: Laszlo Agocs --- src/gui/opengl/qopenglfunctions_4_2_compatibility.h | 10 ++++++++++ src/gui/opengl/qopenglfunctions_4_2_core.h | 10 ++++++++++ src/gui/opengl/qopenglfunctions_4_3_compatibility.h | 10 ++++++++++ src/gui/opengl/qopenglfunctions_4_3_core.h | 11 +++++++++++ src/gui/opengl/qopenglfunctions_4_4_compatibility.h | 10 ++++++++++ src/gui/opengl/qopenglfunctions_4_4_core.h | 10 ++++++++++ src/gui/opengl/qopenglfunctions_4_5_compatibility.h | 10 ++++++++++ src/gui/opengl/qopenglfunctions_4_5_core.h | 11 +++++++++++ src/gui/opengl/qopenglversionfunctions.h | 10 ++++++++++ 9 files changed, 92 insertions(+) (limited to 'src/gui') diff --git a/src/gui/opengl/qopenglfunctions_4_2_compatibility.h b/src/gui/opengl/qopenglfunctions_4_2_compatibility.h index 6726d5fc44..a48d581c2d 100644 --- a/src/gui/opengl/qopenglfunctions_4_2_compatibility.h +++ b/src/gui/opengl/qopenglfunctions_4_2_compatibility.h @@ -57,6 +57,12 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QOpenGLFunctions_4_2_Compatibility : public QAbstractOpenGLFunctions @@ -5632,6 +5638,10 @@ inline void QOpenGLFunctions_4_2_Compatibility::glVertexAttribI1i(GLuint index, QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglfunctions_4_2_core.h b/src/gui/opengl/qopenglfunctions_4_2_core.h index a921329741..5ca98e9808 100644 --- a/src/gui/opengl/qopenglfunctions_4_2_core.h +++ b/src/gui/opengl/qopenglfunctions_4_2_core.h @@ -57,6 +57,12 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QOpenGLFunctions_4_2_Core : public QAbstractOpenGLFunctions @@ -3027,6 +3033,10 @@ inline void QOpenGLFunctions_4_2_Core::glDrawArraysInstancedBaseInstance(GLenum QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglfunctions_4_3_compatibility.h b/src/gui/opengl/qopenglfunctions_4_3_compatibility.h index b9d4eb1d6f..d969f5b3b4 100644 --- a/src/gui/opengl/qopenglfunctions_4_3_compatibility.h +++ b/src/gui/opengl/qopenglfunctions_4_3_compatibility.h @@ -57,6 +57,12 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QOpenGLFunctions_4_3_Compatibility : public QAbstractOpenGLFunctions @@ -5839,6 +5845,10 @@ inline void QOpenGLFunctions_4_3_Compatibility::glVertexAttribI1i(GLuint index, QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglfunctions_4_3_core.h b/src/gui/opengl/qopenglfunctions_4_3_core.h index da552d64af..13675caf62 100644 --- a/src/gui/opengl/qopenglfunctions_4_3_core.h +++ b/src/gui/opengl/qopenglfunctions_4_3_core.h @@ -57,6 +57,13 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QOpenGLFunctions_4_3_Core : public QAbstractOpenGLFunctions @@ -3230,6 +3237,10 @@ inline void QOpenGLFunctions_4_3_Core::glClearBufferData(GLenum target, GLenum i QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglfunctions_4_4_compatibility.h b/src/gui/opengl/qopenglfunctions_4_4_compatibility.h index 7a05bd802d..0acab349a1 100644 --- a/src/gui/opengl/qopenglfunctions_4_4_compatibility.h +++ b/src/gui/opengl/qopenglfunctions_4_4_compatibility.h @@ -59,6 +59,12 @@ QT_BEGIN_NAMESPACE +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + class Q_GUI_EXPORT QOpenGLFunctions_4_4_Compatibility : public QAbstractOpenGLFunctions { public: @@ -5961,6 +5967,10 @@ inline void QOpenGLFunctions_4_4_Compatibility::glVertexP2ui(GLenum type, GLuint QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglfunctions_4_4_core.h b/src/gui/opengl/qopenglfunctions_4_4_core.h index 6b29a9659b..1ad6f40214 100644 --- a/src/gui/opengl/qopenglfunctions_4_4_core.h +++ b/src/gui/opengl/qopenglfunctions_4_4_core.h @@ -57,6 +57,12 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QOpenGLFunctions_4_4_Core : public QAbstractOpenGLFunctions @@ -3415,6 +3421,10 @@ inline void QOpenGLFunctions_4_4_Core::glBufferStorage(GLenum target, GLsizeiptr QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglfunctions_4_5_compatibility.h b/src/gui/opengl/qopenglfunctions_4_5_compatibility.h index a809c1c90b..9d9d14548b 100644 --- a/src/gui/opengl/qopenglfunctions_4_5_compatibility.h +++ b/src/gui/opengl/qopenglfunctions_4_5_compatibility.h @@ -57,6 +57,12 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QOpenGLFunctions_4_5_Compatibility : public QAbstractOpenGLFunctions @@ -6679,6 +6685,10 @@ inline void QOpenGLFunctions_4_5_Compatibility::glGetnMapdv(GLenum target, GLenu QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglfunctions_4_5_core.h b/src/gui/opengl/qopenglfunctions_4_5_core.h index bb1b17f7b1..bf872c628b 100644 --- a/src/gui/opengl/qopenglfunctions_4_5_core.h +++ b/src/gui/opengl/qopenglfunctions_4_5_core.h @@ -57,6 +57,12 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QOpenGLFunctions_4_5_Core : public QAbstractOpenGLFunctions @@ -4056,6 +4062,11 @@ inline void QOpenGLFunctions_4_5_Core::glClipControl(GLenum origin, GLenum depth QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + + #endif // QT_NO_OPENGL && !QT_OPENGL_ES_2 #endif diff --git a/src/gui/opengl/qopenglversionfunctions.h b/src/gui/opengl/qopenglversionfunctions.h index f828e5668b..99c8565fbc 100644 --- a/src/gui/opengl/qopenglversionfunctions.h +++ b/src/gui/opengl/qopenglversionfunctions.h @@ -61,6 +61,12 @@ #include #include +// MemoryBarrier is a macro on some architectures on Windows +#ifdef Q_OS_WIN +#pragma push_macro("MemoryBarrier") +#undef MemoryBarrier +#endif + QT_BEGIN_NAMESPACE class QOpenGLContext; @@ -1897,6 +1903,10 @@ public: QT_END_NAMESPACE +#ifdef Q_OS_WIN +#pragma pop_macro("MemoryBarrier") +#endif + #endif // QT_NO_OPENGL #endif -- cgit v1.2.3 From 03717be7885d84783bc8ea32a65e42e4970f59d6 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Wed, 23 Oct 2019 13:35:13 +0200 Subject: Fix: confusion in QImage paintEngine creation on shared images During the creation of a raster paint engine in QImage::paintEngine(), the QImage will be detached. At least old gcc versions would get confused so that the newly created paintengine would end up in the old QImage copy insteads of the newly detached one. Work around by dropping the temporary engine pointer. Fixes: QTBUG-79383 Change-Id: I27b1f24312269bc2bcc641dc4334397a92e3bfbb Reviewed-by: Allan Sandfeld Jensen --- src/gui/image/qimage.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index dda407181a..2779b97fbd 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4145,11 +4145,11 @@ QPaintEngine *QImage::paintEngine() const if (!d->paintEngine) { QPaintDevice *paintDevice = const_cast(this); - QPaintEngine *paintEngine = 0; QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); if (platformIntegration) - paintEngine = platformIntegration->createImagePaintEngine(paintDevice); - d->paintEngine = paintEngine ? paintEngine : new QRasterPaintEngine(paintDevice); + d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice); + if (!d->paintEngine) + d->paintEngine = new QRasterPaintEngine(paintDevice); } return d->paintEngine; -- cgit v1.2.3 From 6326d1df39fc68e47d1cd34d6cd8b021bdd66045 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 22 Oct 2019 10:47:35 +0200 Subject: Store a native resource binding map in QShader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The deserializer remains compatible with .qsb files without this additional section. Task-number: QTBUG-79368 Change-Id: I03e2a634febbd88da7f6a4369f104855ea31e3af Reviewed-by: Christian Strømme --- src/gui/rhi/qshader.cpp | 144 ++++++++++++++++++++++++++++++++++++++++------ src/gui/rhi/qshader_p.h | 5 ++ src/gui/rhi/qshader_p_p.h | 4 +- 3 files changed, 135 insertions(+), 18 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 6a2c596557..c22b029dc8 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -214,7 +214,8 @@ QT_BEGIN_NAMESPACE QShader, it indicates no shader code was found for the requested key. */ -static const int QSB_VERSION = 1; +static const int QSB_VERSION = 2; +static const int QSB_VERSION_WITHOUT_BINDINGS = 1; /*! Constructs a new, empty (and thus invalid) QShader instance. @@ -345,6 +346,14 @@ void QShader::removeShader(const QShaderKey &key) d->shaders.erase(it); } +static void writeShaderKey(QDataStream *ds, const QShaderKey &k) +{ + *ds << k.source(); + *ds << k.sourceVersion().version(); + *ds << k.sourceVersion().flags(); + *ds << k.sourceVariant(); +} + /*! \return a serialized binary version of all the data held by the QShader, suitable for writing to files or other I/O devices. @@ -365,18 +374,42 @@ QByteArray QShader::serialized() const ds << d->shaders.count(); for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) { const QShaderKey &k(it.key()); - ds << k.source(); - ds << k.sourceVersion().version(); - ds << k.sourceVersion().flags(); - ds << k.sourceVariant(); + writeShaderKey(&ds, k); const QShaderCode &shader(d->shaders.value(k)); ds << shader.shader(); ds << shader.entryPoint(); } + ds << d->bindings.count(); + for (auto it = d->bindings.cbegin(), itEnd = d->bindings.cend(); it != itEnd; ++it) { + const QShaderKey &k(it.key()); + writeShaderKey(&ds, k); + const NativeResourceBindingMap &map(it.value()); + ds << map.count(); + for (auto mapIt = map.cbegin(), mapItEnd = map.cend(); mapIt != mapItEnd; ++mapIt) { + ds << mapIt.key(); + ds << mapIt.value().first; + ds << mapIt.value().second; + } + } return qCompress(buf.buffer()); } +static void readShaderKey(QDataStream *ds, QShaderKey *k) +{ + int intVal; + *ds >> intVal; + k->setSource(QShader::Source(intVal)); + QShaderVersion ver; + *ds >> intVal; + ver.setVersion(intVal); + *ds >> intVal; + ver.setFlags(QShaderVersion::Flags(intVal)); + k->setSourceVersion(ver); + *ds >> intVal; + k->setSourceVariant(QShader::Variant(intVal)); +} + /*! Creates a new QShader instance from the given \a data. @@ -396,8 +429,11 @@ QShader QShader::fromSerialized(const QByteArray &data) Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached int intVal; ds >> intVal; - if (intVal != QSB_VERSION) + const int qsbVersion = intVal; + if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) { + qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion); return QShader(); + } ds >> intVal; d->stage = Stage(intVal); @@ -408,16 +444,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> count; for (int i = 0; i < count; ++i) { QShaderKey k; - ds >> intVal; - k.setSource(Source(intVal)); - QShaderVersion ver; - ds >> intVal; - ver.setVersion(intVal); - ds >> intVal; - ver.setFlags(QShaderVersion::Flags(intVal)); - k.setSourceVersion(ver); - ds >> intVal; - k.setSourceVariant(Variant(intVal)); + readShaderKey(&ds, &k); QShaderCode shader; QByteArray s; ds >> s; @@ -427,6 +454,27 @@ QShader QShader::fromSerialized(const QByteArray &data) d->shaders[k] = shader; } + if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) { + ds >> count; + for (int i = 0; i < count; ++i) { + QShaderKey k; + readShaderKey(&ds, &k); + NativeResourceBindingMap map; + int mapSize; + ds >> mapSize; + for (int b = 0; b < mapSize; ++b) { + int binding; + ds >> binding; + int firstNativeBinding; + ds >> firstNativeBinding; + int secondNativeBinding; + ds >> secondNativeBinding; + map.insert(binding, { firstNativeBinding, secondNativeBinding }); + } + d->bindings.insert(k, map); + } + } + return bs; } @@ -460,7 +508,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) Q_DECL_NOTHROW { return lhs.d->stage == rhs.d->stage && lhs.d->shaders == rhs.d->shaders; - // do not bother with desc, if the shader code is the same, the description must match too + // do not bother with desc and bindings, if the shader code is the same, the description must match too } /*! @@ -586,4 +634,66 @@ QDebug operator<<(QDebug dbg, const QShaderVersion &v) } #endif // QT_NO_DEBUG_STREAM +/*! + \typedef QShader::NativeResourceBindingMap + + Synonym for QHash>. + + The resource binding model QRhi assumes is based on SPIR-V. This means that + uniform buffers, storage buffers, combined image samplers, and storage + images share a common binding point space. The binding numbers in + QShaderDescription and QRhiShaderResourceBinding are expected to match the + \c binding layout qualifier in the Vulkan-compatible GLSL shader. + + Graphics APIs other than Vulkan may use a resource binding model that is + not fully compatible with this. In addition, the generator of the shader + code translated from SPIR-V may choose not to take the SPIR-V binding + qualifiers into account, for various reasons. (this is the case with the + Metal backend of SPIRV-Cross, for example). + + Therefore, a QShader may expose an additional map that describes what the + native binding point for a given SPIR-V binding is. The QRhi backends are + expected to use this map automatically, as appropriate. The value is a + pair, because combined image samplers may map to two native resources (a + texture and a sampler) in some shading languages. In that case the second + value refers to the sampler. +*/ + +/*! + \return the native binding map for \a key or null if no extra mapping is + available, or is not applicable. + */ +const QShader::NativeResourceBindingMap *QShader::nativeResourceBindingMap(const QShaderKey &key) const +{ + auto it = d->bindings.constFind(key); + if (it == d->bindings.cend()) + return nullptr; + + return &it.value(); +} + +/*! + Stores the given native resource binding \a map associated with \a key. + + \sa nativeResourceBindingMap() + */ +void QShader::setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map) +{ + detach(); + d->bindings[key] = map; +} + +/*! + Removes the native resource binding map for \a key. + */ +void QShader::removeResourceBindingMap(const QShaderKey &key) +{ + auto it = d->bindings.find(key); + if (it == d->bindings.end()) + return; + + detach(); + d->bindings.erase(it); +} + QT_END_NAMESPACE diff --git a/src/gui/rhi/qshader_p.h b/src/gui/rhi/qshader_p.h index 243842a95a..4b561b6fa9 100644 --- a/src/gui/rhi/qshader_p.h +++ b/src/gui/rhi/qshader_p.h @@ -149,6 +149,11 @@ public: QByteArray serialized() const; static QShader fromSerialized(const QByteArray &data); + using NativeResourceBindingMap = QHash >; // binding -> native_binding[, native_binding] + const NativeResourceBindingMap *nativeResourceBindingMap(const QShaderKey &key) const; + void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map); + void removeResourceBindingMap(const QShaderKey &key); + private: QShaderPrivate *d; friend struct QShaderPrivate; diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h index 6473590e95..4535e01491 100644 --- a/src/gui/rhi/qshader_p_p.h +++ b/src/gui/rhi/qshader_p_p.h @@ -66,7 +66,8 @@ struct Q_GUI_EXPORT QShaderPrivate : ref(1), stage(other->stage), desc(other->desc), - shaders(other->shaders) + shaders(other->shaders), + bindings(other->bindings) { } @@ -77,6 +78,7 @@ struct Q_GUI_EXPORT QShaderPrivate QShader::Stage stage = QShader::VertexStage; QShaderDescription desc; QHash shaders; + QHash bindings; }; QT_END_NAMESPACE -- cgit v1.2.3 From cc631c15a00f26fa8f6aa703fd7cf9e715be8f3c Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 22 Oct 2019 12:37:34 +0200 Subject: rhi: metal: Remap resource bindings based on the QShader table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...when available. Fall back to the QRhi (i.e. SPIR-V) binding point otherwise (which becomes unsafe once shadertools bumps its SPIRV-Cross snapshot, but is fine for existing .qsb files) Task-number: QTBUG-79368 Change-Id: I2d452fdd4efb484867732c358171a800d3261dcd Reviewed-by: Christian Strømme --- src/gui/rhi/qrhimetal.mm | 97 +++++++++++++++++++++++++++++++-------------- src/gui/rhi/qrhimetal_p_p.h | 7 +++- 2 files changed, 73 insertions(+), 31 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 5f14d917b8..b2d56b43af 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -35,8 +35,6 @@ ****************************************************************************/ #include "qrhimetal_p_p.h" -#include "qshader_p.h" -#include "qshaderdescription_p.h" #include #include #include @@ -143,8 +141,10 @@ struct QMetalShader id lib = nil; id func = nil; std::array localSize; + QShader::NativeResourceBindingMap nativeResourceBindingMap; void release() { + nativeResourceBindingMap.clear(); [lib release]; lib = nil; [func release]; @@ -164,7 +164,7 @@ struct QRhiMetalData const QRhiDepthStencilClearValue &depthStencilClearValue, int colorAttCount); id createMetalLib(const QShader &shader, QShader::Variant shaderVariant, - QString *error, QByteArray *entryPoint); + QString *error, QByteArray *entryPoint, QShaderKey *activeKey); id createMSLShaderFunction(id lib, const QByteArray &entryPoint); struct DeferredReleaseEntry { @@ -653,18 +653,39 @@ QRhiShaderResourceBindings *QRhiMetal::createShaderResourceBindings() return new QMetalShaderResourceBindings(this); } -void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD, +enum class BindingType { + Buffer, + Texture, + Sampler +}; + +static inline int mapBinding(int binding, + int stageIndex, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[], + BindingType type) +{ + const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex]; + if (map) { + auto it = map->constFind(binding); + if (it != map->cend()) + return type == BindingType::Sampler ? it->second : it->first; + } + return binding; +} + +void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, + QMetalCommandBuffer *cbD, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets, - bool offsetOnlyChange) + bool offsetOnlyChange, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]) { - static const int KNOWN_STAGES = 3; struct { QRhiBatchedBindings > buffers; QRhiBatchedBindings bufferOffsets; QRhiBatchedBindings > textures; QRhiBatchedBindings > samplers; - } res[KNOWN_STAGES]; + } res[SUPPORTED_STAGES]; for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) { const QRhiShaderResourceBinding::Data *b = binding.data(); @@ -682,15 +703,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD } } if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[0].buffers.feed(b->binding, mtlbuf); + res[0].buffers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); res[0].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[1].buffers.feed(b->binding, mtlbuf); + res[1].buffers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); res[1].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[2].buffers.feed(b->binding, mtlbuf); + res[2].buffers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); res[2].bufferOffsets.feed(b->binding, offset); } } @@ -700,16 +721,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex); QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[0].textures.feed(b->binding, texD->d->tex); - res[0].samplers.feed(b->binding, samplerD->d->samplerState); + res[0].textures.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); + res[0].samplers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[1].textures.feed(b->binding, texD->d->tex); - res[1].samplers.feed(b->binding, samplerD->d->samplerState); + res[1].textures.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); + res[1].samplers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[2].textures.feed(b->binding, texD->d->tex); - res[2].samplers.feed(b->binding, samplerD->d->samplerState); + res[2].textures.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); + res[2].samplers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); } } break; @@ -722,11 +743,11 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex); id t = texD->d->viewForLevel(b->u.simage.level); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) - res[0].textures.feed(b->binding, t); + res[0].textures.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Texture), t); if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) - res[1].textures.feed(b->binding, t); + res[1].textures.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Texture), t); if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) - res[2].textures.feed(b->binding, t); + res[2].textures.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Texture), t); } break; case QRhiShaderResourceBinding::BufferLoad: @@ -739,15 +760,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD id mtlbuf = bufD->d->buf[0]; uint offset = uint(b->u.sbuf.offset); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[0].buffers.feed(b->binding, mtlbuf); + res[0].buffers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); res[0].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[1].buffers.feed(b->binding, mtlbuf); + res[1].buffers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); res[1].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[2].buffers.feed(b->binding, mtlbuf); + res[2].buffers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); res[2].bufferOffsets.feed(b->binding, offset); } } @@ -758,7 +779,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD } } - for (int idx = 0; idx < KNOWN_STAGES; ++idx) { + for (int idx = 0; idx < SUPPORTED_STAGES; ++idx) { res[idx].buffers.finish(); res[idx].bufferOffsets.finish(); @@ -973,18 +994,22 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind // dynamic uniform buffer offsets always trigger a rebind if (hasDynamicOffsetInSrb || resNeedsRebind || srbChanged || srbRebuilt) { + const QShader::NativeResourceBindingMap *resBindMaps[SUPPORTED_STAGES] = { nullptr, nullptr, nullptr }; if (gfxPsD) { cbD->currentGraphicsSrb = srb; cbD->currentComputeSrb = nullptr; + resBindMaps[0] = &gfxPsD->d->vs.nativeResourceBindingMap; + resBindMaps[1] = &gfxPsD->d->fs.nativeResourceBindingMap; } else { cbD->currentGraphicsSrb = nullptr; cbD->currentComputeSrb = srb; + resBindMaps[2] = &compPsD->d->cs.nativeResourceBindingMap; } cbD->currentSrbGeneration = srbD->generation; cbD->currentResSlot = resSlot; const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChanged && !srbRebuilt; - enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange); + enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange, resBindMaps); } } @@ -3081,9 +3106,10 @@ static inline MTLCullMode toMetalCullMode(QRhiGraphicsPipeline::CullMode c) } id QRhiMetalData::createMetalLib(const QShader &shader, QShader::Variant shaderVariant, - QString *error, QByteArray *entryPoint) + QString *error, QByteArray *entryPoint, QShaderKey *activeKey) { - QShaderCode mtllib = shader.shader({ QShader::MetalLibShader, 12, shaderVariant }); + QShaderKey key = { QShader::MetalLibShader, 12, shaderVariant }; + QShaderCode mtllib = shader.shader(key); if (!mtllib.shader().isEmpty()) { dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(), size_t(mtllib.shader().size()), @@ -3094,6 +3120,7 @@ id QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var dispatch_release(data); if (!err) { *entryPoint = mtllib.entryPoint(); + *activeKey = key; return lib; } else { const QString msg = QString::fromNSString(err.localizedDescription); @@ -3101,7 +3128,8 @@ id QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var } } - QShaderCode mslSource = shader.shader({ QShader::MslShader, 12, shaderVariant }); + key = { QShader::MslShader, 12, shaderVariant }; + QShaderCode mslSource = shader.shader(key); if (mslSource.shader().isEmpty()) { qWarning() << "No MSL 1.2 code found in baked shader" << shader; return nil; @@ -3122,6 +3150,7 @@ id QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var } *entryPoint = mslSource.entryPoint(); + *activeKey = key; return lib; } @@ -3195,9 +3224,12 @@ bool QMetalGraphicsPipeline::build() break; } } else { + const QShader shader = shaderStage.shader(); QString error; QByteArray entryPoint; - id lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint); + QShaderKey activeKey; + id lib = rhiD->d->createMetalLib(shader, shaderStage.shaderVariant(), + &error, &entryPoint, &activeKey); if (!lib) { qWarning("MSL shader compilation failed: %s", qPrintable(error)); return false; @@ -3218,6 +3250,8 @@ bool QMetalGraphicsPipeline::build() case QRhiShaderStage::Vertex: d->vs.lib = lib; d->vs.func = func; + if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey)) + d->vs.nativeResourceBindingMap = *map; rhiD->d->shaderCache.insert(shaderStage, d->vs); [d->vs.lib retain]; [d->vs.func retain]; @@ -3226,6 +3260,8 @@ bool QMetalGraphicsPipeline::build() case QRhiShaderStage::Fragment: d->fs.lib = lib; d->fs.func = func; + if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey)) + d->fs.nativeResourceBindingMap = *map; rhiD->d->shaderCache.insert(shaderStage, d->fs); [d->fs.lib retain]; [d->fs.func retain]; @@ -3360,8 +3396,9 @@ bool QMetalComputePipeline::build() const QShader shader = m_shaderStage.shader(); QString error; QByteArray entryPoint; + QShaderKey activeKey; id lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(), - &error, &entryPoint); + &error, &entryPoint, &activeKey); if (!lib) { qWarning("MSL shader compilation failed: %s", qPrintable(error)); return false; @@ -3375,6 +3412,8 @@ bool QMetalComputePipeline::build() d->cs.lib = lib; d->cs.func = func; d->cs.localSize = shader.description().computeShaderLocalSize(); + if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey)) + d->cs.nativeResourceBindingMap = *map; if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) { for (QMetalShader &s : rhiD->d->shaderCache) diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 688fec8147..2be86db5c8 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -433,10 +433,13 @@ public: qsizetype *curOfs); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD); - void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD, + static const int SUPPORTED_STAGES = 3; + void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, + QMetalCommandBuffer *cbD, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets, - bool offsetOnlyChange); + bool offsetOnlyChange, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]); int effectiveSampleCount(int sampleCount) const; bool importedDevice = false; -- cgit v1.2.3 From 4106275a7fc9ab3abe2fa2ca0b107a3e96e36ca0 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 23 Oct 2019 10:21:24 +0200 Subject: rhi: metal: Fix and clean up committing resource bindings Make it readable by using names instead of mere indices for the stages. There is an important fix in there as well: when in a render pass, only resource for VERTEX and FRAGMENT are taken into account, while in a compute pass those are skipped. This ensures that we do not send messages to a nil or invalid MTLRender/ComputeCommandEncoder. (nil would not be an error but the other is fatal) Task-number: QTBUG-79447 Change-Id: Ibef108cb7c82b5b0fdd2a299cd89fbebe8c3606a Reviewed-by: Paul Olav Tvete --- src/gui/rhi/qrhimetal.mm | 96 +++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 45 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index b2d56b43af..131b2da802 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -686,6 +686,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD QRhiBatchedBindings > textures; QRhiBatchedBindings > samplers; } res[SUPPORTED_STAGES]; + enum { VERTEX = 0, FRAGMENT = 1, COMPUTE = 2 }; for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) { const QRhiShaderResourceBinding::Data *b = binding.data(); @@ -703,16 +704,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD } } if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[0].buffers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[0].bufferOffsets.feed(b->binding, offset); + res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); + res[VERTEX].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[1].buffers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[1].bufferOffsets.feed(b->binding, offset); + res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); + res[FRAGMENT].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[2].buffers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[2].bufferOffsets.feed(b->binding, offset); + res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); + res[COMPUTE].bufferOffsets.feed(b->binding, offset); } } break; @@ -721,16 +722,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex); QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[0].textures.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); - res[0].samplers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); + res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); + res[VERTEX].samplers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[1].textures.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); - res[1].samplers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); + res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); + res[FRAGMENT].samplers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[2].textures.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); - res[2].samplers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); + res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); + res[COMPUTE].samplers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); } } break; @@ -743,11 +744,11 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex); id t = texD->d->viewForLevel(b->u.simage.level); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) - res[0].textures.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Texture), t); + res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), t); if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) - res[1].textures.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Texture), t); + res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), t); if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) - res[2].textures.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Texture), t); + res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), t); } break; case QRhiShaderResourceBinding::BufferLoad: @@ -760,16 +761,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD id mtlbuf = bufD->d->buf[0]; uint offset = uint(b->u.sbuf.offset); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[0].buffers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[0].bufferOffsets.feed(b->binding, offset); + res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); + res[VERTEX].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[1].buffers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[1].bufferOffsets.feed(b->binding, offset); + res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); + res[FRAGMENT].bufferOffsets.feed(b->binding, offset); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[2].buffers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[2].bufferOffsets.feed(b->binding, offset); + res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); + res[COMPUTE].bufferOffsets.feed(b->binding, offset); } } break; @@ -779,25 +780,30 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD } } - for (int idx = 0; idx < SUPPORTED_STAGES; ++idx) { - res[idx].buffers.finish(); - res[idx].bufferOffsets.finish(); + for (int stage = 0; stage < SUPPORTED_STAGES; ++stage) { + if (cbD->recordingPass != QMetalCommandBuffer::RenderPass && (stage == VERTEX || stage == FRAGMENT)) + continue; + if (cbD->recordingPass != QMetalCommandBuffer::ComputePass && stage == COMPUTE) + continue; + + res[stage].buffers.finish(); + res[stage].bufferOffsets.finish(); - for (int i = 0, ie = res[idx].buffers.batches.count(); i != ie; ++i) { - const auto &bufferBatch(res[idx].buffers.batches[i]); - const auto &offsetBatch(res[idx].bufferOffsets.batches[i]); - switch (idx) { - case 0: + for (int i = 0, ie = res[stage].buffers.batches.count(); i != ie; ++i) { + const auto &bufferBatch(res[stage].buffers.batches[i]); + const auto &offsetBatch(res[stage].bufferOffsets.batches[i]); + switch (stage) { + case VERTEX: [cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData() offsets: offsetBatch.resources.constData() withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))]; break; - case 1: + case FRAGMENT: [cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData() offsets: offsetBatch.resources.constData() withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))]; break; - case 2: + case COMPUTE: [cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData() offsets: offsetBatch.resources.constData() withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))]; @@ -811,21 +817,21 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD if (offsetOnlyChange) continue; - res[idx].textures.finish(); - res[idx].samplers.finish(); + res[stage].textures.finish(); + res[stage].samplers.finish(); - for (int i = 0, ie = res[idx].textures.batches.count(); i != ie; ++i) { - const auto &batch(res[idx].textures.batches[i]); - switch (idx) { - case 0: + for (int i = 0, ie = res[stage].textures.batches.count(); i != ie; ++i) { + const auto &batch(res[stage].textures.batches[i]); + switch (stage) { + case VERTEX: [cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData() withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))]; break; - case 1: + case FRAGMENT: [cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData() withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))]; break; - case 2: + case COMPUTE: [cbD->d->currentComputePassEncoder setTextures: batch.resources.constData() withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))]; break; @@ -834,18 +840,18 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD break; } } - for (int i = 0, ie = res[idx].samplers.batches.count(); i != ie; ++i) { - const auto &batch(res[idx].samplers.batches[i]); - switch (idx) { - case 0: + for (int i = 0, ie = res[stage].samplers.batches.count(); i != ie; ++i) { + const auto &batch(res[stage].samplers.batches[i]); + switch (stage) { + case VERTEX: [cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData() withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))]; break; - case 1: + case FRAGMENT: [cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData() withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))]; break; - case 2: + case COMPUTE: [cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData() withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))]; break; -- cgit v1.2.3 From 7c9ffe3e46bca3cfdec6fd1db3da4c96a6d5acd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 23 Oct 2019 14:16:24 +0200 Subject: rhi: Use Q_GLOBAL_STATIC for QRhiGles2 GL program cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defers initialization until actually needed. Change-Id: Idb09dbad0dfa602949d381ee61565d9050e77e7c Reviewed-by: Laszlo Agocs Reviewed-by: Tor Arne Vestbø --- src/gui/rhi/qrhigles2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index dec28cac9b..abee843a74 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -2961,7 +2961,7 @@ bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const return checker.get(ctx)->isSupported(); } -static QOpenGLProgramBinaryCache qrhi_programBinaryCache; +Q_GLOBAL_STATIC(QOpenGLProgramBinaryCache, qrhi_programBinaryCache); static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type) { @@ -2995,7 +2995,7 @@ QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage } diskCacheKey = binaryProgram.cacheKey(); - if (qrhi_programBinaryCache.load(diskCacheKey, program)) { + if (qrhi_programBinaryCache()->load(diskCacheKey, program)) { qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s", program, diskCacheKey.constData()); result = QRhiGles2::DiskCacheHit; @@ -3013,7 +3013,7 @@ void QRhiGles2::trySaveToDiskCache(GLuint program, const QByteArray &cacheKey) if (isProgramBinaryDiskCacheEnabled()) { qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s", program, cacheKey.constData()); - qrhi_programBinaryCache.save(cacheKey, program); + qrhi_programBinaryCache()->save(cacheKey, program); } } -- cgit v1.2.3 From fcbf15c97bac91a889eccaa0cfad10093fd052f0 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Wed, 23 Oct 2019 16:53:00 +0300 Subject: QKeySequence: Add missing names for multimedia keys Task-number: QTBUG-40030 Change-Id: Ib34bcbf42d6dd1206209c2d76444fd8c777278fe Reviewed-by: Shawn Rutledge --- src/gui/kernel/qkeysequence.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/gui') diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 2a86b340af..e1244e1006 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -492,6 +492,8 @@ static const struct { { Qt::Key_LaunchD, QT_TRANSLATE_NOOP("QShortcut", "Launch (D)") }, { Qt::Key_LaunchE, QT_TRANSLATE_NOOP("QShortcut", "Launch (E)") }, { Qt::Key_LaunchF, QT_TRANSLATE_NOOP("QShortcut", "Launch (F)") }, + { Qt::Key_LaunchG, QT_TRANSLATE_NOOP("QShortcut", "Launch (G)") }, + { Qt::Key_LaunchH, QT_TRANSLATE_NOOP("QShortcut", "Launch (H)") }, { Qt::Key_MonBrightnessUp, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Up") }, { Qt::Key_MonBrightnessDown, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Down") }, { Qt::Key_KeyboardLightOnOff, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Light On/Off") }, @@ -518,9 +520,11 @@ static const struct { { Qt::Key_Book, QT_TRANSLATE_NOOP("QShortcut", "Book") }, { Qt::Key_CD, QT_TRANSLATE_NOOP("QShortcut", "CD") }, { Qt::Key_Calculator, QT_TRANSLATE_NOOP("QShortcut", "Calculator") }, + { Qt::Key_Calendar, QT_TRANSLATE_NOOP("QShortcut", "Calendar") }, { Qt::Key_Clear, QT_TRANSLATE_NOOP("QShortcut", "Clear") }, { Qt::Key_ClearGrab, QT_TRANSLATE_NOOP("QShortcut", "Clear Grab") }, { Qt::Key_Close, QT_TRANSLATE_NOOP("QShortcut", "Close") }, + { Qt::Key_ContrastAdjust, QT_TRANSLATE_NOOP("QShortcut", "Adjust contrast") }, { Qt::Key_Copy, QT_TRANSLATE_NOOP("QShortcut", "Copy") }, { Qt::Key_Cut, QT_TRANSLATE_NOOP("QShortcut", "Cut") }, { Qt::Key_Display, QT_TRANSLATE_NOOP("QShortcut", "Display") }, @@ -534,6 +538,7 @@ static const struct { { Qt::Key_LogOff, QT_TRANSLATE_NOOP("QShortcut", "Logoff") }, { Qt::Key_Market, QT_TRANSLATE_NOOP("QShortcut", "Market") }, { Qt::Key_Meeting, QT_TRANSLATE_NOOP("QShortcut", "Meeting") }, + { Qt::Key_Memo, QT_TRANSLATE_NOOP("QShortcut", "Memo") }, { Qt::Key_MenuKB, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Menu") }, { Qt::Key_MenuPB, QT_TRANSLATE_NOOP("QShortcut", "Menu PB") }, { Qt::Key_MySites, QT_TRANSLATE_NOOP("QShortcut", "My Sites") }, @@ -554,6 +559,7 @@ static const struct { { Qt::Key_Support, QT_TRANSLATE_NOOP("QShortcut", "Support") }, { Qt::Key_TaskPane, QT_TRANSLATE_NOOP("QShortcut", "Task Panel") }, { Qt::Key_Terminal, QT_TRANSLATE_NOOP("QShortcut", "Terminal") }, + { Qt::Key_ToDoList, QT_TRANSLATE_NOOP("QShortcut", "To-do list") }, { Qt::Key_Tools, QT_TRANSLATE_NOOP("QShortcut", "Tools") }, { Qt::Key_Travel, QT_TRANSLATE_NOOP("QShortcut", "Travel") }, { Qt::Key_Video, QT_TRANSLATE_NOOP("QShortcut", "Video") }, -- cgit v1.2.3 From d377d1f3a921488525f6e75c850632f559707747 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 21 Oct 2019 15:14:53 +0200 Subject: Enforce QTextDocument::MarkdownFeature compatibility at compile time We use md4c for parsing markdown. It provides flags to control the feature set that will be supported when parsing particular documents. QTextMarkdownImporter::Feature is a fine-grained set of flags that exactly match the md4c feature flags that we support in Qt so far. QTextMarkdownImporter is a private exported class (new in 5.14). We don't expect the corresponding flags in md4c to change in incompatible ways in the future: the md4c authors have as much respect for avoiding compatibility issues as we do, and likely will only add features, not remove them. We now enforce QTextMarkdownImporter::Features compatibility with QTextDocument::MarkdownFeatures by setting them directly. We check QTextMarkdownImporter::Features compatibility with md4c's #define'd feature flags using static asserts, so that any hypothetical incompatibility would be detected at compile time. The enum conversion from QTextDocument::MarkdownFeatures to QTextMarkdownImporter::Features is moved to a new QTextMarkdownImporter constructor; thus the conversions from QTextDocument::MarkdownFeatures to QTextMarkdownImporter::Features, and then to unsigned (in QTextMarkdownImporter::import()) are adjacent in the same private class implementation. If incompatibility ever occurred, we would need to replace one or both of those with another suitable conversion function. Change-Id: I0bf8a21eb7559df1d38406b948ef657f9060c67b Reviewed-by: Vitaly Fanaskov --- src/gui/text/qtextdocument.cpp | 2 +- src/gui/text/qtextdocument.h | 1 - src/gui/text/qtextmarkdownimporter.cpp | 21 +++++++++++++++++++++ src/gui/text/qtextmarkdownimporter_p.h | 34 ++++++++++++++++++---------------- 4 files changed, 40 insertions(+), 18 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 22c249d604..e94f635651 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -3420,7 +3420,7 @@ QString QTextDocument::toMarkdown(QTextDocument::MarkdownFeatures features) cons #if QT_CONFIG(textmarkdownreader) void QTextDocument::setMarkdown(const QString &markdown, QTextDocument::MarkdownFeatures features) { - QTextMarkdownImporter(static_cast(int(features))).import(this, markdown); + QTextMarkdownImporter(features).import(this, markdown); } #endif diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index 2fadc40cd2..7d46238257 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -152,7 +152,6 @@ public: #endif #if QT_CONFIG(textmarkdownwriter) || QT_CONFIG(textmarkdownreader) - // Must be in sync with QTextMarkdownImporter::Features, should be in sync with #define MD_FLAG_* in md4c enum MarkdownFeature { MarkdownNoHTML = 0x0020 | 0x0040, MarkdownDialectCommonMark = 0, diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp index fe7e422923..87ade1f973 100644 --- a/src/gui/text/qtextmarkdownimporter.cpp +++ b/src/gui/text/qtextmarkdownimporter.cpp @@ -60,6 +60,22 @@ static const QChar Space = QLatin1Char(' '); // TODO maybe eliminate the margins after all views recognize BlockQuoteLevel, CSS can format it, etc. static const int BlockQuoteIndent = 40; // pixels, same as in QTextHtmlParserNode::initializeProperties +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureCollapseWhitespace) == MD_FLAG_COLLAPSEWHITESPACE); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeaturePermissiveATXHeaders) == MD_FLAG_PERMISSIVEATXHEADERS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeaturePermissiveURLAutoLinks) == MD_FLAG_PERMISSIVEURLAUTOLINKS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeaturePermissiveMailAutoLinks) == MD_FLAG_PERMISSIVEEMAILAUTOLINKS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureNoIndentedCodeBlocks) == MD_FLAG_NOINDENTEDCODEBLOCKS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureNoHTMLBlocks) == MD_FLAG_NOHTMLBLOCKS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureNoHTMLSpans) == MD_FLAG_NOHTMLSPANS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureTables) == MD_FLAG_TABLES); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureStrikeThrough) == MD_FLAG_STRIKETHROUGH); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeaturePermissiveWWWAutoLinks) == MD_FLAG_PERMISSIVEWWWAUTOLINKS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeaturePermissiveAutoLinks) == MD_FLAG_PERMISSIVEAUTOLINKS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureTasklists) == MD_FLAG_TASKLISTS); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::FeatureNoHTML) == MD_FLAG_NOHTML); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::DialectCommonMark) == MD_DIALECT_COMMONMARK); +Q_STATIC_ASSERT(int(QTextMarkdownImporter::DialectGitHub) == MD_DIALECT_GITHUB); + // -------------------------------------------------------- // MD4C callback function wrappers @@ -122,6 +138,11 @@ QTextMarkdownImporter::QTextMarkdownImporter(QTextMarkdownImporter::Features fea { } +QTextMarkdownImporter::QTextMarkdownImporter(QTextDocument::MarkdownFeatures features) + : QTextMarkdownImporter(static_cast(int(features))) +{ +} + void QTextMarkdownImporter::import(QTextDocument *doc, const QString &markdown) { MD_PARSER callbacks = { diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h index 35655aff8a..f450da5eb3 100644 --- a/src/gui/text/qtextmarkdownimporter_p.h +++ b/src/gui/text/qtextmarkdownimporter_p.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -67,27 +68,28 @@ class Q_GUI_EXPORT QTextMarkdownImporter { public: enum Feature { - // Must be kept in sync with MD_FLAG_* in md4c.h - FeatureCollapseWhitespace = 0x0001, // MD_FLAG_COLLAPSEWHITESPACE - FeaturePermissiveATXHeaders = 0x0002, // MD_FLAG_PERMISSIVEATXHEADERS - FeaturePermissiveURLAutoLinks = 0x0004, // MD_FLAG_PERMISSIVEURLAUTOLINKS - FeaturePermissiveMailAutoLinks = 0x0008, // MD_FLAG_PERMISSIVEEMAILAUTOLINKS - FeatureNoIndentedCodeBlocks = 0x0010, // MD_FLAG_NOINDENTEDCODEBLOCKS - FeatureNoHTMLBlocks = 0x0020, // MD_FLAG_NOHTMLBLOCKS - FeatureNoHTMLSpans = 0x0040, // MD_FLAG_NOHTMLSPANS - FeatureTables = 0x0100, // MD_FLAG_TABLES - FeatureStrikeThrough = 0x0200, // MD_FLAG_STRIKETHROUGH - FeaturePermissiveWWWAutoLinks = 0x0400, // MD_FLAG_PERMISSIVEWWWAUTOLINKS - FeatureTasklists = 0x0800, // MD_FLAG_TASKLISTS + FeatureCollapseWhitespace = 0x0001, + FeaturePermissiveATXHeaders = 0x0002, + FeaturePermissiveURLAutoLinks = 0x0004, + FeaturePermissiveMailAutoLinks = 0x0008, + FeatureNoIndentedCodeBlocks = 0x0010, + FeatureNoHTMLBlocks = 0x0020, + FeatureNoHTMLSpans = 0x0040, + FeatureTables = 0x0100, + FeatureStrikeThrough = 0x0200, + FeaturePermissiveWWWAutoLinks = 0x0400, + FeatureTasklists = 0x0800, // composite flags - FeaturePermissiveAutoLinks = FeaturePermissiveMailAutoLinks | FeaturePermissiveURLAutoLinks | FeaturePermissiveWWWAutoLinks, // MD_FLAG_PERMISSIVEAUTOLINKS - FeatureNoHTML = FeatureNoHTMLBlocks | FeatureNoHTMLSpans, // MD_FLAG_NOHTML - DialectCommonMark = 0, // MD_DIALECT_COMMONMARK - DialectGitHub = FeaturePermissiveAutoLinks | FeatureTables | FeatureStrikeThrough | FeatureTasklists // MD_DIALECT_GITHUB + FeaturePermissiveAutoLinks = FeaturePermissiveMailAutoLinks + | FeaturePermissiveURLAutoLinks | FeaturePermissiveWWWAutoLinks, + FeatureNoHTML = QTextDocument::MarkdownNoHTML, + DialectCommonMark = QTextDocument::MarkdownDialectCommonMark, + DialectGitHub = QTextDocument::MarkdownDialectGitHub }; Q_DECLARE_FLAGS(Features, Feature) QTextMarkdownImporter(Features features); + QTextMarkdownImporter(QTextDocument::MarkdownFeatures features); void import(QTextDocument *doc, const QString &markdown); -- cgit v1.2.3 From dff3843d98d52e2c32fea07371f91117de0667e9 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 18 Oct 2019 09:07:37 +0200 Subject: QShortcut: Properly port to the new configure system Move the feature to corelib so that the QMetaType enumeration values can be properly excluded and there is no need for a dummy class. Use QT_REQUIRE_CONFIG in the headers of classes to be disabled. Add headers/source files in the .pro file depending on the configure feature in libraries and tests. Add the necessary exclusions and use QT_CONFIG. Task-number: QTBUG-76493 Change-Id: I02499ebee1a3d6d9a1e5afd02517beed5f4536b7 Reviewed-by: Mitch Curtis --- src/gui/configure.json | 6 ------ src/gui/kernel/kernel.pri | 15 ++++++++++----- src/gui/kernel/qevent.cpp | 10 +++++----- src/gui/kernel/qevent.h | 12 +++++++----- src/gui/kernel/qguiapplication_p.h | 7 +++++-- src/gui/kernel/qguivariant.cpp | 10 ++++++---- src/gui/kernel/qkeymapper_p.h | 1 - src/gui/kernel/qkeysequence.cpp | 5 ----- src/gui/kernel/qkeysequence.h | 16 ++-------------- src/gui/kernel/qkeysequence_p.h | 4 ++-- src/gui/kernel/qplatformmenu.h | 6 ++++-- src/gui/kernel/qplatformtheme.cpp | 8 +++++--- src/gui/kernel/qplatformtheme.h | 8 ++++++-- src/gui/kernel/qplatformtheme_p.h | 6 ++++-- src/gui/kernel/qshortcutmap.cpp | 4 ---- src/gui/kernel/qshortcutmap_p.h | 6 ++---- src/gui/kernel/qwindowsysteminterface.cpp | 4 ++-- 17 files changed, 60 insertions(+), 68 deletions(-) (limited to 'src/gui') diff --git a/src/gui/configure.json b/src/gui/configure.json index 39b8d0c2b8..90d0c8c134 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -1637,12 +1637,6 @@ "condition": "features.imageformat_xpm", "output": [ "publicFeature", "feature" ] }, - "shortcut": { - "label": "QShortcut", - "purpose": "Provides keyboard accelerators and shortcuts.", - "section": "Kernel", - "output": [ "publicFeature", "feature" ] - }, "action": { "label": "QAction", "purpose": "Provides widget actions.", diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 9c80f1e2cc..237a1c0a3f 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -48,11 +48,8 @@ HEADERS += \ kernel/qinputmethod.h \ kernel/qinputmethod_p.h \ kernel/qinternalmimedata_p.h \ - kernel/qkeysequence.h \ - kernel/qkeysequence_p.h \ kernel/qkeymapper_p.h \ kernel/qpalette.h \ - kernel/qshortcutmap_p.h \ kernel/qsessionmanager.h \ kernel/qsessionmanager_p.h \ kernel/qwindowdefs.h \ @@ -108,12 +105,10 @@ SOURCES += \ kernel/qevent.cpp \ kernel/qinputmethod.cpp \ kernel/qinternalmimedata.cpp \ - kernel/qkeysequence.cpp \ kernel/qkeymapper.cpp \ kernel/qpalette.cpp \ kernel/qguivariant.cpp \ kernel/qscreen.cpp \ - kernel/qshortcutmap.cpp \ kernel/qstylehints.cpp \ kernel/qtouchdevice.cpp \ kernel/qplatformsharedgraphicscache.cpp \ @@ -160,4 +155,14 @@ qtConfig(opengl) { kernel/qopenglwindow.cpp } +qtConfig(shortcut) { + HEADERS += \ + kernel/qshortcutmap_p.h \ + kernel/qkeysequence.h \ + kernel/qkeysequence_p.h + SOURCES += \ + kernel/qshortcutmap.cpp \ + kernel/qkeysequence.cpp +} + win32:HEADERS+=kernel/qwindowdefs_win.h diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index f2f083c277..54502bc6a3 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1224,7 +1224,7 @@ Qt::KeyboardModifiers QKeyEvent::modifiers() const return QInputEvent::modifiers(); } -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) /*! \fn bool QKeyEvent::matches(QKeySequence::StandardKey key) const \since 4.2 @@ -1240,7 +1240,7 @@ bool QKeyEvent::matches(QKeySequence::StandardKey matchKey) const const QList bindings = QKeySequence::keyBindings(matchKey); return bindings.contains(QKeySequence(searchkey)); } -#endif // QT_NO_SHORTCUT +#endif // QT_CONFIG(shortcut) /*! @@ -3581,7 +3581,7 @@ QToolBarChangeEvent::~QToolBarChangeEvent() #endif // QT_NO_TOOLBAR -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) /*! Constructs a shortcut event for the given \a key press, @@ -3602,7 +3602,7 @@ QShortcutEvent::~QShortcutEvent() { } -#endif // QT_NO_SHORTCUT +#endif // QT_CONFIG(shortcut) #ifndef QT_NO_DEBUG_STREAM @@ -3956,7 +3956,7 @@ QT_WARNING_POP dbg << ')'; } break; -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) case QEvent::Shortcut: { const QShortcutEvent *se = static_cast(e); dbg << "QShortcutEvent(" << se->key().toString() << ", id=" << se->shortcutId(); diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 8a0e42f592..28aa78a420 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -45,7 +45,9 @@ #include #include #include -#include +#if QT_CONFIG(shortcut) +# include +#endif #include #include #include // ### Qt 6: Remove @@ -375,7 +377,7 @@ public: ~QKeyEvent(); int key() const { return k; } -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) bool matches(QKeySequence::StandardKey key) const; #endif Qt::KeyboardModifiers modifiers() const; @@ -792,7 +794,7 @@ private: }; #endif -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) class Q_GUI_EXPORT QShortcutEvent : public QEvent { public: @@ -827,10 +829,10 @@ private: Q_GUI_EXPORT QDebug operator<<(QDebug, const QEvent *); #endif -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) inline bool operator==(QKeyEvent *e, QKeySequence::StandardKey key){return (e ? e->matches(key) : false);} inline bool operator==(QKeySequence::StandardKey key, QKeyEvent *e){return (e ? e->matches(key) : false);} -#endif // QT_NO_SHORTCUT +#endif // QT_CONFIG(shortcut) class Q_GUI_EXPORT QPointingDeviceUniqueId { diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index e28607bad6..73d137619e 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -62,7 +62,10 @@ #include #include -#include "private/qshortcutmap_p.h" +#if QT_CONFIG(shortcut) +# include "private/qshortcutmap_p.h" +#endif + #include QT_BEGIN_NAMESPACE @@ -261,7 +264,7 @@ public: QIcon forcedWindowIcon; static QList generic_plugin_list; -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) QShortcutMap shortcutMap; #endif diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index edca8d9423..2d6d12cc21 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -44,7 +44,9 @@ #include "qcursor.h" #include "qfont.h" #include "qimage.h" -#include "qkeysequence.h" +#if QT_CONFIG(shortcut) +# include "qkeysequence.h" +#endif #include "qtransform.h" #include "qmatrix.h" #include "qpalette.h" @@ -188,7 +190,7 @@ static bool convert(const QVariant::Private *d, int t, case QVariant::String: { QString *str = static_cast(result); switch (d->type) { -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) case QVariant::KeySequence: *str = (*v_cast(d)).toString(QKeySequence::NativeText); return true; @@ -238,7 +240,7 @@ static bool convert(const QVariant::Private *d, int t, return true; } break; -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) case QVariant::Int: if (d->type == QVariant::KeySequence) { const QKeySequence &seq = *v_cast(d); @@ -277,7 +279,7 @@ static bool convert(const QVariant::Private *d, int t, return true; } break; -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) case QVariant::KeySequence: { QKeySequence *seq = static_cast(result); switch (d->type) { diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index 8364557020..fd53747fdd 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 2a86b340af..25766467eb 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -42,8 +42,6 @@ #include #include "private/qguiapplication_p.h" -#if !defined(QT_NO_SHORTCUT) || defined(Q_CLANG_QDOC) - #include "qdebug.h" #include #ifndef QT_NO_DATASTREAM @@ -1673,9 +1671,6 @@ QDebug operator<<(QDebug dbg, const QKeySequence &p) } #endif -#endif // QT_NO_SHORTCUT - - /*! \typedef QKeySequence::DataPtr \internal diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index 3dcbbe5941..68f256c37a 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -44,10 +44,9 @@ #include #include -QT_BEGIN_NAMESPACE - +QT_REQUIRE_CONFIG(shortcut); -#if !defined(QT_NO_SHORTCUT) || defined(Q_CLANG_QDOC) +QT_BEGIN_NAMESPACE class QKeySequence; @@ -227,17 +226,6 @@ Q_DECLARE_SHARED(QKeySequence) Q_GUI_EXPORT QDebug operator<<(QDebug, const QKeySequence &); #endif -#else - -class Q_GUI_EXPORT QKeySequence -{ -public: - QKeySequence() {} - QKeySequence(int) {} -}; - -#endif // QT_NO_SHORTCUT - QT_END_NAMESPACE #endif // QKEYSEQUENCE_H diff --git a/src/gui/kernel/qkeysequence_p.h b/src/gui/kernel/qkeysequence_p.h index fbcab5d34e..8c59505561 100644 --- a/src/gui/kernel/qkeysequence_p.h +++ b/src/gui/kernel/qkeysequence_p.h @@ -56,9 +56,10 @@ #include +QT_REQUIRE_CONFIG(shortcut); + QT_BEGIN_NAMESPACE -#ifndef QT_NO_SHORTCUT struct QKeyBinding { QKeySequence::StandardKey standardKey; @@ -87,7 +88,6 @@ public: Q_GUI_EXPORT static QString keyName(int key, QKeySequence::SequenceFormat format); static int decodeString(QString accel, QKeySequence::SequenceFormat format); }; -#endif // QT_NO_SHORTCUT QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h index 28c29a704c..8e470aefd3 100644 --- a/src/gui/kernel/qplatformmenu.h +++ b/src/gui/kernel/qplatformmenu.h @@ -52,7 +52,9 @@ #include #include #include -#include +#if QT_CONFIG(shortcut) +# include +#endif #include QT_BEGIN_NAMESPACE @@ -85,7 +87,7 @@ public: virtual void setRole(MenuRole role) = 0; virtual void setCheckable(bool checkable) = 0; virtual void setChecked(bool isChecked) = 0; -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) virtual void setShortcut(const QKeySequence& shortcut) = 0; #endif virtual void setEnabled(bool enabled) = 0; diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index f906f808d8..ff6f32de10 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -167,7 +167,7 @@ QT_BEGIN_NAMESPACE */ -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) // Table of key bindings. It must be sorted on key sequence: // The integer value of VK_KEY | Modifier Keys (e.g., VK_META, and etc.) // A priority of 1 indicates that this is the primary key binding when multiple are defined. @@ -623,7 +623,7 @@ static inline int maybeSwapShortcut(int shortcut) } #endif -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) // mixed-mode predicate: all of these overloads are actually needed (but not all for every compiler) struct ByStandardKey { typedef bool result_type; @@ -688,6 +688,7 @@ QString QPlatformTheme::standardButtonText(int button) const return QPlatformTheme::defaultStandardButtonText(button); } +#if QT_CONFIG(shortcut) /*! Returns the mnemonic that should be used for a standard \a button. @@ -700,6 +701,7 @@ QKeySequence QPlatformTheme::standardButtonShortcut(int button) const Q_UNUSED(button) return QKeySequence(); } +#endif // QT_CONFIG(shortcut) QString QPlatformTheme::defaultStandardButtonText(int button) { @@ -784,7 +786,7 @@ unsigned QPlatformThemePrivate::currentKeyPlatforms() { const uint keyboardScheme = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::KeyboardScheme).toInt(); unsigned result = 1u << keyboardScheme; -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) if (keyboardScheme == QPlatformTheme::KdeKeyboardScheme || keyboardScheme == QPlatformTheme::GnomeKeyboardScheme || keyboardScheme == QPlatformTheme::CdeKeyboardScheme) diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 356c4ea3ea..7b88af954c 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -51,7 +51,9 @@ #include #include -#include +#if QT_CONFIG(shortcut) +# include +#endif QT_BEGIN_NAMESPACE @@ -312,12 +314,14 @@ public: QPlatformTheme::IconOptions iconOptions = nullptr) const; virtual QIconEngine *createIconEngine(const QString &iconName) const; -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) virtual QList keyBindings(QKeySequence::StandardKey key) const; #endif virtual QString standardButtonText(int button) const; +#if QT_CONFIG(shortcut) virtual QKeySequence standardButtonShortcut(int button) const; +#endif static QVariant defaultThemeHint(ThemeHint hint); static QString defaultStandardButtonText(int button); diff --git a/src/gui/kernel/qplatformtheme_p.h b/src/gui/kernel/qplatformtheme_p.h index 73deb890bb..2c16fec141 100644 --- a/src/gui/kernel/qplatformtheme_p.h +++ b/src/gui/kernel/qplatformtheme_p.h @@ -52,7 +52,9 @@ // #include -#include "private/qkeysequence_p.h" +#if QT_CONFIG(shortcut) +# include "private/qkeysequence_p.h" +#endif QT_BEGIN_NAMESPACE @@ -67,7 +69,7 @@ public: void initializeSystemPalette(); -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) static const QKeyBinding keyBindings[]; static const uint numberOfKeyBindings; #endif diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 0395c1db38..b5cd342138 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -48,8 +48,6 @@ #include -#ifndef QT_NO_SHORTCUT - QT_BEGIN_NAMESPACE // To enable verbose output uncomment below @@ -714,5 +712,3 @@ void QShortcutMap::dumpMap() const #endif QT_END_NAMESPACE - -#endif // QT_NO_SHORTCUT diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h index 8fc68229fb..aa3dd969f0 100644 --- a/src/gui/kernel/qshortcutmap_p.h +++ b/src/gui/kernel/qshortcutmap_p.h @@ -56,9 +56,9 @@ #include "QtCore/qvector.h" #include "QtCore/qscopedpointer.h" -QT_BEGIN_NAMESPACE +QT_REQUIRE_CONFIG(shortcut); -#ifndef QT_NO_SHORTCUT +QT_BEGIN_NAMESPACE // To enable dump output uncomment below //#define Dump_QShortcutMap @@ -106,8 +106,6 @@ private: QScopedPointer d_ptr; }; -#endif // QT_NO_SHORTCUT - QT_END_NAMESPACE #endif // QSHORTCUTMAP_P_H diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 5f61853a6d..5ae8013b82 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -434,7 +434,7 @@ void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, ulong t bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestamp, int keyCode, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text, bool autorepeat, ushort count) { -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) if (!window) window = QGuiApplication::focusWindow(); @@ -1238,7 +1238,7 @@ Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *window, QEvent::Type t, int k, Qt:: Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1) { -#ifndef QT_NO_SHORTCUT +#if QT_CONFIG(shortcut) // FIXME: This method should not allow targeting a specific object, but should // instead forward the event to a window, which then takes care of normal event -- cgit v1.2.3 From 698a95dc8ad2218711293d3ee699a0a956e13eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Tue, 22 Oct 2019 16:43:12 +0200 Subject: QFontDatabase: Delete redundant semicolons There are too many semicolons. Delete some. Fixes two warnings from Clang 9.0.1. Change-Id: I363a6a2de9c075c03da62c58ad46828c04a95440 Reviewed-by: Friedemann Kleint --- src/gui/text/qfontengine_p.h | 2 +- src/gui/text/qtextengine_p.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index a5c78d5372..03e14c737a 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -136,7 +136,7 @@ public: signed char format = 0; uchar *data = nullptr; private: - Q_DISABLE_COPY(Glyph); + Q_DISABLE_COPY(Glyph) }; virtual ~QFontEngine(); diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index fddda7f2f8..76b9757eba 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -351,7 +351,7 @@ struct QScriptItem Q_DECL_CONSTEXPR QFixed height() const noexcept { return ascent + descent; } private: friend class QVector; - QScriptItem() {}; // for QVector, don't use + QScriptItem() {} // for QVector, don't use }; Q_DECLARE_TYPEINFO(QScriptItem, Q_PRIMITIVE_TYPE); -- cgit v1.2.3 From a21d4395f4f9afea52b6c2da359ce6ad21ebc763 Mon Sep 17 00:00:00 2001 From: Yulong Bai Date: Thu, 10 Oct 2019 23:05:16 +0200 Subject: Drag'n'Drop: fix attached Drag object deleted when DnD is progressing The attached Drag object's owner, i.e. its parent, is also the dragged item. So the attached Drag object will also be destroyed as the dragged item is deleted. Fixes: QTBUG-65701 Change-Id: I39b0a3180f205c427deed5c70cd1912524f9324e Reviewed-by: Shawn Rutledge --- src/gui/kernel/qdnd.cpp | 9 +++++---- src/gui/kernel/qdnd_p.h | 4 ++-- src/gui/kernel/qdrag.cpp | 7 +++++-- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp index 5c5f166554..dd541af3b8 100644 --- a/src/gui/kernel/qdnd.cpp +++ b/src/gui/kernel/qdnd.cpp @@ -113,11 +113,12 @@ Qt::DropAction QDragManager::drag(QDrag *o) m_object->d_func()->target = 0; - QGuiApplicationPrivate::instance()->notifyDragStarted(o); + QGuiApplicationPrivate::instance()->notifyDragStarted(m_object.data()); const Qt::DropAction result = m_platformDrag->drag(m_object); - m_object = 0; - if (!m_platformDrag->ownsDragObject()) - o->deleteLater(); + if (!m_object.isNull() && !m_platformDrag->ownsDragObject()) + m_object->deleteLater(); + + m_object.clear(); return result; } diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h index 8f8eb03f87..f095fbf7a0 100644 --- a/src/gui/kernel/qdnd_p.h +++ b/src/gui/kernel/qdnd_p.h @@ -101,13 +101,13 @@ public: void setCurrentTarget(QObject *target, bool dropped = false); QObject *currentTarget() const; - QDrag *object() const { return m_object; } + QPointer object() const { return m_object; } QObject *source() const; private: QObject *m_currentDropTarget; QPlatformDrag *m_platformDrag; - QDrag *m_object; + QPointer m_object; static QDragManager *m_instance; Q_DISABLE_COPY_MOVE(QDragManager) diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp index dcd0d13d5c..8e2f7be23e 100644 --- a/src/gui/kernel/qdrag.cpp +++ b/src/gui/kernel/qdrag.cpp @@ -279,8 +279,11 @@ Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defa } d->supported_actions = supportedActions; d->default_action = transformedDefaultDropAction; - d->executed_action = QDragManager::self()->drag(this); - + QPointer self = this; + auto executed_action = QDragManager::self()->drag(self.data()); + if (self.isNull()) + return Qt::IgnoreAction; + d->executed_action = executed_action; return d->executed_action; } -- cgit v1.2.3 From 226a60baf50c9c91a98c01c3dd9c0ced750f8d0e Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 21 Oct 2019 15:19:18 +0200 Subject: Replace Q_ALIGNOF usage in qtbase with C++11 alignof keyword The macro is not documented, so not part of the public Qt API. It is made obsolete by the alignof keyword in C++11. Remove the usage of the macro across qtbase, in particular the workarounds for compilers that didn't support alignof, and that will not be supported in Qt 6. The macro definition is left in place, no need to break existing code. Task-number: QTBUG-76414 Change-Id: I1cfedcd4dd748128696cdfb546d97aae4f98c3da Reviewed-by: Allan Sandfeld Jensen --- src/gui/text/qfontengine_qpf2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp index 409176d41b..36d1cd5b9b 100644 --- a/src/gui/text/qfontengine_qpf2.cpp +++ b/src/gui/text/qfontengine_qpf2.cpp @@ -168,7 +168,7 @@ const QFontEngineQPF2::Glyph *QFontEngineQPF2::findGlyph(glyph_t g) const bool QFontEngineQPF2::verifyHeader(const uchar *data, int size) { - VERIFY(quintptr(data) % Q_ALIGNOF(Header) == 0); + VERIFY(quintptr(data) % alignof(Header) == 0); VERIFY(size >= int(sizeof(Header))); const Header *header = reinterpret_cast(data); if (header->magic[0] != 'Q' -- cgit v1.2.3 From 3ea6a13a01f513ab491f698109fdf189e6264203 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 21 Oct 2019 15:27:04 +0200 Subject: Replace usage of Q_DECL_ALIGN with C++11 alignas keyword The macro is not documented, so can be considered private API. Pre-C++11 compilers that don't support alignas will no longer be supported with Qt 6. The macro definition for the standard case of compilers supporting the alignof keyword is left in place. Task-number: QTBUG-76414 Change-Id: I7d722e4faf09ae998a972d3ed914de808ab316d7 Reviewed-by: Thiago Macieira --- src/gui/painting/qdrawhelper_ssse3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/painting/qdrawhelper_ssse3.cpp b/src/gui/painting/qdrawhelper_ssse3.cpp index 14d7047bb6..a175b591dd 100644 --- a/src/gui/painting/qdrawhelper_ssse3.cpp +++ b/src/gui/painting/qdrawhelper_ssse3.cpp @@ -197,7 +197,7 @@ void qt_memfill24_ssse3(quint24 *dest, quint24 color, qsizetype count) quint24 *end = dest + count; constexpr uchar x = 2, y = 1, z = 0; - Q_DECL_ALIGN(__m128i) static const uchar + alignas(__m128i) static const uchar shuffleMask[16 + 1] = { x, y, z, x, y, z, x, y, z, x, y, z, x, y, z, x, y }; __m128i mval1 = _mm_shuffle_epi8(m, _mm_load_si128(reinterpret_cast(shuffleMask))); -- cgit v1.2.3 From aa91b0083e14197c332d4284472b9fa8ef179320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Sun, 27 Oct 2019 18:25:39 +0100 Subject: qpa: Add note about QScreen taking care of primary screen during removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I31b4ed6e6597e22172dcca7180750f1392b9ad68 Reviewed-by: Simon Hausmann Reviewed-by: Tor Arne Vestbø --- src/gui/kernel/qwindowsysteminterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 4f1056e906..ba04f8701d 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -828,7 +828,8 @@ void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *ps, bool isPrima */ void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen) { - // Important to keep this order since the QSceen doesn't own the platform screen + // Important to keep this order since the QSceen doesn't own the platform screen. + // The QScreen destructor will take care changing the primary screen, so no need here. delete platformScreen->screen(); delete platformScreen; } -- cgit v1.2.3 From 58a67e4e0a88e52d71eef5d08df1465f7ac610ae Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 28 Oct 2019 16:37:57 +0100 Subject: rhi: Move to CBOR in QShader and expand the autotest Binary JSON is said to become deprecated. Therefore, add support for CBOR. Binary JSON is still supported for deserialization, so all existing .qsb files will continue to work, as long as the binaryjson feature is enabled in the Qt build. Also makes QShaderDescription comparable. This is important for tests in particular. A nice side effect of using CBOR is that .qsb files become smaller. For a typical Qt Quick material shader this can mean a reduction of 300 bytes or more. Task-number: QTBUG-79576 Change-Id: I5547c0266e3e8128c9653e954e47487352267f71 Reviewed-by: Paul Olav Tvete --- src/gui/rhi/qshader.cpp | 23 +++--- src/gui/rhi/qshader_p_p.h | 6 ++ src/gui/rhi/qshaderdescription.cpp | 152 ++++++++++++++++++++++++++++++++++++- src/gui/rhi/qshaderdescription_p.h | 40 ++++++++++ 4 files changed, 209 insertions(+), 12 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index c22b029dc8..14d780b4e4 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -214,9 +214,6 @@ QT_BEGIN_NAMESPACE QShader, it indicates no shader code was found for the requested key. */ -static const int QSB_VERSION = 2; -static const int QSB_VERSION_WITHOUT_BINDINGS = 1; - /*! Constructs a new, empty (and thus invalid) QShader instance. */ @@ -368,9 +365,9 @@ QByteArray QShader::serialized() const if (!buf.open(QIODevice::WriteOnly)) return QByteArray(); - ds << QSB_VERSION; + ds << QShaderPrivate::QSB_VERSION; ds << d->stage; - ds << d->desc.toBinaryJson(); + ds << d->desc.toCbor(); ds << d->shaders.count(); for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) { const QShaderKey &k(it.key()); @@ -429,9 +426,12 @@ QShader QShader::fromSerialized(const QByteArray &data) Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached int intVal; ds >> intVal; - const int qsbVersion = intVal; - if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) { - qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion); + d->qsbVersion = intVal; + if (d->qsbVersion != QShaderPrivate::QSB_VERSION + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) + { + qWarning("Attempted to deserialize QShader with unknown version %d.", d->qsbVersion); return QShader(); } @@ -439,7 +439,10 @@ QShader QShader::fromSerialized(const QByteArray &data) d->stage = Stage(intVal); QByteArray descBin; ds >> descBin; - d->desc = QShaderDescription::fromBinaryJson(descBin); + if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) + d->desc = QShaderDescription::fromCbor(descBin); + else + d->desc = QShaderDescription::fromBinaryJson(descBin); int count; ds >> count; for (int i = 0; i < count; ++i) { @@ -454,7 +457,7 @@ QShader QShader::fromSerialized(const QByteArray &data) d->shaders[k] = shader; } - if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) { + if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) { ds >> count; for (int i = 0; i < count; ++i) { QShaderKey k; diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h index 4535e01491..8c89f2b45f 100644 --- a/src/gui/rhi/qshader_p_p.h +++ b/src/gui/rhi/qshader_p_p.h @@ -57,6 +57,10 @@ QT_BEGIN_NAMESPACE struct Q_GUI_EXPORT QShaderPrivate { + static const int QSB_VERSION = 3; + static const int QSB_VERSION_WITH_BINARY_JSON = 2; + static const int QSB_VERSION_WITHOUT_BINDINGS = 1; + QShaderPrivate() : ref(1) { @@ -64,6 +68,7 @@ struct Q_GUI_EXPORT QShaderPrivate QShaderPrivate(const QShaderPrivate *other) : ref(1), + qsbVersion(other->qsbVersion), stage(other->stage), desc(other->desc), shaders(other->shaders), @@ -75,6 +80,7 @@ struct Q_GUI_EXPORT QShaderPrivate static const QShaderPrivate *get(const QShader *s) { return s->d; } QAtomicInt ref; + int qsbVersion = QSB_VERSION; QShader::Stage stage = QShader::VertexStage; QShaderDescription desc; QHash shaders; diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 179d5f3a07..d0f73f6aa7 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -335,11 +338,27 @@ bool QShaderDescription::isValid() const /*! \return a serialized binary version of the data. - \sa toJson() + \sa toJson(), toCbor() */ QByteArray QShaderDescription::toBinaryJson() const { +#if QT_CONFIG(binaryjson) return d->makeDoc().toBinaryData(); +#else + qWarning("Cannot generate binary JSON from QShaderDescription due to disabled binaryjson feature"); + return QByteArray(); +#endif +} + +/*! + \return a serialized binary version of the data in CBOR (Concise Binary + Object Representation) format. + + \sa QCborValue, toBinaryJson(), toJson() + */ +QByteArray QShaderDescription::toCbor() const +{ + return QCborValue::fromJsonValue(d->makeDoc().object()).toCbor(); } /*! @@ -347,7 +366,7 @@ QByteArray QShaderDescription::toBinaryJson() const \note There is no deserialization method provided for JSON text. - \sa toBinaryJson() + \sa toBinaryJson(), toCbor() */ QByteArray QShaderDescription::toJson() const { @@ -357,11 +376,38 @@ QByteArray QShaderDescription::toJson() const /*! Deserializes the given binary JSON \a data and returns a new QShaderDescription. + + \sa fromCbor() */ QShaderDescription QShaderDescription::fromBinaryJson(const QByteArray &data) { QShaderDescription desc; +#if QT_CONFIG(binaryjson) QShaderDescriptionPrivate::get(&desc)->loadDoc(QJsonDocument::fromBinaryData(data)); +#else + Q_UNUSED(data); + qWarning("Cannot load QShaderDescription from binary JSON due to disabled binaryjson feature"); +#endif + return desc; +} + +/*! + Deserializes the given CBOR \a data and returns a new QShaderDescription. + + \sa fromBinaryJson() + */ +QShaderDescription QShaderDescription::fromCbor(const QByteArray &data) +{ + QShaderDescription desc; + const QCborValue cbor = QCborValue::fromCbor(data); + if (cbor.isMap()) { + const QJsonDocument doc(cbor.toMap().toJsonObject()); + QShaderDescriptionPrivate::get(&desc)->loadDoc(doc); + } + if (cbor.isArray()) { + const QJsonDocument doc(cbor.toArray().toJsonArray()); + QShaderDescriptionPrivate::get(&desc)->loadDoc(doc); + } return desc; } @@ -1119,4 +1165,106 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc) } } +/*! + Returns \c true if the two QShaderDescription objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription + */ +bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW +{ + if (lhs.d == rhs.d) + return true; + + return lhs.d->inVars == rhs.d->inVars + && lhs.d->outVars == rhs.d->outVars + && lhs.d->uniformBlocks == rhs.d->uniformBlocks + && lhs.d->pushConstantBlocks == rhs.d->pushConstantBlocks + && lhs.d->storageBlocks == rhs.d->storageBlocks + && lhs.d->combinedImageSamplers == rhs.d->combinedImageSamplers + && lhs.d->storageImages == rhs.d->storageImages + && lhs.d->localSize == rhs.d->localSize; +} + +/*! + Returns \c true if the two InOutVariable objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::InOutVariable + */ +bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW +{ + return lhs.name == rhs.name + && lhs.type == rhs.type + && lhs.location == rhs.location + && lhs.binding == rhs.binding + && lhs.descriptorSet == rhs.descriptorSet + && lhs.imageFormat == rhs.imageFormat + && lhs.imageFlags == rhs.imageFlags; +} + +/*! + Returns \c true if the two BlockVariable objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::BlockVariable + */ +bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW +{ + return lhs.name == rhs.name + && lhs.type == rhs.type + && lhs.offset == rhs.offset + && lhs.size == rhs.size + && lhs.arrayDims == rhs.arrayDims + && lhs.arrayStride == rhs.arrayStride + && lhs.matrixStride == rhs.matrixStride + && lhs.matrixIsRowMajor == rhs.matrixIsRowMajor + && lhs.structMembers == rhs.structMembers; +} + +/*! + Returns \c true if the two UniformBlock objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::UniformBlock + */ +bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW +{ + return lhs.blockName == rhs.blockName + && lhs.structName == rhs.structName + && lhs.size == rhs.size + && lhs.binding == rhs.binding + && lhs.descriptorSet == rhs.descriptorSet + && lhs.members == rhs.members; +} + +/*! + Returns \c true if the two PushConstantBlock objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::PushConstantBlock + */ +bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW +{ + return lhs.name == rhs.name + && lhs.size == rhs.size + && lhs.members == rhs.members; +} + +/*! + Returns \c true if the two StorageBlock objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::StorageBlock + */ +bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW +{ + return lhs.blockName == rhs.blockName + && lhs.instanceName == rhs.instanceName + && lhs.knownSize == rhs.knownSize + && lhs.binding == rhs.binding + && lhs.descriptorSet == rhs.descriptorSet + && lhs.members == rhs.members; +} + QT_END_NAMESPACE diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 5a63b998cd..e02a53dcb5 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -69,9 +69,11 @@ public: bool isValid() const; QByteArray toBinaryJson() const; + QByteArray toCbor() const; QByteArray toJson() const; static QShaderDescription fromBinaryJson(const QByteArray &data); + static QShaderDescription fromCbor(const QByteArray &data); enum VariableType { Unknown = 0, @@ -263,6 +265,7 @@ private: #ifndef QT_NO_DEBUG_STREAM friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &); #endif + friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags) @@ -276,6 +279,43 @@ Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlo Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &); #endif +Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW; + +inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + QT_END_NAMESPACE #endif -- cgit v1.2.3 From bc4e7aecc0db534ad4e52691f70c98f5ad643230 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 30 Oct 2019 11:42:58 +0100 Subject: Don't try to insert items out of bounds The q_items list is only used to hold a full list of all items in the layout. They are kept in order for a linear layout, so that users see them in the right order, but there's no real guarantee for that anyway if combined with spacers and other non-items. Continue to try keeping the order, but ensure indices that are out of bounds are treated as appends to the list. Change-Id: I22721c1fa8b329c5d16ad00c5cb780e099693cda Reviewed-by: Simon Hausmann --- src/gui/util/qgridlayoutengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp index 33adac40b2..bff5b4ddde 100644 --- a/src/gui/util/qgridlayoutengine.cpp +++ b/src/gui/util/qgridlayoutengine.cpp @@ -960,7 +960,7 @@ void QGridLayoutEngine::insertItem(QGridLayoutItem *item, int index) { maybeExpandGrid(item->lastRow(), item->lastColumn()); - if (index == -1) + if (index < 0 || index >= q_items.size()) q_items.append(item); else q_items.insert(index, item); -- cgit v1.2.3 From 1299a2330ae14a6a901f574ea01fc63715e1b87d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 22 May 2019 15:57:45 +0200 Subject: Move QListSpecialMethods over to QVector Extend QVector with special methods for QByteArray and QString, just as QList had them in Qt 5. This also means that QStringList and QByteArrayList are now implemented through a QVector, not a QList anymore. QListIterator is now slightly source incompatible as QStringList is a QVector, but that will be fixed in a follow-up change when QList will start mapping to a QVector. Change-Id: I7cfb8a72d4d95b347bbd386892f244b7203b41c2 Reviewed-by: Simon Hausmann --- src/gui/painting/qcolor.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/gui') diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index f0d7dd23ad..c3111f9e3b 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -46,6 +46,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE -- cgit v1.2.3 From c3eb521a0f10112df6b61d2592351c4eef2e1f9b Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 23 Oct 2019 17:17:49 +0200 Subject: Update UCD data to Unicode 12.1.0's Revision 24 Had to teach the update program to accept category Lm as for Joining_Transparent, for the sake of a new ArabicShaping.txt entry. Added three new Unicode versions, several new scripts and a new word-break class. Updated UCD's test data for tst_QTextBoundaryFinder. This left 57 tests failing; I have commented out the data rows for those tests, pending someone with more knowledge addressing this. Task-number: QTBUG-79631 Task-number: QTBUG-79418 Change-Id: Ic33d3b3551195d47a84d98e84020f57a68f0b201 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qharfbuzzng.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index 2f25aea92b..9c8582b43d 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2013 Konstantin Ritt ** Contact: https://www.qt.io/licensing/ ** @@ -216,7 +216,20 @@ static const hb_script_t _qtscript_to_hbscript[] = { HB_SCRIPT_MASARAM_GONDI, HB_SCRIPT_NUSHU, HB_SCRIPT_SOYOMBO, - HB_SCRIPT_ZANABAZAR_SQUARE + HB_SCRIPT_ZANABAZAR_SQUARE, + + // Unicode 12.1 additions (not present in harfbuzz-ng 1.7.4) + hb_script_t(HB_TAG('D', 'o', 'g', 'r')), // Script_Dogra + hb_script_t(HB_TAG('G', 'o', 'n', 'g')), // Script_GunjalaGondi + hb_script_t(HB_TAG('R', 'o', 'h', 'g')), // Script_HanifiRohingya + hb_script_t(HB_TAG('M', 'a', 'k', 'a')), // Script_Makasar + hb_script_t(HB_TAG('M', 'e', 'd', 'f')), // Script_Medefaidrin + hb_script_t(HB_TAG('S', 'o', 'g', 'o')), // Script_OldSogdian + hb_script_t(HB_TAG('S', 'o', 'g', 'd')), // Script_Sogdian + hb_script_t(HB_TAG('E', 'l', 'y', 'm')), // Script_Elymaic + hb_script_t(HB_TAG('N', 'a', 'n', 'd')), // Script_Nandinagari + hb_script_t(HB_TAG('H', 'm', 'n', 'p')), // Script_NyiakengPuachueHmong + hb_script_t(HB_TAG('W', 'c', 'h', 'o')), // Script_Wancho }; Q_STATIC_ASSERT(QChar::ScriptCount == sizeof(_qtscript_to_hbscript) / sizeof(_qtscript_to_hbscript[0])); -- cgit v1.2.3 From cff492fed1d98f45c4c1f4011f1451120c0d1c23 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 19 Jun 2019 13:00:11 +0200 Subject: Extract QGuiAction(Group) from QAction(Group) into QtGui Simply moving QAction to QtGui was not deemed possible since it operates on a set of controls of some kind. The approach to extract a base class was taken instead, named QGuiAction following the QGuiApplication scheme. QAction remains in widgets, but changes base class. For QActionGroup, the functions addAction(text/icon), which create an action, cannot be implemented in QtGui, hence a base class is needed, too (unless they are deprecated and removed). - Extract base classes providing functionality not based on QtWidgets, using virtuals in QGuiActionPrivate to provide customization points - Change QActionEvent to take QGuiAction, removing the need to forward declare QAction in QtGui [ChangeLog][QtGui] Added QGuiAction(Group) and made the equivalent existing classes in Qt Widgets derive from them. This provides basic functionality for implementing actions in QML. Task-number: QTBUG-69478 Change-Id: Ic490a5e3470939ee8af612d46ff41d4c8c91fbdf Reviewed-by: Lars Knoll Reviewed-by: Mitch Curtis Reviewed-by: Oliver Wolff Reviewed-by: Allan Sandfeld Jensen --- src/gui/kernel/kernel.pri | 12 + src/gui/kernel/qevent.cpp | 10 +- src/gui/kernel/qevent.h | 10 +- src/gui/kernel/qguiaction.cpp | 1214 ++++++++++++++++++++++++++++++++++++ src/gui/kernel/qguiaction.h | 198 ++++++ src/gui/kernel/qguiaction_p.h | 128 ++++ src/gui/kernel/qguiactiongroup.cpp | 345 ++++++++++ src/gui/kernel/qguiactiongroup.h | 104 +++ src/gui/kernel/qguiactiongroup_p.h | 91 +++ 9 files changed, 2102 insertions(+), 10 deletions(-) create mode 100644 src/gui/kernel/qguiaction.cpp create mode 100644 src/gui/kernel/qguiaction.h create mode 100644 src/gui/kernel/qguiaction_p.h create mode 100644 src/gui/kernel/qguiactiongroup.cpp create mode 100644 src/gui/kernel/qguiactiongroup.h create mode 100644 src/gui/kernel/qguiactiongroup_p.h (limited to 'src/gui') diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 237a1c0a3f..42bb81fa24 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -126,6 +126,18 @@ SOURCES += \ kernel/qhighdpiscaling.cpp \ kernel/qtestsupport_gui.cpp +qtConfig(action) { + HEADERS += \ + kernel/qguiaction.h \ + kernel/qguiaction_p.h \ + kernel/qguiactiongroup.h \ + kernel/qguiactiongroup_p.h + + SOURCES += \ + kernel/qguiactiongroup.cpp \ + kernel/qguiaction.cpp +} + qtConfig(draganddrop) { HEADERS += \ kernel/qdnd_p.h \ diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 54502bc6a3..23defef50c 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3324,18 +3324,18 @@ QWhatsThisClickedEvent::~QWhatsThisClickedEvent() /*! \class QActionEvent \brief The QActionEvent class provides an event that is generated - when a QAction is added, removed, or changed. + when a QGuiAction is added, removed, or changed. \ingroup events \inmodule QtGui - Actions can be added to widgets using QWidget::addAction(). This - generates an \l ActionAdded event, which you can handle to provide + Actions can be added to controls, for example by using QWidget::addAction(). + This generates an \l ActionAdded event, which you can handle to provide custom behavior. For example, QToolBar reimplements QWidget::actionEvent() to create \l{QToolButton}s for the actions. - \sa QAction, QWidget::addAction(), QWidget::removeAction(), QWidget::actions() + \sa QGuiAction, QWidget::addAction(), QWidget::removeAction(), QWidget::actions() */ /*! @@ -3346,7 +3346,7 @@ QWhatsThisClickedEvent::~QWhatsThisClickedEvent() type is ActionAdded, the action is to be inserted before the action \a before. If \a before is 0, the action is appended. */ -QActionEvent::QActionEvent(int type, QAction *action, QAction *before) +QActionEvent::QActionEvent(int type, QGuiAction *action, QGuiAction *before) : QEvent(static_cast(type)), act(action), bef(before) {} diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 28aa78a420..85d22319ae 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE -class QAction; +class QGuiAction; #ifndef QT_NO_GESTURES class QGesture; #endif @@ -756,13 +756,13 @@ private: #ifndef QT_NO_ACTION class Q_GUI_EXPORT QActionEvent : public QEvent { - QAction *act, *bef; + QGuiAction *act, *bef; public: - QActionEvent(int type, QAction *action, QAction *before = nullptr); + QActionEvent(int type, QGuiAction *action, QGuiAction *before = nullptr); ~QActionEvent(); - inline QAction *action() const { return act; } - inline QAction *before() const { return bef; } + inline QGuiAction *action() const { return act; } + inline QGuiAction *before() const { return bef; } }; #endif diff --git a/src/gui/kernel/qguiaction.cpp b/src/gui/kernel/qguiaction.cpp new file mode 100644 index 0000000000..7c7d86f5ab --- /dev/null +++ b/src/gui/kernel/qguiaction.cpp @@ -0,0 +1,1214 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguiaction.h" +#include "qguiactiongroup.h" + +#include "qguiaction_p.h" +#include "qguiapplication.h" +#include "qevent.h" +#include "qlist.h" +#include "qstylehints.h" +#if QT_CONFIG(shortcut) +# include +#endif +#include +#include + +#define QAPP_CHECK(functionName) \ + if (Q_UNLIKELY(!QCoreApplication::instance())) { \ + qWarning("QAction: Initialize Q(Gui)Application before calling '" functionName "'."); \ + return; \ + } + +QT_BEGIN_NAMESPACE + +/* + internal: guesses a descriptive text from a text suited for a menu entry + */ +static QString qt_strippedText(QString s) +{ + s.remove(QLatin1String("...")); + for (int i = 0; i < s.size(); ++i) { + if (s.at(i) == QLatin1Char('&')) + s.remove(i, 1); + } + return s.trimmed(); +} + +QGuiActionPrivate::QGuiActionPrivate() : +#if QT_CONFIG(shortcut) + autorepeat(1), +#endif + enabled(1), forceDisabled(0), visible(1), forceInvisible(0), checkable(0), + checked(0), separator(0), fontSet(false), + iconVisibleInMenu(-1), shortcutVisibleInContextMenu(-1) +{ +} + +#if QT_CONFIG(shortcut) +static bool dummy(QObject *, Qt::ShortcutContext) { return false; } // only for GUI testing. + +QShortcutMap::ContextMatcher QGuiActionPrivate::contextMatcher() const +{ + return dummy; +} +#endif // QT_CONFIG(shortcut) + +QGuiActionPrivate::~QGuiActionPrivate() = default; + +void QGuiActionPrivate::sendDataChanged() +{ + Q_Q(QGuiAction); + QActionEvent e(QEvent::ActionChanged, q); + QCoreApplication::sendEvent(q, &e); + + emit q->changed(); +} + +#if QT_CONFIG(shortcut) +void QGuiActionPrivate::redoGrab(QShortcutMap &map) +{ + Q_Q(QGuiAction); + if (shortcutId) + map.removeShortcut(shortcutId, q); + if (shortcut.isEmpty()) + return; + shortcutId = map.addShortcut(q, shortcut, shortcutContext, contextMatcher()); + if (!enabled) + map.setShortcutEnabled(false, shortcutId, q); + if (!autorepeat) + map.setShortcutAutoRepeat(false, shortcutId, q); +} + +void QGuiActionPrivate::redoGrabAlternate(QShortcutMap &map) +{ + Q_Q(QGuiAction); + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) + map.removeShortcut(id, q); + } + alternateShortcutIds.clear(); + if (alternateShortcuts.isEmpty()) + return; + for(int i = 0; i < alternateShortcuts.count(); ++i) { + const QKeySequence& alternate = alternateShortcuts.at(i); + if (!alternate.isEmpty()) + alternateShortcutIds.append(map.addShortcut(q, alternate, shortcutContext, contextMatcher())); + else + alternateShortcutIds.append(0); + } + if (!enabled) { + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); + map.setShortcutEnabled(false, id, q); + } + } + if (!autorepeat) { + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); + map.setShortcutAutoRepeat(false, id, q); + } + } +} + +void QGuiActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) +{ + Q_Q(QGuiAction); + if (shortcutId) + map.setShortcutEnabled(enable, shortcutId, q); + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) + map.setShortcutEnabled(enable, id, q); + } +} +#endif // QT_NO_SHORTCUT + + +/*! + \class QGuiAction + \brief QGuiAction is the base class for actions, an abstract user interface + action that can be inserted into widgets. + \since 6.0 + + \inmodule QtGui + + In applications many common commands can be invoked via menus, + toolbar buttons, and keyboard shortcuts. Since the user expects + each command to be performed in the same way, regardless of the + user interface used, it is useful to represent each command as + an \e action. + + Actions can be added to menus and toolbars, and will + automatically keep them in sync. For example, in a word processor, + if the user presses a Bold toolbar button, the Bold menu item + will automatically be checked. + + Actions can be created as independent objects, but they may + also be created during the construction of menus; the QMenu class + contains convenience functions for creating actions suitable for + use as menu items. + + A QGuiAction may contain an icon, menu text, a shortcut, status text, + "What's This?" text, and a tooltip. Most of these can be set in + the constructor. They can also be set independently with + setIcon(), setText(), setIconText(), setShortcut(), + setStatusTip(), setWhatsThis(), and setToolTip(). For menu items, + it is possible to set an individual font with setFont(). + + We recommend that actions are created as children of the window + they are used in. In most cases actions will be children of + the application's main window. + + \sa QMenu, QToolBar, {Application Example} +*/ + +/*! + \fn void QGuiAction::trigger() + + This is a convenience slot that calls activate(Trigger). +*/ + +/*! + \fn void QGuiAction::hover() + + This is a convenience slot that calls activate(Hover). +*/ + +/*! + \enum QGuiAction::MenuRole + + This enum describes how an action should be moved into the application menu on \macos. + + \value NoRole This action should not be put into the application menu + \value TextHeuristicRole This action should be put in the application menu based on the action's text + as described in the QMenuBar documentation. + \value ApplicationSpecificRole This action should be put in the application menu with an application specific role + \value AboutQtRole This action handles the "About Qt" menu item. + \value AboutRole This action should be placed where the "About" menu item is in the application menu. The text of + the menu item will be set to "About ". The application name is fetched from the + \c{Info.plist} file in the application's bundle (See \l{Qt for macOS - Deployment}). + \value PreferencesRole This action should be placed where the "Preferences..." menu item is in the application menu. + \value QuitRole This action should be placed where the Quit menu item is in the application menu. + + Setting this value only has effect on items that are in the immediate menus + of the menubar, not the submenus of those menus. For example, if you have + File menu in your menubar and the File menu has a submenu, setting the + MenuRole for the actions in that submenu have no effect. They will never be moved. +*/ + +/*! + Constructs an action with \a parent. If \a parent is an action + group the action will be automatically inserted into the group. + + \note The \a parent argument is optional since Qt 5.7. +*/ +QGuiAction::QGuiAction(QObject *parent) + : QGuiAction(*new QGuiActionPrivate, parent) +{ +} + +/*! + Constructs an action with some \a text and \a parent. If \a + parent is an action group the action will be automatically + inserted into the group. + + The action uses a stripped version of \a text (e.g. "\&Menu + Option..." becomes "Menu Option") as descriptive text for + tool buttons. You can override this by setting a specific + description with setText(). The same text will be used for + tooltips unless you specify a different text using + setToolTip(). + +*/ +QGuiAction::QGuiAction(const QString &text, QObject *parent) + : QGuiAction(parent) +{ + Q_D(QGuiAction); + d->text = text; +} + +/*! + Constructs an action with an \a icon and some \a text and \a + parent. If \a parent is an action group the action will be + automatically inserted into the group. + + The action uses a stripped version of \a text (e.g. "\&Menu + Option..." becomes "Menu Option") as descriptive text for + tool buttons. You can override this by setting a specific + description with setText(). The same text will be used for + tooltips unless you specify a different text using + setToolTip(). +*/ +QGuiAction::QGuiAction(const QIcon &icon, const QString &text, QObject *parent) + : QGuiAction(text, parent) +{ + Q_D(QGuiAction); + d->icon = icon; +} + +/*! + \internal +*/ +QGuiAction::QGuiAction(QGuiActionPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QGuiAction); + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} + +#if QT_CONFIG(shortcut) +/*! + \property QGuiAction::shortcut + \brief the action's primary shortcut key + + Valid keycodes for this property can be found in \l Qt::Key and + \l Qt::Modifier. There is no default shortcut key. +*/ +void QGuiAction::setShortcut(const QKeySequence &shortcut) +{ + QAPP_CHECK("setShortcut"); + + Q_D(QGuiAction); + if (d->shortcut == shortcut) + return; + + d->shortcut = shortcut; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); + d->sendDataChanged(); +} + +/*! + Sets \a shortcuts as the list of shortcuts that trigger the + action. The first element of the list is the primary shortcut. + + \sa shortcut +*/ +void QGuiAction::setShortcuts(const QList &shortcuts) +{ + Q_D(QGuiAction); + + QList listCopy = shortcuts; + + QKeySequence primary; + if (!listCopy.isEmpty()) + primary = listCopy.takeFirst(); + + if (d->shortcut == primary && d->alternateShortcuts == listCopy) + return; + + QAPP_CHECK("setShortcuts"); + + d->shortcut = primary; + d->alternateShortcuts = listCopy; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); + d->redoGrabAlternate(QGuiApplicationPrivate::instance()->shortcutMap); + d->sendDataChanged(); +} + +/*! + Sets a platform dependent list of shortcuts based on the \a key. + The result of calling this function will depend on the currently running platform. + Note that more than one shortcut can assigned by this action. + If only the primary shortcut is required, use setShortcut instead. + + \sa QKeySequence::keyBindings() +*/ +void QGuiAction::setShortcuts(QKeySequence::StandardKey key) +{ + QList list = QKeySequence::keyBindings(key); + setShortcuts(list); +} + +/*! + Returns the primary shortcut. + + \sa setShortcuts() +*/ +QKeySequence QGuiAction::shortcut() const +{ + Q_D(const QGuiAction); + return d->shortcut; +} + +/*! + Returns the list of shortcuts, with the primary shortcut as + the first element of the list. + + \sa setShortcuts() +*/ +QList QGuiAction::shortcuts() const +{ + Q_D(const QGuiAction); + QList shortcuts; + if (!d->shortcut.isEmpty()) + shortcuts << d->shortcut; + if (!d->alternateShortcuts.isEmpty()) + shortcuts << d->alternateShortcuts; + return shortcuts; +} + +/*! + \property QGuiAction::shortcutContext + \brief the context for the action's shortcut + + Valid values for this property can be found in \l Qt::ShortcutContext. + The default value is Qt::WindowShortcut. +*/ +void QGuiAction::setShortcutContext(Qt::ShortcutContext context) +{ + Q_D(QGuiAction); + if (d->shortcutContext == context) + return; + QAPP_CHECK("setShortcutContext"); + d->shortcutContext = context; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); + d->redoGrabAlternate(QGuiApplicationPrivate::instance()->shortcutMap); + d->sendDataChanged(); +} + +Qt::ShortcutContext QGuiAction::shortcutContext() const +{ + Q_D(const QGuiAction); + return d->shortcutContext; +} + +/*! + \property QGuiAction::autoRepeat + \brief whether the action can auto repeat + + If true, the action will auto repeat when the keyboard shortcut + combination is held down, provided that keyboard auto repeat is + enabled on the system. + The default value is true. +*/ +void QGuiAction::setAutoRepeat(bool on) +{ + Q_D(QGuiAction); + if (d->autorepeat == on) + return; + QAPP_CHECK("setAutoRepeat"); + d->autorepeat = on; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); + d->redoGrabAlternate(QGuiApplicationPrivate::instance()->shortcutMap); + d->sendDataChanged(); +} + +bool QGuiAction::autoRepeat() const +{ + Q_D(const QGuiAction); + return d->autorepeat; +} +#endif // QT_CONFIG(shortcut) + +/*! + \property QGuiAction::font + \brief the action's font + + The font property is used to render the text set on the + QAction. The font will can be considered a hint as it will not be + consulted in all cases based upon application and style. + + By default, this property contains the application's default font. + + \sa setText() +*/ +void QGuiAction::setFont(const QFont &font) +{ + Q_D(QGuiAction); + if (d->font == font) + return; + + d->fontSet = true; + d->font = font; + d->sendDataChanged(); +} + +QFont QGuiAction::font() const +{ + Q_D(const QGuiAction); + return d->font; +} + + +/*! + Destroys the object and frees allocated resources. +*/ +QGuiAction::~QGuiAction() +{ + Q_D(QGuiAction); + if (d->group) + d->group->removeAction(this); +#if QT_CONFIG(shortcut) + if (d->shortcutId && qApp) { + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->shortcutId, this); + for (int id : qAsConst(d->alternateShortcutIds)) + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(id, this); + } +#endif +} + +/*! + Sets this action group to \a group. The action will be automatically + added to the group's list of actions. + + Actions within the group will be mutually exclusive. + + \sa QGuiActionGroup, guiActionGroup() +*/ +void QGuiAction::setActionGroup(QGuiActionGroup *group) +{ + Q_D(QGuiAction); + if(group == d->group) + return; + + if(d->group) + d->group->removeAction(this); + d->group = group; + if(group) + group->addAction(this); + d->sendDataChanged(); +} + +/*! + Returns the action group for this action. If no action group manages + this action, then \nullptr will be returned. + + \sa QGuiActionGroup, setActionGroup() +*/ +QGuiActionGroup *QGuiAction::guiActionGroup() const +{ + Q_D(const QGuiAction); + return d->group; +} + + +/*! + \property QGuiAction::icon + \brief the action's icon + + In toolbars, the icon is used as the tool button icon; in menus, + it is displayed to the left of the menu text. There is no default + icon. + + If a null icon (QIcon::isNull()) is passed into this function, + the icon of the action is cleared. +*/ +void QGuiAction::setIcon(const QIcon &icon) +{ + Q_D(QGuiAction); + d->icon = icon; + d->sendDataChanged(); +} + +QIcon QGuiAction::icon() const +{ + Q_D(const QGuiAction); + return d->icon; +} + +/*! + If \a b is true then this action will be considered a separator. + + How a separator is represented depends on the widget it is inserted + into. Under most circumstances the text, submenu, and icon will be + ignored for separator actions. + + \sa isSeparator() +*/ +void QGuiAction::setSeparator(bool b) +{ + Q_D(QGuiAction); + if (d->separator == b) + return; + + d->separator = b; + d->sendDataChanged(); +} + +/*! + Returns \c true if this action is a separator action; otherwise it + returns \c false. + + \sa setSeparator() +*/ +bool QGuiAction::isSeparator() const +{ + Q_D(const QGuiAction); + return d->separator; +} + +/*! + \property QGuiAction::text + \brief the action's descriptive text + + If the action is added to a menu, the menu option will consist of + the icon (if there is one), the text, and the shortcut (if there + is one). If the text is not explicitly set in the constructor, or + by using setText(), the action's description icon text will be + used as text. There is no default text. + + \sa iconText +*/ +void QGuiAction::setText(const QString &text) +{ + Q_D(QGuiAction); + if (d->text == text) + return; + + d->text = text; + d->sendDataChanged(); +} + +QString QGuiAction::text() const +{ + Q_D(const QGuiAction); + QString s = d->text; + if(s.isEmpty()) { + s = d->iconText; + s.replace(QLatin1Char('&'), QLatin1String("&&")); + } + return s; +} + +/*! + \property QGuiAction::iconText + \brief the action's descriptive icon text + + If QToolBar::toolButtonStyle is set to a value that permits text to + be displayed, the text defined held in this property appears as a + label in the relevant tool button. + + It also serves as the default text in menus and tooltips if the action + has not been defined with setText() or setToolTip(), and will + also be used in toolbar buttons if no icon has been defined using setIcon(). + + If the icon text is not explicitly set, the action's normal text will be + used for the icon text. + + By default, this property contains an empty string. + + \sa setToolTip(), setStatusTip() +*/ +void QGuiAction::setIconText(const QString &text) +{ + Q_D(QGuiAction); + if (d->iconText == text) + return; + + d->iconText = text; + d->sendDataChanged(); +} + +QString QGuiAction::iconText() const +{ + Q_D(const QGuiAction); + if (d->iconText.isEmpty()) + return qt_strippedText(d->text); + return d->iconText; +} + +/*! + \property QGuiAction::toolTip + \brief the action's tooltip + + This text is used for the tooltip. If no tooltip is specified, + the action's text is used. + + By default, this property contains the action's text. + + \sa setStatusTip(), setShortcut() +*/ +void QGuiAction::setToolTip(const QString &tooltip) +{ + Q_D(QGuiAction); + if (d->tooltip == tooltip) + return; + + d->tooltip = tooltip; + d->sendDataChanged(); +} + +QString QGuiAction::toolTip() const +{ + Q_D(const QGuiAction); + if (d->tooltip.isEmpty()) { + if (!d->text.isEmpty()) + return qt_strippedText(d->text); + return qt_strippedText(d->iconText); + } + return d->tooltip; +} + +/*! + \property QGuiAction::statusTip + \brief the action's status tip + + The status tip is displayed on all status bars provided by the + action's top-level parent widget. + + By default, this property contains an empty string. + + \sa setToolTip(), showStatusText() +*/ +void QGuiAction::setStatusTip(const QString &statustip) +{ + Q_D(QGuiAction); + if (d->statustip == statustip) + return; + + d->statustip = statustip; + d->sendDataChanged(); +} + +QString QGuiAction::statusTip() const +{ + Q_D(const QGuiAction); + return d->statustip; +} + +/*! + \property QGuiAction::whatsThis + \brief the action's "What's This?" help text + + The "What's This?" text is used to provide a brief description of + the action. The text may contain rich text. There is no default + "What's This?" text. + + \sa QWhatsThis +*/ +void QGuiAction::setWhatsThis(const QString &whatsthis) +{ + Q_D(QGuiAction); + if (d->whatsthis == whatsthis) + return; + + d->whatsthis = whatsthis; + d->sendDataChanged(); +} + +QString QGuiAction::whatsThis() const +{ + Q_D(const QGuiAction); + return d->whatsthis; +} + +/*! + \enum QGuiAction::Priority + + This enum defines priorities for actions in user interface. + + \value LowPriority The action should not be prioritized in + the user interface. + + \value NormalPriority + + \value HighPriority The action should be prioritized in + the user interface. + + \sa priority +*/ + + +/*! + \property QGuiAction::priority + + \brief the actions's priority in the user interface. + + This property can be set to indicate how the action should be prioritized + in the user interface. + + For instance, when toolbars have the Qt::ToolButtonTextBesideIcon + mode set, then actions with LowPriority will not show the text + labels. +*/ +void QGuiAction::setPriority(Priority priority) +{ + Q_D(QGuiAction); + if (d->priority == priority) + return; + + d->priority = priority; + d->sendDataChanged(); +} + +QGuiAction::Priority QGuiAction::priority() const +{ + Q_D(const QGuiAction); + return d->priority; +} + +/*! + \property QGuiAction::checkable + \brief whether the action is a checkable action + + A checkable action is one which has an on/off state. For example, + in a word processor, a Bold toolbar button may be either on or + off. An action which is not a toggle action is a command action; + a command action is simply executed, e.g. file save. + By default, this property is \c false. + + In some situations, the state of one toggle action should depend + on the state of others. For example, "Left Align", "Center" and + "Right Align" toggle actions are mutually exclusive. To achieve + exclusive toggling, add the relevant toggle actions to a + QGuiActionGroup with the QGuiActionGroup::exclusive property set to + true. + + \sa setChecked() +*/ +void QGuiAction::setCheckable(bool b) +{ + Q_D(QGuiAction); + if (d->checkable == b) + return; + + d->checkable = b; + d->checked = false; + d->sendDataChanged(); +} + +bool QGuiAction::isCheckable() const +{ + Q_D(const QGuiAction); + return d->checkable; +} + +/*! + \fn void QGuiAction::toggle() + + This is a convenience function for the \l checked property. + Connect to it to change the checked state to its opposite state. +*/ +void QGuiAction::toggle() +{ + Q_D(QGuiAction); + setChecked(!d->checked); +} + +/*! + \property QGuiAction::checked + \brief whether the action is checked. + + Only checkable actions can be checked. By default, this is false + (the action is unchecked). + + \note The notifier signal for this property is toggled(). As toggling + a QAction changes its state, it will also emit a changed() signal. + + \sa checkable, toggled() +*/ +void QGuiAction::setChecked(bool b) +{ + Q_D(QGuiAction); + if (!d->checkable || d->checked == b) + return; + + QPointer guard(this); + d->checked = b; + d->sendDataChanged(); + if (guard) + emit toggled(b); +} + +bool QGuiAction::isChecked() const +{ + Q_D(const QGuiAction); + return d->checked; +} + +/*! + \fn void QGuiAction::setDisabled(bool b) + + This is a convenience function for the \l enabled property, that + is useful for signals--slots connections. If \a b is true the + action is disabled; otherwise it is enabled. +*/ + +/*! + \property QGuiAction::enabled + \brief whether the action is enabled + + Disabled actions cannot be chosen by the user. They do not + disappear from menus or toolbars, but they are displayed in a way + which indicates that they are unavailable. For example, they might + be displayed using only shades of gray. + + \uicontrol{What's This?} help on disabled actions is still available, provided + that the QAction::whatsThis property is set. + + An action will be disabled when all widgets to which it is added + (with QWidget::addAction()) are disabled or not visible. When an + action is disabled, it is not possible to trigger it through its + shortcut. + + By default, this property is \c true (actions are enabled). + + \sa text +*/ +void QGuiAction::setEnabled(bool b) +{ + Q_D(QGuiAction); + if (b == d->enabled && b != d->forceDisabled) + return; + d->forceDisabled = !b; + if (b && (!d->visible || (d->group && !d->group->isEnabled()))) + return; + QAPP_CHECK("setEnabled"); + d->enabled = b; +#if QT_CONFIG(shortcut) + d->setShortcutEnabled(b, QGuiApplicationPrivate::instance()->shortcutMap); +#endif + d->sendDataChanged(); +} + +bool QGuiAction::isEnabled() const +{ + Q_D(const QGuiAction); + return d->enabled; +} + +/*! + \property QGuiAction::visible + \brief whether the action can be seen (e.g. in menus and toolbars) + + If \e visible is true the action can be seen (e.g. in menus and + toolbars) and chosen by the user; if \e visible is false the + action cannot be seen or chosen by the user. + + Actions which are not visible are \e not grayed out; they do not + appear at all. + + By default, this property is \c true (actions are visible). +*/ +void QGuiAction::setVisible(bool b) +{ + Q_D(QGuiAction); + if (b == d->visible && b != d->forceInvisible) + return; + QAPP_CHECK("setVisible"); + d->forceInvisible = !b; + d->visible = b; + d->enabled = b && !d->forceDisabled && (!d->group || d->group->isEnabled()) ; +#if QT_CONFIG(shortcut) + d->setShortcutEnabled(d->enabled, QGuiApplicationPrivate::instance()->shortcutMap); +#endif + d->sendDataChanged(); +} + + +bool QGuiAction::isVisible() const +{ + Q_D(const QGuiAction); + return d->visible; +} + +/*! + \reimp +*/ +bool QGuiAction::event(QEvent *e) +{ +#if QT_CONFIG(shortcut) + if (e->type() == QEvent::Shortcut) { + QShortcutEvent *se = static_cast(e); + Q_ASSERT_X(se->key() == d_func()->shortcut || d_func()->alternateShortcuts.contains(se->key()), + "QAction::event", + "Received shortcut event from incorrect shortcut"); + if (se->isAmbiguous()) + qWarning("QAction::event: Ambiguous shortcut overload: %s", se->key().toString(QKeySequence::NativeText).toLatin1().constData()); + else + activate(Trigger); + return true; + } +#endif // QT_CONFIG(shortcut) + return QObject::event(e); +} + +/*! + Returns the user data as set in QAction::setData. + + \sa setData() +*/ +QVariant QGuiAction::data() const +{ + Q_D(const QGuiAction); + return d->userData; +} + +/*! + Sets the action's internal data to the given \a userData. + + \sa data() +*/ +void QGuiAction::setData(const QVariant &data) +{ + Q_D(QGuiAction); + if (d->userData == data) + return; + d->userData = data; + d->sendDataChanged(); +} + +/*! + Sends the relevant signals for ActionEvent \a event. + + Action based widgets use this API to cause the QAction + to emit signals as well as emitting their own. +*/ +void QGuiAction::activate(ActionEvent event) +{ + Q_D(QGuiAction); + if(event == Trigger) { + QPointer guard = this; + if(d->checkable) { + // the checked action of an exclusive group may not be unchecked + if (d->checked && (d->group + && d->group->exclusionPolicy() == QGuiActionGroup::ExclusionPolicy::Exclusive + && d->group->checkedGuiAction() == this)) { + if (!guard.isNull()) + emit triggered(true); + return; + } + setChecked(!d->checked); + } + if (!guard.isNull()) + emit triggered(d->checked); + } else if(event == Hover) { + emit hovered(); + } +} + +/*! + \fn void QGuiAction::triggered(bool checked) + + This signal is emitted when an action is activated by the user; + for example, when the user clicks a menu option, toolbar button, + or presses an action's shortcut key combination, or when trigger() + was called. Notably, it is \e not emitted when setChecked() or + toggle() is called. + + If the action is checkable, \a checked is true if the action is + checked, or false if the action is unchecked. + + \sa activate(), toggled(), checked +*/ + +/*! + \fn void QGuiAction::toggled(bool checked) + + This signal is emitted whenever a checkable action changes its + isChecked() status. This can be the result of a user interaction, + or because setChecked() was called. As setChecked() changes the + QAction, it emits changed() in addition to toggled(). + + \a checked is true if the action is checked, or false if the + action is unchecked. + + \sa activate(), triggered(), checked +*/ + +/*! + \fn void QGuiAction::hovered() + + This signal is emitted when an action is highlighted by the user; + for example, when the user pauses with the cursor over a menu option, + toolbar button, or presses an action's shortcut key combination. + + \sa activate() +*/ + +/*! + \fn void QGuiAction::changed() + + This signal is emitted when an action has changed. If you + are only interested in actions in a given widget, you can + watch for QWidget::actionEvent() sent with an + QEvent::ActionChanged. + + \sa QWidget::actionEvent() +*/ + +/*! + \enum QGuiAction::ActionEvent + + This enum type is used when calling QAction::activate() + + \value Trigger this will cause the QAction::triggered() signal to be emitted. + + \value Hover this will cause the QAction::hovered() signal to be emitted. +*/ + +/*! + \property QGuiAction::menuRole + \brief the action's menu role + + This indicates what role the action serves in the application menu on + \macos. By default all actions have the TextHeuristicRole, which means that + the action is added based on its text (see QMenuBar for more information). + + The menu role can only be changed before the actions are put into the menu + bar in \macos (usually just before the first application window is + shown). +*/ +void QGuiAction::setMenuRole(MenuRole menuRole) +{ + Q_D(QGuiAction); + if (d->menuRole == menuRole) + return; + + d->menuRole = menuRole; + d->sendDataChanged(); +} + +QGuiAction::MenuRole QGuiAction::menuRole() const +{ + Q_D(const QGuiAction); + return d->menuRole; +} + +/*! + \property QGuiAction::iconVisibleInMenu + \brief Whether or not an action should show an icon in a menu + + In some applications, it may make sense to have actions with icons in the + toolbar, but not in menus. If true, the icon (if valid) is shown in the menu, when it + is false, it is not shown. + + The default is to follow whether the Qt::AA_DontShowIconsInMenus attribute + is set for the application. Explicitly settings this property overrides + the presence (or abscence) of the attribute. + + For example: + \snippet code/src_gui_kernel_qaction.cpp 0 + + \sa icon, QCoreApplication::setAttribute() +*/ +void QGuiAction::setIconVisibleInMenu(bool visible) +{ + Q_D(QGuiAction); + if (d->iconVisibleInMenu == -1 || visible != bool(d->iconVisibleInMenu)) { + int oldValue = d->iconVisibleInMenu; + d->iconVisibleInMenu = visible; + // Only send data changed if we really need to. + if (oldValue != -1 + || visible == !QCoreApplication::testAttribute(Qt::AA_DontShowIconsInMenus)) { + d->sendDataChanged(); + } + } +} + +bool QGuiAction::isIconVisibleInMenu() const +{ + Q_D(const QGuiAction); + if (d->iconVisibleInMenu == -1) { + return !QCoreApplication::testAttribute(Qt::AA_DontShowIconsInMenus); + } + return d->iconVisibleInMenu; +} + +/*! + \property QGuiAction::shortcutVisibleInContextMenu + \brief Whether or not an action should show a shortcut in a context menu + + In some applications, it may make sense to have actions with shortcuts in + context menus. If true, the shortcut (if valid) is shown when the action is + shown via a context menu, when it is false, it is not shown. + + The default is to follow whether the Qt::AA_DontShowShortcutsInContextMenus attribute + is set for the application, falling back to the widget style hint. + Explicitly setting this property overrides the presence (or abscence) of the attribute. + + \sa shortcut, QCoreApplication::setAttribute() +*/ +void QGuiAction::setShortcutVisibleInContextMenu(bool visible) +{ + Q_D(QGuiAction); + if (d->shortcutVisibleInContextMenu == -1 || visible != bool(d->shortcutVisibleInContextMenu)) { + int oldValue = d->shortcutVisibleInContextMenu; + d->shortcutVisibleInContextMenu = visible; + // Only send data changed if we really need to. + if (oldValue != -1 + || visible == !QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus)) { + d->sendDataChanged(); + } + } +} + +bool QGuiAction::isShortcutVisibleInContextMenu() const +{ + Q_D(const QGuiAction); + if (d->shortcutVisibleInContextMenu == -1) { + return !QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus) + && QGuiApplication::styleHints()->showShortcutsInContextMenus(); + } + return d->shortcutVisibleInContextMenu; +} + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug d, const QGuiAction *action) +{ + QDebugStateSaver saver(d); + d.nospace(); + d << "QAction(" << static_cast(action); + if (action) { + d << " text=" << action->text(); + if (!action->toolTip().isEmpty()) + d << " toolTip=" << action->toolTip(); + if (action->isCheckable()) + d << " checked=" << action->isChecked(); +#if QT_CONFIG(shortcut) + if (!action->shortcut().isEmpty()) + d << " shortcut=" << action->shortcut(); +#endif + d << " menuRole="; + QtDebugUtils::formatQEnum(d, action->menuRole()); + d << " visible=" << action->isVisible(); + } else { + d << '0'; + } + d << ')'; + return d; +} +#endif // QT_NO_DEBUG_STREAM + +QT_END_NAMESPACE + +#include "moc_qguiaction.cpp" diff --git a/src/gui/kernel/qguiaction.h b/src/gui/kernel/qguiaction.h new file mode 100644 index 0000000000..bd7d13e156 --- /dev/null +++ b/src/gui/kernel/qguiaction.h @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIACTION_H +#define QGUIACTION_H + +#include +#if QT_CONFIG(shortcut) +# include +#endif +#include +#include +#include + +QT_REQUIRE_CONFIG(action); + +QT_BEGIN_NAMESPACE + +class QActionEvent; +class QGuiActionGroup; +class QGuiActionPrivate; + +class Q_GUI_EXPORT QGuiAction : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGuiAction) + + Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY changed) + Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY changed) + Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY changed) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY changed) + Q_PROPERTY(QString iconText READ iconText WRITE setIconText NOTIFY changed) + Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY changed) + Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip NOTIFY changed) + Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis NOTIFY changed) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed) +#if QT_CONFIG(shortcut) + Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut NOTIFY changed) + Q_PROPERTY(Qt::ShortcutContext shortcutContext READ shortcutContext WRITE setShortcutContext NOTIFY changed) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY changed) +#endif // QT_CONFIG(shortcut) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed) + Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed) + Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed) + Q_PROPERTY(bool shortcutVisibleInContextMenu READ isShortcutVisibleInContextMenu WRITE setShortcutVisibleInContextMenu NOTIFY changed) + Q_PROPERTY(Priority priority READ priority WRITE setPriority) + +public: + // note this is copied into qplatformmenu.h, which must stay in sync + enum MenuRole { NoRole = 0, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole, + AboutRole, PreferencesRole, QuitRole }; + Q_ENUM(MenuRole) + enum Priority { LowPriority = 0, + NormalPriority = 128, + HighPriority = 256}; + Q_ENUM(Priority) + explicit QGuiAction(QObject *parent = nullptr); + explicit QGuiAction(const QString &text, QObject *parent = nullptr); + explicit QGuiAction(const QIcon &icon, const QString &text, QObject *parent = nullptr); + + ~QGuiAction(); + + void setActionGroup(QGuiActionGroup *group); + QGuiActionGroup *guiActionGroup() const; + void setIcon(const QIcon &icon); + QIcon icon() const; + + void setText(const QString &text); + QString text() const; + + void setIconText(const QString &text); + QString iconText() const; + + void setToolTip(const QString &tip); + QString toolTip() const; + + void setStatusTip(const QString &statusTip); + QString statusTip() const; + + void setWhatsThis(const QString &what); + QString whatsThis() const; + + void setPriority(Priority priority); + Priority priority() const; + + void setSeparator(bool b); + bool isSeparator() const; + +#if QT_CONFIG(shortcut) + void setShortcut(const QKeySequence &shortcut); + QKeySequence shortcut() const; + + void setShortcuts(const QList &shortcuts); + void setShortcuts(QKeySequence::StandardKey); + QList shortcuts() const; + + void setShortcutContext(Qt::ShortcutContext context); + Qt::ShortcutContext shortcutContext() const; + + void setAutoRepeat(bool); + bool autoRepeat() const; +#endif // QT_CONFIG(shortcut) + + void setFont(const QFont &font); + QFont font() const; + + void setCheckable(bool); + bool isCheckable() const; + + QVariant data() const; + void setData(const QVariant &var); + + bool isChecked() const; + + bool isEnabled() const; + + bool isVisible() const; + + enum ActionEvent { Trigger, Hover }; + void activate(ActionEvent event); + + void setMenuRole(MenuRole menuRole); + MenuRole menuRole() const; + + void setIconVisibleInMenu(bool visible); + bool isIconVisibleInMenu() const; + + void setShortcutVisibleInContextMenu(bool show); + bool isShortcutVisibleInContextMenu() const; + +protected: + bool event(QEvent *) override; + QGuiAction(QGuiActionPrivate &dd, QObject *parent); + +public Q_SLOTS: + void trigger() { activate(Trigger); } + void hover() { activate(Hover); } + void setChecked(bool); + void toggle(); + void setEnabled(bool); + inline void setDisabled(bool b) { setEnabled(!b); } + void setVisible(bool); + +Q_SIGNALS: + void changed(); + void triggered(bool checked = false); + void hovered(); + void toggled(bool); + +private: + Q_DISABLE_COPY(QGuiAction) + friend class QGuiActionGroup; +}; + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug, const QGuiAction *); +#endif + +QT_END_NAMESPACE + +#endif // QGUIACTION_H diff --git a/src/gui/kernel/qguiaction_p.h b/src/gui/kernel/qguiaction_p.h new file mode 100644 index 0000000000..3358ed1070 --- /dev/null +++ b/src/gui/kernel/qguiaction_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIACTION_P_H +#define QGUIACTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#if QT_CONFIG(shortcut) +# include +#endif +#include "private/qobject_p.h" + +QT_REQUIRE_CONFIG(action); + +QT_BEGIN_NAMESPACE + +class QShortcutMap; + +class Q_GUI_EXPORT QGuiActionPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGuiAction) +public: + QGuiActionPrivate(); + ~QGuiActionPrivate(); + +#if QT_CONFIG(shortcut) + virtual QShortcutMap::ContextMatcher contextMatcher() const; +#endif + + static QGuiActionPrivate *get(QGuiAction *q) + { + return q->d_func(); + } + + + QPointer group; + QString text; + QString iconText; + QIcon icon; + QString tooltip; + QString statustip; + QString whatsthis; +#if QT_CONFIG(shortcut) + QKeySequence shortcut; + QList alternateShortcuts; +#endif + QVariant userData; +#if QT_CONFIG(shortcut) + int shortcutId = 0; + QVector alternateShortcutIds; + Qt::ShortcutContext shortcutContext = Qt::WindowShortcut; + uint autorepeat : 1; +#endif + QFont font; + uint enabled : 1, forceDisabled : 1; + uint visible : 1, forceInvisible : 1; + uint checkable : 1; + uint checked : 1; + uint separator : 1; + uint fontSet : 1; + + int iconVisibleInMenu : 2; // Only has values -1, 0, and 1 + int shortcutVisibleInContextMenu : 2; // Only has values -1, 0, and 1 + + QGuiAction::MenuRole menuRole = QGuiAction::TextHeuristicRole; + QGuiAction::Priority priority = QGuiAction::NormalPriority; + +#if QT_CONFIG(shortcut) + void redoGrab(QShortcutMap &map); + void redoGrabAlternate(QShortcutMap &map); + void setShortcutEnabled(bool enable, QShortcutMap &map); +#endif // QT_NO_SHORTCUT + + void sendDataChanged(); +}; + +QT_END_NAMESPACE + +#endif // QACTION_P_H diff --git a/src/gui/kernel/qguiactiongroup.cpp b/src/gui/kernel/qguiactiongroup.cpp new file mode 100644 index 0000000000..82f5e0a0af --- /dev/null +++ b/src/gui/kernel/qguiactiongroup.cpp @@ -0,0 +1,345 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguiactiongroup.h" + +#include "qguiaction.h" +#include "qguiaction_p.h" +#include "qguiactiongroup_p.h" +#include "qevent.h" +#include "qlist.h" + +QT_BEGIN_NAMESPACE + +QGuiActionGroupPrivate::QGuiActionGroupPrivate() : + enabled(1), visible(1) +{ +} + +QGuiActionGroupPrivate::~QGuiActionGroupPrivate() = default; + +void QGuiActionGroup::_q_actionChanged() +{ + Q_D(QGuiActionGroup); + auto action = qobject_cast(sender()); + Q_ASSERT_X(action != nullptr, "QGuiActionGroup::_q_actionChanged", "internal error"); + if (d->exclusionPolicy != QGuiActionGroup::ExclusionPolicy::None) { + if (action->isChecked()) { + if (action != d->current) { + if (!d->current.isNull()) + d->current->setChecked(false); + d->current = action; + } + } else if (action == d->current) { + d->current = nullptr; + } + } +} + +void QGuiActionGroup::_q_actionTriggered() +{ + Q_D(QGuiActionGroup); + auto action = qobject_cast(sender()); + Q_ASSERT_X(action != nullptr, "QGuiActionGroup::_q_actionTriggered", "internal error"); + d->emitSignal(QGuiActionGroupPrivate::Triggered, action); +} + +void QGuiActionGroup::_q_actionHovered() +{ + Q_D(QGuiActionGroup); + auto action = qobject_cast(sender()); + Q_ASSERT_X(action != nullptr, "QGuiActionGroup::_q_actionHovered", "internal error"); + d->emitSignal(QGuiActionGroupPrivate::Hovered, action); +} + +/*! + \class QGuiActionGroup + \brief The QGuiActionGroup class groups actions together. + \since 6.0 + + \inmodule QtGui + + QGuiActionGroup is a base class for classes grouping + classes inhheriting QGuiAction objects together. + + In some situations it is useful to group QGuiAction objects together. + For example, if you have a \uicontrol{Left Align} action, a \uicontrol{Right + Align} action, a \uicontrol{Justify} action, and a \uicontrol{Center} action, + only one of these actions should be active at any one time. One + simple way of achieving this is to group the actions together in + an action group, inheriting QGuiActionGroup. + + \sa QGuiAction +*/ + +/*! + \enum QGuiActionGroup::ExclusionPolicy + + This enum specifies the different policies that can be used to + control how the group performs exclusive checking on checkable actions. + + \value None + The actions in the group can be checked independently of each other. + + \value Exclusive + Exactly one action can be checked at any one time. + This is the default policy. + + \value ExclusiveOptional + At most one action can be checked at any one time. The actions + can also be all unchecked. + + \sa exclusionPolicy +*/ + +/*! + Constructs an action group for the \a parent object. + + The action group is exclusive by default. Call setExclusive(false) + to make the action group non-exclusive. To make the group exclusive + but allow unchecking the active action call instead + setExclusionPolicy(QGuiActionGroup::ExclusionPolicy::ExclusiveOptional) +*/ +QGuiActionGroup::QGuiActionGroup(QObject* parent) : + QGuiActionGroup(*new QGuiActionGroupPrivate, parent) +{ +} + +QGuiActionGroup::QGuiActionGroup(QGuiActionGroupPrivate &dd, QObject *parent) : + QObject(dd, parent) +{ +} + +/*! + Destroys the action group. +*/ +QGuiActionGroup::~QGuiActionGroup() = default; + +/*! + \fn QGuiAction *QGuiActionGroup::addAction(QGuiAction *action) + + Adds the \a action to this group, and returns it. + + Normally an action is added to a group by creating it with the + group as its parent, so this function is not usually used. + + \sa QGuiAction::setActionGroup() +*/ +QGuiAction *QGuiActionGroup::addAction(QGuiAction* a) +{ + Q_D(QGuiActionGroup); + if (!d->actions.contains(a)) { + d->actions.append(a); + QObject::connect(a, &QGuiAction::triggered, this, &QGuiActionGroup::_q_actionTriggered); + QObject::connect(a, &QGuiAction::changed, this, &QGuiActionGroup::_q_actionChanged); + QObject::connect(a, &QGuiAction::hovered, this, &QGuiActionGroup::_q_actionHovered); + } + if (!a->d_func()->forceDisabled) { + a->setEnabled(d->enabled); + a->d_func()->forceDisabled = false; + } + if (!a->d_func()->forceInvisible) { + a->setVisible(d->visible); + a->d_func()->forceInvisible = false; + } + if (a->isChecked()) + d->current = a; + QGuiActionGroup *oldGroup = a->d_func()->group; + if (oldGroup != this) { + if (oldGroup) + oldGroup->removeAction(a); + a->d_func()->group = this; + a->d_func()->sendDataChanged(); + } + return a; +} + +/*! + Removes the \a action from this group. The action will have no + parent as a result. + + \sa QGuiAction::setActionGroup() +*/ +void QGuiActionGroup::removeAction(QGuiAction *action) +{ + Q_D(QGuiActionGroup); + if (d->actions.removeAll(action)) { + if (action == d->current) + d->current = nullptr; + QObject::disconnect(action, &QGuiAction::triggered, this, &QGuiActionGroup::_q_actionTriggered); + QObject::disconnect(action, &QGuiAction::changed, this, &QGuiActionGroup::_q_actionChanged); + QObject::disconnect(action, &QGuiAction::hovered, this, &QGuiActionGroup::_q_actionHovered); + action->d_func()->group = nullptr; + } +} + +/*! + Returns the list of this groups's actions. This may be empty. +*/ +QList QGuiActionGroup::guiActions() const +{ + Q_D(const QGuiActionGroup); + return d->actions; +} + +/*! + \brief Enable or disable the group exclusion checking + + This is a convenience method that calls + setExclusionPolicy(ExclusionPolicy::Exclusive). + + \sa QGuiActionGroup::exclusionPolicy +*/ +void QGuiActionGroup::setExclusive(bool b) +{ + setExclusionPolicy(b ? QGuiActionGroup::ExclusionPolicy::Exclusive + : QGuiActionGroup::ExclusionPolicy::None); +} + +/*! + \brief Returs true if the group is exclusive + + The group is exclusive if the ExclusionPolicy is either Exclusive + or ExclusionOptional. + +*/ +bool QGuiActionGroup::isExclusive() const +{ + return exclusionPolicy() != QGuiActionGroup::ExclusionPolicy::None; +} + +/*! + \property QGuiActionGroup::exclusionPolicy + \brief This property holds the group exclusive checking policy + + If exclusionPolicy is set to Exclusive, only one checkable + action in the action group can ever be active at any time. If the user + chooses another checkable action in the group, the one they chose becomes + active and the one that was active becomes inactive. If exclusionPolicy is + set to ExclusionOptional the group is exclusive but the active checkable + action in the group can be unchecked leaving the group with no actions + checked. + + \sa QGuiAction::checkable +*/ +void QGuiActionGroup::setExclusionPolicy(QGuiActionGroup::ExclusionPolicy policy) +{ + Q_D(QGuiActionGroup); + d->exclusionPolicy = policy; +} + +QGuiActionGroup::ExclusionPolicy QGuiActionGroup::exclusionPolicy() const +{ + Q_D(const QGuiActionGroup); + return d->exclusionPolicy; +} + +/*! + \fn void QGuiActionGroup::setDisabled(bool b) + + This is a convenience function for the \l enabled property, that + is useful for signals--slots connections. If \a b is true the + action group is disabled; otherwise it is enabled. +*/ + +/*! + \property QGuiActionGroup::enabled + \brief whether the action group is enabled + + Each action in the group will be enabled or disabled unless it + has been explicitly disabled. + + \sa QGuiAction::setEnabled() +*/ +void QGuiActionGroup::setEnabled(bool b) +{ + Q_D(QGuiActionGroup); + d->enabled = b; + for (auto action : qAsConst(d->actions)) { + if (!action->d_func()->forceDisabled) { + action->setEnabled(b); + action->d_func()->forceDisabled = false; + } + } +} + +bool QGuiActionGroup::isEnabled() const +{ + Q_D(const QGuiActionGroup); + return d->enabled; +} + +/*! + Returns the currently checked action in the group, or \nullptr if + none are checked. +*/ +QGuiAction *QGuiActionGroup::checkedGuiAction() const +{ + Q_D(const QGuiActionGroup); + return d->current.data(); +} + +/*! + \property QGuiActionGroup::visible + \brief whether the action group is visible + + Each action in the action group will match the visible state of + this group unless it has been explicitly hidden. + + \sa QGuiAction::setEnabled() +*/ +void QGuiActionGroup::setVisible(bool b) +{ + Q_D(QGuiActionGroup); + d->visible = b; + for (auto action : qAsConst(d->actions)) { + if (!action->d_func()->forceInvisible) { + action->setVisible(b); + action->d_func()->forceInvisible = false; + } + } +} + +bool QGuiActionGroup::isVisible() const +{ + Q_D(const QGuiActionGroup); + return d->visible; +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qguiactiongroup.h b/src/gui/kernel/qguiactiongroup.h new file mode 100644 index 0000000000..ef08fb2e04 --- /dev/null +++ b/src/gui/kernel/qguiactiongroup.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIACTIONGROUP_H +#define QGUIACTIONGROUP_H + +#include +#include + +QT_REQUIRE_CONFIG(action); + +QT_BEGIN_NAMESPACE + +class QGuiActionGroupPrivate; + +class Q_GUI_EXPORT QGuiActionGroup : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGuiActionGroup) + + Q_PROPERTY(QGuiActionGroup::ExclusionPolicy exclusionPolicy READ exclusionPolicy WRITE setExclusionPolicy) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible) + +public: + enum class ExclusionPolicy { + None, + Exclusive, + ExclusiveOptional + }; + Q_ENUM(ExclusionPolicy) + + explicit QGuiActionGroup(QObject *parent); + ~QGuiActionGroup(); + + QGuiAction *addAction(QGuiAction *a); + void removeAction(QGuiAction *a); + QList guiActions() const; + QGuiAction *checkedGuiAction() const; + + bool isExclusive() const; + bool isEnabled() const; + bool isVisible() const; + ExclusionPolicy exclusionPolicy() const; + + +public Q_SLOTS: + void setEnabled(bool); + inline void setDisabled(bool b) { setEnabled(!b); } + void setVisible(bool); + void setExclusive(bool); + void setExclusionPolicy(ExclusionPolicy policy); + +private Q_SLOTS: + void _q_actionTriggered(); + void _q_actionHovered(); + void _q_actionChanged(); + +protected: + QGuiActionGroup(QGuiActionGroupPrivate &dd, QObject *parent); + +private: + Q_DISABLE_COPY(QGuiActionGroup) +}; + +QT_END_NAMESPACE + +#endif // QGUIACTIONGROUP_H diff --git a/src/gui/kernel/qguiactiongroup_p.h b/src/gui/kernel/qguiactiongroup_p.h new file mode 100644 index 0000000000..99a58262c9 --- /dev/null +++ b/src/gui/kernel/qguiactiongroup_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIACTIONGROUP_P_H +#define QGUIACTIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#if QT_CONFIG(shortcut) +# include +#endif +#include "private/qobject_p.h" + +QT_REQUIRE_CONFIG(action); + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QGuiActionGroupPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGuiActionGroup) +public: + enum Signal { Triggered, Hovered }; + + QGuiActionGroupPrivate(); + ~QGuiActionGroupPrivate(); + + virtual void emitSignal(Signal, QGuiAction *) {} + + QList actions; + QPointer current; + uint enabled : 1; + uint visible : 1; + QGuiActionGroup::ExclusionPolicy exclusionPolicy = QGuiActionGroup::ExclusionPolicy::Exclusive; + +private: + void _q_actionTriggered(); //private slot + void _q_actionChanged(); //private slot + void _q_actionHovered(); //private slot +}; + +QT_END_NAMESPACE + +#endif // QACTIONGROUP_P_H -- cgit v1.2.3 From c0adcf0f226e247c1f2f515cd33d7945573e96a5 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 16 Oct 2019 16:11:57 +0200 Subject: Fix text-rendering regression on semi-transparent background on Linux The short-cut for semi-transparent backgrounds has to take precedence over the disabled gamma-correction short-cut. The order got inversed in one function during 5.14 refactoring. Change-Id: I0e54428839428068b602a13eddbf69897ed0797d Reviewed-by: Eirik Aavitsland Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/painting/qdrawhelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index e5f752b94e..e8d129d047 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6044,11 +6044,11 @@ static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba // nothing } else if (coverage == 0xffffffff && qAlpha(src) == 255) { blend_pixel(*dst, src); - } else if (!colorProfile) { - *dst = rgbBlend(*dst, src, coverage); } else if (*dst < 0xff000000) { // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 blend_pixel(*dst, src, qRgbAvg(coverage)); + } else if (!colorProfile) { + *dst = rgbBlend(*dst, src, coverage); } else if (srcLinear.isOpaque()) { rgbBlendPixel(dst, coverage, srcLinear, colorProfile); } else { -- cgit v1.2.3 From 5367f76e1755aecf9527660d1c00e4e6d29d7c78 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 18 Oct 2019 15:03:08 +0200 Subject: QAction: Properly port to the new configure system Use QT_REQUIRE_CONFIG in the headers of classes to be disabled. Add headers/source files in the .pro file depending on the configure feature in libraries and tests. Add the necessary exclusions and use QT_CONFIG. Only the widgets/kernel tests were made to compile since also the buttons depend on the action feature and it would become too involved. Task-number: QTBUG-69478 Change-Id: Id5bf88bc108f2bbb14dce8625bfdcb7eb0deb8e3 Reviewed-by: Oliver Wolff Reviewed-by: Volker Hilsheimer --- src/gui/configure.json | 4 ++-- src/gui/kernel/qevent.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/gui') diff --git a/src/gui/configure.json b/src/gui/configure.json index 90d0c8c134..5b8063d720 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -1638,8 +1638,8 @@ "output": [ "publicFeature", "feature" ] }, "action": { - "label": "QAction", - "purpose": "Provides widget actions.", + "label": "Q(Gui)Action(Group)", + "purpose": "Provides abstract user interface actions.", "section": "Kernel", "output": [ "publicFeature", "feature" ] }, diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 85d22319ae..6f3215652b 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -753,7 +753,7 @@ private: }; #endif -#ifndef QT_NO_ACTION +#if QT_CONFIG(action) class Q_GUI_EXPORT QActionEvent : public QEvent { QGuiAction *act, *bef; @@ -764,7 +764,7 @@ public: inline QGuiAction *action() const { return act; } inline QGuiAction *before() const { return bef; } }; -#endif +#endif // QT_CONFIG(action) class Q_GUI_EXPORT QFileOpenEvent : public QEvent { -- cgit v1.2.3 From 89f1f14c5e9a49f25345a65d81b3518d58ecb91a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 22 Oct 2019 10:53:54 +0200 Subject: Extract QGuiShortcut [ChangeLog][QtGui] Added QGuiShortcut and made the equivalent existing classes in Qt Widgets derive from them. This provides basic functionality for adding shortcut handling in QML. Fixes: QTBUG-79638 Task-number: QTBUG-76493 Change-Id: I5bbd2c8f192660e93c4690b9f894643275090e4d Reviewed-by: Volker Hilsheimer --- src/gui/kernel/kernel.pri | 3 + src/gui/kernel/qguishortcut.cpp | 354 ++++++++++++++++++++++++++++++++++++++++ src/gui/kernel/qguishortcut.h | 98 +++++++++++ src/gui/kernel/qguishortcut_p.h | 92 +++++++++++ 4 files changed, 547 insertions(+) create mode 100644 src/gui/kernel/qguishortcut.cpp create mode 100644 src/gui/kernel/qguishortcut.h create mode 100644 src/gui/kernel/qguishortcut_p.h (limited to 'src/gui') diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 42bb81fa24..3784abdacc 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -169,10 +169,13 @@ qtConfig(opengl) { qtConfig(shortcut) { HEADERS += \ + kernel/qguishortcut.h \ + kernel/qguishortcut_p.h \ kernel/qshortcutmap_p.h \ kernel/qkeysequence.h \ kernel/qkeysequence_p.h SOURCES += \ + kernel/qguishortcut.cpp \ kernel/qshortcutmap.cpp \ kernel/qkeysequence.cpp } diff --git a/src/gui/kernel/qguishortcut.cpp b/src/gui/kernel/qguishortcut.cpp new file mode 100644 index 0000000000..add1dce12e --- /dev/null +++ b/src/gui/kernel/qguishortcut.cpp @@ -0,0 +1,354 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguishortcut.h" +#include "qguishortcut_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#define QAPP_CHECK(functionName) \ + if (Q_UNLIKELY(!qApp)) { \ + qWarning("QGuiShortcut: Initialize QGuiApplication before calling '" functionName "'."); \ + return; \ + } + +/*! + \class QGuiShortcut + \brief The QGuiShortcut class is a base class for handling keyboard shortcuts. + + \ingroup events + \inmodule QtGui + \since 6.0 + + The QGuiShortcut class is a base class for classes providing a way of + connecting keyboard shortcuts to Qt's \l{signals and slots} mechanism, + so that objects can be informed when a shortcut is executed. The shortcut + can be set up to contain all the key presses necessary to + describe a keyboard shortcut, including the states of modifier + keys such as \uicontrol Shift, \uicontrol Ctrl, and \uicontrol Alt. + + \target mnemonic + + \sa QShortcutEvent, QKeySequence, QAction +*/ + +/*! + \fn void QGuiShortcut::activated() + + This signal is emitted when the user types the shortcut's key + sequence. + + \sa activatedAmbiguously() +*/ + +/*! + \fn void QGuiShortcut::activatedAmbiguously() + + When a key sequence is being typed at the keyboard, it is said to + be ambiguous as long as it matches the start of more than one + shortcut. + + When a shortcut's key sequence is completed, + activatedAmbiguously() is emitted if the key sequence is still + ambiguous (i.e., it is the start of one or more other shortcuts). + The activated() signal is not emitted in this case. + + \sa activated() +*/ + +static bool simpleContextMatcher(QObject *object, Qt::ShortcutContext context) +{ + auto guiShortcut = qobject_cast(object); + if (QGuiApplication::applicationState() != Qt::ApplicationActive || guiShortcut == nullptr) + return false; + if (context == Qt::ApplicationShortcut) + return true; + auto focusWindow = QGuiApplication::focusWindow(); + if (!focusWindow) + return false; + auto window = qobject_cast(guiShortcut->parent()); + if (!window) + return false; + if (focusWindow == window && focusWindow->isTopLevel()) + return context == Qt::WindowShortcut || context == Qt::WidgetWithChildrenShortcut; + return focusWindow->isAncestorOf(window, QWindow::ExcludeTransients); +} + +QShortcutMap::ContextMatcher QGuiShortcutPrivate::contextMatcher() const +{ + return simpleContextMatcher; +} + +void QGuiShortcutPrivate::redoGrab(QShortcutMap &map) +{ + Q_Q(QGuiShortcut); + if (Q_UNLIKELY(!parent)) { + qWarning("QGuiShortcut: No window parent defined"); + return; + } + + if (sc_id) + map.removeShortcut(sc_id, q); + if (sc_sequence.isEmpty()) + return; + sc_id = map.addShortcut(q, sc_sequence, sc_context, contextMatcher()); + if (!sc_enabled) + map.setShortcutEnabled(false, sc_id, q); + if (!sc_autorepeat) + map.setShortcutAutoRepeat(false, sc_id, q); +} + +/*! + Constructs a QGuiShortcut object for the \a parent window. Since no + shortcut key sequence is specified, the shortcut will not emit any + signals. + + \sa setKey() +*/ +QGuiShortcut::QGuiShortcut(QWindow *parent) + : QGuiShortcut(*new QGuiShortcutPrivate, parent) +{ +} + +/*! + Constructs a QGuiShortcut object for the \a parent window. The shortcut + operates on its parent, listening for \l{QShortcutEvent}s that + match the \a key sequence. Depending on the ambiguity of the + event, the shortcut will call the \a member function, or the \a + ambiguousMember function, if the key press was in the shortcut's + \a context. +*/ +QGuiShortcut::QGuiShortcut(const QKeySequence &key, QWindow *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext context) + : QGuiShortcut(*new QGuiShortcutPrivate, key, parent, member, ambiguousMember, context) +{ +} + +/*! + \internal +*/ +QGuiShortcut::QGuiShortcut(QGuiShortcutPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_ASSERT(parent != nullptr); +} + +/*! + \internal +*/ +QGuiShortcut::QGuiShortcut(QGuiShortcutPrivate &dd, + const QKeySequence &key, QObject *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext context) + : QGuiShortcut(dd, parent) +{ + QAPP_CHECK("QGuiShortcut"); + + Q_D(QGuiShortcut); + d->sc_context = context; + d->sc_sequence = key; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); + if (member) + connect(this, SIGNAL(activated()), parent, member); + if (ambiguousMember) + connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember); +} + +/*! + Destroys the shortcut. +*/ +QGuiShortcut::~QGuiShortcut() +{ + Q_D(QGuiShortcut); + if (qApp) + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->sc_id, this); +} + +/*! + \property QGuiShortcut::key + \brief the shortcut's key sequence + + This is a key sequence with an optional combination of Shift, Ctrl, + and Alt. The key sequence may be supplied in a number of ways: + + \snippet code/src_gui_kernel_qshortcut.cpp 1 + + By default, this property contains an empty key sequence. +*/ +void QGuiShortcut::setKey(const QKeySequence &key) +{ + Q_D(QGuiShortcut); + if (d->sc_sequence == key) + return; + QAPP_CHECK("setKey"); + d->sc_sequence = key; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); +} + +QKeySequence QGuiShortcut::key() const +{ + Q_D(const QGuiShortcut); + return d->sc_sequence; +} + +/*! + \property QGuiShortcut::enabled + \brief whether the shortcut is enabled + + An enabled shortcut emits the activated() or activatedAmbiguously() + signal when a QShortcutEvent occurs that matches the shortcut's + key() sequence. + + If the application is in \c WhatsThis mode the shortcut will not emit + the signals, but will show the "What's This?" text instead. + + By default, this property is \c true. + + \sa whatsThis +*/ +void QGuiShortcut::setEnabled(bool enable) +{ + Q_D(QGuiShortcut); + if (d->sc_enabled == enable) + return; + QAPP_CHECK("setEnabled"); + d->sc_enabled = enable; + QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable, d->sc_id, this); +} + +bool QGuiShortcut::isEnabled() const +{ + Q_D(const QGuiShortcut); + return d->sc_enabled; +} + +/*! + \property QGuiShortcut::context + \brief the context in which the shortcut is valid + + A shortcut's context decides in which circumstances a shortcut is + allowed to be triggered. The normal context is Qt::WindowShortcut, + which allows the shortcut to trigger if the parent (the widget + containing the shortcut) is a subwidget of the active top-level + window. + + By default, this property is set to Qt::WindowShortcut. +*/ +void QGuiShortcut::setContext(Qt::ShortcutContext context) +{ + Q_D(QGuiShortcut); + if (d->sc_context == context) + return; + QAPP_CHECK("setContext"); + d->sc_context = context; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); +} + +Qt::ShortcutContext QGuiShortcut::context() const +{ + Q_D(const QGuiShortcut); + return d->sc_context; +} + +/*! + \property QGuiShortcut::autoRepeat + \brief whether the shortcut can auto repeat + + If true, the shortcut will auto repeat when the keyboard shortcut + combination is held down, provided that keyboard auto repeat is + enabled on the system. + The default value is true. +*/ +void QGuiShortcut::setAutoRepeat(bool on) +{ + Q_D(QGuiShortcut); + if (d->sc_autorepeat == on) + return; + QAPP_CHECK("setAutoRepeat"); + d->sc_autorepeat = on; + QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on, d->sc_id, this); +} + +bool QGuiShortcut::autoRepeat() const +{ + Q_D(const QGuiShortcut); + return d->sc_autorepeat; +} + +/*! + Returns the shortcut's ID. + + \sa QShortcutEvent::shortcutId() +*/ +int QGuiShortcut::id() const +{ + Q_D(const QGuiShortcut); + return d->sc_id; +} + +/*! + \internal +*/ +bool QGuiShortcut::event(QEvent *e) +{ + Q_D(QGuiShortcut); + if (d->sc_enabled && e->type() == QEvent::Shortcut) { + auto se = static_cast(e); + if (se->shortcutId() == d->sc_id && se->key() == d->sc_sequence + && !d->handleWhatsThis()) { + if (se->isAmbiguous()) + emit activatedAmbiguously(); + else + emit activated(); + return true; + } + } + return QObject::event(e); +} + +QT_END_NAMESPACE + +#include "moc_qguishortcut.cpp" diff --git a/src/gui/kernel/qguishortcut.h b/src/gui/kernel/qguishortcut.h new file mode 100644 index 0000000000..fb64f10c84 --- /dev/null +++ b/src/gui/kernel/qguishortcut.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUISHORTCUT_H +#define QGUISHORTCUT_H + +#include +#include +#include + +QT_REQUIRE_CONFIG(shortcut); + +QT_BEGIN_NAMESPACE + +class QGuiShortcutPrivate; +class QWindow; + +class Q_GUI_EXPORT QGuiShortcut : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGuiShortcut) + Q_PROPERTY(QKeySequence key READ key WRITE setKey) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat) + Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext) +public: + explicit QGuiShortcut(QWindow *parent); + explicit QGuiShortcut(const QKeySequence& key, QWindow *parent, + const char *member = nullptr, const char *ambiguousMember = nullptr, + Qt::ShortcutContext context = Qt::WindowShortcut); + ~QGuiShortcut(); + + void setKey(const QKeySequence& key); + QKeySequence key() const; + + void setEnabled(bool enable); + bool isEnabled() const; + + void setContext(Qt::ShortcutContext context); + Qt::ShortcutContext context() const; + + void setAutoRepeat(bool on); + bool autoRepeat() const; + + int id() const; + +Q_SIGNALS: + void activated(); + void activatedAmbiguously(); + +protected: + QGuiShortcut(QGuiShortcutPrivate &dd, QObject *parent); + QGuiShortcut(QGuiShortcutPrivate &dd, const QKeySequence& key, QObject *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext context); + + bool event(QEvent *e) override; +}; + +QT_END_NAMESPACE + +#endif // QGUISHORTCUT_H diff --git a/src/gui/kernel/qguishortcut_p.h b/src/gui/kernel/qguishortcut_p.h new file mode 100644 index 0000000000..420b02ef1a --- /dev/null +++ b/src/gui/kernel/qguishortcut_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUISHORTCUT_P_H +#define QGUISHORTCUT_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 +#include "qguishortcut.h" +#include + +#include +#include + +#include + + + +QT_BEGIN_NAMESPACE + +class QShortcutMap; + +/* + \internal + Private data accessed through d-pointer. +*/ +class Q_GUI_EXPORT QGuiShortcutPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGuiShortcut) +public: + QGuiShortcutPrivate() = default; + + virtual QShortcutMap::ContextMatcher contextMatcher() const; + virtual bool handleWhatsThis() { return false; } + + QKeySequence sc_sequence; + Qt::ShortcutContext sc_context = Qt::WindowShortcut; + bool sc_enabled = true; + bool sc_autorepeat = true; + int sc_id = 0; + void redoGrab(QShortcutMap &map); +}; + +QT_END_NAMESPACE + +#endif // QGUISHORTCUT_P_H -- cgit v1.2.3