Merge remote-tracking branch 'origin/5.6' into 5.7

Change-Id: I9cfefaf22b010fca937be77979f5fb50574bb71e
This commit is contained in:
Liang Qi 2016-09-21 07:14:33 +02:00
commit d10e4c193b
18 changed files with 332 additions and 121 deletions

View File

@ -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]

View File

@ -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]

View File

@ -0,0 +1,5 @@
#! [0]
HEADERS += mycocoaeventfilter.h
OBJECTIVE_SOURCES += mycocoaeventfilter.mm
LIBS += -framework AppKit
#! [0]

View File

@ -83,7 +83,7 @@ QT_BEGIN_NAMESPACE
/*! /*!
\property QAbstractProxyModel::sourceModel \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 //detects the deletion of the source model

View File

@ -96,14 +96,25 @@ QAbstractNativeEventFilter::~QAbstractNativeEventFilter()
In both cases, the \a message can be casted to a MSG pointer. 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. 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 In your reimplementation of this function, if you want to filter
the \a message out, i.e. stop it being handled further, return the \a message out, i.e. stop it being handled further, return
true; otherwise return false. true; otherwise return false.
Example: \b {Linux example}
\snippet code/src_corelib_kernel_qabstractnativeeventfilter.cpp 0 \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 QT_END_NAMESPACE

View File

@ -585,7 +585,7 @@ void QBrush::detach(Qt::BrushStyle newStyle)
if (newStyle == d->style && d->ref.load() == 1) if (newStyle == d->style && d->ref.load() == 1)
return; return;
QScopedPointer<QBrushData> x; QScopedPointer<QBrushData, QBrushDataPointerDeleter> x;
switch(newStyle) { switch(newStyle) {
case Qt::TexturePattern: { case Qt::TexturePattern: {
QTexturedBrushData *tbd = new QTexturedBrushData; QTexturedBrushData *tbd = new QTexturedBrushData;
@ -601,28 +601,30 @@ void QBrush::detach(Qt::BrushStyle newStyle)
} }
case Qt::LinearGradientPattern: case Qt::LinearGradientPattern:
case Qt::RadialGradientPattern: case Qt::RadialGradientPattern:
case Qt::ConicalGradientPattern: case Qt::ConicalGradientPattern: {
x.reset(new QGradientBrushData); QGradientBrushData *gbd = new QGradientBrushData;
switch (d->style) { switch (d->style) {
case Qt::LinearGradientPattern: case Qt::LinearGradientPattern:
case Qt::RadialGradientPattern: case Qt::RadialGradientPattern:
case Qt::ConicalGradientPattern: case Qt::ConicalGradientPattern:
static_cast<QGradientBrushData *>(x.data())->gradient = gbd->gradient =
static_cast<QGradientBrushData *>(d.data())->gradient; static_cast<QGradientBrushData *>(d.data())->gradient;
break; break;
default: default:
break; break;
} }
x.reset(gbd);
break; break;
}
default: default:
x.reset(new QBrushData); x.reset(new QBrushData);
break; break;
} }
x->ref.store(1); x->ref.store(1); // must be first lest the QBrushDataPointerDeleter turns into a no-op
x->style = newStyle; x->style = newStyle;
x->color = d->color; x->color = d->color;
x->transform = d->transform; x->transform = d->transform;
d.reset(x.take()); d.swap(x);
} }

View File

@ -59,8 +59,15 @@ Q_LOGGING_CATEGORY(qLcEvdevKeyMap, "qt.qpa.input.keymap")
// simple builtin US keymap // simple builtin US keymap
#include "qevdevkeyboard_defaultmap_p.h" #include "qevdevkeyboard_defaultmap_p.h"
QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, int fd, bool disableZap, bool enableCompose, const QString &keymapFile) void QFdContainer::reset() Q_DECL_NOTHROW
: m_device(device), m_fd(fd), m_notify(Q_NULLPTR), {
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_modifiers(0), m_composing(0), m_dead_unicode(0xffff),
m_no_zap(disableZap), m_do_compose(enableCompose), m_no_zap(disableZap), m_do_compose(enableCompose),
m_keymap(0), m_keymap_size(0), m_keycompose(0), m_keycompose_size(0) 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(); unloadKeymap();
// socket notifier for events on the keyboard device // 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())); connect(m_notify, SIGNAL(activated(int)), this, SLOT(readKeycode()));
} }
QEvdevKeyboardHandler::~QEvdevKeyboardHandler() QEvdevKeyboardHandler::~QEvdevKeyboardHandler()
{ {
unloadKeymap(); unloadKeymap();
if (m_fd >= 0)
qt_safe_close(m_fd);
} }
QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device,
@ -118,13 +122,12 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device,
qCDebug(qLcEvdevKey) << "Opening keyboard at" << device; qCDebug(qLcEvdevKey) << "Opening keyboard at" << device;
int fd; QFdContainer fd(qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0));
fd = qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); if (fd.get() >= 0) {
if (fd >= 0) { ::ioctl(fd.get(), EVIOCGRAB, grab);
::ioctl(fd, EVIOCGRAB, grab);
if (repeatDelay > 0 && repeatRate > 0) { if (repeatDelay > 0 && repeatRate > 0) {
int kbdrep[2] = { repeatDelay, repeatRate }; int kbdrep[2] = { repeatDelay, repeatRate };
::ioctl(fd, EVIOCSREP, kbdrep); ::ioctl(fd.get(), EVIOCSREP, kbdrep);
} }
return new QEvdevKeyboardHandler(device, fd, disableZap, enableCompose, keymapFile); 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.code = led;
led_ie.value = state; 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() void QEvdevKeyboardHandler::readKeycode()
@ -153,7 +156,7 @@ void QEvdevKeyboardHandler::readKeycode()
int n = 0; int n = 0;
forever { 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) { if (result == 0) {
qWarning("evdevkeyboard: Got EOF from the input device"); qWarning("evdevkeyboard: Got EOF from the input device");
@ -166,8 +169,7 @@ void QEvdevKeyboardHandler::readKeycode()
if (errno == ENODEV) { if (errno == ENODEV) {
delete m_notify; delete m_notify;
m_notify = Q_NULLPTR; m_notify = Q_NULLPTR;
qt_safe_close(m_fd); m_fd.reset();
m_fd = -1;
} }
return; return;
} }
@ -478,7 +480,7 @@ void QEvdevKeyboardHandler::unloadKeymap()
//Set locks according to keyboard leds //Set locks according to keyboard leds
quint16 ledbits[1]; quint16 ledbits[1];
memset(ledbits, 0, sizeof(ledbits)); 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"); qWarning("evdevkeyboard: Failed to query led states");
switchLed(LED_NUML,false); switchLed(LED_NUML,false);
switchLed(LED_CAPSL, false); switchLed(LED_CAPSL, false);

View File

@ -129,12 +129,25 @@ inline QDataStream &operator<<(QDataStream &ds, const QEvdevKeyboardMap::Composi
return ds << c.first << c.second << c.result; 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 class QEvdevKeyboardHandler : public QObject
{ {
Q_OBJECT Q_OBJECT
public: 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(); ~QEvdevKeyboardHandler();
enum KeycodeAction { enum KeycodeAction {
@ -187,7 +200,7 @@ private:
void switchLed(int, bool); void switchLed(int, bool);
QString m_device; QString m_device;
int m_fd; QFdContainer m_fd;
QSocketNotifier *m_notify; QSocketNotifier *m_notify;
// keymap handling // keymap handling

View File

@ -252,6 +252,8 @@ QStringList QConnmanManagerInterface::getServices()
bool QConnmanManagerInterface::requestScan(const QString &type) bool QConnmanManagerInterface::requestScan(const QString &type)
{ {
bool scanned = false; bool scanned = false;
if (technologiesMap.isEmpty())
getTechnologies();
Q_FOREACH (QConnmanTechnologyInterface *tech, technologiesMap) { Q_FOREACH (QConnmanTechnologyInterface *tech, technologiesMap) {
if (tech->type() == type) { if (tech->type() == type) {
tech->scan(); tech->scan();

View File

@ -330,6 +330,11 @@ void QCocoaGLContext::updateSurfaceFormat()
[pixelFormat release]; [pixelFormat release];
GLint swapInterval = -1;
[m_context getValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
if (swapInterval >= 0)
m_format.setSwapInterval(swapInterval);
// Restore the original context // Restore the original context
CGLSetCurrentContext(oldContext); CGLSetCurrentContext(oldContext);
} }

View File

@ -319,7 +319,7 @@ QIOSMenu::QIOSMenu()
: QPlatformMenu() : QPlatformMenu()
, m_tag(0) , m_tag(0)
, m_enabled(true) , m_enabled(true)
, m_visible(true) , m_visible(false)
, m_text(QString()) , m_text(QString())
, m_menuType(DefaultMenu) , m_menuType(DefaultMenu)
, m_effectiveMenuType(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) 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; return;
emit aboutToShow(); emit aboutToShow();
@ -439,6 +439,8 @@ void QIOSMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, c
toggleShowUsingUIPickerView(true); toggleShowUsingUIPickerView(true);
break; break;
} }
m_visible = true;
} }
void QIOSMenu::dismiss() void QIOSMenu::dismiss()
@ -460,6 +462,7 @@ void QIOSMenu::dismiss()
} }
m_currentMenu = 0; m_currentMenu = 0;
m_visible = false;
} }
void QIOSMenu::toggleShowUsingUIMenuController(bool show) void QIOSMenu::toggleShowUsingUIMenuController(bool show)

View File

@ -228,6 +228,10 @@
@implementation QIOSViewController @implementation QIOSViewController
@synthesize prefersStatusBarHidden;
@synthesize preferredStatusBarUpdateAnimation;
@synthesize preferredStatusBarStyle;
- (id)initWithQIOSScreen:(QIOSScreen *)screen - (id)initWithQIOSScreen:(QIOSScreen *)screen
{ {
if (self = [self init]) { if (self = [self init]) {

View File

@ -91,7 +91,7 @@ QIOSWindow::~QIOSWindow()
// practice this doesn't seem to happen when removing the view from its superview. To ensure that // 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 // Qt's internal state for touch and mouse handling is kept consistent, we therefor have to force
// cancellation of all touch events. // cancellation of all touch events.
[m_view touchesCancelled:0 withEvent:0]; [m_view touchesCancelled:[NSSet set] withEvent:0];
clearAccessibleCache(); clearAccessibleCache();
m_view->m_qioswindow = 0; m_view->m_qioswindow = 0;

View File

@ -423,7 +423,8 @@
// We do this by assuming that there are no cases where a // We do this by assuming that there are no cases where a
// sub-set of the active touch events are intentionally cancelled. // 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"); qWarning("Subset of active touches cancelled by UIKit");
m_activeTouches.clear(); m_activeTouches.clear();

View File

@ -748,8 +748,7 @@ void QXcbKeyboard::updateKeymap()
// update xkb state object // update xkb state object
xkb_state_unref(xkb_state); xkb_state_unref(xkb_state);
xkb_state = new_state; xkb_state = new_state;
if (!connection()->hasXKB()) updateXKBMods();
updateXKBMods();
checkForLatinLayout(); checkForLatinLayout();
} }
@ -774,32 +773,37 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
} }
#endif #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) void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
{ {
if (m_config && !connection()->hasXKB()) { if (m_config && !connection()->hasXKB()) {
const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); updateXKBStateFromState(xkb_state, state);
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)");
}
} }
} }
@ -1463,7 +1467,16 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
if (type == QEvent::KeyPress) if (type == QEvent::KeyPress)
targetWindow->updateNetWmUserTime(time); 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(); QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
QMetaMethod method; QMetaMethod method;
@ -1482,11 +1495,13 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
Q_ARG(uint, code), Q_ARG(uint, code),
Q_ARG(uint, state), Q_ARG(uint, state),
Q_ARG(bool, type == QEvent::KeyPress)); Q_ARG(bool, type == QEvent::KeyPress));
if (retval) if (retval) {
xkb_state_unref(kb_state);
return; 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 // Ιf control modifier is set we should prefer latin character, this is
// used for standard shortcuts in checks like "key == QKeySequence::Copy", // 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, QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers,
code, sym, state, string, isAutoRepeat); code, sym, state, string, isAutoRepeat);
} }
xkb_state_unref(kb_state);
} }
QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const

View File

@ -104,6 +104,8 @@ protected:
void checkForLatinLayout(); void checkForLatinLayout();
private: private:
void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state);
bool m_config; bool m_config;
xcb_keycode_t m_autorepeat_code; xcb_keycode_t m_autorepeat_code;

View File

@ -459,6 +459,24 @@ void tst_QTextDocument::findMultiple()
cursor = doc->find(expr, cursor); cursor = doc->find(expr, cursor);
QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar"));
QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); 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() void tst_QTextDocument::basicIsModifiedChecks()

View File

@ -26,14 +26,7 @@
** **
****************************************************************************/ ****************************************************************************/
#include <QGuiApplication> #include <QtGui>
#include <QOpenGLWindow>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QPainter>
#include <QElapsedTimer>
#include <QCommandLineParser>
#include <QScreen>
const char applicationDescription[] = "\n\ const char applicationDescription[] = "\n\
This application opens multiple windows and continuously schedules updates for\n\ This application opens multiple windows and continuously schedules updates for\n\
@ -62,67 +55,95 @@ class Window : public QOpenGLWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
Window(int n) : idx(n) { Window(int index) : windowNumber(index + 1), x(0), framesSwapped(0) {
r = g = b = fps = 0;
y = 0; color = QColor::fromHsl((index * 30) % 360, 255, 127).toRgb();
resize(200, 200); resize(200, 200);
setObjectName(QString("Window %1").arg(windowNumber));
connect(this, SIGNAL(frameSwapped()), SLOT(frameSwapped())); connect(this, SIGNAL(frameSwapped()), SLOT(frameSwapped()));
fpsTimer.start();
} }
void paintGL() { void paintGL() {
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); 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); 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); QPainter painter(this);
p.setPen(Qt::white); painter.drawLine(x, 0, x, height());
p.drawText(QPoint(20, y), QString(QLatin1String("Window %1 (%2 FPS)")).arg(idx).arg(fps)); x = ++x % width();
y += 1;
if (y > height() - 20)
y = 20;
update();
} }
public slots: public slots:
void frameSwapped() { void frameSwapped() {
++framesSwapped; ++framesSwapped;
if (fpsTimer.elapsed() > 1000) { update();
fps = qRound(framesSwapped * (1000.0 / fpsTimer.elapsed())); }
framesSwapped = 0;
fpsTimer.restart(); 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: private:
int idx; int windowNumber;
GLfloat r, g, b; QColor color;
int y; int x;
int framesSwapped; int framesSwapped;
QElapsedTimer fpsTimer; friend void printFps();
int fps;
}; };
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) int main(int argc, char **argv)
{ {
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
@ -144,30 +165,24 @@ int main(int argc, char **argv)
parser.process(app); parser.process(app);
QSurfaceFormat fmt; QSurfaceFormat defaultSurfaceFormat;
if (parser.isSet(noVsyncOption)) { defaultSurfaceFormat.setSwapInterval(parser.isSet(noVsyncOption) ? 0 : 1);
qDebug("swap interval 0 (no throttling)"); QSurfaceFormat::setDefaultFormat(defaultSurfaceFormat);
fmt.setSwapInterval(0);
} else {
qDebug("swap interval 1 (sync to vblank)");
}
QSurfaceFormat::setDefaultFormat(fmt);
QRect availableGeometry = app.primaryScreen()->availableGeometry(); QRect availableGeometry = app.primaryScreen()->availableGeometry();
int numberOfWindows = qMax(parser.value(numWindowsOption).toInt(), 1); int numberOfWindows = qMax(parser.value(numWindowsOption).toInt(), 1);
QList<QWindow *> windows; QList<QWindow *> windows;
for (int i = 0; i < numberOfWindows; ++i) { for (int i = 0; i < numberOfWindows; ++i) {
Window *w = new Window(i + 1); Window *w = new Window(i);
windows << w; windows << w;
if (i == 0 && parser.isSet(vsyncOneOption)) { if (i == 0 && parser.isSet(vsyncOneOption)) {
qDebug("swap interval 1 for first window only"); QSurfaceFormat vsyncedSurfaceFormat = defaultSurfaceFormat;
QSurfaceFormat vsyncedSurfaceFormat = fmt;
vsyncedSurfaceFormat.setSwapInterval(1); vsyncedSurfaceFormat.setSwapInterval(1);
w->setFormat(vsyncedSurfaceFormat); w->setFormat(vsyncedSurfaceFormat);
fmt.setSwapInterval(0); defaultSurfaceFormat.setSwapInterval(0);
QSurfaceFormat::setDefaultFormat(fmt); QSurfaceFormat::setDefaultFormat(defaultSurfaceFormat);
} }
static int windowWidth = w->width() + 20; static int windowWidth = w->width() + 20;
@ -182,9 +197,15 @@ int main(int argc, char **argv)
QPoint position = availableGeometry.topLeft(); QPoint position = availableGeometry.topLeft();
position += QPoint(col * windowWidth, row * windowHeight); position += QPoint(col * windowWidth, row * windowHeight);
w->setFramePosition(position); 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(); int r = app.exec();
qDeleteAll(windows); qDeleteAll(windows);
return r; return r;