summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2014-05-06 16:19:14 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-05-06 16:50:03 +0200
commit1326cd15f7ba985551f0fddc717e3bfc01ddda85 (patch)
tree024eb871ed5f4e8c02e21412475e6e9929a2b030 /src/plugins
parentfe70367fe06984d1ac84cc276ca3fd3edc4193c7 (diff)
parentbeb7258a56b6ec76531b73cc07ee30132a3f548f (diff)
Merge remote-tracking branch 'origin/stable' into dev
Conflicts: mkspecs/qnx-x86-qcc/qplatformdefs.h src/corelib/global/qglobal.h src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp src/opengl/qgl.cpp src/opengl/qglpixelbuffer.cpp src/opengl/qglshaderprogram.cpp tests/auto/opengl/qglthreads/tst_qglthreads.cpp Change-Id: Iaba137884d3526a139000ca26fee02bb27b5cdb5
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/bearer/networkmanager/qnetworkmanagerservice.h4
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp196
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.h4
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm41
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm25
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm15
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm3
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm47
-rw-r--r--src/plugins/platforms/direct2d/direct2d.pro1
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp10
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h3
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp872
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h33
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp5
-rw-r--r--src/plugins/platforms/directfb/directfb.pro1
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pro1
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.h2
-rw-r--r--src/plugins/platforms/ios/ios.pro1
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm7
-rw-r--r--src/plugins/platforms/ios/quiview_textinput.mm2
-rw-r--r--src/plugins/platforms/kms/kms.pro1
-rw-r--r--src/plugins/platforms/linuxfb/linuxfb.pro1
-rw-r--r--src/plugins/platforms/minimal/minimal.pro1
-rw-r--r--src/plugins/platforms/minimalegl/minimalegl.pro1
-rw-r--r--src/plugins/platforms/offscreen/offscreen.pro1
-rw-r--r--src/plugins/platforms/openwfd/openwf.pro1
-rw-r--r--src/plugins/platforms/qnx/qnx.pro1
-rw-r--r--src/plugins/platforms/qnx/qqnxfiledialoghelper.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.cpp5
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp10
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp25
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h2
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp89
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp24
-rw-r--r--src/plugins/platforms/windows/windows.pro1
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp10
-rw-r--r--src/plugins/platforms/winrt/winrt.pro1
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp28
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h14
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp75
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp129
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h4
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro1
-rw-r--r--src/plugins/printsupport/windows/windows.pro2
58 files changed, 1350 insertions, 413 deletions
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
index 74a25c1370..9493218024 100644
--- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
+++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
@@ -197,7 +197,7 @@ public:
Privacy = 0x1
};
- Q_DECLARE_FLAGS(ApFlags, ApFlag);
+ Q_DECLARE_FLAGS(ApFlags, ApFlag)
enum ApSecurityFlag {
ApSecurityNone = 0x0,
@@ -213,7 +213,7 @@ public:
Key8021x = 0x200
};
- Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag);
+ Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag)
explicit QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent = 0);
~QNetworkManagerInterfaceAccessPoint();
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index 3324d9ba49..e255a49ac7 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
** Contact: http://www.qt-project.org/legal
**
@@ -338,7 +339,7 @@ static JNINativeMethod methods[] = {
QAndroidInputContext::QAndroidInputContext()
- : QPlatformInputContext(), m_blockUpdateSelection(false), m_batchEditNestingLevel(0)
+ : QPlatformInputContext(), m_composingTextStart(-1), m_blockUpdateSelection(false), m_batchEditNestingLevel(0), m_focusObject(0)
{
QtAndroid::AttachedJNIEnv env;
if (!env.jniEnv)
@@ -431,9 +432,24 @@ QAndroidInputContext *QAndroidInputContext::androidInputContext()
return m_androidInputContext;
}
+// cursor position getter that also works with editors that have not been updated to the new API
+static inline int getAbsoluteCursorPosition(const QSharedPointer<QInputMethodQueryEvent> &query)
+{
+ QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
+ return absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt();
+}
+
+// position of the start of the current block
+static inline int getBlockPosition(const QSharedPointer<QInputMethodQueryEvent> &query)
+{
+ QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
+ return absolutePos.isValid() ? absolutePos.toInt() - query->value(Qt::ImCursorPosition).toInt() : 0;
+}
+
void QAndroidInputContext::reset()
{
clear();
+ m_batchEditNestingLevel = 0;
if (qGuiApp->focusObject())
QtAndroidInput::resetSoftwareKeyboard();
else
@@ -449,13 +465,20 @@ void QAndroidInputContext::updateCursorPosition()
{
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) {
- // make sure it also works with editors that have not been updated to the new API
- QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
- const int cursorPos = absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt();
+ const int cursorPos = getAbsoluteCursorPosition(query);
const int composeLength = m_composingText.length();
- const int composeStart = composeLength ? cursorPos : -1;
- QtAndroidInput::updateSelection(cursorPos + composeLength, cursorPos + composeLength, //empty selection
- composeStart, composeStart + composeLength); // pre-edit text
+
+ //Q_ASSERT(m_composingText.isEmpty() == (m_composingTextStart == -1));
+ if (m_composingText.isEmpty() != (m_composingTextStart == -1))
+ qWarning() << "Input method out of sync" << m_composingText << m_composingTextStart;
+
+
+ // Qt's idea of the cursor position is the start of the preedit area, so we have to maintain our own preedit cursor pos
+ int realCursorPosition = cursorPos;
+ if (!m_composingText.isEmpty())
+ realCursorPosition = m_composingCursor;
+ QtAndroidInput::updateSelection(realCursorPosition, realCursorPosition, //empty selection
+ m_composingTextStart, m_composingTextStart + composeLength); // pre-edit text
}
}
@@ -529,9 +552,22 @@ bool QAndroidInputContext::isComposing() const
void QAndroidInputContext::clear()
{
m_composingText.clear();
+ m_composingTextStart = -1;
m_extractedText.clear();
}
+
+void QAndroidInputContext::setFocusObject(QObject *object)
+{
+ if (object != m_focusObject) {
+ m_focusObject = object;
+ if (!m_composingText.isEmpty())
+ finishComposingText();
+ reset();
+ }
+ QPlatformInputContext::setFocusObject(object);
+}
+
void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodEvent *event)
{
QCoreApplication::sendEvent(receiver, event);
@@ -557,8 +593,18 @@ jboolean QAndroidInputContext::endBatchEdit()
jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/)
{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return JNI_FALSE;
+
+
+ const int cursorPos = getAbsoluteCursorPosition(query);
m_composingText = text;
- return finishComposingText();
+ m_composingTextStart = cursorPos;
+ m_composingCursor = cursorPos + text.length();
+ finishComposingText();
+ //### move cursor to newCursorPosition and call updateCursorPosition()
+ return JNI_TRUE;
}
jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength)
@@ -568,6 +614,7 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right
return JNI_TRUE;
m_composingText.clear();
+ m_composingTextStart = -1;
QInputMethodEvent event;
event.setCommitString(QString(), -leftLength, leftLength+rightLength);
@@ -605,7 +652,9 @@ jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
return res;
}
-const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint hintMaxChars, jint /*hintMaxLines*/, jint /*flags*/)
+
+
+const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint /*hintMaxChars*/, jint /*hintMaxLines*/, jint /*flags*/)
{
// Note to self: "if the GET_EXTRACTED_TEXT_MONITOR flag is set, you should be calling
// updateExtractedText(View, int, ExtractedText) whenever you call
@@ -616,28 +665,37 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
return m_extractedText;
int localPos = query->value(Qt::ImCursorPosition).toInt(); //position before pre-edit text relative to the current block
- QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
- int blockPos = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0; // position of the start of the current block
- QString blockText = query->value(Qt::ImSurroundingText).toString() + m_composingText;
+ int blockPos = getBlockPosition(query);
+ QString blockText = query->value(Qt::ImSurroundingText).toString();
int composeLength = m_composingText.length();
+ if (composeLength > 0) {
+ //Qt doesn't give us the preedit text, so we have to insert it at the correct position
+ int localComposePos = m_composingTextStart - blockPos;
+ blockText = blockText.left(localComposePos) + m_composingText + blockText.mid(localComposePos);
+ }
+
int cpos = localPos + composeLength; //actual cursor pos relative to the current block
int localOffset = 0; // start of extracted text relative to the current block
- if (hintMaxChars) {
- if (cpos > hintMaxChars)
- localOffset = cpos - hintMaxChars;
- m_extractedText.text = blockText.mid(localOffset, hintMaxChars);
- }
- m_extractedText.startOffset = blockPos + localOffset; // "The offset in the overall text at which the extracted text starts."
+ // It is documented that we should try to return hintMaxChars
+ // characters, but that's not what the standard Android controls do, and
+ // there are input methods out there that (surprise) seem to depend on
+ // what happens in reality rather than what's documented.
+
+ m_extractedText.text = blockText;
+ m_extractedText.startOffset = blockPos + localOffset;
const QString &selection = query->value(Qt::ImCurrentSelection).toString();
const int selLen = selection.length();
if (selLen) {
m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt() - localOffset;
m_extractedText.selectionEnd = m_extractedText.selectionStart + selLen;
- } else {
+ } else if (composeLength > 0) {
+ m_extractedText.selectionStart = m_composingCursor - m_extractedText.startOffset;
+ m_extractedText.selectionEnd = m_composingCursor - m_extractedText.startOffset;
+ } else {
m_extractedText.selectionStart = cpos - localOffset;
m_extractedText.selectionEnd = cpos - localOffset;
}
@@ -656,6 +714,7 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/)
QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
{
+ //### the preedit text could theoretically be after the cursor
QVariant textAfter = queryFocusObjectThreadSafe(Qt::ImTextAfterCursor, QVariant(length));
if (textAfter.isValid()) {
return textAfter.toString().left(length);
@@ -678,7 +737,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
{
QVariant textBefore = queryFocusObjectThreadSafe(Qt::ImTextBeforeCursor, QVariant(length));
if (textBefore.isValid()) {
- return textBefore.toString().left(length) + m_composingText;
+ return textBefore.toString().right(length) + m_composingText;
}
//compatibility code for old controls that do not implement the new API
@@ -691,15 +750,34 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
if (!text.length())
return text;
- const int wordLeftPos = cursorPos - length;
- return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos) + m_composingText;
+ //### the preedit text does not need to be immediately before the cursor
+ if (cursorPos <= length)
+ return text.left(cursorPos) + m_composingText;
+ else
+ return text.mid(cursorPos - length, length) + m_composingText;
}
+/*
+ Android docs say that this function should remove the current preedit text
+ if any, and replace it with the given text. Any selected text should be
+ removed. The cursor is then moved to newCursorPosition. If > 0, this is
+ relative to the end of the text - 1; if <= 0, this is relative to the start
+ of the text.
+ */
+
jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return JNI_FALSE;
+
+ const int cursorPos = getAbsoluteCursorPosition(query);
if (newCursorPosition > 0)
newCursorPosition += text.length() - 1;
+
m_composingText = text;
+ m_composingTextStart = text.isEmpty() ? -1 : cursorPos;
+ m_composingCursor = cursorPos + newCursorPosition;
QList<QInputMethodEvent::Attribute> attributes;
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
newCursorPosition,
@@ -714,23 +792,26 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
QInputMethodEvent event(m_composingText, attributes);
sendInputMethodEvent(&event);
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
- if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) {
- QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
- const int cursorPos = absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt();
- const int preeditLength = text.length();
- QtAndroidInput::updateSelection(cursorPos+preeditLength, cursorPos+preeditLength, -1, -1);
- }
+ updateCursorPosition();
return JNI_TRUE;
}
// Android docs say:
// * start may be after end, same meaning as if swapped
-// * this function must not trigger updateSelection
+// * this function should not trigger updateSelection
// * if start == end then we should stop composing
jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
{
+ // Qt will not include the current preedit text in the query results, and interprets all
+ // parameters relative to the text excluding the preedit. The simplest solution is therefore to
+ // tell Qt that we commit the text before we set the new region. This may cause a little flicker, but is
+ // much more robust than trying to keep the two different world views in sync
+
+ bool wasComposing = !m_composingText.isEmpty();
+ if (wasComposing)
+ finishComposingText();
+
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -745,19 +826,23 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
Therefore, the length of the region is end - start
*/
+
int length = end - start;
int localPos = query->value(Qt::ImCursorPosition).toInt();
- QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
- int blockPosition = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0;
+ int blockPosition = getBlockPosition(query);
int localStart = start - blockPosition; // Qt uses position inside block
+ int currentCursor = wasComposing ? m_composingCursor : blockPosition + localPos;
bool updateSelectionWasBlocked = m_blockUpdateSelection;
m_blockUpdateSelection = true;
QString text = query->value(Qt::ImSurroundingText).toString();
+
m_composingText = text.mid(localStart, length);
+ m_composingTextStart = start;
+ m_composingCursor = currentCursor;
- //in the Qt text controls, the cursor position is the start of the preedit
+ //in the Qt text controls, the preedit is defined relative to the cursor position
int relativeStart = localStart - localPos;
QList<QInputMethodEvent::Attribute> attributes;
@@ -769,13 +854,22 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
QVariant(underlined)));
// Keep the cursor position unchanged (don't move to end of preedit)
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, localPos - localStart, length, QVariant()));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, currentCursor - start, 1, QVariant()));
QInputMethodEvent event(m_composingText, attributes);
event.setCommitString(QString(), relativeStart, length);
sendInputMethodEvent(&event);
m_blockUpdateSelection = updateSelectionWasBlocked;
+
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQuery();
+ if (!query2.isNull()) {
+ qDebug() << "Setting. Prev local cpos:" << localPos << "block pos:" <<blockPosition << "comp.start:" << m_composingTextStart << "rel.start:" << relativeStart << "len:" << length << "cpos attr:" << localPos - localStart;
+ qDebug() << "New cursor pos" << getAbsoluteCursorPosition(query2);
+ }
+#endif
+
return JNI_TRUE;
}
@@ -785,18 +879,36 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end)
if (query.isNull())
return JNI_FALSE;
- int localPos = query->value(Qt::ImCursorPosition).toInt();
- QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
- int blockPosition = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0;
+ int blockPosition = getBlockPosition(query);
+ int localCursorPos = start - blockPosition;
QList<QInputMethodEvent::Attribute> attributes;
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
- start - blockPosition,
- end - start,
- QVariant()));
+ if (!m_composingText.isEmpty() && start == end) {
+ // not actually changing the selection; just moving the
+ // preedit cursor
+ int localOldPos = query->value(Qt::ImCursorPosition).toInt();
+ int pos = localCursorPos - localOldPos;
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1, QVariant()));
+
+ //but we have to tell Qt about the compose text all over again
+
+ // Show compose text underlined
+ QTextCharFormat underlined;
+ underlined.setFontUnderline(true);
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, m_composingText.length(),
+ QVariant(underlined)));
+ m_composingCursor = start;
- QInputMethodEvent event(QString(), attributes);
+ } else {
+ // actually changing the selection
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
+ localCursorPos,
+ end - start,
+ QVariant()));
+ }
+ QInputMethodEvent event(m_composingText, attributes);
sendInputMethodEvent(&event);
+ updateCursorPosition();
return JNI_TRUE;
}
diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h
index f7b29a855f..a467e4849e 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/qandroidinputcontext.h
@@ -95,6 +95,7 @@ public:
bool isComposing() const;
void clear();
+ void setFocusObject(QObject *object);
//---------------//
jboolean beginBatchEdit();
@@ -133,9 +134,12 @@ private slots:
private:
ExtractedText m_extractedText;
QString m_composingText;
+ int m_composingTextStart;
+ int m_composingCursor;
QMetaObject::Connection m_updateCursorPosConnection;
bool m_blockUpdateSelection;
int m_batchEditNestingLevel;
+ QObject *m_focusObject;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index a60f4adc28..1f9c0e051d 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -2,6 +2,7 @@ TARGET = qcocoa
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
OBJECTIVE_SOURCES += main.mm \
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 1df4230385..dd3b9f53db 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -168,6 +168,14 @@
// TODO: multi-selection: NSAccessibilitySelectedTextRangesAttribute,
}
+ if (iface->valueInterface()) {
+ [attributes addObjectsFromArray: [[NSArray alloc] initWithObjects:
+ NSAccessibilityMinValueAttribute,
+ NSAccessibilityMaxValueAttribute,
+ nil
+ ]];
+ }
+
return [attributes autorelease];
}
@@ -191,6 +199,19 @@
return [QCocoaAccessibleElement elementWithId: parentId];
}
+
+- (id) minValueAttribute:(QAccessibleInterface*)iface {
+ if (QAccessibleValueInterface *val = iface->valueInterface())
+ return [NSNumber numberWithDouble: val->minimumValue().toDouble()];
+ return nil;
+}
+
+- (id) maxValueAttribute:(QAccessibleInterface*)iface {
+ if (QAccessibleValueInterface *val = iface->valueInterface())
+ return [NSNumber numberWithDouble: val->maximumValue().toDouble()];
+ return nil;
+}
+
- (id)accessibilityAttributeValue:(NSString *)attribute {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface) {
@@ -272,6 +293,10 @@
return [NSNumber numberWithInt: textBeforeCursor.count(QLatin1Char('\n'))];
}
return nil;
+ } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) {
+ return [self minValueAttribute:iface];
+ } else if ([attribute isEqualToString:NSAccessibilityMaxValueAttribute]) {
+ return [self maxValueAttribute:iface];
}
return nil;
@@ -332,7 +357,7 @@
startOffset = text.indexOf(QLatin1Char('\n'), startOffset) + 1;
if (startOffset < 0) // invalid line number, return the first line
startOffset = 0;
- int endOffset = text.indexOf(QLatin1Char('\n'), startOffset + 1);
+ int endOffset = text.indexOf(QLatin1Char('\n'), startOffset);
if (endOffset == -1)
endOffset = text.length();
return [NSValue valueWithRange:NSMakeRange(quint32(startOffset), quint32(endOffset - startOffset))];
@@ -359,6 +384,12 @@
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
return iface->state().focusable ? YES : NO;
+ } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ if (iface->textInterface() && iface->state().editable)
+ return YES;
+ if (iface->valueInterface())
+ return YES;
+ return NO;
} else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
return iface->textInterface() ? YES : NO;
}
@@ -372,6 +403,14 @@
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
if (QAccessibleActionInterface *action = iface->actionInterface())
action->doAction(QAccessibleActionInterface::setFocusAction());
+ } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ if (iface->textInterface()) {
+ QString text = QString::fromNSString((NSString *)value);
+ iface->setText(QAccessible::Value, text);
+ } else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) {
+ double val = [value doubleValue];
+ valueIface->setCurrentValue(val);
+ }
} else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
if (QAccessibleTextInterface *text = iface->textInterface()) {
NSRange range = [value rangeValue];
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 0274ed8201..de6c6585e9 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -134,6 +134,8 @@ public:
void interrupt();
void flush();
+ bool event(QEvent *);
+
friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher);
};
@@ -163,7 +165,6 @@ public:
// The following variables help organizing modal sessions:
QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
bool currentExecIsNSAppRun;
- bool modalSessionOnNSAppRun;
bool nsAppRunCalledByQt;
bool cleanupModalSessionsNeeded;
uint processEventsCalled;
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index 495a54cac4..e0ce9f9648 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -734,13 +734,25 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
updateChildrenWorksWhenModal();
currentModalSessionCached = 0;
if (currentExecIsNSAppRun) {
- modalSessionOnNSAppRun = true;
- q->wakeUp();
+ QEvent *e = new QEvent(QEvent::User);
+ qApp->postEvent(q, e, Qt::HighEventPriority);
} else {
q->interrupt();
}
}
+bool QCocoaEventDispatcher::event(QEvent *e)
+{
+ Q_D(QCocoaEventDispatcher);
+
+ if (e->type() == QEvent::User) {
+ d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents);
+ return true;
+ }
+
+ return QObject::event(e);
+}
+
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
{
Q_Q(QCocoaEventDispatcher);
@@ -777,7 +789,6 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
runLoopTimerRef(0),
blockSendPostedEvents(false),
currentExecIsNSAppRun(false),
- modalSessionOnNSAppRun(false),
nsAppRunCalledByQt(false),
cleanupModalSessionsNeeded(false),
processEventsCalled(0),
@@ -908,14 +919,6 @@ void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info)
// processEvents() was called "manually," ignore this source for now
d->maybeCancelWaitForMoreEvents();
return;
- } else if (d->modalSessionOnNSAppRun) {
- // We're about to spawn the 1st modal session on top of the main runloop.
- // Instead of calling processPostedEvents(), which would need us stop
- // NSApp, we just re-enter processEvents(). This is equivalent to calling
- // QDialog::exec() except that it's done in a non-blocking way.
- d->modalSessionOnNSAppRun = false;
- d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents);
- return;
}
d->processPostedEvents();
d->maybeCancelWaitForMoreEvents();
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 59fda96dff..3ee1dab84d 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -68,6 +68,7 @@ public:
void setEnabled(bool enabled);
void setVisible(bool visible);
void showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item);
+ void dismiss();
void syncSeparatorsCollapsible(bool enable);
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 6acc062eb9..44bc3b8f69 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -490,6 +490,11 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatf
[(QNSView *)view resetMouseButtons];
}
+void QCocoaMenu::dismiss()
+{
+ [m_nativeMenu cancelTracking];
+}
+
QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const
{
if (0 <= position && position < m_menuItems.count())
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index ffc0fabdce..aceb9b619b 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -124,6 +124,8 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor
m_menus.insert(beforeMenu ? m_menus.indexOf(beforeMenu) : m_menus.size(), menu);
if (!menu->menuBar())
insertNativeMenu(menu, beforeMenu);
+ if (m_window && m_window->window()->isActive())
+ updateMenuBarImmediately();
}
void QCocoaMenuBar::removeNativeMenu(QCocoaMenu *menu)
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index 61706c19bc..1efc9f9bfd 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -57,6 +57,7 @@
QT_FORWARD_DECLARE_OBJC_CLASS(NSMenuItem);
QT_FORWARD_DECLARE_OBJC_CLASS(NSMenu);
QT_FORWARD_DECLARE_OBJC_CLASS(NSObject);
+QT_FORWARD_DECLARE_OBJC_CLASS(NSView);
QT_BEGIN_NAMESPACE
@@ -86,6 +87,8 @@ public:
void setChecked(bool isChecked);
void setEnabled(bool isEnabled);
+ void setNativeContents(WId item);
+
inline QString text() const { return m_text; }
inline NSMenuItem * nsItem() { return m_native; }
NSMenuItem *sync();
@@ -105,6 +108,7 @@ private:
QKeySequence mergeAccel();
NSMenuItem *m_native;
+ NSView *m_itemView;
QString m_text;
bool m_textSynced;
QIcon m_icon;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index 58fe07bc62..99d26034bf 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -91,6 +91,7 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel)
QCocoaMenuItem::QCocoaMenuItem() :
m_native(NULL),
+ m_itemView(nil),
m_textSynced(false),
m_menu(NULL),
m_isVisible(true),
@@ -110,6 +111,8 @@ QCocoaMenuItem::~QCocoaMenuItem()
} else {
[m_native release];
}
+
+ [m_itemView release];
}
void QCocoaMenuItem::setText(const QString &text)
@@ -178,6 +181,17 @@ void QCocoaMenuItem::setEnabled(bool enabled)
m_enabled = enabled;
}
+void QCocoaMenuItem::setNativeContents(WId item)
+{
+ NSView *itemView = (NSView *)item;
+ [m_itemView release];
+ m_itemView = [itemView retain];
+ [m_itemView setAutoresizesSubviews:YES];
+ [m_itemView setAutoresizingMask:NSViewWidthSizable];
+ [m_itemView setHidden:NO];
+ [m_itemView setNeedsDisplay:YES];
+}
+
NSMenuItem *QCocoaMenuItem::sync()
{
if (m_isSeparator != [m_native isSeparatorItem]) {
@@ -281,6 +295,7 @@ NSMenuItem *QCocoaMenuItem::sync()
[m_native setHidden: !m_isVisible];
[m_native setEnabled: m_enabled];
+ [m_native setView:m_itemView];
QString text = mergeText();
QKeySequence accel = mergeAccel();
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 5def64ee0a..60152b56b2 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -1375,7 +1375,8 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow()
qPlatformWindow:this];
if ((type & Qt::Popup) == Qt::Popup)
[window setHasShadow:YES];
- [window setHidesOnDeactivate: NO];
+
+ [window setHidesOnDeactivate:(type & Qt::Tool) == Qt::Tool];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 0b9683a3ef..24a9f6fff0 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -42,6 +42,7 @@
#include <QtCore/qglobal.h>
#include <Carbon/Carbon.h>
+#include <dlfcn.h>
#include "qnsview.h"
#include "qcocoawindow.h"
@@ -65,6 +66,9 @@
static QTouchDevice *touchDevice = 0;
+// ### HACK Remove once 10.8 is unsupported
+static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
+
@interface NSEvent (Qt_Compile_Leopard_DeviceDelta)
- (CGFloat)deviceDeltaX;
- (CGFloat)deviceDeltaY;
@@ -73,6 +77,13 @@ static QTouchDevice *touchDevice = 0;
@implementation QNSView
++ (void)initialize
+{
+ NSString **notificationNameVar = (NSString **)dlsym(RTLD_NEXT, "NSWindowDidChangeOcclusionStateNotification");
+ if (notificationNameVar)
+ _q_NSWindowDidChangeOcclusionStateNotification = *notificationNameVar;
+}
+
- (id) init
{
self = [super initWithFrame : NSMakeRect(0,0, 300,300)];
@@ -192,6 +203,19 @@ static QTouchDevice *touchDevice = 0;
}
}
+- (void)viewDidMoveToWindow
+{
+ if (self.window) {
+ // This is the case of QWidgetAction's generated QWidget inserted in an NSMenu.
+ // 10.9 and newer get the NSWindowDidChangeOcclusionStateNotification
+ if (!_q_NSWindowDidChangeOcclusionStateNotification
+ && [self.window.className isEqualToString:@"NSCarbonMenuWindow"])
+ m_platformWindow->exposeWindow();
+ } else {
+ m_platformWindow->obscureWindow();
+ }
+}
+
- (void)viewWillMoveToWindow:(NSWindow *)newWindow
{
// ### Merge "normal" window code path with this one for 5.1.
@@ -325,6 +349,23 @@ static QTouchDevice *touchDevice = 0;
m_platformWindow->obscureWindow();
} else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) {
m_platformWindow->exposeWindow();
+ } else if (_q_NSWindowDidChangeOcclusionStateNotification
+ && [notificationName isEqualToString:_q_NSWindowDidChangeOcclusionStateNotification]) {
+#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+// ### HACK Remove the enum declaration, the warning disabling and the cast further down once 10.8 is unsupported
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wobjc-method-access"
+ enum { NSWindowOcclusionStateVisible = 1UL << 1 };
+#endif
+ // Older versions managed in -[QNSView viewDidMoveToWindow].
+ // Support QWidgetAction in NSMenu. Mavericks only sends this notification.
+ // Ideally we should support this in Qt as well, in order to disable animations
+ // when the window is occluded.
+ if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible)
+ m_platformWindow->exposeWindow();
+#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+#pragma clang diagnostic pop
+#endif
} else if (notificationName == NSWindowDidChangeScreenNotification) {
if (m_window) {
NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen];
@@ -637,10 +678,14 @@ static QTouchDevice *touchDevice = 0;
return [super mouseDown:theEvent];
m_sendUpAsRightButton = false;
if (m_platformWindow->m_activePopupWindow) {
+ Qt::WindowType type = m_platformWindow->m_activePopupWindow->type();
QWindowSystemInterface::handleCloseEvent(m_platformWindow->m_activePopupWindow);
QWindowSystemInterface::flushWindowSystemEvents();
m_platformWindow->m_activePopupWindow = 0;
- return;
+ // Consume the mouse event when closing the popup, except for tool tips
+ // were it's expected that the event is processed normally.
+ if (type != Qt::ToolTip)
+ return;
}
if ([self hasMarkedText]) {
NSInputManager* inputManager = [NSInputManager currentInputManager];
diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro
index 4f986b57d7..439d31fb56 100644
--- a/src/plugins/platforms/direct2d/direct2d.pro
+++ b/src/plugins/platforms/direct2d/direct2d.pro
@@ -2,6 +2,7 @@ TARGET = qdirect2d
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QWindowsDirect2DIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT *= core-private
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
index 079ad6f127..e4ce81bd24 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
@@ -75,6 +75,16 @@ QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore()
{
}
+void QWindowsDirect2DBackingStore::beginPaint(const QRegion &)
+{
+ platformPixmap(m_pixmap.data())->bitmap()->deviceContext()->begin();
+}
+
+void QWindowsDirect2DBackingStore::endPaint()
+{
+ platformPixmap(m_pixmap.data())->bitmap()->deviceContext()->end();
+}
+
QPaintDevice *QWindowsDirect2DBackingStore::paintDevice()
{
return m_pixmap.data();
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
index 9776d234e8..fc6802aaa2 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
@@ -58,6 +58,9 @@ public:
QWindowsDirect2DBackingStore(QWindow *window);
~QWindowsDirect2DBackingStore();
+ void beginPaint(const QRegion &);
+ void endPaint();
+
QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
void flush(QWindow *window, const QRegion &region, const QPoint &offset) Q_DECL_OVERRIDE;
void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
index 98248515e6..3be05ee1e0 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
@@ -84,8 +84,6 @@ Q_DECL_CONSTEXPR inline D2D1::ColorF to_d2d_color_f(const QColor &c)
Q_DECL_CONSTEXPR inline D2D1_MATRIX_3X2_F to_d2d_matrix_3x2_f(const QTransform &transform)
{
- Q_ASSERT(transform.isAffine());
-
return D2D1::Matrix3x2F(transform.m11(), transform.m12(),
transform.m21(), transform.m22(),
transform.m31(), transform.m32());
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
index d8f34fc3ed..58c30b6eeb 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -52,6 +52,7 @@
#include "qwindowsfontdatabase.h"
#include "qwindowsintegration.h"
+#include <QtCore/QStack>
#include <QtGui/private/qpaintengine_p.h>
#include <QtGui/private/qtextengine_p.h>
#include <QtGui/private/qfontengine_p.h>
@@ -71,8 +72,15 @@ QT_BEGIN_NAMESPACE
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd370979(v=vs.85).aspx
enum {
D2DDebugDrawInitialStateTag = -1,
- D2DDebugDrawImageTag = 1,
- D2DDebugFillTag,
+ D2DDebugFillTag = 1,
+ D2DDebugFillRectTag,
+ D2DDebugDrawRectsTag,
+ D2DDebugDrawRectFsTag,
+ D2DDebugDrawLinesTag,
+ D2DDebugDrawLineFsTag,
+ D2DDebugDrawEllipseTag,
+ D2DDebugDrawEllipseFTag,
+ D2DDebugDrawImageTag,
D2DDebugDrawPixmapTag,
D2DDebugDrawStaticTextItemTag,
D2DDebugDrawTextItemTag
@@ -80,9 +88,19 @@ enum {
//Clipping flags
enum {
- UserClip = 0x1,
- SimpleSystemClip = 0x2
+ SimpleSystemClip = 0x1
};
+
+enum ClipType {
+ AxisAlignedClip,
+ LayerClip
+};
+
+// Since d2d is a float-based system we need to be able to snap our drawing to whole pixels.
+// Applying the magical aliasing offset to coordinates will do so, just make sure that
+// aliased painting is turned on on the d2d device context.
+static const qreal MAGICAL_ALIASING_OFFSET = 0.5;
+
#define D2D_TAG(tag) d->dc()->SetTags(tag, tag)
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert);
@@ -92,51 +110,127 @@ static inline ID2D1Factory1 *factory()
return QWindowsDirect2DContext::instance()->d2dFactory();
}
-// XXX reduce code duplication between painterPathToPathGeometry and
-// vectorPathToID2D1PathGeometry, the two are quite similar
-
-static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &path)
+class Direct2DPathGeometryWriter
{
- ComPtr<ID2D1PathGeometry1> geometry;
- ComPtr<ID2D1GeometrySink> sink;
+public:
+ Direct2DPathGeometryWriter()
+ : m_inFigure(false)
+ , m_roundCoordinates(false)
+ {
- HRESULT hr = factory()->CreatePathGeometry(&geometry);
- if (FAILED(hr)) {
- qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr);
- return NULL;
}
- hr = geometry->Open(&sink);
- if (FAILED(hr)) {
- qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr);
- return NULL;
+ bool begin()
+ {
+ HRESULT hr = factory()->CreatePathGeometry(&m_geometry);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr);
+ return false;
+ }
+
+ hr = m_geometry->Open(&m_sink);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr);
+ return false;
+ }
+
+ return true;
}
- switch (path.fillRule()) {
- case Qt::WindingFill:
- sink->SetFillMode(D2D1_FILL_MODE_WINDING);
- break;
- case Qt::OddEvenFill:
- sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
- break;
+ void setWindingFillEnabled(bool enable)
+ {
+ if (enable)
+ m_sink->SetFillMode(D2D1_FILL_MODE_WINDING);
+ else
+ m_sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
+ }
+
+ void setAliasingEnabled(bool enable)
+ {
+ m_roundCoordinates = enable;
+ }
+
+ bool isInFigure() const
+ {
+ return m_inFigure;
}
- bool inFigure = false;
+ void moveTo(const QPointF &point)
+ {
+ if (m_inFigure)
+ m_sink->EndFigure(D2D1_FIGURE_END_OPEN);
+
+ m_sink->BeginFigure(adjusted(point), D2D1_FIGURE_BEGIN_FILLED);
+ m_inFigure = true;
+ }
+
+ void lineTo(const QPointF &point)
+ {
+ m_sink->AddLine(adjusted(point));
+ }
+
+ void curveTo(const QPointF &p1, const QPointF &p2, const QPointF &p3)
+ {
+ D2D1_BEZIER_SEGMENT segment = {
+ adjusted(p1),
+ adjusted(p2),
+ adjusted(p3)
+ };
+
+ m_sink->AddBezier(segment);
+ }
+
+ void close()
+ {
+ if (m_inFigure)
+ m_sink->EndFigure(D2D1_FIGURE_END_OPEN);
+
+ m_sink->Close();
+ }
+
+ ComPtr<ID2D1PathGeometry1> geometry() const
+ {
+ return m_geometry;
+ }
+
+private:
+ D2D1_POINT_2F adjusted(const QPointF &point)
+ {
+ static const QPointF adjustment(MAGICAL_ALIASING_OFFSET,
+ MAGICAL_ALIASING_OFFSET);
+
+ if (m_roundCoordinates)
+ return to_d2d_point_2f(point + adjustment);
+ else
+ return to_d2d_point_2f(point);
+ }
+
+ ComPtr<ID2D1PathGeometry1> m_geometry;
+ ComPtr<ID2D1GeometrySink> m_sink;
+
+ bool m_inFigure;
+ bool m_roundCoordinates;
+};
+
+static ComPtr<ID2D1PathGeometry1> painterPathToID2D1PathGeometry(const QPainterPath &path, bool alias)
+{
+ Direct2DPathGeometryWriter writer;
+ if (!writer.begin())
+ return NULL;
+
+ writer.setWindingFillEnabled(path.fillRule() == Qt::WindingFill);
+ writer.setAliasingEnabled(alias);
for (int i = 0; i < path.elementCount(); i++) {
const QPainterPath::Element element = path.elementAt(i);
switch (element.type) {
case QPainterPath::MoveToElement:
- if (inFigure)
- sink->EndFigure(D2D1_FIGURE_END_OPEN);
-
- sink->BeginFigure(to_d2d_point_2f(element), D2D1_FIGURE_BEGIN_FILLED);
- inFigure = true;
+ writer.moveTo(element);
break;
case QPainterPath::LineToElement:
- sink->AddLine(to_d2d_point_2f(element));
+ writer.lineTo(element);
break;
case QPainterPath::CurveToElement:
@@ -149,13 +243,7 @@ static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &
Q_ASSERT(data1.type == QPainterPath::CurveToDataElement);
Q_ASSERT(data2.type == QPainterPath::CurveToDataElement);
- D2D1_BEZIER_SEGMENT segment;
-
- segment.point1 = to_d2d_point_2f(element);
- segment.point2 = to_d2d_point_2f(data1);
- segment.point3 = to_d2d_point_2f(data2);
-
- sink->AddBezier(segment);
+ writer.curveTo(element, data1, data2);
}
break;
@@ -165,55 +253,22 @@ static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &
}
}
- if (inFigure)
- sink->EndFigure(D2D1_FIGURE_END_OPEN);
-
- sink->Close();
-
- return geometry;
+ writer.close();
+ return writer.geometry();
}
static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPath &path, bool alias)
{
- ComPtr<ID2D1PathGeometry1> pathGeometry;
- HRESULT hr = factory()->CreatePathGeometry(pathGeometry.GetAddressOf());
- if (FAILED(hr)) {
- qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr);
- return NULL;
- }
-
- if (path.isEmpty())
- return pathGeometry;
-
- ComPtr<ID2D1GeometrySink> sink;
- hr = pathGeometry->Open(sink.GetAddressOf());
- if (FAILED(hr)) {
- qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr);
+ Direct2DPathGeometryWriter writer;
+ if (!writer.begin())
return NULL;
- }
-
- sink->SetFillMode(path.hasWindingFill() ? D2D1_FILL_MODE_WINDING
- : D2D1_FILL_MODE_ALTERNATE);
- bool inFigure = false;
+ writer.setWindingFillEnabled(path.hasWindingFill());
+ writer.setAliasingEnabled(alias);
const QPainterPath::ElementType *types = path.elements();
const int count = path.elementCount();
- const qreal *points = 0;
-
- QScopedArrayPointer<qreal> rounded_points;
-
- if (alias) {
- // Aliased painting, round to whole numbers
- rounded_points.reset(new qreal[count * 2]);
- points = rounded_points.data();
-
- for (int i = 0; i < (count * 2); i++)
- rounded_points[i] = qRound(path.points()[i]);
- } else {
- // Antialiased painting, keep original numbers
- points = path.points();
- }
+ const qreal *points = path.points();
Q_ASSERT(points);
@@ -226,15 +281,11 @@ static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPat
switch (types[i]) {
case QPainterPath::MoveToElement:
- if (inFigure)
- sink->EndFigure(D2D1_FIGURE_END_OPEN);
-
- sink->BeginFigure(D2D1::Point2F(x, y), D2D1_FIGURE_BEGIN_FILLED);
- inFigure = true;
+ writer.moveTo(QPointF(x, y));
break;
case QPainterPath::LineToElement:
- sink->AddLine(D2D1::Point2F(x, y));
+ writer.lineTo(QPointF(x, y));
break;
case QPainterPath::CurveToElement:
@@ -251,13 +302,7 @@ static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPat
const qreal x3 = points[i * 2];
const qreal y3 = points[i * 2 + 1];
- D2D1_BEZIER_SEGMENT segment = {
- D2D1::Point2F(x, y),
- D2D1::Point2F(x2, y2),
- D2D1::Point2F(x3, y3)
- };
-
- sink->AddBezier(segment);
+ writer.curveTo(QPointF(x, y), QPointF(x2, y2), QPointF(x3, y3));
}
break;
@@ -267,23 +312,17 @@ static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPat
}
}
} else {
- sink->BeginFigure(D2D1::Point2F(points[0], points[1]), D2D1_FIGURE_BEGIN_FILLED);
- inFigure = true;
-
+ writer.moveTo(QPointF(points[0], points[1]));
for (int i = 1; i < count; i++)
- sink->AddLine(D2D1::Point2F(points[i * 2], points[i * 2 + 1]));
+ writer.lineTo(QPointF(points[i * 2], points[i * 2 + 1]));
}
- if (inFigure) {
+ if (writer.isInFigure())
if (path.hasImplicitClose())
- sink->AddLine(D2D1::Point2F(points[0], points[1]));
+ writer.lineTo(QPointF(points[0], points[1]));
- sink->EndFigure(D2D1_FIGURE_END_OPEN);
- }
-
- sink->Close();
-
- return pathGeometry;
+ writer.close();
+ return writer.geometry();
}
class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate
@@ -302,8 +341,8 @@ public:
QWindowsDirect2DBitmap *bitmap;
- QPainterPath clipPath;
unsigned int clipFlags;
+ QStack<ClipType> pushedClips;
QPointF currentBrushOrigin;
@@ -354,81 +393,97 @@ public:
: D2D1_ANTIALIAS_MODE_ALIASED;
}
- void updateTransform()
+ void updateTransform(const QTransform &transform)
{
- Q_Q(const QWindowsDirect2DPaintEngine);
- // Note the loss of info going from 3x3 to 3x2 matrix here
- dc()->SetTransform(to_d2d_matrix_3x2_f(q->state()->transform()));
+ dc()->SetTransform(to_d2d_matrix_3x2_f(transform));
}
- void updateOpacity()
+ void updateOpacity(qreal opacity)
{
- Q_Q(const QWindowsDirect2DPaintEngine);
- qreal opacity = q->state()->opacity;
if (brush.brush)
brush.brush->SetOpacity(opacity);
if (pen.brush)
pen.brush->SetOpacity(opacity);
}
- void pushClip()
+ void pushClip(const QVectorPath &path)
{
- popClip();
+ Q_Q(QWindowsDirect2DPaintEngine);
+
+ if (path.isEmpty()) {
+ D2D_RECT_F rect = {0, 0, 0, 0};
+ dc()->PushAxisAlignedClip(rect, antialiasMode());
+ pushedClips.push(AxisAlignedClip);
+ } else if (path.isRect() && (q->state()->matrix.type() <= QTransform::TxScale)) {
+ const qreal * const points = path.points();
+ D2D_RECT_F rect = {
+ points[0], // left
+ points[1], // top
+ points[2], // right,
+ points[5] // bottom
+ };
- ComPtr<ID2D1PathGeometry1> geometry = painterPathToPathGeometry(clipPath);
- if (!geometry)
- return;
+ dc()->PushAxisAlignedClip(rect, antialiasMode());
+ pushedClips.push(AxisAlignedClip);
+ } else {
+ ComPtr<ID2D1PathGeometry1> geometry = vectorPathToID2D1PathGeometry(path, antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED);
+ if (!geometry) {
+ qWarning("%s: Could not convert vector path to painter path!", __FUNCTION__);
+ return;
+ }
- dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(),
- geometry.Get(),
- antialiasMode(),
- D2D1::IdentityMatrix(),
- 1.0,
- NULL,
- D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND),
- NULL);
- clipFlags |= UserClip;
+ dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(),
+ geometry.Get(),
+ antialiasMode(),
+ D2D1::IdentityMatrix(),
+ 1.0,
+ NULL,
+ D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND),
+ NULL);
+ pushedClips.push(LayerClip);
+ }
}
- void popClip()
+ void clearClips()
{
- if (clipFlags & UserClip) {
- dc()->PopLayer();
- clipFlags &= ~UserClip;
+ while (!pushedClips.isEmpty()) {
+ switch (pushedClips.pop()) {
+ case AxisAlignedClip:
+ dc()->PopAxisAlignedClip();
+ break;
+ case LayerClip:
+ dc()->PopLayer();
+ break;
+ }
}
}
- void updateClipEnabled()
+ void updateClipEnabled(bool enabled)
{
- Q_Q(const QWindowsDirect2DPaintEngine);
- if (!q->state()->clipEnabled)
- popClip();
- else if (!(clipFlags & UserClip))
- pushClip();
+ if (!enabled)
+ clearClips();
+ else if (pushedClips.isEmpty())
+ replayClipOperations();
}
- void updateClipPath(const QPainterPath &path, Qt::ClipOperation operation)
+ void clip(const QVectorPath &path, Qt::ClipOperation operation)
{
switch (operation) {
case Qt::NoClip:
- popClip();
+ clearClips();
break;
case Qt::ReplaceClip:
- clipPath = path;
- pushClip();
+ clearClips();
+ pushClip(path);
break;
case Qt::IntersectClip:
- clipPath &= path;
- pushClip();
+ pushClip(path);
break;
}
}
- void updateCompositionMode()
+ void updateCompositionMode(QPainter::CompositionMode mode)
{
- Q_Q(const QWindowsDirect2DPaintEngine);
- QPainter::CompositionMode mode = q->state()->compositionMode();
-
switch (mode) {
case QPainter::CompositionMode_Source:
dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
@@ -447,7 +502,7 @@ public:
{
Q_Q(const QWindowsDirect2DPaintEngine);
- if (qbrush_fast_equals(brush.qbrush, newBrush))
+ if (qbrush_fast_equals(brush.qbrush, newBrush) && (brush.brush || brush.emulate))
return;
brush.brush = to_d2d_brush(newBrush, &brush.emulate);
@@ -459,12 +514,10 @@ public:
}
}
- void updateBrushOrigin()
+ void updateBrushOrigin(const QPointF &brushOrigin)
{
- Q_Q(const QWindowsDirect2DPaintEngine);
-
negateCurrentBrushOrigin();
- applyBrushOrigin(q->state()->brushOrigin);
+ applyBrushOrigin(brushOrigin);
}
void negateCurrentBrushOrigin()
@@ -492,12 +545,10 @@ public:
currentBrushOrigin = origin;
}
- void updatePen()
+ void updatePen(const QPen &newPen)
{
Q_Q(const QWindowsDirect2DPaintEngine);
- const QPen &newPen = q->state()->pen;
-
- if (qpen_fast_equals(newPen, pen.qpen))
+ if (qpen_fast_equals(newPen, pen.qpen) && (pen.brush || pen.emulate))
return;
pen.reset();
@@ -658,7 +709,91 @@ public:
break;
case Qt::LinearGradientPattern:
+ if (newBrush.gradient()->spread() != QGradient::PadSpread) {
+ *needsEmulation = true;
+ } else {
+ ComPtr<ID2D1LinearGradientBrush> linear;
+ const QLinearGradient *qlinear = static_cast<const QLinearGradient *>(newBrush.gradient());
+
+ D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES linearGradientBrushProperties;
+ ComPtr<ID2D1GradientStopCollection> gradientStopCollection;
+
+ const QGradientStops &qstops = qlinear->stops();
+ QVector<D2D1_GRADIENT_STOP> stops(qstops.count());
+
+ linearGradientBrushProperties.startPoint = to_d2d_point_2f(qlinear->start());
+ linearGradientBrushProperties.endPoint = to_d2d_point_2f(qlinear->finalStop());
+
+ for (int i = 0; i < stops.size(); i++) {
+ stops[i].position = qstops[i].first;
+ stops[i].color = to_d2d_color_f(qstops[i].second);
+ }
+
+ hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not create gradient stop collection for linear gradient: %#x", __FUNCTION__, hr);
+ break;
+ }
+
+ hr = dc()->CreateLinearGradientBrush(linearGradientBrushProperties, gradientStopCollection.Get(),
+ &linear);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not create Direct2D linear gradient brush: %#x", __FUNCTION__, hr);
+ break;
+ }
+
+ hr = linear.As(&result);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not convert Direct2D linear gradient brush: %#x", __FUNCTION__, hr);
+ break;
+ }
+ }
+ break;
+
case Qt::RadialGradientPattern:
+ if (newBrush.gradient()->spread() != QGradient::PadSpread) {
+ *needsEmulation = true;
+ } else {
+ ComPtr<ID2D1RadialGradientBrush> radial;
+ const QRadialGradient *qradial = static_cast<const QRadialGradient *>(newBrush.gradient());
+
+ D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES radialGradientBrushProperties;
+ ComPtr<ID2D1GradientStopCollection> gradientStopCollection;
+
+ const QGradientStops &qstops = qradial->stops();
+ QVector<D2D1_GRADIENT_STOP> stops(qstops.count());
+
+ radialGradientBrushProperties.center = to_d2d_point_2f(qradial->center());
+ radialGradientBrushProperties.gradientOriginOffset = to_d2d_point_2f(qradial->focalPoint() - qradial->center());
+ radialGradientBrushProperties.radiusX = qradial->radius();
+ radialGradientBrushProperties.radiusY = qradial->radius();
+
+ for (int i = 0; i < stops.size(); i++) {
+ stops[i].position = qstops[i].first;
+ stops[i].color = to_d2d_color_f(qstops[i].second);
+ }
+
+ hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not create gradient stop collection for radial gradient: %#x", __FUNCTION__, hr);
+ break;
+ }
+
+ hr = dc()->CreateRadialGradientBrush(radialGradientBrushProperties, gradientStopCollection.Get(),
+ &radial);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not create Direct2D radial gradient brush: %#x", __FUNCTION__, hr);
+ break;
+ }
+
+ radial.As(&result);
+ if (FAILED(hr)) {
+ qWarning("%s: Could not convert Direct2D radial gradient brush: %#x", __FUNCTION__, hr);
+ break;
+ }
+ }
+ break;
+
case Qt::ConicalGradientPattern:
*needsEmulation = true;
break;
@@ -706,16 +841,9 @@ QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap
: QPaintEngineEx(*(new QWindowsDirect2DPaintEnginePrivate(bitmap)))
{
QPaintEngine::PaintEngineFeatures unsupported =
- // As of 1.1 Direct2D gradient support is deficient for linear and radial gradients
- QPaintEngine::LinearGradientFill
- | QPaintEngine::RadialGradientFill
-
- // As of 1.1 Direct2D does not support conical gradients at all
- | QPaintEngine::ConicalGradientFill
-
// As of 1.1 Direct2D does not natively support complex composition modes
// However, using Direct2D effects that implement them should be possible
- | QPaintEngine::PorterDuff
+ QPaintEngine::PorterDuff
| QPaintEngine::BlendModes
| QPaintEngine::RasterOpModes
@@ -739,7 +867,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev)
QPainterPath p;
p.addRegion(systemClip());
- ComPtr<ID2D1PathGeometry1> geometry = painterPathToPathGeometry(p);
+ ComPtr<ID2D1PathGeometry1> geometry = painterPathToID2D1PathGeometry(p, d->antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED);
if (!geometry)
return false;
@@ -761,6 +889,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev)
D2D_TAG(D2DDebugDrawInitialStateTag);
+ setActive(true);
return true;
}
@@ -768,7 +897,7 @@ bool QWindowsDirect2DPaintEngine::end()
{
Q_D(QWindowsDirect2DPaintEngine);
// First pop any user-applied clipping
- d->popClip();
+ d->clearClips();
// Now the system clip from begin() above
if (d->clipFlags & SimpleSystemClip) {
d->dc()->PopAxisAlignedClip();
@@ -784,6 +913,23 @@ QPaintEngine::Type QWindowsDirect2DPaintEngine::type() const
return QPaintEngine::Direct2D;
}
+void QWindowsDirect2DPaintEngine::setState(QPainterState *s)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+
+ QPaintEngineEx::setState(s);
+ d->clearClips();
+
+ clipEnabledChanged();
+ penChanged();
+ brushChanged();
+ brushOriginChanged();
+ opacityChanged();
+ compositionModeChanged();
+ renderHintsChanged();
+ transformChanged();
+}
+
void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QWindowsDirect2DPaintEngine);
@@ -792,28 +938,10 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br
if (path.isEmpty())
return;
- d->updateBrush(brush);
-
- if (d->brush.emulate) {
- // We mostly (only?) get here when gradients are required.
- // We could probably natively support linear and radial gradients that have pad reflect
-
- QImage img(d->bitmap->size(), QImage::Format_ARGB32);
- img.fill(Qt::transparent);
-
- QPainter p;
- QPaintEngine *engine = img.paintEngine();
- if (engine->isExtended() && p.begin(&img)) {
- QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine);
- extended->fill(path, brush);
- if (!p.end())
- qWarning("%s: Paint Engine end returned false", __FUNCTION__);
-
- drawImage(img.rect(), img, img.rect());
- } else {
- qWarning("%s: Could not fall back to QImage", __FUNCTION__);
- }
+ ensureBrush(brush);
+ if (emulationRequired(BrushEmulation)) {
+ rasterFill(path, brush);
return;
}
@@ -829,46 +957,22 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br
d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get());
}
-// For clipping we convert everything to painter paths since it allows
-// calculating intersections easily. It might be faster to convert to
-// ID2D1Geometry and use its operations, although that needs to measured.
-// The implementation would be more complex in any case.
-
void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
{
- clip(path.convertToPainterPath(), op);
-}
-
-void QWindowsDirect2DPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
-{
- QPainterPath p;
- p.addRect(rect);
- clip(p, op);
-}
-
-void QWindowsDirect2DPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
-{
- QPainterPath p;
- p.addRegion(region);
- clip(p, op);
-}
-
-void QWindowsDirect2DPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
-{
Q_D(QWindowsDirect2DPaintEngine);
- d->updateClipPath(path, op);
+ d->clip(path, op);
}
void QWindowsDirect2DPaintEngine::clipEnabledChanged()
{
Q_D(QWindowsDirect2DPaintEngine);
- d->updateClipEnabled();
+ d->updateClipEnabled(state()->clipEnabled);
}
void QWindowsDirect2DPaintEngine::penChanged()
{
Q_D(QWindowsDirect2DPaintEngine);
- d->updatePen();
+ d->updatePen(state()->pen);
}
void QWindowsDirect2DPaintEngine::brushChanged()
@@ -880,19 +984,19 @@ void QWindowsDirect2DPaintEngine::brushChanged()
void QWindowsDirect2DPaintEngine::brushOriginChanged()
{
Q_D(QWindowsDirect2DPaintEngine);
- d->updateBrushOrigin();
+ d->updateBrushOrigin(state()->brushOrigin);
}
void QWindowsDirect2DPaintEngine::opacityChanged()
{
Q_D(QWindowsDirect2DPaintEngine);
- d->updateOpacity();
+ d->updateOpacity(state()->opacity);
}
void QWindowsDirect2DPaintEngine::compositionModeChanged()
{
Q_D(QWindowsDirect2DPaintEngine);
- d->updateCompositionMode();
+ d->updateCompositionMode(state()->compositionMode());
}
void QWindowsDirect2DPaintEngine::renderHintsChanged()
@@ -904,7 +1008,199 @@ void QWindowsDirect2DPaintEngine::renderHintsChanged()
void QWindowsDirect2DPaintEngine::transformChanged()
{
Q_D(QWindowsDirect2DPaintEngine);
- d->updateTransform();
+ d->updateTransform(state()->transform());
+}
+
+void QWindowsDirect2DPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ D2D_TAG(D2DDebugFillRectTag);
+
+ ensureBrush(brush);
+
+ if (emulationRequired(BrushEmulation)) {
+ QPaintEngineEx::fillRect(rect, brush);
+ } else {
+ QRectF r = rect.normalized();
+ adjustForAliasing(&r);
+
+ if (d->brush.brush)
+ d->dc()->FillRectangle(to_d2d_rect_f(rect), d->brush.brush.Get());
+ }
+}
+
+void QWindowsDirect2DPaintEngine::drawRects(const QRect *rects, int rectCount)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ D2D_TAG(D2DDebugDrawRectsTag);
+
+ ensureBrush();
+ ensurePen();
+
+ if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) {
+ QPaintEngineEx::drawRects(rects, rectCount);
+ } else {
+ QRectF rect;
+ for (int i = 0; i < rectCount; i++) {
+ rect = rects[i].normalized();
+ adjustForAliasing(&rect);
+
+ D2D1_RECT_F d2d_rect = to_d2d_rect_f(rect);
+
+ if (d->brush.brush)
+ d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get());
+
+ if (d->pen.brush)
+ d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ }
+ }
+}
+
+void QWindowsDirect2DPaintEngine::drawRects(const QRectF *rects, int rectCount)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ D2D_TAG(D2DDebugDrawRectFsTag);
+
+ ensureBrush();
+ ensurePen();
+
+ if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) {
+ QPaintEngineEx::drawRects(rects, rectCount);
+ } else {
+ QRectF rect;
+ for (int i = 0; i < rectCount; i++) {
+ rect = rects[i].normalized();
+ adjustForAliasing(&rect);
+
+ D2D1_RECT_F d2d_rect = to_d2d_rect_f(rect);
+
+ if (d->brush.brush)
+ d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get());
+
+ if (d->pen.brush)
+ d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ }
+ }
+}
+
+void QWindowsDirect2DPaintEngine::drawLines(const QLine *lines, int lineCount)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ D2D_TAG(D2DDebugDrawLinesTag);
+
+ ensurePen();
+
+ if (emulationRequired(PenEmulation)) {
+ QPaintEngineEx::drawLines(lines, lineCount);
+ } else if (d->pen.brush) {
+ for (int i = 0; i < lineCount; i++) {
+ QPointF p1 = lines[i].p1();
+ QPointF p2 = lines[i].p2();
+
+ // Match raster engine output
+ if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) {
+ fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())),
+ d->pen.qpen.brush());
+ continue;
+ }
+
+ adjustForAliasing(&p1);
+ adjustForAliasing(&p2);
+
+ D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1);
+ D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2);
+
+ d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ }
+ }
+}
+
+void QWindowsDirect2DPaintEngine::drawLines(const QLineF *lines, int lineCount)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ D2D_TAG(D2DDebugDrawLineFsTag);
+
+ ensurePen();
+
+ if (emulationRequired(PenEmulation)) {
+ QPaintEngineEx::drawLines(lines, lineCount);
+ } else if (d->pen.brush) {
+ for (int i = 0; i < lineCount; i++) {
+ QPointF p1 = lines[i].p1();
+ QPointF p2 = lines[i].p2();
+
+ // Match raster engine output
+ if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) {
+ fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())),
+ d->pen.qpen.brush());
+ continue;
+ }
+
+ adjustForAliasing(&p1);
+ adjustForAliasing(&p2);
+
+ D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1);
+ D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2);
+
+ d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ }
+ }
+}
+
+void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ D2D_TAG(D2DDebugDrawEllipseFTag);
+
+ ensureBrush();
+ ensurePen();
+
+ if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) {
+ QPaintEngineEx::drawEllipse(r);
+ } else {
+ QPointF p = r.center();
+ adjustForAliasing(&p);
+
+ D2D1_ELLIPSE ellipse = {
+ to_d2d_point_2f(p),
+ r.width() / 2.0,
+ r.height() / 2.0
+ };
+
+ if (d->brush.brush)
+ d->dc()->FillEllipse(ellipse, d->brush.brush.Get());
+
+ if (d->pen.brush)
+ d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ }
+}
+
+void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &r)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ D2D_TAG(D2DDebugDrawEllipseTag);
+
+ ensureBrush();
+ ensurePen();
+
+ if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) {
+ QPaintEngineEx::drawEllipse(r);
+ } else {
+ QPointF p = r.center();
+ adjustForAliasing(&p);
+
+ D2D1_ELLIPSE ellipse = {
+ to_d2d_point_2f(p),
+ r.width() / 2.0,
+ r.height() / 2.0
+ };
+
+ if (d->brush.brush)
+ d->dc()->FillEllipse(ellipse, d->brush.brush.Get());
+
+ if (d->pen.brush)
+ d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ }
}
void QWindowsDirect2DPaintEngine::drawImage(const QRectF &rectangle, const QImage &image,
@@ -938,6 +1234,8 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r,
QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle());
QWindowsDirect2DBitmap *bitmap = pp->bitmap();
+ ensurePen();
+
if (bitmap->bitmap() != d->bitmap->bitmap()) {
// Good, src bitmap != dst bitmap
if (sr.isValid())
@@ -1036,12 +1334,11 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText
Q_D(QWindowsDirect2DPaintEngine);
D2D_TAG(D2DDebugDrawStaticTextItemTag);
- if (qpen_style(d->pen.qpen) == Qt::NoPen)
- return;
-
if (staticTextItem->numGlyphs == 0)
return;
+ ensurePen();
+
// If we can't support the current configuration with Direct2D, fall back to slow path
// Most common cases are perspective transform and gradient brush as pen
if ((state()->transform().isAffine() == false) || d->pen.emulate) {
@@ -1086,13 +1383,12 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem
Q_D(QWindowsDirect2DPaintEngine);
D2D_TAG(D2DDebugDrawTextItemTag);
- if (qpen_style(d->pen.qpen) == Qt::NoPen)
- return;
-
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
if (ti.glyphs.numGlyphs == 0)
return;
+ ensurePen();
+
// If we can't support the current configuration with Direct2D, fall back to slow path
// Most common cases are perspective transform and gradient brush as pen
if ((state()->transform().isAffine() == false) || d->pen.emulate) {
@@ -1194,4 +1490,132 @@ void QWindowsDirect2DPaintEngine::drawGlyphRun(const D2D1_POINT_2F &pos,
DWRITE_MEASURING_MODE_GDI_CLASSIC);
}
+void QWindowsDirect2DPaintEngine::ensureBrush()
+{
+ ensureBrush(state()->brush);
+}
+
+void QWindowsDirect2DPaintEngine::ensureBrush(const QBrush &brush)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ d->updateBrush(brush);
+}
+
+void QWindowsDirect2DPaintEngine::ensurePen()
+{
+ ensurePen(state()->pen);
+}
+
+void QWindowsDirect2DPaintEngine::ensurePen(const QPen &pen)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+ d->updatePen(pen);
+}
+
+void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBrush &brush)
+{
+ Q_D(QWindowsDirect2DPaintEngine);
+
+ QImage img(d->bitmap->size(), QImage::Format_ARGB32);
+ img.fill(Qt::transparent);
+
+ QPainter p;
+ QPaintEngine *engine = img.paintEngine();
+
+ if (engine->isExtended() && p.begin(&img)) {
+ p.setRenderHints(state()->renderHints);
+ p.setCompositionMode(state()->compositionMode());
+ p.setOpacity(state()->opacity);
+ p.setBrushOrigin(state()->brushOrigin);
+ p.setBrush(state()->brush);
+ p.setPen(state()->pen);
+
+ QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine);
+ foreach (const QPainterClipInfo &info, state()->clipInfo) {
+ extended->state()->matrix = info.matrix;
+ extended->transformChanged();
+
+ switch (info.clipType) {
+ case QPainterClipInfo::RegionClip:
+ extended->clip(info.region, info.operation);
+ break;
+ case QPainterClipInfo::PathClip:
+ extended->clip(info.path, info.operation);
+ break;
+ case QPainterClipInfo::RectClip:
+ extended->clip(info.rect, info.operation);
+ break;
+ case QPainterClipInfo::RectFClip:
+ qreal right = info.rectf.x() + info.rectf.width();
+ qreal bottom = info.rectf.y() + info.rectf.height();
+ qreal pts[] = { info.rectf.x(), info.rectf.y(),
+ right, info.rectf.y(),
+ right, bottom,
+ info.rectf.x(), bottom };
+ QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint);
+ extended->clip(vp, info.operation);
+ break;
+ }
+ }
+
+ extended->state()->matrix = state()->matrix;
+ extended->transformChanged();
+
+ extended->fill(path, brush);
+ if (!p.end())
+ qWarning("%s: Paint Engine end returned false", __FUNCTION__);
+
+ d->updateClipEnabled(false);
+ d->updateTransform(QTransform());
+ drawImage(img.rect(), img, img.rect());
+ transformChanged();
+ clipEnabledChanged();
+ } else {
+ qWarning("%s: Could not fall back to QImage", __FUNCTION__);
+ }
+}
+
+bool QWindowsDirect2DPaintEngine::emulationRequired(EmulationType type) const
+{
+ Q_D(const QWindowsDirect2DPaintEngine);
+
+ if (!state()->matrix.isAffine())
+ return true;
+
+ switch (type) {
+ case PenEmulation:
+ return d->pen.emulate;
+ break;
+ case BrushEmulation:
+ return d->brush.emulate;
+ break;
+ }
+
+ return false;
+}
+
+bool QWindowsDirect2DPaintEngine::antiAliasingEnabled() const
+{
+ return state()->renderHints & QPainter::Antialiasing;
+}
+
+void QWindowsDirect2DPaintEngine::adjustForAliasing(QRectF *rect)
+{
+ if (!antiAliasingEnabled()) {
+ rect->adjust(MAGICAL_ALIASING_OFFSET,
+ MAGICAL_ALIASING_OFFSET,
+ MAGICAL_ALIASING_OFFSET,
+ MAGICAL_ALIASING_OFFSET);
+ }
+}
+
+void QWindowsDirect2DPaintEngine::adjustForAliasing(QPointF *point)
+{
+ static const QPointF adjustment(MAGICAL_ALIASING_OFFSET,
+ MAGICAL_ALIASING_OFFSET);
+
+ if (!antiAliasingEnabled())
+ (*point) += adjustment;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
index 6c74a07e88..badd7a7688 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -65,12 +65,10 @@ public:
Type type() const Q_DECL_OVERRIDE;
- void fill(const QVectorPath &path, const QBrush &brush) Q_DECL_OVERRIDE;
+ void setState(QPainterState *s) Q_DECL_OVERRIDE;
+ void fill(const QVectorPath &path, const QBrush &brush) Q_DECL_OVERRIDE;
void clip(const QVectorPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE;
- void clip(const QRect &rect, Qt::ClipOperation op) Q_DECL_OVERRIDE;
- void clip(const QRegion &region, Qt::ClipOperation op) Q_DECL_OVERRIDE;
- void clip(const QPainterPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE;
void clipEnabledChanged() Q_DECL_OVERRIDE;
void penChanged() Q_DECL_OVERRIDE;
@@ -81,6 +79,17 @@ public:
void renderHintsChanged() Q_DECL_OVERRIDE;
void transformChanged() Q_DECL_OVERRIDE;
+ void fillRect(const QRectF &rect, const QBrush &brush) Q_DECL_OVERRIDE;
+
+ void drawRects(const QRect *rects, int rectCount) Q_DECL_OVERRIDE;
+ void drawRects(const QRectF *rects, int rectCount) Q_DECL_OVERRIDE;
+
+ void drawLines(const QLine *lines, int lineCount) Q_DECL_OVERRIDE;
+ void drawLines(const QLineF *lines, int lineCount) Q_DECL_OVERRIDE;
+
+ void drawEllipse(const QRectF &r) Q_DECL_OVERRIDE;
+ void drawEllipse(const QRect &r) Q_DECL_OVERRIDE;
+
void drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE;
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE;
@@ -91,6 +100,20 @@ private:
void drawGlyphRun(const D2D1_POINT_2F &pos, IDWriteFontFace *fontFace, const QFont &font,
int numGlyphs, const UINT16 *glyphIndices, const FLOAT *glyphAdvances,
const DWRITE_GLYPH_OFFSET *glyphOffsets, bool rtl);
+
+ void ensureBrush();
+ void ensureBrush(const QBrush &brush);
+ void ensurePen();
+ void ensurePen(const QPen &pen);
+
+ void rasterFill(const QVectorPath &path, const QBrush &brush);
+
+ enum EmulationType { PenEmulation, BrushEmulation };
+ bool emulationRequired(EmulationType type) const;
+
+ bool antiAliasingEnabled() const;
+ void adjustForAliasing(QRectF *rect);
+ void adjustForAliasing(QPointF *point);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
index bf860f982e..50d0cb81f5 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
@@ -54,6 +54,9 @@ QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWi
: QWindowsWindow(window, data)
, m_needsFullFlush(true)
{
+ if (window->type() == Qt::Desktop)
+ return; // No further handling for Qt::Desktop
+
DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
@@ -125,7 +128,7 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion
}
m_bitmap->deviceContext()->end();
- m_swapChain->Present(1, 0);
+ m_swapChain->Present(0, 0);
}
void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size)
diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro
index ec4a612b52..89d8d42cea 100644
--- a/src/plugins/platforms/directfb/directfb.pro
+++ b/src/plugins/platforms/directfb/directfb.pro
@@ -2,6 +2,7 @@ TARGET = qdirectfb
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QDirectFbIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro
index 8827f7680c..3ebe05b35e 100644
--- a/src/plugins/platforms/eglfs/eglfs.pro
+++ b/src/plugins/platforms/eglfs/eglfs.pro
@@ -2,6 +2,7 @@ TARGET = qeglfs
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QEglFSIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
SOURCES += $$PWD/main.cpp
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h
index c8c31816a0..f3fd06037e 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.h
+++ b/src/plugins/platforms/eglfs/qeglfswindow.h
@@ -91,7 +91,7 @@ private:
Created = 0x01,
HasNativeWindow = 0x02
};
- Q_DECLARE_FLAGS(Flags, Flag);
+ Q_DECLARE_FLAGS(Flags, Flag)
Flags m_flags;
};
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
index b7e074b95a..ffc4ff9b12 100644
--- a/src/plugins/platforms/ios/ios.pro
+++ b/src/plugins/platforms/ios/ios.pro
@@ -2,6 +2,7 @@ TARGET = qios
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QIOSIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 9a2c55f7f2..8be3846e06 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -229,6 +229,13 @@
[super touchesEnded:touches withEvent:event];
}
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ m_touchPressWhileKeyboardVisible = NO;
+ [self performSelectorOnMainThread:@selector(touchesEndedPostDelivery) withObject:nil waitUntilDone:NO];
+ [super touchesCancelled:touches withEvent:event];
+}
+
- (void)touchesEndedPostDelivery
{
// Do some clean-up _after_ touchEnd has been delivered to QUIView
diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/quiview_textinput.mm
index 28fb23d57b..3f6c6d1256 100644
--- a/src/plugins/platforms/ios/quiview_textinput.mm
+++ b/src/plugins/platforms/ios/quiview_textinput.mm
@@ -473,6 +473,8 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
QCoreApplication::sendEvent(focusObject, &e);
QFont qfont = qvariant_cast<QFont>(e.value(Qt::ImFont));
UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()];
+ if (!uifont)
+ return [NSDictionary dictionary];
return [NSDictionary dictionaryWithObject:uifont forKey:UITextInputTextFontKey];
}
diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro
index 1b3678f13a..baa8778153 100644
--- a/src/plugins/platforms/kms/kms.pro
+++ b/src/plugins/platforms/kms/kms.pro
@@ -2,6 +2,7 @@ TARGET = qkms
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QKmsIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro
index 9e9f9b29b7..389d45c29c 100644
--- a/src/plugins/platforms/linuxfb/linuxfb.pro
+++ b/src/plugins/platforms/linuxfb/linuxfb.pro
@@ -2,6 +2,7 @@ TARGET = qlinuxfb
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QLinuxFbIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro
index 3131b16232..3ed4d2cdde 100644
--- a/src/plugins/platforms/minimal/minimal.pro
+++ b/src/plugins/platforms/minimal/minimal.pro
@@ -2,6 +2,7 @@ TARGET = qminimal
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/minimalegl/minimalegl.pro b/src/plugins/platforms/minimalegl/minimalegl.pro
index 00c83eb1ca..e78dcb8bc5 100644
--- a/src/plugins/platforms/minimalegl/minimalegl.pro
+++ b/src/plugins/platforms/minimalegl/minimalegl.pro
@@ -2,6 +2,7 @@ TARGET = qminimalegl
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QMinimalEglIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro
index 5db5e32e65..94eeac6acc 100644
--- a/src/plugins/platforms/offscreen/offscreen.pro
+++ b/src/plugins/platforms/offscreen/offscreen.pro
@@ -2,6 +2,7 @@ TARGET = qoffscreen
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QOffscreenIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/openwfd/openwf.pro b/src/plugins/platforms/openwfd/openwf.pro
index 2dbcb282db..38bac057bd 100644
--- a/src/plugins/platforms/openwfd/openwf.pro
+++ b/src/plugins/platforms/openwfd/openwf.pro
@@ -2,6 +2,7 @@ TARGET = qopenwf
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QOpenWFDIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro
index 04c6087cd1..856b7d2abe 100644
--- a/src/plugins/platforms/qnx/qnx.pro
+++ b/src/plugins/platforms/qnx/qnx.pro
@@ -161,4 +161,5 @@ include (../../../platformsupport/fontdatabases/fontdatabases.pri)
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QQnxIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h
index e83fc445d6..83af966a00 100644
--- a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h
+++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h
@@ -88,7 +88,9 @@ Q_SIGNALS:
void dialogClosed();
private Q_SLOTS:
+#if !defined(Q_OS_BLACKBERRY_TABLET)
void emitSignals();
+#endif
private:
void setNameFilter(const QString &filter);
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
index eb9fac540f..ead6e73a87 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
@@ -64,10 +64,13 @@ QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context, bo
initWindow();
// Set window usage
+ if (window->type() == Qt::Desktop)
+ return;
+
const int val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
const int result = screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_USAGE, &val);
if (result != 0)
- qFatal("QQnxEglWindow: failed to set window alpha usage, errno=%d", errno);
+ qFatal("QQnxRasterWindow: failed to set window alpha usage, errno=%d", errno);
}
void QQnxRasterWindow::post(const QRegion &dirty)
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index 2707f14db2..9ba0f5cd2e 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -97,9 +97,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
const int envHeight = envPhySizeStrList.size() == 2 ? envPhySizeStrList[1].toInt() : -1;
if (envWidth <= 0 || envHeight <= 0) {
- qFatal("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format "
- "\"width,height\" in mm, with width, height > 0. "
- "Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90");
+ qWarning("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format "
+ "\"width,height\" in mm, with width, height > 0. Defaulting to 150x90. "
+ "Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90");
return QSize(150, 90);
}
@@ -114,8 +114,8 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
return defSize;
#else
if (primaryScreen)
- qFatal("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. "
- "Could not determine physical screen size.");
+ qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. "
+ "Could not determine physical screen size. Defaulting to 150x90.");
return QSize(150, 90);
#endif
}
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index 2e0febff20..5a405f9577 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -174,7 +174,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
// indication that we want to create a child window and join that window group.
const QVariant windowGroup = window->property("qnxInitialWindowGroup");
- if (window->type() == Qt::CoverWindow || window->type() == Qt::Desktop) {
+ if (window->type() == Qt::CoverWindow) {
// Cover windows have to be top level to be accessible to window delegate (i.e. navigator)
// Desktop windows also need to be toplevel because they are not
// supposed to be part of the window hierarchy tree
@@ -189,10 +189,13 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
m_isTopLevel = !needRootWindow || !platformScreen->rootWindow();
}
+ if (window->type() == Qt::Desktop) // A desktop widget does not need a libscreen window
+ return;
+
if (m_isTopLevel) {
Q_SCREEN_CRITICALERROR(screen_create_window(&m_window, m_screenContext),
"Could not create top level window"); // Creates an application window
- if (window->type() != Qt::CoverWindow && window->type() != Qt::Desktop) {
+ if (window->type() != Qt::CoverWindow) {
if (needRootWindow)
platformScreen->setRootWindow(this);
}
@@ -245,9 +248,9 @@ void QQnxWindow::setGeometry(const QRect &rect)
if (shouldMakeFullScreen())
newGeometry = screen()->geometry();
- setGeometryHelper(newGeometry);
+ if (window()->type() != Qt::Desktop)
+ setGeometryHelper(newGeometry);
- QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
if (isExposed())
QWindowSystemInterface::handleExposeEvent(window(), newGeometry);
}
@@ -278,13 +281,15 @@ void QQnxWindow::setGeometryHelper(const QRect &rect)
"Failed to set window source size");
screen_flush_context(m_screenContext, 0);
+
+ QWindowSystemInterface::handleGeometryChange(window(), rect);
}
void QQnxWindow::setVisible(bool visible)
{
qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible;
- if (m_visible == visible)
+ if (m_visible == visible || window()->type() == Qt::Desktop)
return;
// The first time through we join a window group if appropriate.
@@ -667,6 +672,9 @@ void QQnxWindow::setRotation(int rotation)
void QQnxWindow::initWindow()
{
+ if (window()->type() == Qt::Desktop)
+ return;
+
// Alpha channel is always pre-multiplied if present
int val = SCREEN_PRE_MULTIPLIED_ALPHA;
Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val),
@@ -711,12 +719,7 @@ void QQnxWindow::initWindow()
if (window()->parent() && window()->parent()->handle())
setParent(window()->parent()->handle());
- if (shouldMakeFullScreen())
- setGeometryHelper(screen()->geometry());
- else
- setGeometryHelper(window()->geometry());
-
- QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry());
+ setGeometryHelper(shouldMakeFullScreen() ? screen()->geometry() : window()->geometry());
}
void QQnxWindow::createWindowGroup()
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index 9a2006396f..94df903336 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -75,7 +75,7 @@ public:
bool isExposed() const;
- WId winId() const { return (WId)m_window; }
+ WId winId() const { return window()->type() == Qt::Desktop ? -1 : (WId)m_window; }
screen_window_t nativeHandle() const { return m_window; }
void setBufferSize(const QSize &size);
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 7643177395..ccff2d3e9f 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -49,11 +49,11 @@
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
#include "qwindowstabletsupport.h"
+#include <private/qguiapplication_p.h>
#ifndef QT_NO_ACCESSIBILITY
# include "accessible/qwindowsaccessibility.h"
#endif
#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
-# include <private/qguiapplication_p.h>
# include <private/qsessionmanager_p.h>
# include "qwindowssessionmanager.h"
#endif
@@ -76,6 +76,9 @@
#include <stdlib.h>
#include <stdio.h>
#include <windowsx.h>
+#ifndef Q_OS_WINCE
+# include <comdef.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -213,7 +216,7 @@ bool QWindowsUser32DLL::initTouch()
unregisterTouchWindow = (UnregisterTouchWindow)(library.resolve("UnregisterTouchWindow"));
getTouchInputInfo = (GetTouchInputInfo)(library.resolve("GetTouchInputInfo"));
closeTouchInputHandle = (CloseTouchInputHandle)(library.resolve("CloseTouchInputHandle"));
- return registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && getTouchInputInfo;
+ return registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && closeTouchInputHandle;
}
/*!
@@ -325,6 +328,10 @@ QWindowsContextPrivate::QWindowsContextPrivate()
m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
m_keyMapper.setUseRTLExtensions(true);
}
+ if (FAILED(m_oleInitializeResult)) {
+ qWarning() << "QWindowsContext: OleInitialize() failed: "
+ << QWindowsContext::comErrorString(m_oleInitializeResult);
+ }
}
QWindowsContext::QWindowsContext() :
@@ -734,45 +741,70 @@ HWND QWindowsContext::createDummyWindow(const QString &classNameIn,
QByteArray QWindowsContext::comErrorString(HRESULT hr)
{
+ QByteArray result = QByteArrayLiteral("COM error 0x")
+ + QByteArray::number(quintptr(hr), 16) + ' ';
switch (hr) {
case S_OK:
- return QByteArrayLiteral("S_OK");
+ result += QByteArrayLiteral("S_OK");
+ break;
case S_FALSE:
- return QByteArrayLiteral("S_FALSE");
+ result += QByteArrayLiteral("S_FALSE");
+ break;
case E_UNEXPECTED:
- return QByteArrayLiteral("E_UNEXPECTED");
+ result += QByteArrayLiteral("E_UNEXPECTED");
+ break;
case CO_E_ALREADYINITIALIZED:
- return QByteArrayLiteral("CO_E_ALREADYINITIALIZED");
+ result += QByteArrayLiteral("CO_E_ALREADYINITIALIZED");
+ break;
case CO_E_NOTINITIALIZED:
- return QByteArrayLiteral("CO_E_NOTINITIALIZED");
+ result += QByteArrayLiteral("CO_E_NOTINITIALIZED");
+ break;
case RPC_E_CHANGED_MODE:
- return QByteArrayLiteral("RPC_E_CHANGED_MODE");
+ result += QByteArrayLiteral("RPC_E_CHANGED_MODE");
+ break;
case OLE_E_WRONGCOMPOBJ:
- return QByteArrayLiteral("OLE_E_WRONGCOMPOBJ");
+ result += QByteArrayLiteral("OLE_E_WRONGCOMPOBJ");
+ break;
case CO_E_NOT_SUPPORTED:
- return QByteArrayLiteral("CO_E_NOT_SUPPORTED");
+ result += QByteArrayLiteral("CO_E_NOT_SUPPORTED");
+ break;
case E_NOTIMPL:
- return QByteArrayLiteral("E_NOTIMPL");
+ result += QByteArrayLiteral("E_NOTIMPL");
+ break;
case E_INVALIDARG:
- return QByteArrayLiteral("E_INVALIDARG");
+ result += QByteArrayLiteral("E_INVALIDARG");
+ break;
case E_NOINTERFACE:
- return QByteArrayLiteral("E_NOINTERFACE");
+ result += QByteArrayLiteral("E_NOINTERFACE");
+ break;
case E_POINTER:
- return QByteArrayLiteral("E_POINTER");
+ result += QByteArrayLiteral("E_POINTER");
+ break;
case E_HANDLE:
- return QByteArrayLiteral("E_HANDLE");
+ result += QByteArrayLiteral("E_HANDLE");
+ break;
case E_ABORT:
- return QByteArrayLiteral("E_ABORT");
+ result += QByteArrayLiteral("E_ABORT");
+ break;
case E_FAIL:
- return QByteArrayLiteral("E_FAIL");
+ result += QByteArrayLiteral("E_FAIL");
+ break;
case RPC_E_WRONG_THREAD:
- return QByteArrayLiteral("RPC_E_WRONG_THREAD");
+ result += QByteArrayLiteral("RPC_E_WRONG_THREAD");
+ break;
case RPC_E_THREAD_NOT_INIT:
- return QByteArrayLiteral("RPC_E_THREAD_NOT_INIT");
+ result += QByteArrayLiteral("RPC_E_THREAD_NOT_INIT");
+ break;
default:
break;
}
- return "Unknown error 0x" + QByteArray::number(quint64(hr), 16);
+#ifndef Q_OS_WINCE
+ _com_error error(hr);
+ result += QByteArrayLiteral(" (");
+ result += QString::fromWCharArray(error.ErrorMessage()).toLocal8Bit();
+ result += ')';
+#endif // !Q_OS_WINCE
+ return result;
}
/*!
@@ -1068,6 +1100,21 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
{
QWindow *nextActiveWindow = 0;
if (et == QtWindows::FocusInEvent) {
+ QWindow *topWindow = QWindowsWindow::topLevelOf(platformWindow->window());
+ QWindow *modalWindow = 0;
+ if (QGuiApplicationPrivate::instance()->isWindowBlocked(topWindow, &modalWindow) && topWindow != modalWindow) {
+ modalWindow->requestActivate();
+ return;
+ }
+ // QTBUG-32867: Invoking WinAPI SetParent() can cause focus-in for the
+ // window which is not desired for native child widgets.
+ if (platformWindow->testFlag(QWindowsWindow::WithinSetParent)) {
+ QWindow *currentFocusWindow = QGuiApplication::focusWindow();
+ if (currentFocusWindow && currentFocusWindow != platformWindow->window()) {
+ currentFocusWindow->requestActivate();
+ return;
+ }
+ }
nextActiveWindow = platformWindow->window();
} else {
// Focus out: Is the next window known and different
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
index 1432dfdcd9..940d75614c 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
@@ -1040,7 +1040,11 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script)
{
- return new QWindowsMultiFontEngine(fontEngine, script);
+ if (script == QChar::Script_Common)
+ return new QWindowsMultiFontEngine(fontEngine, script);
+ // ### as long as fallbacksForFamily() does not take script parameter into account,
+ // prefer QFontEngineMultiQPA's loadEngine() implementation for complex scripts
+ return QPlatformFontDatabase::fontEngineMulti(fontEngine, script);
}
QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
@@ -1619,8 +1623,7 @@ QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFon
result << QString::fromLatin1("Arial");
}
- if (script == QChar::Script_Common || script == QChar::Script_Han)
- result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
+ result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
<< script << result << m_families.size();
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
index 51961014d9..734f645e65 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
@@ -477,8 +477,7 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF
}
#endif
- if (script == QChar::Script_Common || script == QChar::Script_Han)
- result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
+ result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
<< script << result << m_families;
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index 4f3a007bd7..29c43fc7a5 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -1032,7 +1032,7 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph,
int iw = gm.width.toInt();
int ih = gm.height.toInt();
- if (iw <= 0 || iw <= 0)
+ if (iw <= 0 || ih <= 0)
return 0;
bool has_transformation = t.type() > QTransform::TxTranslate;
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 0be9f5c626..aed7ad9c46 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -250,7 +250,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co
return true;
case ThreadedOpenGL:
#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC)
- return QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL
+ return QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL
? QWindowsEGLContext::hasThreadedOpenGLCapability() : true;
# else
return true;
@@ -315,7 +315,7 @@ QPlatformOpenGLContext
{
qCDebug(lcQpaGl) << __FUNCTION__ << context->format();
#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC)
- if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) {
+ if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) {
if (d->m_staticEGLContext.isNull()) {
QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create();
if (!staticContext)
@@ -326,7 +326,7 @@ QPlatformOpenGLContext
}
#endif
#if !defined(QT_OPENGL_ES_2)
- if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) {
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
if (d->m_staticOpenGLContext.isNull())
d->m_staticOpenGLContext =
QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create());
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
index 7e15be1d19..06c0122bbb 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
@@ -125,7 +125,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour
return 0;
}
#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC)
- if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) {
+ if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) {
QWindowsEGLContext *windowsEglContext = static_cast<QWindowsEGLContext *>(context->handle());
if (resource == QByteArrayLiteral("eglDisplay"))
return windowsEglContext->eglDisplay();
@@ -136,7 +136,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour
}
#endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC
#if !defined(QT_OPENGL_ES_2)
- if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) {
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle());
if (resource == QByteArrayLiteral("renderingContext"))
return windowsContext->renderingContext();
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 6349c1e355..6a3930dc78 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -230,12 +230,16 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette)
result.setColor(QPalette::All, QPalette::Text, tipTextColor);
result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
+ result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor);
+ result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor);
const QColor disabled =
mixColors(result.foreground().color(), result.button().color());
result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
result.setColor(QPalette::Disabled, QPalette::Text, disabled);
+ result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled);
result.setColor(QPalette::Disabled, QPalette::Base, Qt::white);
result.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white);
+ result.setColor(QPalette::Disabled, QPalette::ToolTipBase, Qt::white);
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 00229a7540..2a221e71ca 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -886,7 +886,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
if (aWindow->surfaceType() == QWindow::OpenGLSurface) {
setFlag(OpenGLSurface);
#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC)
- if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL)
+ if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL)
setFlag(OpenGL_ES2);
#endif
}
@@ -1022,17 +1022,17 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w)
while (QWindow *parent = w->parent())
w = parent;
- const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(w->handle());
-
- // In case the topmost parent is embedded, find next ancestor using native methods
- if (ww->isEmbedded(0)) {
- HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT);
- const HWND desktopHwnd = GetDesktopWindow();
- const QWindowsContext *ctx = QWindowsContext::instance();
- while (parentHWND && parentHWND != desktopHwnd) {
- if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND))
- return topLevelOf(ancestor->window());
- parentHWND = GetAncestor(parentHWND, GA_PARENT);
+ if (const QPlatformWindow *handle = w->handle()) {
+ const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(handle);
+ if (ww->isEmbedded(0)) {
+ HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT);
+ const HWND desktopHwnd = GetDesktopWindow();
+ const QWindowsContext *ctx = QWindowsContext::instance();
+ while (parentHWND && parentHWND != desktopHwnd) {
+ if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND))
+ return topLevelOf(ancestor->window());
+ parentHWND = GetAncestor(parentHWND, GA_PARENT);
+ }
}
}
return w;
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index 188bd7917c..cc0373c077 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -2,6 +2,7 @@ TARGET = qwindows
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QWindowsIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT *= core-private
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index 2e38f81499..583441f396 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -1020,7 +1020,9 @@ HRESULT QWinRTScreen::onOrientationChanged(IInspectable *)
HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args)
{
QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier);
+ QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier);
backPress.setAccepted(false);
+ backRelease.setAccepted(false);
QObject *receiver = m_visibleWindows.isEmpty()
? static_cast<QObject *>(QGuiApplication::instance())
@@ -1028,12 +1030,8 @@ HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs
// If the event is ignored, the app will suspend
QGuiApplication::sendEvent(receiver, &backPress);
- if (backPress.isAccepted()) {
- args->put_Handled(true);
- // If the app accepts the event, send the release for symmetry
- QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier);
- QGuiApplication::sendEvent(receiver, &backRelease);
- }
+ QGuiApplication::sendEvent(receiver, &backRelease);
+ args->put_Handled(backPress.isAccepted() || backRelease.isAccepted());
return S_OK;
}
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 60c87bb61a..0122bf9475 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -12,6 +12,7 @@ winphone {
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index de907f87df..30d5c911e7 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -574,12 +574,32 @@ bool QGLXContext::m_supportsThreading = true;
// binary search.
static const char *qglx_threadedgl_blacklist_renderer[] = {
"Chromium", // QTBUG-32225 (initialization fails)
- "Mesa DRI Intel(R) Sandybridge Mobile", // QTBUG-34492 (flickering in fullscreen)
0
};
+// This disables threaded rendering on anything using mesa, e.g.
+// - nvidia/nouveau
+// - amd/gallium
+// - intel
+// - some software opengl implementations
+//
+// The client glx vendor string is used to identify those setups as that seems to show the least
+// variance between the bad configurations. It's always "Mesa Project and SGI". There are some
+// configurations which don't use mesa and which can do threaded rendering (amd and nvidia chips
+// with their own proprietary drivers).
+//
+// This, of course, is very broad and disables threaded rendering on a lot of devices which would
+// be able to use it. However, the bugs listed below don't follow any easily recognizable pattern
+// and we should rather be safe.
+//
+// http://cgit.freedesktop.org/xcb/libxcb/commit/?id=be0fe56c3bcad5124dcc6c47a2fad01acd16f71a will
+// fix some of the issues. Basically, the proprietary drivers seem to have a way of working around
+// a fundamental flaw with multithreaded access to xcb, but mesa doesn't. The blacklist should be
+// reevaluated once that patch is released in some version of xcb.
static const char *qglx_threadedgl_blacklist_vendor[] = {
- "nouveau", // QTCREATORBUG-10875 (crash in creator)
+ "Mesa Project and SGI", // QTCREATORBUG-10875 (crash in creator)
+ // QTBUG-34492 (flickering in fullscreen)
+ // QTBUG-38221
0
};
@@ -627,9 +647,9 @@ void QGLXContext::queryDummyContext()
}
}
- if (const char *vendor = (const char *) glGetString(GL_VENDOR)) {
+ if (glxvendor) {
for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) {
- if (strstr(vendor, qglx_threadedgl_blacklist_vendor[i]) != 0) {
+ if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) {
m_supportsThreading = false;
break;
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index f5f6c712c5..e3b81c2b40 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1791,6 +1791,19 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub
return true;
}
+bool QXcbConnection::xi2GetButtonState(void *event, int buttonNum)
+{
+ xXIDeviceEvent *xideviceevent = static_cast<xXIDeviceEvent *>(event);
+ unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1];
+
+ for (int i = 0; i < (xideviceevent->buttons_len * 4); i++) {
+ if (buttonNum < 8)
+ return (buttonsMaskAddr[i] & (1 << buttonNum));
+ buttonNum -= 8;
+ }
+ return false;
+}
+
// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
// - "pad0" became "extension"
// - "pad1" and "pad" became "pad0"
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index c5fe2e33d5..1719d8ec6b 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -402,6 +402,12 @@ public:
#elif defined(XCB_USE_XINPUT2)
void xi2Select(xcb_window_t window);
#endif
+#ifdef XCB_USE_XINPUT21
+ bool isUsingXInput21() { return m_xi2Enabled && m_xi2Minor >= 1; }
+#else
+ bool isUsingXInput21() { return false; }
+#endif
+
void sync();
void flush() { xcb_flush(m_connection); }
@@ -455,6 +461,10 @@ public:
QXcbSystemTrayTracker *systemTrayTracker();
+#ifdef XCB_USE_XINPUT2
+ void handleEnterEvent(const xcb_enter_notify_event_t *);
+#endif
+
private slots:
void processXcbEvents();
@@ -508,11 +518,12 @@ private:
QVector<TabletData> m_tabletData;
#endif
struct ScrollingDevice {
- ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0) { }
+ ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { }
int deviceId;
int verticalIndex, horizontalIndex;
double verticalIncrement, horizontalIncrement;
Qt::Orientations orientations;
+ Qt::Orientations legacyOrientations;
QPointF lastScrollPosition;
};
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
@@ -522,6 +533,7 @@ private:
#if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO)
static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value);
static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode);
+ static bool xi2GetButtonState(void *event, int buttonNum);
#endif
xcb_connection_t *m_connection;
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index d80b49ccbb..831ccba6f6 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -134,7 +134,6 @@ void QXcbConnection::initializeXInput2()
#ifdef XCB_USE_XINPUT21
case XIScrollClass: {
XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(devices[i].classes[c]);
- scrollingDevice.deviceId = devices[i].deviceid;
if (sci->scroll_type == XIScrollTypeVertical) {
scrollingDevice.orientations |= Qt::Vertical;
scrollingDevice.verticalIndex = sci->number;
@@ -147,6 +146,20 @@ void QXcbConnection::initializeXInput2()
}
break;
}
+ case XIButtonClass: {
+ XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]);
+ for (int i=0; i < bci->num_buttons; ++i) {
+ const int buttonAtom = qatom(bci->labels[i]);
+ if (buttonAtom == QXcbAtom::ButtonWheelUp
+ || buttonAtom == QXcbAtom::ButtonWheelDown) {
+ scrollingDevice.legacyOrientations |= Qt::Vertical;
+ } else if (buttonAtom == QXcbAtom::ButtonHorizWheelLeft
+ || buttonAtom == QXcbAtom::ButtonHorizWheelRight) {
+ scrollingDevice.legacyOrientations |= Qt::Horizontal;
+ }
+ }
+ break;
+ }
#endif
default:
break;
@@ -170,7 +183,10 @@ void QXcbConnection::initializeXInput2()
#endif // QT_NO_TABLETEVENT
#ifdef XCB_USE_XINPUT21
- if (scrollingDevice.orientations) {
+ if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
+ scrollingDevice.deviceId = devices[i].deviceid;
+ // Only use legacy wheel button events when we don't have real scroll valuators.
+ scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations;
m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
if (Q_UNLIKELY(debug_xinput_devices))
qDebug() << " it's a scrolling device";
@@ -256,6 +272,7 @@ void QXcbConnection::xi2Select(xcb_window_t window)
if (!m_scrollingDevices.isEmpty()) {
QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
bitMask = XI_MotionMask;
+ bitMask |= XI_ButtonReleaseMask;
int i=0;
Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) {
xiEventMask[i].deviceid = scrollingDevice.deviceId;
@@ -524,6 +541,35 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
}
}
+void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *)
+{
+#ifdef XCB_USE_XINPUT21
+ QHash<int, ScrollingDevice>::iterator it = m_scrollingDevices.begin();
+ const QHash<int, ScrollingDevice>::iterator end = m_scrollingDevices.end();
+ while (it != end) {
+ ScrollingDevice& scrollingDevice = it.value();
+ int nrDevices = 0;
+ XIDeviceInfo* xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), scrollingDevice.deviceId, &nrDevices);
+ if (nrDevices <= 0) {
+ it = m_scrollingDevices.erase(it);
+ continue;
+ }
+ for (int c = 0; c < xiDeviceInfo->num_classes; ++c) {
+ if (xiDeviceInfo->classes[c]->type == XIValuatorClass) {
+ XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(xiDeviceInfo->classes[c]);
+ const int valuatorAtom = qatom(vci->label);
+ if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
+ scrollingDevice.lastScrollPosition.setX(vci->value);
+ else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
+ scrollingDevice.lastScrollPosition.setY(vci->value);
+ }
+ }
+ XIFreeDeviceInfo(xiDeviceInfo);
+ ++it;
+ }
+#endif
+}
+
void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice)
{
#ifdef XCB_USE_XINPUT21
@@ -566,6 +612,31 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers);
}
}
+ } else if (xiEvent->evtype == XI_ButtonRelease) {
+ xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
+ QPoint angleDelta;
+ if (scrollingDevice.legacyOrientations & Qt::Vertical) {
+ if (xi2GetButtonState(xiDeviceEvent, 4))
+ angleDelta.setY(120);
+ else if (xi2GetButtonState(xiDeviceEvent, 5))
+ angleDelta.setY(-120);
+ }
+ if (scrollingDevice.legacyOrientations & Qt::Horizontal) {
+ if (xi2GetButtonState(xiDeviceEvent, 6))
+ angleDelta.setX(120);
+ if (xi2GetButtonState(xiDeviceEvent, 7))
+ angleDelta.setX(-120);
+ }
+ if (!angleDelta.isNull()) {
+ QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
+ QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
+ Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
+ if (modifiers & Qt::AltModifier)
+ std::swap(angleDelta.rx(), angleDelta.ry());
+ QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers);
+ }
+ }
}
#else
Q_UNUSED(event);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 5a2002f1d4..3645b6469a 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -485,7 +485,7 @@ QXcbWindow::~QXcbWindow()
void QXcbWindow::destroy()
{
if (connection()->focusWindow() == this)
- connection()->setFocusWindow(0);
+ doFocusOut();
if (m_syncCounter && m_usingSyncProtocol)
Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
@@ -554,7 +554,7 @@ QMargins QXcbWindow::frameMargins() const
xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, NULL);
if (reply) {
- if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1) {
+ if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1 || reply->parent == XCB_WINDOW_NONE) {
foundRoot = true;
} else {
window = parent;
@@ -671,6 +671,9 @@ void QXcbWindow::show()
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+ if (QGuiApplication::modalWindow() == window())
+ requestActivateWindow();
+
m_screen->windowShown(this);
connection()->sync();
@@ -694,6 +697,68 @@ void QXcbWindow::hide()
m_mapped = false;
}
+static QWindow *tlWindow(QWindow *window)
+{
+ if (window && window->parent())
+ return tlWindow(window->parent());
+ return window;
+}
+
+bool QXcbWindow::relayFocusToModalWindow() const
+{
+ QWindow *w = tlWindow(static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver());
+ QWindow *modal_window = 0;
+ if (QGuiApplicationPrivate::instance()->isWindowBlocked(w,&modal_window) && modal_window != w) {
+ modal_window->requestActivate();
+ connection()->flush();
+ return true;
+ }
+
+ return false;
+}
+
+void QXcbWindow::doFocusIn()
+{
+ if (relayFocusToModalWindow())
+ return;
+ QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
+ connection()->setFocusWindow(static_cast<QXcbWindow *>(w->handle()));
+ QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
+}
+
+static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event)
+{
+ if (!event) {
+ // FocusIn event is not in the queue, proceed with FocusOut normally.
+ QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason);
+ return true;
+ }
+ uint response_type = event->response_type & ~0x80;
+ if (response_type == XCB_FOCUS_IN)
+ return true;
+
+ /* We are also interested in XEMBED_FOCUS_IN events */
+ if (response_type == XCB_CLIENT_MESSAGE) {
+ xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
+ if (cme->type == connection->atom(QXcbAtom::_XEMBED)
+ && cme->data.data32[1] == XEMBED_FOCUS_IN)
+ return true;
+ }
+
+ return false;
+}
+
+void QXcbWindow::doFocusOut()
+{
+ if (relayFocusToModalWindow())
+ return;
+ connection()->setFocusWindow(0);
+ // Do not set the active window to 0 if there is a FocusIn coming.
+ // There is however no equivalent for XPutBackEvent so register a
+ // callback for QXcbConnection instead.
+ connection()->addPeekFunc(focusInPeeker);
+}
+
struct QtMotifWmHints {
quint32 flags, functions, decorations;
qint32 input_mode;
@@ -1514,6 +1579,8 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
QWindowSystemInterface::handleCloseEvent(window());
} else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) {
connection()->setTime(event->data.data32[1]);
+ relayFocusToModalWindow();
+ return;
} else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
if (event->window == m_screen->root())
return;
@@ -1549,8 +1616,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
} else if (event->type == atom(QXcbAtom::_XEMBED)) {
handleXEmbedMessage(event);
} else if (event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) {
- connection()->setFocusWindow(this);
- QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
+ doFocusIn();
} else if (event->type == atom(QXcbAtom::MANAGER)
|| event->type == atom(QXcbAtom::_NET_WM_STATE)
|| event->type == atom(QXcbAtom::WM_CHANGE_STATE)) {
@@ -1705,16 +1771,16 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
if (isWheel) {
-#ifndef XCB_USE_XINPUT21
- // Logic borrowed from qapplication_x11.cpp
- int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1);
- bool hor = (((event->detail == 4 || event->detail == 5)
- && (modifiers & Qt::AltModifier))
- || (event->detail == 6 || event->detail == 7));
-
- QWindowSystemInterface::handleWheelEvent(window(), event->time,
- local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers);
-#endif
+ if (!connection()->isUsingXInput21()) {
+ // Logic borrowed from qapplication_x11.cpp
+ int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1);
+ bool hor = (((event->detail == 4 || event->detail == 5)
+ && (modifiers & Qt::AltModifier))
+ || (event->detail == 6 || event->detail == 7));
+
+ QWindowSystemInterface::handleWheelEvent(window(), event->time,
+ local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers);
+ }
return;
}
@@ -1778,6 +1844,9 @@ public:
void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event)
{
connection()->setTime(event->time);
+#ifdef XCB_USE_XINPUT2
+ connection()->handleEnterEvent(event);
+#endif
if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB)
|| event->detail == XCB_NOTIFY_DETAIL_VIRTUAL
@@ -1865,41 +1934,13 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
{
- QWindow *w = window();
- w = static_cast<QWindowPrivate *>(QObjectPrivate::get(w))->eventReceiver();
- connection()->setFocusWindow(static_cast<QXcbWindow *>(w->handle()));
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
+ doFocusIn();
}
-static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event)
-{
- if (!event) {
- // FocusIn event is not in the queue, proceed with FocusOut normally.
- QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason);
- return true;
- }
- uint response_type = event->response_type & ~0x80;
- if (response_type == XCB_FOCUS_IN)
- return true;
-
- /* We are also interested in XEMBED_FOCUS_IN events */
- if (response_type == XCB_CLIENT_MESSAGE) {
- xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
- if (cme->type == connection->atom(QXcbAtom::_XEMBED)
- && cme->data.data32[1] == XEMBED_FOCUS_IN)
- return true;
- }
-
- return false;
-}
void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
{
- connection()->setFocusWindow(0);
- // Do not set the active window to 0 if there is a FocusIn coming.
- // There is however no equivalent for XPutBackEvent so register a
- // callback for QXcbConnection instead.
- connection()->addPeekFunc(focusInPeeker);
+ doFocusOut();
}
void QXcbWindow::updateSyncRequestCounter()
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index a90ad7b5ed..12d17023fb 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -176,6 +176,10 @@ private:
void show();
void hide();
+ bool relayFocusToModalWindow() const;
+ void doFocusIn();
+ void doFocusOut();
+
QXcbScreen *m_screen;
xcb_window_t m_window;
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
index 9e4e997f55..a52aaa4a2e 100644
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ b/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -2,6 +2,7 @@ TARGET = qxcb
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QXcbIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/printsupport/windows/windows.pro b/src/plugins/printsupport/windows/windows.pro
index 364e19e68e..3366262ef0 100644
--- a/src/plugins/printsupport/windows/windows.pro
+++ b/src/plugins/printsupport/windows/windows.pro
@@ -21,4 +21,4 @@ HEADERS += \
OTHER_FILES += windows.json
-LIBS += -lwinspool -lcomdlg32
+LIBS += -lwinspool -lcomdlg32 -lgdi32 -luser32