diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-11-26 10:51:33 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-11-26 10:51:34 +0100 |
commit | 3061dc4abdfbd1a536918935d380872de6655521 (patch) | |
tree | ff440ed0c7d5816cc7e2874f73fdabfb0bce493f /src/plugins | |
parent | 25b2b682d616dd52c3515f443e3d25fc0224f3a2 (diff) | |
parent | 9b8570c4e9359eb8b45b39c28aa9d8c140f3fc44 (diff) |
Merge remote-tracking branch 'origin/release' into stable
Change-Id: I83ff8f4d7dffd7385013a1bd8a1732a89ee20d56
Diffstat (limited to 'src/plugins')
25 files changed, 576 insertions, 94 deletions
diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/src/androidjnimain.cpp index 3ab4eedb26..3064e5d4e2 100644 --- a/src/plugins/platforms/android/src/androidjnimain.cpp +++ b/src/plugins/platforms/android/src/androidjnimain.cpp @@ -40,6 +40,7 @@ ** ****************************************************************************/ +#include <QtGui/private/qguiapplication_p.h> #include <dlfcn.h> #include <pthread.h> @@ -691,7 +692,7 @@ static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state { m_activityActive = (state == Qt::ApplicationActive); - if (!m_androidPlatformIntegration) + if (!m_androidPlatformIntegration || !QGuiApplicationPrivate::platformIntegration()) return; QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state)); diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp index 6d0ec306ab..ae3e257d3c 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp @@ -242,6 +242,15 @@ QVariant QAndroidPlatformIntegration::styleHint(StyleHint hint) const } } +Qt::WindowState QAndroidPlatformIntegration::defaultWindowState(Qt::WindowFlags flags) const +{ + // Don't maximize dialogs on Android + if (flags & Qt::Dialog & ~Qt::Window) + return Qt::WindowNoState; + + return QPlatformIntegration::defaultWindowState(flags); +} + static const QLatin1String androidThemeName("android"); QStringList QAndroidPlatformIntegration::themeNames() const { diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.h b/src/plugins/platforms/android/src/qandroidplatformintegration.h index 3b34cdf7df..bd08ad694c 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.h @@ -121,6 +121,7 @@ public: #endif QVariant styleHint(StyleHint hint) const; + Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const Q_DECL_OVERRIDE; QStringList themeNames() const; QPlatformTheme *createPlatformTheme(const QString &name) const; diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp index 0ceac97e35..308bb70faf 100644 --- a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp @@ -125,7 +125,7 @@ const QFont *QAndroidPlatformTheme::font(Font type) const return &(it.value()); // default in case the style has not set a font - static QFont systemFont("Roboto", 12.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi + static QFont systemFont("Roboto", 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi if (type == QPlatformTheme::SystemFont) return &systemFont; return 0; diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 0fea55ac68..5a8664747e 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -175,6 +175,7 @@ void QCocoaMenuBar::handleReparent(QWindow *newParentWindow) if (newParentWindow == NULL) { m_window = NULL; } else { + newParentWindow->create(); m_window = static_cast<QCocoaWindow*>(newParentWindow->handle()); m_window->setMenubar(this); } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index c22f254aef..4da47f4f1f 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -465,8 +465,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) { Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); NSInteger styleMask = NSBorderlessWindowMask; + if (flags & Qt::FramelessWindowHint) + return styleMask; if ((type & Qt::Popup) == Qt::Popup) { - if (!windowIsPopupType(type) && !(flags & Qt::FramelessWindowHint)) + if (!windowIsPopupType(type)) styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); } else { @@ -485,7 +487,7 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) } else { styleMask = NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask; } - } else if (!(flags & Qt::FramelessWindowHint)) { + } else { if (flags & Qt::WindowMaximizeButtonHint) styleMask |= NSResizableWindowMask; if (flags & Qt::WindowTitleHint) diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm index 775074baae..cf702c82af 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm @@ -58,6 +58,25 @@ self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; self.window.rootViewController = [[[QIOSViewController alloc] init] autorelease]; +#if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_7_0) + QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion; + + // We prefer to keep the root viewcontroller in fullscreen layout, so that + // we don't have to compensate for the viewcontroller position. This also + // gives us the same behavior on iOS 5/6 as on iOS 7, where full screen layout + // is the only way. + if (iosVersion < QSysInfo::MV_IOS_7_0) + self.window.rootViewController.wantsFullScreenLayout = YES; + + // Use translucent statusbar by default on iOS6 iPhones (unless the user changed + // the default in the Info.plist), so that windows placed under the stausbar are + // still visible, just like on iOS7. + if (iosVersion >= QSysInfo::MV_IOS_6_0 && iosVersion < QSysInfo::MV_IOS_7_0 + && [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone + && [UIApplication sharedApplication].statusBarStyle == UIStatusBarStyleDefault) + [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent]; +#endif + self.window.hidden = NO; return YES; diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm index 2dadc5672b..5ea5fbd8d1 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.mm +++ b/src/plugins/platforms/ios/qiosbackingstore.mm @@ -56,6 +56,9 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window) fmt.setDepthBufferSize(16); fmt.setStencilBufferSize(8); + // Needed to prevent QOpenGLContext::makeCurrent() from failing + window->setSurfaceType(QSurface::OpenGLSurface); + m_context->setFormat(fmt); m_context->setScreen(window->screen()); m_context->create(); @@ -69,9 +72,6 @@ QIOSBackingStore::~QIOSBackingStore() void QIOSBackingStore::beginPaint(const QRegion &) { - // Needed to prevent QOpenGLContext::makeCurrent() from failing - window()->setSurfaceType(QSurface::OpenGLSurface); - m_context->makeCurrent(window()); QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle()); @@ -102,6 +102,8 @@ void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin // the child window overlaps a sibling window that's draws using a separate QOpenGLContext. return; } + + m_context->makeCurrent(window); m_context->swapBuffers(window); } @@ -115,7 +117,7 @@ void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents) // backing store and always keep the paint device's size in sync with the // window size in beginPaint(). - if (size != window()->size()) + if (size != window()->size() && !window()->inherits("QWidgetWindow")) qWarning() << "QIOSBackingStore needs to have the same size as its window"; } diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h index 41b0d7f93a..1c76d29389 100644 --- a/src/plugins/platforms/ios/qiosglobal.h +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -53,10 +53,11 @@ class QPlatformScreen; bool isQtApplication(); -CGRect toCGRect(const QRect &rect); -QRect fromCGRect(const CGRect &rect); -CGPoint toCGPoint(const QPoint &point); -QPoint fromCGPoint(const CGPoint &point); +CGRect toCGRect(const QRectF &rect); +QRectF fromCGRect(const CGRect &rect); +CGPoint toCGPoint(const QPointF &point); +QPointF fromCGPoint(const CGPoint &point); + Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation); UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation); QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen); diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index be68e4d7d5..d749b8f514 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -58,24 +58,24 @@ bool isQtApplication() return isQt; } -CGRect toCGRect(const QRect &rect) +CGRect toCGRect(const QRectF &rect) { return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); } -QRect fromCGRect(const CGRect &rect) +QRectF fromCGRect(const CGRect &rect) { - return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + return QRectF(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); } -CGPoint toCGPoint(const QPoint &point) +CGPoint toCGPoint(const QPointF &point) { return CGPointMake(point.x(), point.y()); } -QPoint fromCGPoint(const CGPoint &point) +QPointF fromCGPoint(const CGPoint &point) { - return QPoint(point.x, point.y); + return QPointF(point.x, point.y); } Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation) diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 78c1b260e6..533ba686e1 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -44,6 +44,7 @@ #include <UIKit/UIKit.h> +#include <QtGui/qtransform.h> #include <qpa/qplatforminputcontext.h> QT_BEGIN_NAMESPACE @@ -60,13 +61,17 @@ public: void showInputPanel(); void hideInputPanel(); bool isInputPanelVisible() const; + void setFocusObject(QObject *object); - void focusViewChanged(UIView *view); + void focusWindowChanged(QWindow *focusWindow); + void scrollRootView(); private: QIOSKeyboardListener *m_keyboardListener; - UIView *m_focusView; + UIView<UIKeyInput> *m_focusView; + QTransform m_inputItemTransform; bool m_hasPendingHideRequest; + bool m_inSetFocusObject; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index d430589037..0e43429015 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -48,7 +48,12 @@ @public QIOSInputContext *m_context; BOOL m_keyboardVisible; + BOOL m_keyboardVisibleAndDocked; QRectF m_keyboardRect; + QRectF m_keyboardEndRect; + NSTimeInterval m_duration; + UIViewAnimationCurve m_curve; + UIViewController *m_viewController; } @end @@ -60,8 +65,30 @@ if (self) { m_context = context; m_keyboardVisible = NO; - // After the keyboard became undockable (iOS5), UIKeyboardWillShow/UIKeyboardWillHide - // no longer works for all cases. So listen to keyboard frame changes instead: + m_keyboardVisibleAndDocked = NO; + m_duration = 0; + m_curve = UIViewAnimationCurveEaseOut; + m_viewController = 0; + + if (isQtApplication()) { + // Get the root view controller that is on the same screen as the keyboard: + for (UIWindow *uiWindow in [[UIApplication sharedApplication] windows]) { + if (uiWindow.screen == [UIScreen mainScreen]) { + m_viewController = [uiWindow.rootViewController retain]; + break; + } + } + Q_ASSERT(m_viewController); + } + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(keyboardWillShow:) + name:@"UIKeyboardWillShowNotification" object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(keyboardWillHide:) + name:@"UIKeyboardWillHideNotification" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrame:) @@ -72,25 +99,68 @@ - (void) dealloc { + [m_viewController release]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:@"UIKeyboardWillShowNotification" object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:@"UIKeyboardWillHideNotification" object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardDidChangeFrameNotification" object:nil]; [super dealloc]; } -- (void) keyboardDidChangeFrame:(NSNotification *)notification +- (QRectF) getKeyboardRect:(NSNotification *)notification { - CGRect frame; - [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&frame]; + // For Qt applications we rotate the keyboard rect to align with the screen + // orientation (which is the interface orientation of the root view controller). + // For hybrid apps we follow native behavior, and return the rect unmodified: + CGRect keyboardFrame = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue]; + if (isQtApplication()) { + UIView *view = m_viewController.view; + return fromCGRect(CGRectOffset([view convertRect:keyboardFrame fromView:view.window], 0, -view.bounds.origin.y)); + } else { + return fromCGRect(keyboardFrame); + } +} - m_keyboardRect = fromPortraitToPrimary(fromCGRect(frame), QGuiApplication::primaryScreen()->handle()); +- (void) keyboardDidChangeFrame:(NSNotification *)notification +{ + m_keyboardRect = [self getKeyboardRect:notification]; m_context->emitKeyboardRectChanged(); - BOOL visible = CGRectIntersectsRect(frame, [UIScreen mainScreen].bounds); + BOOL visible = m_keyboardRect.intersects(fromCGRect([UIScreen mainScreen].bounds)); if (m_keyboardVisible != visible) { m_keyboardVisible = visible; m_context->emitInputPanelVisibleChanged(); } + + // If the keyboard was visible and docked from before, this is just a geometry + // change (normally caused by an orientation change). In that case, update scroll: + if (m_keyboardVisibleAndDocked) + m_context->scrollRootView(); +} + +- (void) keyboardWillShow:(NSNotification *)notification +{ + // Note that UIKeyboardWillShowNotification is only sendt when the keyboard is docked. + m_keyboardVisibleAndDocked = YES; + m_keyboardEndRect = [self getKeyboardRect:notification]; + if (!m_duration) { + m_duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + m_curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16; + } + m_context->scrollRootView(); +} + +- (void) keyboardWillHide:(NSNotification *)notification +{ + // Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked. + m_keyboardVisibleAndDocked = NO; + m_keyboardEndRect = [self getKeyboardRect:notification]; + m_context->scrollRootView(); } @end @@ -100,7 +170,11 @@ QIOSInputContext::QIOSInputContext() , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_focusView(0) , m_hasPendingHideRequest(false) + , m_inSetFocusObject(false) { + if (isQtApplication()) + connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::scrollRootView); + connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSInputContext::focusWindowChanged); } QIOSInputContext::~QIOSInputContext() @@ -142,10 +216,76 @@ bool QIOSInputContext::isInputPanelVisible() const return m_keyboardListener->m_keyboardVisible; } -void QIOSInputContext::focusViewChanged(UIView *view) +void QIOSInputContext::setFocusObject(QObject *) +{ + m_inputItemTransform = qApp->inputMethod()->inputItemTransform(); + + if (!m_focusView || !m_focusView.isFirstResponder) + return; + + // Since m_focusView is the first responder, it means that the keyboard is open and we + // should update keyboard layout. But there seem to be no way to tell it to reread the + // UITextInputTraits from m_focusView. To work around that, we quickly resign first + // responder status just to reassign it again. To not remove the focusObject in the same + // go, we need to call the super implementation of resignFirstResponder. Since the call + // will cause a 'keyboardWillHide' notification to be sendt, we also block scrollRootView + // to avoid artifacts: + m_inSetFocusObject = true; + SEL sel = @selector(resignFirstResponder); + [[m_focusView superclass] instanceMethodForSelector:sel](m_focusView, sel); + m_inSetFocusObject = false; + [m_focusView becomeFirstResponder]; +} + +void QIOSInputContext::focusWindowChanged(QWindow *focusWindow) { + UIView<UIKeyInput> *view = reinterpret_cast<UIView<UIKeyInput> *>(focusWindow->handle()->winId()); if ([m_focusView isFirstResponder]) [view becomeFirstResponder]; [m_focusView release]; m_focusView = [view retain]; } + +void QIOSInputContext::scrollRootView() +{ + // Scroll the root view (screen) if: + // - our backend controls the root view controller on the main screen (no hybrid app) + // - the focus object is on the same screen as the keyboard. + // - the first responder is a QUIView, and not some other foreign UIView. + // - the keyboard is docked. Otherwise the user can move the keyboard instead. + // - the inputItem has not been moved/scrolled + if (!isQtApplication() || !m_focusView || m_inSetFocusObject) + return; + + if (m_inputItemTransform != qApp->inputMethod()->inputItemTransform()) { + // The inputItem has moved since the last scroll update. To avoid competing + // with the application where the cursor/inputItem should be, we bail: + return; + } + + UIView *view = m_keyboardListener->m_viewController.view; + qreal scrollTo = 0; + + if (m_focusView.isFirstResponder + && m_keyboardListener->m_keyboardVisibleAndDocked + && m_focusView.window == view.window) { + QRectF cursorRect = qGuiApp->inputMethod()->cursorRectangle(); + cursorRect.translate(qGuiApp->focusWindow()->geometry().topLeft()); + qreal keyboardY = m_keyboardListener->m_keyboardEndRect.y(); + int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y(); + const int margin = 20; + + if (cursorRect.bottomLeft().y() > keyboardY - margin) + scrollTo = qMin(view.bounds.size.height - keyboardY, cursorRect.y() - statusBarY - margin); + } + + if (scrollTo != view.bounds.origin.y) { + // Scroll the view the same way a UIScrollView works: by changing bounds.origin: + CGRect newBounds = view.bounds; + newBounds.origin.y = scrollTo; + [UIView animateWithDuration:m_keyboardListener->m_duration delay:0 + options:m_keyboardListener->m_curve + animations:^{ view.bounds = newBounds; } + completion:0]; + } +} diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 44ac749454..5c8f67bda2 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -160,7 +160,7 @@ QPlatformServices *QIOSIntegration::services() const QVariant QIOSIntegration::styleHint(StyleHint hint) const { switch (hint) { - case ShowIsFullScreen: + case ShowIsMaximized: return true; case SetFocusOnTouchRelease: return true; diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h index e70ff4b1a9..173bd11719 100644 --- a/src/plugins/platforms/ios/qiosscreen.h +++ b/src/plugins/platforms/ios/qiosscreen.h @@ -50,8 +50,10 @@ QT_BEGIN_NAMESPACE -class QIOSScreen : public QPlatformScreen +class QIOSScreen : public QObject, public QPlatformScreen { + Q_OBJECT + public: QIOSScreen(unsigned int screenIndex); ~QIOSScreen(); @@ -73,6 +75,10 @@ public: UIScreen *uiScreen() const; void updateProperties(); + void layoutWindows(); + +public slots: + void updateStatusBarVisibility(); private: UIScreen *m_uiScreen; diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index de6585fd19..57522cb1a3 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -139,6 +139,8 @@ QIOSScreen::QIOSScreen(unsigned int screenIndex) m_unscaledDpi = 163; // Regular iPhone DPI } + connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSScreen::updateStatusBarVisibility); + updateProperties(); } @@ -156,7 +158,7 @@ void QIOSScreen::updateProperties() } bool inPortrait = UIInterfaceOrientationIsPortrait(uiWindow.rootViewController.interfaceOrientation); - QRect geometry = inPortrait ? fromCGRect(m_uiScreen.bounds) + QRect geometry = inPortrait ? fromCGRect(m_uiScreen.bounds).toRect() : QRect(m_uiScreen.bounds.origin.x, m_uiScreen.bounds.origin.y, m_uiScreen.bounds.size.height, m_uiScreen.bounds.size.width); @@ -182,7 +184,66 @@ void QIOSScreen::updateProperties() } if (screen()) - resizeMaximizedWindows(); + layoutWindows(); +} + +void QIOSScreen::updateStatusBarVisibility() +{ + QWindow *focusWindow = QGuiApplication::focusWindow(); + + // If we don't have a focus window we leave the status + // bar as is, so that the user can activate a new window + // with the same window state without the status bar jumping + // back and forth. + if (!focusWindow) + return; + + UIView *view = reinterpret_cast<UIView *>(focusWindow->handle()->winId()); +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0) { + [view.viewController setNeedsStatusBarAppearanceUpdate]; + } else +#endif + { + bool wasHidden = [UIApplication sharedApplication].statusBarHidden; + QIOSViewController *viewController = static_cast<QIOSViewController *>(view.viewController); + [[UIApplication sharedApplication] + setStatusBarHidden:[viewController prefersStatusBarHidden] + withAnimation:UIStatusBarAnimationNone]; + + if ([UIApplication sharedApplication].statusBarHidden != wasHidden) + updateProperties(); + } +} + +void QIOSScreen::layoutWindows() +{ + QList<QWindow*> windows = QGuiApplication::topLevelWindows(); + + const QRect oldGeometry = screen()->geometry(); + const QRect oldAvailableGeometry = screen()->availableGeometry(); + const QRect newGeometry = geometry(); + const QRect newAvailableGeometry = availableGeometry(); + + for (int i = 0; i < windows.size(); ++i) { + QWindow *window = windows.at(i); + + if (platformScreenForWindow(window) != this) + continue; + + QIOSWindow *platformWindow = static_cast<QIOSWindow *>(window->handle()); + if (!platformWindow) + continue; + + // FIXME: Handle more complex cases of no-state and/or child windows when rotating + + if (window->windowState() & Qt::WindowFullScreen + || (window->windowState() & Qt::WindowNoState && window->geometry() == oldGeometry)) + platformWindow->applyGeometry(newGeometry); + else if (window->windowState() & Qt::WindowMaximized + || (window->windowState() & Qt::WindowNoState && window->geometry() == oldAvailableGeometry)) + platformWindow->applyGeometry(newAvailableGeometry); + } } QRect QIOSScreen::geometry() const @@ -247,4 +308,6 @@ UIScreen *QIOSScreen::uiScreen() const return m_uiScreen; } +#include "moc_qiosscreen.cpp" + QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h index d5a61cb3f4..a0017808d3 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.h +++ b/src/plugins/platforms/ios/qiosviewcontroller.h @@ -42,5 +42,6 @@ #import <UIKit/UIKit.h> @interface QIOSViewController : UIViewController +- (BOOL)prefersStatusBarHidden; @end diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 1d5e69beac..2e7e44d32c 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -42,9 +42,11 @@ #import "qiosviewcontroller.h" #include <QtGui/QGuiApplication> +#include <QtGui/QWindow> #include <QtGui/QScreen> #include "qiosscreen.h" #include "qiosglobal.h" +#include "qioswindow.h" @implementation QIOSViewController @@ -55,12 +57,22 @@ return YES; } +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_6_0) -(NSUInteger)supportedInterfaceOrientations { // We need to tell iOS that we support all orientations in order to set // status bar orientation when application content orientation changes. return UIInterfaceOrientationMaskAll; } +#endif + +#if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_6_0) +-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + Q_UNUSED(interfaceOrientation); + return YES; +} +#endif - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { @@ -74,5 +86,28 @@ qiosScreen->updateProperties(); } +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0) +- (UIStatusBarStyle)preferredStatusBarStyle +{ + // Since we don't place anything behind the status bare by default, we + // end up with a black area, so we have to enable the white text mode + // of the iOS7 statusbar. + return UIStatusBarStyleLightContent; + + // FIXME: Try to detect the content underneath the statusbar and choose + // an appropriate style, and/or expose Qt APIs to control the style. +} +#endif + +- (BOOL)prefersStatusBarHidden +{ + QWindow *focusWindow = QGuiApplication::focusWindow(); + if (!focusWindow) + return [UIApplication sharedApplication].statusBarHidden; + + QIOSWindow *topLevel = static_cast<QIOSWindow *>(focusWindow->handle())->topLevelWindow(); + return topLevel->window()->windowState() == Qt::WindowFullScreen; +} + @end diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 6e8683af00..a5e122bda1 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -85,7 +85,11 @@ public: WId winId() const { return WId(m_view); }; + QIOSWindow *topLevelWindow() const; + private: + void applyGeometry(const QRect &rect); + QUIView *m_view; QRect m_normalGeometry; @@ -97,6 +101,8 @@ private: inline Qt::WindowType windowType() { return static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask)); } inline bool windowIsPopup() { return windowType() & Qt::Popup & ~Qt::Window; } + + friend class QIOSScreen; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 2413a45e11..0dd810bdf6 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -105,18 +105,10 @@ CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer); eaglLayer.opaque = TRUE; eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, + [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; - // Set up text input - autocapitalizationType = UITextAutocapitalizationTypeNone; - autocorrectionType = UITextAutocorrectionTypeNo; - enablesReturnKeyAutomatically = NO; - keyboardAppearance = UIKeyboardAppearanceDefault; - keyboardType = UIKeyboardTypeDefault; - returnKeyType = UIReturnKeyDone; - secureTextEntry = NO; - m_nextTouchId = 0; + [self updateTextInputTraits]; if (isQtApplication()) self.hidden = YES; @@ -153,6 +145,15 @@ self.clipsToBounds = NO; } +- (void)setNeedsDisplay +{ + [super setNeedsDisplay]; + + // We didn't implement drawRect: so we have to manually + // mark the layer as needing display. + [self.layer setNeedsDisplay]; +} + - (void)layoutSubviews { // This method is the de facto way to know that view has been resized, @@ -165,15 +166,53 @@ qWarning() << m_qioswindow->window() << "is backed by a UIView that has a transform set. This is not supported."; - QRect geometry = fromCGRect(self.frame); - m_qioswindow->QPlatformWindow::setGeometry(geometry); - QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), geometry); - QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), QRect(QPoint(), geometry.size())); + // The original geometry requested by setGeometry() might be different + // from what we end up with after applying window constraints. + QRect requestedGeometry = m_qioswindow->geometry(); + + QRect actualGeometry; + if (m_qioswindow->window()->isTopLevel()) { + UIWindow *uiWindow = self.window; + UIView *rootView = uiWindow.rootViewController.view; + CGRect rootViewPositionInRelationToRootViewController = + [rootView convertRect:uiWindow.bounds fromView:uiWindow]; + + actualGeometry = fromCGRect(CGRectOffset([self.superview convertRect:self.frame toView:rootView], + -rootViewPositionInRelationToRootViewController.origin.x, + -rootViewPositionInRelationToRootViewController.origin.y + + rootView.bounds.origin.y)).toRect(); + } else { + actualGeometry = fromCGRect(self.frame).toRect(); + } + + // Persist the actual/new geometry so that QWindow::geometry() can + // be queried on the resize event. + m_qioswindow->QPlatformWindow::setGeometry(actualGeometry); + + QRect previousGeometry = requestedGeometry != actualGeometry ? + requestedGeometry : qt_window_private(m_qioswindow->window())->geometry; + + QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), actualGeometry, previousGeometry); + QWindowSystemInterface::flushWindowSystemEvents(); - // If we have a new size here we need to resize the FBO's corresponding buffers, - // but we defer that to when the application calls makeCurrent. + if (actualGeometry.size() != previousGeometry.size()) { + // Trigger expose event on resize + [self setNeedsDisplay]; - [super layoutSubviews]; + // A new size means we also need to resize the FBO's corresponding buffers, + // but we defer that to when the application calls makeCurrent. + } +} + +- (void)displayLayer:(CALayer *)layer +{ + QRect geometry = fromCGRect(layer.frame).toRect(); + Q_ASSERT(m_qioswindow->geometry() == geometry); + Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible()); + + QRegion region = self.hidden ? QRegion() : QRect(QPoint(), geometry.size()); + QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region); + QWindowSystemInterface::flushWindowSystemEvents(); } - (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state @@ -195,7 +234,7 @@ } else { touchPoint.state = state; touchPoint.pressure = (state == Qt::TouchPointReleased) ? 0.0 : 1.0; - QPoint touchPos = fromCGPoint([uiTouch locationInView:rootView]); + QPoint touchPos = fromCGPoint([uiTouch locationInView:rootView]).toPoint(); touchPoint.area = QRectF(touchPos, QSize(0, 0)); touchPoint.normalPosition = QPointF(touchPos.x() / rootViewSize.width, touchPos.y() / rootViewSize.height); } @@ -296,6 +335,7 @@ // user cannot type. And since the keyboard will open when a view becomes // the first responder, it's now a good time to inform QPA that the QWindow // this view backs became active: + [self updateTextInputTraits]; QWindowSystemInterface::handleWindowActivated(m_qioswindow->window()); return [super becomeFirstResponder]; } @@ -318,8 +358,11 @@ { QString string = QString::fromUtf8([text UTF8String]); int key = 0; - if ([text isEqualToString:@"\n"]) + if ([text isEqualToString:@"\n"]) { key = (int)Qt::Key_Return; + if (self.returnKeyType == UIReturnKeyDone) + [self resignFirstResponder]; + } // Send key event to window system interface QWindowSystemInterface::handleKeyEvent( @@ -337,6 +380,47 @@ 0, QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier); } +- (void)updateTextInputTraits +{ + // Ask the current focus object what kind of input it + // expects, and configure the keyboard appropriately: + QObject *focusObject = QGuiApplication::focusObject(); + if (!focusObject) + return; + QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints); + if (!QCoreApplication::sendEvent(focusObject, &queryEvent)) + return; + if (!queryEvent.value(Qt::ImEnabled).toBool()) + return; + + Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt()); + + self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone; + self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText); + self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ? + UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault; + + if (hints & Qt::ImhUppercaseOnly) + self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters; + else if (hints & Qt::ImhNoAutoUppercase) + self.autocapitalizationType = UITextAutocapitalizationTypeNone; + else + self.autocapitalizationType = UITextAutocapitalizationTypeSentences; + + if (hints & Qt::ImhUrlCharactersOnly) + self.keyboardType = UIKeyboardTypeURL; + else if (hints & Qt::ImhEmailCharactersOnly) + self.keyboardType = UIKeyboardTypeEmailAddress; + else if (hints & Qt::ImhDigitsOnly) + self.keyboardType = UIKeyboardTypeNumberPad; + else if (hints & Qt::ImhFormattedNumbersOnly) + self.keyboardType = UIKeyboardTypeDecimalPad; + else if (hints & Qt::ImhDialableCharactersOnly) + self.keyboardType = UIKeyboardTypeNumberPad; + else + self.keyboardType = UIKeyboardTypeDefault; +} + @end @implementation UIView (QIOS) @@ -393,8 +477,8 @@ bool QIOSWindow::blockedByModal() void QIOSWindow::setVisible(bool visible) { - QPlatformWindow::setVisible(visible); m_view.hidden = !visible; + [m_view setNeedsDisplay]; if (!isQtApplication()) return; @@ -412,6 +496,10 @@ void QIOSWindow::setVisible(bool visible) if (visible) { requestActivateWindow(); + + if (window()->isTopLevel()) + static_cast<QIOSScreen *>(screen())->updateStatusBarVisibility(); + } else { // Activate top-most visible QWindow: NSArray *subviews = m_view.viewController.view.subviews; @@ -429,40 +517,90 @@ void QIOSWindow::setVisible(bool visible) void QIOSWindow::setGeometry(const QRect &rect) { - // If the window is in fullscreen, just bookkeep the requested - // geometry in case the window goes into Qt::WindowNoState later: m_normalGeometry = rect; - if (window()->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) + + if (window()->windowState() != Qt::WindowNoState) { + QPlatformWindow::setGeometry(rect); + + // The layout will realize the requested geometry was not applied, and + // send geometry-change events that match the actual geometry. + [m_view setNeedsLayout]; + + if (window()->inherits("QWidgetWindow")) { + // QWidget wrongly assumes that setGeometry resets the window + // state back to Qt::NoWindowState, so we need to inform it that + // that his is not the case by re-issuing the current window state. + QWindowSystemInterface::handleWindowStateChanged(window(), window()->windowState()); + + // It also needs to be told immediately that the geometry it requested + // did not apply, otherwise it will continue on as if it did, instead + // of waiting for a resize event. + [m_view layoutIfNeeded]; + } + return; + } - // Since we don't support transformations on the UIView, we can set the frame - // directly and let UIKit deal with translating that into bounds and center. - // Changing the size of the view will end up in a call to -[QUIView layoutSubviews] - // which will update QWindowSystemInterface with the new size. - m_view.frame = toCGRect(rect); + applyGeometry(rect); +} + +void QIOSWindow::applyGeometry(const QRect &rect) +{ + // Geometry changes are asynchronous, but QWindow::geometry() is + // expected to report back the 'requested geometry' until we get + // a callback with the updated geometry from the window system. + // The baseclass takes care of persisting this for us. + QPlatformWindow::setGeometry(rect); + + if (window()->isTopLevel()) { + // The QWindow is in QScreen coordinates, which maps to a possibly rotated root-view-controller. + // Since the root-view-controller might be translated in relation to the UIWindow, we need to + // check specifically for that and compensate. Also check if the root view has been scrolled + // as a result of the keyboard being open. + UIWindow *uiWindow = m_view.window; + UIView *rootView = uiWindow.rootViewController.view; + CGRect rootViewPositionInRelationToRootViewController = + [rootView convertRect:uiWindow.bounds fromView:uiWindow]; + + m_view.frame = CGRectOffset([m_view.superview convertRect:toCGRect(rect) fromView:rootView], + rootViewPositionInRelationToRootViewController.origin.x, + rootViewPositionInRelationToRootViewController.origin.y + + rootView.bounds.origin.y); + } else { + // Easy, in parent's coordinates + m_view.frame = toCGRect(rect); + } + + // iOS will automatically trigger -[layoutSubviews:] for resize, + // but not for move, so we force it just in case. + [m_view setNeedsLayout]; + + if (window()->inherits("QWidgetWindow")) + [m_view layoutIfNeeded]; } void QIOSWindow::setWindowState(Qt::WindowState state) { - // FIXME: Figure out where or how we should disable/enable the statusbar. - // Perhaps setting QWindow to maximized should also mean that we'll show - // the statusbar, and vice versa for fullscreen? + // Update the QWindow representation straight away, so that + // we can update the statusbar visibility based on the new + // state before applying geometry changes. + qt_window_private(window())->windowState = state; - if (state != Qt::WindowNoState) - m_normalGeometry = geometry(); + if (window()->isTopLevel() && window()->isVisible() && window()->isActive()) + static_cast<QIOSScreen *>(screen())->updateStatusBarVisibility(); switch (state) { case Qt::WindowNoState: - setGeometry(m_normalGeometry); + applyGeometry(m_normalGeometry); break; case Qt::WindowMaximized: - setGeometry(screen()->availableGeometry()); + applyGeometry(screen()->availableGeometry()); break; case Qt::WindowFullScreen: - setGeometry(screen()->geometry()); + applyGeometry(screen()->geometry()); break; case Qt::WindowMinimized: - setGeometry(QRect()); + applyGeometry(QRect()); break; case Qt::WindowActive: Q_UNREACHABLE(); @@ -486,6 +624,23 @@ void QIOSWindow::setParent(const QPlatformWindow *parentWindow) } } +QIOSWindow *QIOSWindow::topLevelWindow() const +{ + QWindow *window = this->window(); + while (window) { + QWindow *parent = window->parent(); + if (!parent) + parent = window->transientParent(); + + if (!parent) + break; + + window = parent; + } + + return static_cast<QIOSWindow *>(window->handle()); +} + void QIOSWindow::requestActivateWindow() { // Note that several windows can be active at the same time if they exist in the same @@ -499,8 +654,6 @@ void QIOSWindow::requestActivateWindow() if (window()->isTopLevel()) raise(); - QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); - static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view); QWindowSystemInterface::handleWindowActivated(window()); } diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index aeacbeef69..bc7219de5c 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -2,9 +2,6 @@ TARGET = qqnx QT += platformsupport-private core-private gui-private -# The PPS based platform integration is currently used for both BB10 and plain QNX -CONFIG += qqnx_pps - # Uncomment this to build with support for IMF once it becomes available in the BBNDK #CONFIG += qqnx_imf @@ -132,7 +129,8 @@ CONFIG(qqnx_pps) { qqnxclipboard.h \ qqnxbuttoneventnotifier.h - LIBS += -lpps -lclipboard + LIBS += -lpps + !contains(DEFINES, QT_NO_CLIPBOARD): LIBS += -lclipboard CONFIG(qqnx_imf) { DEFINES += QQNX_IMF diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp index 6afc3cad21..b57227a60b 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -58,12 +58,13 @@ QT_BEGIN_NAMESPACE QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow) : QQnxWindow(window, context, needRootWindow), - m_requestedBufferSize(window->geometry().size()), m_platformOpenGLContext(0), m_newSurfaceRequested(true), m_eglSurface(EGL_NO_SURFACE) { initWindow(); + m_requestedBufferSize = screen()->rootWindow() == this ? + screen()->geometry().size() : window->geometry().size(); } QQnxEglWindow::~QQnxEglWindow() @@ -145,6 +146,9 @@ EGLSurface QQnxEglWindow::getSurface() void QQnxEglWindow::setGeometry(const QRect &rect) { + //If this is the root window, it has to be shown fullscreen + const QRect &newGeometry = screen()->rootWindow() == this ? screen()->geometry() : rect; + //We need to request that the GL context updates // the EGLsurface on which it is rendering. { @@ -152,11 +156,11 @@ void QQnxEglWindow::setGeometry(const QRect &rect) // setting m_requestedBufferSize and therefore extended the scope to include // that test. const QMutexLocker locker(&m_mutex); - m_requestedBufferSize = rect.size(); - if (m_platformOpenGLContext != 0 && bufferSize() != rect.size()) + m_requestedBufferSize = newGeometry.size(); + if (m_platformOpenGLContext != 0 && bufferSize() != newGeometry.size()) m_newSurfaceRequested.testAndSetRelease(false, true); } - QQnxWindow::setGeometry(rect); + QQnxWindow::setGeometry(newGeometry); } QSize QQnxEglWindow::requestedBufferSize() const diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 1e58d482d4..b25c0b5b29 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -136,7 +136,7 @@ void QQnxWindow::setGeometry(const QRect &rect) // Calling flushWindowSystemEvents() here would flush input events which // could result in re-entering QQnxWindow::setGeometry() again. - QWindowSystemInterface::setSynchronousWindowsSystemEvents(true); //This does not work + QWindowSystemInterface::setSynchronousWindowsSystemEvents(true); QWindowSystemInterface::handleGeometryChange(window(), newGeometry); QWindowSystemInterface::handleExposeEvent(window(), newGeometry); QWindowSystemInterface::setSynchronousWindowsSystemEvents(false); @@ -608,13 +608,15 @@ void QQnxWindow::initWindow() setWindowState(window()->windowState()); if (window()->parent() && window()->parent()->handle()) setParent(window()->parent()->handle()); - setGeometryHelper(window()->geometry()); + if (screen()->rootWindow() == this) { - setGeometry(screen()->geometry()); + setGeometryHelper(screen()->geometry()); + QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry()); + } else { + setGeometryHelper(window()->geometry()); } } - void QQnxWindow::createWindowGroup() { // Generate a random window group name diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index e2594207fe..2743ef029d 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -86,6 +86,10 @@ QWindowsKeyMapper::~QWindowsKeyMapper() #define VK_OEM_3 0xC0 #endif +// We not only need the scancode itself but also the extended bit of key messages. Thus we need +// the additional bit when masking the scancode. +enum { scancodeBitmask = 0x1ff }; + // Key recorder ------------------------------------------------------------------------[ start ] -- struct KeyRecord { KeyRecord(int c, int a, int s, const QString &t) : code(c), ascii(a), state(s), text(t) {} @@ -567,7 +571,7 @@ void QWindowsKeyMapper::updateKeyMap(const MSG &msg) { unsigned char kbdBuffer[256]; // Will hold the complete keyboard state GetKeyboardState(kbdBuffer); - const quint32 scancode = (msg.lParam >> 16) & 0xff; + const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; updatePossibleKeyCodes(kbdBuffer, scancode, msg.wParam); } @@ -754,7 +758,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms { const int msgType = msg.message; - const quint32 scancode = (msg.lParam >> 16) & 0xff; + const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; const quint32 vk_key = msg.wParam; quint32 nModifiers = 0; diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index e6fa8fc898..e504d93fba 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -415,12 +415,17 @@ bool QGLXContext::m_supportsThreading = true; // If this list grows to any significant size, change it a // proper string table and make the implementation below use // binary search. -static const char *qglx_threadedgl_blacklist[] = { +static const char *qglx_threadedgl_blacklist_renderer[] = { "Chromium", // QTBUG-32225 (initialization fails) "Mesa DRI Intel(R) Sandybridge Mobile", // QTBUG-34492 (flickering in fullscreen) 0 }; +static const char *qglx_threadedgl_blacklist_vendor[] = { + "nouveau", // QTCREATORBUG-10875 (crash in creator) + 0 +}; + void QGLXContext::queryDummyContext() { if (m_queriedDummyContext) @@ -437,8 +442,8 @@ void QGLXContext::queryDummyContext() oldSurface = oldContext->surface(); QScopedPointer<QSurface> surface; - const char *vendor = glXGetClientString(glXGetCurrentDisplay(), GLX_VENDOR); - if (vendor && !strcmp(vendor, "ATI")) { + const char *glxvendor = glXGetClientString(glXGetCurrentDisplay(), GLX_VENDOR); + if (glxvendor && !strcmp(glxvendor, "ATI")) { QWindow *window = new QWindow; window->resize(64, 64); window->setSurfaceType(QSurface::OpenGLSurface); @@ -454,11 +459,19 @@ void QGLXContext::queryDummyContext() context.create(); context.makeCurrent(surface.data()); + m_supportsThreading = true; + const char *renderer = (const char *) glGetString(GL_RENDERER); + for (int i = 0; qglx_threadedgl_blacklist_renderer[i]; ++i) { + if (strstr(renderer, qglx_threadedgl_blacklist_renderer[i]) != 0) { + m_supportsThreading = false; + break; + } + } - m_supportsThreading = true; - for (int i = 0; qglx_threadedgl_blacklist[i]; ++i) { - if (strstr(renderer, qglx_threadedgl_blacklist[i]) != 0) { + const char *vendor = (const char *) glGetString(GL_VENDOR); + for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { + if (strstr(vendor, 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 cc8c42f96b..4d2735ca85 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1749,10 +1749,26 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub return true; } -bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode) +// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: +// - "pad0" became "extension" +// - "pad1" and "pad" became "pad0" +// New and old version of this struct share the following fields: +// NOTE: API might change again in the next release of xcb in which case this comment will +// need to be updated to reflect the reality. +typedef struct qt_xcb_ge_event_t { + uint8_t response_type; + uint8_t extension; + uint16_t sequence; + uint32_t length; + uint16_t event_type; +} qt_xcb_ge_event_t; + +bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCode) { - // xGenericEvent has "extension" on the second byte, xcb_ge_event_t has "pad0". - if (event->pad0 == opCode) { + qt_xcb_ge_event_t *event = (qt_xcb_ge_event_t *)ev; + // xGenericEvent has "extension" on the second byte, the same is true for xcb_ge_event_t starting from + // the xcb version 1.9.3, prior to that it was called "pad0". + if (event->extension == opCode) { // xcb event structs contain stuff that wasn't on the wire, the full_sequence field // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes. // Move this data back to have the same layout in memory as it was on the wire |