diff options
author | Sergio Ahumada <sahumada@blackberry.com> | 2014-06-11 20:11:59 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-06-11 23:06:01 +0200 |
commit | 490e79e39ee90ad89bac164891177160d1926fdf (patch) | |
tree | f6e993c617f81ccd75563e1ceeef5ee5efd1b818 /src/plugins | |
parent | a6d7e09e89a73b3706aabbf2d08586f238348c7c (diff) | |
parent | 7ffbfed7c791b1c8e514b5c9d24e8b80de3f21c2 (diff) |
Merge "Merge remote-tracking branch 'origin/stable' into 5.3" into refs/staging/5.3
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/platforms/android/androidjniaccessibility.cpp | 13 | ||||
-rw-r--r-- | src/plugins/platforms/android/androidjnimain.cpp | 17 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm | 9 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaintegration.mm | 41 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfswindow.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosinputcontext.mm | 10 | ||||
-rw-r--r-- | src/plugins/platforms/ios/quiview.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/ios/quiview_textinput.mm | 89 | ||||
-rw-r--r-- | src/plugins/platforms/windows/accessible/iaccessible2.cpp | 1 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowskeymapper.cpp | 1 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 34 |
11 files changed, 145 insertions, 73 deletions
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index d9f5cec27a..9d43c2f758 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -47,6 +47,7 @@ #include "qwindow.h" #include "qrect.h" #include "QtGui/qaccessible.h" +#include <QtCore/private/qjnihelpers_p.h> #include "qdebug.h" @@ -207,7 +208,7 @@ if (!clazz) { \ if (desc.isEmpty()) desc = iface->text(QAccessible::Description); if (QAccessibleTextInterface *textIface = iface->textInterface()) { - if (textIface->selectionCount() > 0) { + if (m_setTextSelectionMethodID && textIface->selectionCount() > 0) { int startSelection; int endSelection; textIface->selection(0, &startSelection, &endSelection); @@ -259,12 +260,15 @@ if (!clazz) { \ bool registerNatives(JNIEnv *env) { + if (QtAndroidPrivate::androidSdkVersion() < 16) + return true; // We need API level 16 or higher + jclass clazz; FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/accessibility/QtNativeAccessibility"); jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz)); if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { - __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed"); + __android_log_print(ANDROID_LOG_FATAL,"Qt A11y", "RegisterNatives failed"); return false; } @@ -277,9 +281,12 @@ if (!clazz) { \ GET_AND_CHECK_STATIC_METHOD(m_setEnabledMethodID, nodeInfoClass, "setEnabled", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setFocusableMethodID, nodeInfoClass, "setFocusable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setFocusedMethodID, nodeInfoClass, "setFocused", "(Z)V"); - GET_AND_CHECK_STATIC_METHOD(m_setTextSelectionMethodID, nodeInfoClass, "setTextSelection", "(II)V"); GET_AND_CHECK_STATIC_METHOD(m_setVisibleToUserMethodID, nodeInfoClass, "setVisibleToUser", "(Z)V"); + if (QtAndroidPrivate::androidSdkVersion() >= 18) { + GET_AND_CHECK_STATIC_METHOD(m_setTextSelectionMethodID, nodeInfoClass, "setTextSelection", "(II)V"); + } + return true; } } diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index d484a2faff..f711a68a71 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -423,6 +423,7 @@ namespace QtAndroid m_destroySurfaceMethodID, surfaceId); } + } // namespace QtAndroid @@ -743,15 +744,6 @@ static int registerNatives(JNIEnv *env) return JNI_TRUE; } -jint androidApiLevel(JNIEnv *env) -{ - jclass clazz; - FIND_AND_CHECK_CLASS("android/os/Build$VERSION"); - jfieldID fieldId; - GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "SDK_INT", "I"); - return env->GetStaticIntField(clazz, fieldId); -} - Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) { typedef union { @@ -774,17 +766,12 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) || !QtAndroidInput::registerNatives(env) || !QtAndroidClipboard::registerNatives(env) || !QtAndroidMenu::registerNatives(env) + || !QtAndroidAccessibility::registerNatives(env) || !QtAndroidDialogHelpers::registerNatives(env)) { __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); return -1; } - jint apiLevel = androidApiLevel(env); - if (apiLevel >= 16 && !QtAndroidAccessibility::registerNatives(env)) { - __android_log_print(ANDROID_LOG_FATAL, "Qt A11y", "registerNatives failed"); - return -1; - } - m_javaVM = vm; return JNI_VERSION_1_4; } diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 548c6a23f0..f89439734f 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -223,7 +223,14 @@ static void cleanupCocoaApplicationDelegate() // events while the event loop is still running. const QWindowList topLevels = QGuiApplication::topLevelWindows(); for (int i = 0; i < topLevels.size(); ++i) { - QWindowSystemInterface::handleCloseEvent(topLevels.at(i)); + QWindow *topLevelWindow = topLevels.at(i); + // Widgets have alreay received a CloseEvent from the QApplication + // QCloseEvent handler. (see canQuit above). Prevent running the + // CloseEvent logic twice, call close() directly. + if (topLevelWindow->inherits("QWidgetWindow")) + topLevelWindow->close(); + else + QWindowSystemInterface::handleCloseEvent(topLevelWindow); } QWindowSystemInterface::flushWindowSystemEvents(); diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 19753ccc89..fca7fa042c 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -158,23 +158,42 @@ qreal QCocoaScreen::devicePixelRatio() const QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const { - // Get a z-ordered list of windows. Iterate through it until - // we find a (Qt) window which contains the point. - for (NSWindow *nsWindow in [NSApp orderedWindows]) { - if (![nsWindow isKindOfClass:[QNSWindow class]]) + NSPoint screenPoint = qt_mac_flipPoint(point); + + // Search (hit test) for the top-level window. [NSWidow windowNumberAtPoint: + // belowWindowWithWindowNumber] may return windows that are not interesting + // to Qt. The search iterates until a suitable window or no window is found. + NSInteger topWindowNumber = 0; + QWindow *window = 0; + do { + // Get the top-most window, below any previously rejected window. + topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint + belowWindowWithWindowNumber:topWindowNumber]; + + // Continue the search if the window does not belong to this process. + NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber]; + if (nsWindow == 0) continue; - QNSWindow *qnsWindow = static_cast<QNSWindow *>(nsWindow); - QCocoaWindow *cocoaWindow = qnsWindow.helper.platformWindow; + + // Continue the search if the window does not belong to Qt. + if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)]) + continue; + + id<QNSWindowProtocol> proto = static_cast<id<QNSWindowProtocol> >(nsWindow); + QCocoaWindow *cocoaWindow = proto.helper.platformWindow; if (!cocoaWindow) continue; - QWindow *window = cocoaWindow->window(); + window = cocoaWindow->window(); + + // Continue the search if the window is not a top-level window. if (!window->isTopLevel()) continue; - if (window->geometry().contains(point)) - return window; - } - return QPlatformScreen::topLevelAt(point); + // Stop searching. The current window is the correct window. + break; + } while (topWindowNumber > 0); + + return window; } extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index f3fd06037e..4403e3c28e 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -66,6 +66,8 @@ public: void lower() Q_DECL_OVERRIDE; void propagateSizeHints() Q_DECL_OVERRIDE { } + void setOpacity(qreal) Q_DECL_OVERRIDE { } + void setMask(const QRegion &) Q_DECL_OVERRIDE { } bool setKeyboardGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } bool setMouseGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 8be3846e06..d109d53168 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -54,7 +54,6 @@ QIOSInputContext *m_context; BOOL m_keyboardVisible; BOOL m_keyboardVisibleAndDocked; - BOOL m_ignoreKeyboardChanges; BOOL m_touchPressWhileKeyboardVisible; BOOL m_keyboardHiddenByGesture; QRectF m_keyboardRect; @@ -74,7 +73,6 @@ m_context = context; m_keyboardVisible = NO; m_keyboardVisibleAndDocked = NO; - m_ignoreKeyboardChanges = NO; m_touchPressWhileKeyboardVisible = NO; m_keyboardHiddenByGesture = NO; m_duration = 0; @@ -160,7 +158,7 @@ - (void) keyboardWillShow:(NSNotification *)notification { - if (m_ignoreKeyboardChanges) + if ([QUIView inUpdateKeyboardLayout]) return; // Note that UIKeyboardWillShowNotification is only sendt when the keyboard is docked. m_keyboardVisibleAndDocked = YES; @@ -175,7 +173,7 @@ - (void) keyboardWillHide:(NSNotification *)notification { - if (m_ignoreKeyboardChanges) + if ([QUIView inUpdateKeyboardLayout]) return; // Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked. m_keyboardVisibleAndDocked = NO; @@ -407,11 +405,7 @@ void QIOSInputContext::update(Qt::InputMethodQueries query) void QIOSInputContext::reset() { - // Since the call to reset will cause a 'keyboardWillHide' - // notification to be sendt, we block keyboard nofifications to avoid artifacts: - m_keyboardListener->m_ignoreKeyboardChanges = true; [m_focusView reset]; - m_keyboardListener->m_ignoreKeyboardChanges = false; } void QIOSInputContext::commit() diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h index 575dedab89..122e7c604b 100644 --- a/src/plugins/platforms/ios/quiview.h +++ b/src/plugins/platforms/ios/quiview.h @@ -75,4 +75,5 @@ - (void)updateInputMethodWithQuery:(Qt::InputMethodQueries)query; - (void)reset; - (void)commit; ++ (bool)inUpdateKeyboardLayout; @end diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/quiview_textinput.mm index 03006b3f99..e65ac1cc46 100644 --- a/src/plugins/platforms/ios/quiview_textinput.mm +++ b/src/plugins/platforms/ios/quiview_textinput.mm @@ -45,9 +45,12 @@ class StaticVariables { public: QInputMethodQueryEvent inputMethodQueryEvent; + bool inUpdateKeyboardLayout; QTextCharFormat markedTextFormat; - StaticVariables() : inputMethodQueryEvent(Qt::ImQueryInput) + StaticVariables() + : inputMethodQueryEvent(Qt::ImQueryInput) + , inUpdateKeyboardLayout(false) { // There seems to be no way to query how the preedit text // should be drawn. So we need to hard-code the color. @@ -152,6 +155,47 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); return [super resignFirstResponder]; } ++ (bool)inUpdateKeyboardLayout +{ + return staticVariables()->inUpdateKeyboardLayout; +} + +- (void)updateKeyboardLayout +{ + if (![self isFirstResponder]) + return; + + // There seems to be no API to inform that the keyboard layout needs to update. + // As a work-around, we quickly resign first responder just to reassign it again. + QScopedValueRollback<bool> rollback(staticVariables()->inUpdateKeyboardLayout); + staticVariables()->inUpdateKeyboardLayout = true; + [super resignFirstResponder]; + [self updateTextInputTraits]; + [super becomeFirstResponder]; +} + +- (void)updateUITextInputDelegate:(NSNumber *)intQuery +{ + // As documented, we should not report textWillChange/textDidChange unless the text + // was changed externally. That will cause spell checking etc to fail. But we don't + // really know if the text/selection was changed by UITextInput or Qt/app when getting + // update calls from Qt. We therefore use a less ideal approach where we always assume + // that UITextView caused the change if we're currently processing an event sendt from it. + if (m_inSendEventToFocusObject) + return; + + Qt::InputMethodQueries query = Qt::InputMethodQueries([intQuery intValue]); + if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) { + [self.inputDelegate selectionWillChange:id<UITextInput>(self)]; + [self.inputDelegate selectionDidChange:id<UITextInput>(self)]; + } + + if (query & Qt::ImSurroundingText) { + [self.inputDelegate textWillChange:id<UITextInput>(self)]; + [self.inputDelegate textDidChange:id<UITextInput>(self)]; + } +} + - (void)updateInputMethodWithQuery:(Qt::InputMethodQueries)query { Q_UNUSED(query); @@ -160,26 +204,13 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); if (!focusObject) return; - if (!m_inSendEventToFocusObject) { - if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) - [self.inputDelegate selectionWillChange:id<UITextInput>(self)]; - if (query & Qt::ImSurroundingText) - [self.inputDelegate textWillChange:id<UITextInput>(self)]; - } - // Note that we ignore \a query, and instead update using Qt::ImQueryInput. This enables us to just // store the event without copying out the result from the event each time. Besides, we seem to be // called with Qt::ImQueryInput when only changing selection, and always if typing text. So there would // not be any performance gain by only updating \a query. staticVariables()->inputMethodQueryEvent = QInputMethodQueryEvent(Qt::ImQueryInput); QCoreApplication::sendEvent(focusObject, &staticVariables()->inputMethodQueryEvent); - - if (!m_inSendEventToFocusObject) { - if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) - [self.inputDelegate selectionDidChange:id<UITextInput>(self)]; - if (query & Qt::ImSurroundingText) - [self.inputDelegate textDidChange:id<UITextInput>(self)]; - } + [self updateUITextInputDelegate:[NSNumber numberWithInt:int(query)]]; } - (void)sendEventToFocusObject:(QEvent &)e @@ -189,35 +220,31 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); return; // While sending the event, we will receive back updateInputMethodWithQuery calls. - // To not confuse iOS, we cannot not call textWillChange/textDidChange at that - // point since it will cause spell checking etc to fail. So we use a guard. + // Note that it would be more correct to post the event instead, but UITextInput expects + // callbacks to take effect immediately (it will query us for information after a callback). + QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject); m_inSendEventToFocusObject = YES; QCoreApplication::sendEvent(focusObject, &e); - m_inSendEventToFocusObject = NO; } - (void)reset { - [self.inputDelegate textWillChange:id<UITextInput>(self)]; [self setMarkedText:@"" selectedRange:NSMakeRange(0, 0)]; [self updateInputMethodWithQuery:Qt::ImQueryInput]; - - if ([self isFirstResponder]) { - // There seem to be no way to inform that the keyboard needs to update (since - // text input traits might have changed). As a work-around, we quickly resign - // first responder status just to reassign it again: - [super resignFirstResponder]; - [self updateTextInputTraits]; - [super becomeFirstResponder]; - } - [self.inputDelegate textDidChange:id<UITextInput>(self)]; + // Guard agains recursive callbacks by posting calls to UITextInput + [self performSelectorOnMainThread:@selector(updateKeyboardLayout) withObject:nil waitUntilDone:NO]; + [self performSelectorOnMainThread:@selector(updateUITextInputDelegate:) + withObject:[NSNumber numberWithInt:int(Qt::ImQueryInput)] + waitUntilDone:NO]; } - (void)commit { - [self.inputDelegate textWillChange:id<UITextInput>(self)]; [self unmarkText]; - [self.inputDelegate textDidChange:id<UITextInput>(self)]; + // Guard agains recursive callbacks by posting calls to UITextInput + [self performSelectorOnMainThread:@selector(updateUITextInputDelegate:) + withObject:[NSNumber numberWithInt:int(Qt::ImSurroundingText)] + waitUntilDone:NO]; } - (QVariant)imValue:(Qt::InputMethodQuery)query diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 7f2ed86404..d56925d0c4 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -522,6 +522,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale) QLocale l; res.country = QStringToBSTR(QLocale::countryToString(l.country())); res.language = QStringToBSTR(QLocale::languageToString(l.language())); + res.variant = QStringToBSTR(QString()); *locale = res; return S_OK; } diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 0b257cc48f..6bcfe01a18 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -893,6 +893,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms case Qt::Key_Plus: case Qt::Key_Minus: case Qt::Key_Period: + case Qt::Key_Comma: case Qt::Key_0: case Qt::Key_1: case Qt::Key_2: diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index a46fe437d8..74d8b7c2c8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -337,12 +337,38 @@ void QXcbWindow::create() #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL) { m_window = xcb_generate_id(xcb_connection()); + m_visualId = m_screen->screen()->root_visual; m_depth = m_screen->screen()->root_depth; + + uint32_t mask = 0; + uint32_t values[3]; + + if (m_format.alphaBufferSize() == 8) { + xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(m_screen->screen()); + while (depthIter.rem) { + if (depthIter.data->depth == 32) { + xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data); + if (visualIter.rem) { + m_visualId = visualIter.data->visual_id; + m_depth = 32; + uint32_t colormap = xcb_generate_id(xcb_connection()); + xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap, + xcb_parent_id, m_visualId); + mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP; + values[0] = m_screen->screen()->white_pixel; + values[1] = m_screen->screen()->black_pixel; + values[2] = colormap; + break; + } + } + xcb_depth_next(&depthIter); + } + } + m_imageFormat = imageFormatForDepth(m_depth); - m_visualId = m_screen->screen()->root_visual; Q_XCB_CALL(xcb_create_window(xcb_connection(), - XCB_COPY_FROM_PARENT, // depth -- same as root + m_depth, m_window, // window id xcb_parent_id, // parent window id rect.x(), @@ -352,8 +378,8 @@ void QXcbWindow::create() 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class m_visualId, // visual - 0, // value mask - 0)); // value list + mask, + values)); } connection()->addWindowEventListener(m_window, this); |