summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h49
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm57
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.pro5
-rw-r--r--src/corelib/itemmodels/qabstractproxymodel.cpp2
-rw-r--r--src/corelib/kernel/qabstractnativeeventfilter.cpp15
-rw-r--r--src/gui/painting/qbrush.cpp14
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp34
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h17
-rw-r--r--src/plugins/bearer/connman/qconnmanservice_linux.cpp2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm5
-rw-r--r--src/plugins/platforms/ios/qiosmenu.mm7
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm4
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm2
-rw-r--r--src/plugins/platforms/ios/quiview.mm3
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp72
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h2
-rw-r--r--tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp18
-rw-r--r--tests/manual/qopenglwindow/multiwindow/main.cpp145
18 files changed, 332 insertions, 121 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
new file mode 100644
index 0000000000..6666bc56c5
--- /dev/null
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Samuel Gaist <samuel.gaist@edeltech.ch>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [0]
+#include <QAbstractNativeEventFilter>
+
+class MyCocoaEventFilter : public QAbstractNativeEventFilter
+{
+public:
+ bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE;
+};
+//! [0]
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
new file mode 100644
index 0000000000..8abd576259
--- /dev/null
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Samuel Gaist <samuel.gaist@edeltech.ch>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [0]
+#include "mycocoaeventfilter.h"
+
+#import <AppKit/AppKit.h>
+
+bool CocoaNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *)
+{
+ if (eventType == "mac_generic_NSEvent") {
+ NSEvent *event = static_cast<NSEvent *>(message);
+ if ([event type] == NSKeyDown) {
+ // Handle key event
+ qDebug() << QString::fromNSString([event characters]);
+ }
+ }
+ return false;
+}
+//! [0]
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.pro b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.pro
new file mode 100644
index 0000000000..8f447be514
--- /dev/null
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.pro
@@ -0,0 +1,5 @@
+#! [0]
+HEADERS += mycocoaeventfilter.h
+OBJECTIVE_SOURCES += mycocoaeventfilter.mm
+LIBS += -framework AppKit
+#! [0]
diff --git a/src/corelib/itemmodels/qabstractproxymodel.cpp b/src/corelib/itemmodels/qabstractproxymodel.cpp
index 886b2d0d27..39bfdd7782 100644
--- a/src/corelib/itemmodels/qabstractproxymodel.cpp
+++ b/src/corelib/itemmodels/qabstractproxymodel.cpp
@@ -83,7 +83,7 @@ QT_BEGIN_NAMESPACE
/*!
\property QAbstractProxyModel::sourceModel
- \brief the source model this proxy model.
+ \brief the source model of this proxy model.
*/
//detects the deletion of the source model
diff --git a/src/corelib/kernel/qabstractnativeeventfilter.cpp b/src/corelib/kernel/qabstractnativeeventfilter.cpp
index 351657d42c..dcbb92f044 100644
--- a/src/corelib/kernel/qabstractnativeeventfilter.cpp
+++ b/src/corelib/kernel/qabstractnativeeventfilter.cpp
@@ -96,14 +96,25 @@ QAbstractNativeEventFilter::~QAbstractNativeEventFilter()
In both cases, the \a message can be casted to a MSG pointer.
The \a result pointer is only used on Windows, and corresponds to the LRESULT pointer.
- On Mac, \a eventType is set to "mac_generic_NSEvent", and the \a message can be casted to an EventRef.
+ On macOS, \a eventType is set to "mac_generic_NSEvent", and the \a message can be casted to an NSEvent pointer.
In your reimplementation of this function, if you want to filter
the \a message out, i.e. stop it being handled further, return
true; otherwise return false.
- Example:
+ \b {Linux example}
\snippet code/src_corelib_kernel_qabstractnativeeventfilter.cpp 0
+
+ \b {macOS example}
+
+ mycocoaeventfilter.h:
+ \snippet code/src_corelib_kernel_qabstractnativeeventfilter.h 0
+
+ mycocoaeventfilter.mm:
+ \snippet code/src_corelib_kernel_qabstractnativeeventfilter.mm 0
+
+ myapp.pro:
+ \snippet code/src_corelib_kernel_qabstractnativeeventfilter.pro 0
*/
QT_END_NAMESPACE
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index 3a296ac40c..0d26457c15 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -585,7 +585,7 @@ void QBrush::detach(Qt::BrushStyle newStyle)
if (newStyle == d->style && d->ref.load() == 1)
return;
- QScopedPointer<QBrushData> x;
+ QScopedPointer<QBrushData, QBrushDataPointerDeleter> x;
switch(newStyle) {
case Qt::TexturePattern: {
QTexturedBrushData *tbd = new QTexturedBrushData;
@@ -601,28 +601,30 @@ void QBrush::detach(Qt::BrushStyle newStyle)
}
case Qt::LinearGradientPattern:
case Qt::RadialGradientPattern:
- case Qt::ConicalGradientPattern:
- x.reset(new QGradientBrushData);
+ case Qt::ConicalGradientPattern: {
+ QGradientBrushData *gbd = new QGradientBrushData;
switch (d->style) {
case Qt::LinearGradientPattern:
case Qt::RadialGradientPattern:
case Qt::ConicalGradientPattern:
- static_cast<QGradientBrushData *>(x.data())->gradient =
+ gbd->gradient =
static_cast<QGradientBrushData *>(d.data())->gradient;
break;
default:
break;
}
+ x.reset(gbd);
break;
+ }
default:
x.reset(new QBrushData);
break;
}
- x->ref.store(1);
+ x->ref.store(1); // must be first lest the QBrushDataPointerDeleter turns into a no-op
x->style = newStyle;
x->color = d->color;
x->transform = d->transform;
- d.reset(x.take());
+ d.swap(x);
}
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
index c7f6dd2740..0eb6fc0847 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
@@ -59,8 +59,15 @@ Q_LOGGING_CATEGORY(qLcEvdevKeyMap, "qt.qpa.input.keymap")
// simple builtin US keymap
#include "qevdevkeyboard_defaultmap_p.h"
-QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, int fd, bool disableZap, bool enableCompose, const QString &keymapFile)
- : m_device(device), m_fd(fd), m_notify(Q_NULLPTR),
+void QFdContainer::reset() Q_DECL_NOTHROW
+{
+ if (m_fd >= 0)
+ qt_safe_close(m_fd);
+ m_fd = -1;
+}
+
+QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, QFdContainer &fd, bool disableZap, bool enableCompose, const QString &keymapFile)
+ : m_device(device), m_fd(fd.release()), m_notify(Q_NULLPTR),
m_modifiers(0), m_composing(0), m_dead_unicode(0xffff),
m_no_zap(disableZap), m_do_compose(enableCompose),
m_keymap(0), m_keymap_size(0), m_keycompose(0), m_keycompose_size(0)
@@ -75,16 +82,13 @@ QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, int fd, bool
unloadKeymap();
// socket notifier for events on the keyboard device
- m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
+ m_notify = new QSocketNotifier(m_fd.get(), QSocketNotifier::Read, this);
connect(m_notify, SIGNAL(activated(int)), this, SLOT(readKeycode()));
}
QEvdevKeyboardHandler::~QEvdevKeyboardHandler()
{
unloadKeymap();
-
- if (m_fd >= 0)
- qt_safe_close(m_fd);
}
QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device,
@@ -118,13 +122,12 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device,
qCDebug(qLcEvdevKey) << "Opening keyboard at" << device;
- int fd;
- fd = qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0);
- if (fd >= 0) {
- ::ioctl(fd, EVIOCGRAB, grab);
+ QFdContainer fd(qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0));
+ if (fd.get() >= 0) {
+ ::ioctl(fd.get(), EVIOCGRAB, grab);
if (repeatDelay > 0 && repeatRate > 0) {
int kbdrep[2] = { repeatDelay, repeatRate };
- ::ioctl(fd, EVIOCSREP, kbdrep);
+ ::ioctl(fd.get(), EVIOCSREP, kbdrep);
}
return new QEvdevKeyboardHandler(device, fd, disableZap, enableCompose, keymapFile);
@@ -144,7 +147,7 @@ void QEvdevKeyboardHandler::switchLed(int led, bool state)
led_ie.code = led;
led_ie.value = state;
- qt_safe_write(m_fd, &led_ie, sizeof(led_ie));
+ qt_safe_write(m_fd.get(), &led_ie, sizeof(led_ie));
}
void QEvdevKeyboardHandler::readKeycode()
@@ -153,7 +156,7 @@ void QEvdevKeyboardHandler::readKeycode()
int n = 0;
forever {
- int result = qt_safe_read(m_fd, reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n);
+ int result = qt_safe_read(m_fd.get(), reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n);
if (result == 0) {
qWarning("evdevkeyboard: Got EOF from the input device");
@@ -166,8 +169,7 @@ void QEvdevKeyboardHandler::readKeycode()
if (errno == ENODEV) {
delete m_notify;
m_notify = Q_NULLPTR;
- qt_safe_close(m_fd);
- m_fd = -1;
+ m_fd.reset();
}
return;
}
@@ -478,7 +480,7 @@ void QEvdevKeyboardHandler::unloadKeymap()
//Set locks according to keyboard leds
quint16 ledbits[1];
memset(ledbits, 0, sizeof(ledbits));
- if (::ioctl(m_fd, EVIOCGLED(sizeof(ledbits)), ledbits) < 0) {
+ if (::ioctl(m_fd.get(), EVIOCGLED(sizeof(ledbits)), ledbits) < 0) {
qWarning("evdevkeyboard: Failed to query led states");
switchLed(LED_NUML,false);
switchLed(LED_CAPSL, false);
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
index b94323fcbb..1ec4915855 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
@@ -129,12 +129,25 @@ inline QDataStream &operator<<(QDataStream &ds, const QEvdevKeyboardMap::Composi
return ds << c.first << c.second << c.result;
}
+class QFdContainer
+{
+ int m_fd;
+ Q_DISABLE_COPY(QFdContainer);
+public:
+ explicit QFdContainer(int fd = -1) Q_DECL_NOTHROW : m_fd(fd) {}
+ ~QFdContainer() { reset(); }
+
+ int get() const Q_DECL_NOTHROW { return m_fd; }
+
+ int release() Q_DECL_NOTHROW { int result = m_fd; m_fd = -1; return result; }
+ void reset() Q_DECL_NOTHROW;
+};
class QEvdevKeyboardHandler : public QObject
{
Q_OBJECT
public:
- QEvdevKeyboardHandler(const QString &device, int fd, bool disableZap, bool enableCompose, const QString &keymapFile);
+ QEvdevKeyboardHandler(const QString &device, QFdContainer &fd, bool disableZap, bool enableCompose, const QString &keymapFile);
~QEvdevKeyboardHandler();
enum KeycodeAction {
@@ -187,7 +200,7 @@ private:
void switchLed(int, bool);
QString m_device;
- int m_fd;
+ QFdContainer m_fd;
QSocketNotifier *m_notify;
// keymap handling
diff --git a/src/plugins/bearer/connman/qconnmanservice_linux.cpp b/src/plugins/bearer/connman/qconnmanservice_linux.cpp
index 7fbbe2cd07..44cadc1b19 100644
--- a/src/plugins/bearer/connman/qconnmanservice_linux.cpp
+++ b/src/plugins/bearer/connman/qconnmanservice_linux.cpp
@@ -252,6 +252,8 @@ QStringList QConnmanManagerInterface::getServices()
bool QConnmanManagerInterface::requestScan(const QString &type)
{
bool scanned = false;
+ if (technologiesMap.isEmpty())
+ getTechnologies();
Q_FOREACH (QConnmanTechnologyInterface *tech, technologiesMap) {
if (tech->type() == type) {
tech->scan();
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 628357eb39..ccb11f80f1 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -330,6 +330,11 @@ void QCocoaGLContext::updateSurfaceFormat()
[pixelFormat release];
+ GLint swapInterval = -1;
+ [m_context getValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
+ if (swapInterval >= 0)
+ m_format.setSwapInterval(swapInterval);
+
// Restore the original context
CGLSetCurrentContext(oldContext);
}
diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm
index db1b5b8cc8..41594232ff 100644
--- a/src/plugins/platforms/ios/qiosmenu.mm
+++ b/src/plugins/platforms/ios/qiosmenu.mm
@@ -319,7 +319,7 @@ QIOSMenu::QIOSMenu()
: QPlatformMenu()
, m_tag(0)
, m_enabled(true)
- , m_visible(true)
+ , m_visible(false)
, m_text(QString())
, m_menuType(DefaultMenu)
, m_effectiveMenuType(DefaultMenu)
@@ -412,7 +412,7 @@ void QIOSMenu::handleItemSelected(QIOSMenuItem *menuItem)
void QIOSMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
{
- if (m_currentMenu == this || !m_visible || !m_enabled || !parentWindow)
+ if (m_currentMenu == this || !parentWindow)
return;
emit aboutToShow();
@@ -439,6 +439,8 @@ void QIOSMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, c
toggleShowUsingUIPickerView(true);
break;
}
+
+ m_visible = true;
}
void QIOSMenu::dismiss()
@@ -460,6 +462,7 @@ void QIOSMenu::dismiss()
}
m_currentMenu = 0;
+ m_visible = false;
}
void QIOSMenu::toggleShowUsingUIMenuController(bool show)
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index 2acb247572..fd88664d15 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -228,6 +228,10 @@
@implementation QIOSViewController
+@synthesize prefersStatusBarHidden;
+@synthesize preferredStatusBarUpdateAnimation;
+@synthesize preferredStatusBarStyle;
+
- (id)initWithQIOSScreen:(QIOSScreen *)screen
{
if (self = [self init]) {
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index ddf856d7a4..8099d13147 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -91,7 +91,7 @@ QIOSWindow::~QIOSWindow()
// practice this doesn't seem to happen when removing the view from its superview. To ensure that
// Qt's internal state for touch and mouse handling is kept consistent, we therefor have to force
// cancellation of all touch events.
- [m_view touchesCancelled:0 withEvent:0];
+ [m_view touchesCancelled:[NSSet set] withEvent:0];
clearAccessibleCache();
m_view->m_qioswindow = 0;
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index e38be68343..9c7acc9278 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -423,7 +423,8 @@
// We do this by assuming that there are no cases where a
// sub-set of the active touch events are intentionally cancelled.
- if (touches && (static_cast<NSInteger>([touches count]) != m_activeTouches.count()))
+ NSInteger count = static_cast<NSInteger>([touches count]);
+ if (count != 0 && count != m_activeTouches.count())
qWarning("Subset of active touches cancelled by UIKit");
m_activeTouches.clear();
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index bb7d5c714a..4e4bfad1d6 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -748,8 +748,7 @@ void QXcbKeyboard::updateKeymap()
// update xkb state object
xkb_state_unref(xkb_state);
xkb_state = new_state;
- if (!connection()->hasXKB())
- updateXKBMods();
+ updateXKBMods();
checkForLatinLayout();
}
@@ -774,32 +773,37 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
}
#endif
+void QXcbKeyboard::updateXKBStateFromState(struct xkb_state *kb_state, quint16 state)
+{
+ const quint32 modsDepressed = xkb_state_serialize_mods(kb_state, XKB_STATE_MODS_DEPRESSED);
+ const quint32 modsLatched = xkb_state_serialize_mods(kb_state, XKB_STATE_MODS_LATCHED);
+ const quint32 modsLocked = xkb_state_serialize_mods(kb_state, XKB_STATE_MODS_LOCKED);
+ const quint32 xkbMask = xkbModMask(state);
+
+ const quint32 latched = modsLatched & xkbMask;
+ const quint32 locked = modsLocked & xkbMask;
+ quint32 depressed = modsDepressed & xkbMask;
+ // set modifiers in depressed if they don't appear in any of the final masks
+ depressed |= ~(depressed | latched | locked) & xkbMask;
+
+ const xkb_state_component newState
+ = xkb_state_update_mask(kb_state,
+ depressed,
+ latched,
+ locked,
+ 0,
+ 0,
+ (state >> 13) & 3); // bits 13 and 14 report the state keyboard group
+
+ if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
+ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ }
+}
+
void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
{
if (m_config && !connection()->hasXKB()) {
- const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED);
- const quint32 modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
- const quint32 modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
- const quint32 xkbMask = xkbModMask(state);
-
- const quint32 latched = modsLatched & xkbMask;
- const quint32 locked = modsLocked & xkbMask;
- quint32 depressed = modsDepressed & xkbMask;
- // set modifiers in depressed if they don't appear in any of the final masks
- depressed |= ~(depressed | latched | locked) & xkbMask;
-
- const xkb_state_component newState
- = xkb_state_update_mask(xkb_state,
- depressed,
- latched,
- locked,
- 0,
- 0,
- (state >> 13) & 3); // bits 13 and 14 report the state keyboard group
-
- if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
- //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
- }
+ updateXKBStateFromState(xkb_state, state);
}
}
@@ -1463,7 +1467,16 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
if (type == QEvent::KeyPress)
targetWindow->updateNetWmUserTime(time);
- xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code);
+ // Have a temporary keyboard state filled in from state
+ // this way we allow for synthetic events to have different state
+ // from the current state i.e. you can have Alt+Ctrl pressed
+ // and receive a synthetic key event that has neither Alt nor Ctrl pressed
+ struct xkb_state *kb_state = xkb_state_new(xkb_keymap);
+ if (!kb_state)
+ return;
+ updateXKBStateFromState(kb_state, state);
+
+ xcb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, code);
QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
QMetaMethod method;
@@ -1482,11 +1495,13 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
Q_ARG(uint, code),
Q_ARG(uint, state),
Q_ARG(bool, type == QEvent::KeyPress));
- if (retval)
+ if (retval) {
+ xkb_state_unref(kb_state);
return;
+ }
}
- QString string = lookupString(xkb_state, code);
+ QString string = lookupString(kb_state, code);
// Ιf control modifier is set we should prefer latin character, this is
// used for standard shortcuts in checks like "key == QKeySequence::Copy",
@@ -1557,6 +1572,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers,
code, sym, state, string, isAutoRepeat);
}
+ xkb_state_unref(kb_state);
}
QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 75e6d2ec82..18f1aa5732 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -104,6 +104,8 @@ protected:
void checkForLatinLayout();
private:
+ void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state);
+
bool m_config;
xcb_keycode_t m_autorepeat_code;
diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
index b2b2f25615..aba5b301be 100644
--- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
+++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
@@ -459,6 +459,24 @@ void tst_QTextDocument::findMultiple()
cursor = doc->find(expr, cursor);
QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar"));
QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3);
+
+ QRegularExpression regularExpression("bar");
+
+ cursor.movePosition(QTextCursor::End);
+ cursor = doc->find(regularExpression, cursor, QTextDocument::FindBackward);
+ QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar"));
+ QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3);
+ cursor = doc->find(regularExpression, cursor, QTextDocument::FindBackward);
+ QCOMPARE(cursor.selectionStart(), text.indexOf("bar"));
+ QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3);
+
+ cursor.movePosition(QTextCursor::Start);
+ cursor = doc->find(regularExpression, cursor);
+ QCOMPARE(cursor.selectionStart(), text.indexOf("bar"));
+ QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3);
+ cursor = doc->find(regularExpression, cursor);
+ QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar"));
+ QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3);
}
void tst_QTextDocument::basicIsModifiedChecks()
diff --git a/tests/manual/qopenglwindow/multiwindow/main.cpp b/tests/manual/qopenglwindow/multiwindow/main.cpp
index 0788408b47..1f84758bc9 100644
--- a/tests/manual/qopenglwindow/multiwindow/main.cpp
+++ b/tests/manual/qopenglwindow/multiwindow/main.cpp
@@ -26,14 +26,7 @@
**
****************************************************************************/
-#include <QGuiApplication>
-#include <QOpenGLWindow>
-#include <QOpenGLContext>
-#include <QOpenGLFunctions>
-#include <QPainter>
-#include <QElapsedTimer>
-#include <QCommandLineParser>
-#include <QScreen>
+#include <QtGui>
const char applicationDescription[] = "\n\
This application opens multiple windows and continuously schedules updates for\n\
@@ -62,67 +55,95 @@ class Window : public QOpenGLWindow
{
Q_OBJECT
public:
- Window(int n) : idx(n) {
- r = g = b = fps = 0;
- y = 0;
+ Window(int index) : windowNumber(index + 1), x(0), framesSwapped(0) {
+
+ color = QColor::fromHsl((index * 30) % 360, 255, 127).toRgb();
+
resize(200, 200);
+ setObjectName(QString("Window %1").arg(windowNumber));
+
connect(this, SIGNAL(frameSwapped()), SLOT(frameSwapped()));
- fpsTimer.start();
}
void paintGL() {
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
- f->glClearColor(r, g, b, 1);
+ f->glClearColor(color.redF(), color.greenF(), color.blueF(), 1);
f->glClear(GL_COLOR_BUFFER_BIT);
- switch (idx % 3) {
- case 0:
- r += 0.005f;
- break;
- case 1:
- g += 0.005f;
- break;
- case 2:
- b += 0.005f;
- break;
- }
- if (r > 1)
- r = 0;
- if (g > 1)
- g = 0;
- if (b > 1)
- b = 0;
-
- QPainter p(this);
- p.setPen(Qt::white);
- p.drawText(QPoint(20, y), QString(QLatin1String("Window %1 (%2 FPS)")).arg(idx).arg(fps));
- y += 1;
- if (y > height() - 20)
- y = 20;
- update();
+ QPainter painter(this);
+ painter.drawLine(x, 0, x, height());
+ x = ++x % width();
}
public slots:
void frameSwapped() {
++framesSwapped;
- if (fpsTimer.elapsed() > 1000) {
- fps = qRound(framesSwapped * (1000.0 / fpsTimer.elapsed()));
- framesSwapped = 0;
- fpsTimer.restart();
- }
+ update();
+ }
+
+protected:
+ void exposeEvent(QExposeEvent *event) {
+ if (!isExposed())
+ return;
+
+ QSurfaceFormat format = context()->format();
+ qDebug() << this << format.swapBehavior() << "with Vsync =" << (format.swapInterval() ? "ON" : "OFF");
+ if (format.swapInterval() != requestedFormat().swapInterval())
+ qWarning() << "WARNING: Did not get requested swap interval of" << requestedFormat().swapInterval() << "for" << this;
+
+ QOpenGLWindow::exposeEvent(event);
+ }
+
+ void mousePressEvent(QMouseEvent *event) {
+ qDebug() << this << event;
+ color.setHsl((color.hue() + 90) % 360, color.saturation(), color.lightness());
+ color = color.toRgb();
}
private:
- int idx;
- GLfloat r, g, b;
- int y;
+ int windowNumber;
+ QColor color;
+ int x;
int framesSwapped;
- QElapsedTimer fpsTimer;
- int fps;
+ friend void printFps();
};
+static const qreal kFpsInterval = 500;
+
+void printFps()
+{
+ static QElapsedTimer timer;
+ if (!timer.isValid()) {
+ timer.start();
+ return;
+ }
+
+ const qreal frameFactor = (kFpsInterval / timer.elapsed()) * (1000.0 / kFpsInterval);
+
+ QDebug output = qDebug().nospace();
+
+ qreal averageFps = 0;
+ const QWindowList windows = QGuiApplication::topLevelWindows();
+ for (int i = 0; i < windows.size(); ++i) {
+ Window *w = qobject_cast<Window*>(windows.at(i));
+ Q_ASSERT(w);
+
+ int fps = qRound(w->framesSwapped * frameFactor);
+ output << (i + 1) << "=" << fps << ", ";
+
+ averageFps += fps;
+ w->framesSwapped = 0;
+ }
+ averageFps = qRound(averageFps / windows.size());
+ qreal msPerFrame = 1000.0 / averageFps;
+
+ output << "avg=" << averageFps << ", ms=" << msPerFrame;
+
+ timer.restart();
+}
+
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
@@ -144,30 +165,24 @@ int main(int argc, char **argv)
parser.process(app);
- QSurfaceFormat fmt;
- if (parser.isSet(noVsyncOption)) {
- qDebug("swap interval 0 (no throttling)");
- fmt.setSwapInterval(0);
- } else {
- qDebug("swap interval 1 (sync to vblank)");
- }
- QSurfaceFormat::setDefaultFormat(fmt);
+ QSurfaceFormat defaultSurfaceFormat;
+ defaultSurfaceFormat.setSwapInterval(parser.isSet(noVsyncOption) ? 0 : 1);
+ QSurfaceFormat::setDefaultFormat(defaultSurfaceFormat);
QRect availableGeometry = app.primaryScreen()->availableGeometry();
int numberOfWindows = qMax(parser.value(numWindowsOption).toInt(), 1);
QList<QWindow *> windows;
for (int i = 0; i < numberOfWindows; ++i) {
- Window *w = new Window(i + 1);
+ Window *w = new Window(i);
windows << w;
if (i == 0 && parser.isSet(vsyncOneOption)) {
- qDebug("swap interval 1 for first window only");
- QSurfaceFormat vsyncedSurfaceFormat = fmt;
+ QSurfaceFormat vsyncedSurfaceFormat = defaultSurfaceFormat;
vsyncedSurfaceFormat.setSwapInterval(1);
w->setFormat(vsyncedSurfaceFormat);
- fmt.setSwapInterval(0);
- QSurfaceFormat::setDefaultFormat(fmt);
+ defaultSurfaceFormat.setSwapInterval(0);
+ QSurfaceFormat::setDefaultFormat(defaultSurfaceFormat);
}
static int windowWidth = w->width() + 20;
@@ -182,9 +197,15 @@ int main(int argc, char **argv)
QPoint position = availableGeometry.topLeft();
position += QPoint(col * windowWidth, row * windowHeight);
w->setFramePosition(position);
- w->show();
+ w->showNormal();
}
+ QTimer fpsTimer;
+ fpsTimer.setInterval(kFpsInterval);
+ fpsTimer.setTimerType(Qt::PreciseTimer);
+ QObject::connect(&fpsTimer, &QTimer::timeout, &printFps);
+ fpsTimer.start();
+
int r = app.exec();
qDeleteAll(windows);
return r;