diff options
Diffstat (limited to 'src/plugins')
50 files changed, 1066 insertions, 362 deletions
diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp index 9bdb1decde..a45c199419 100644 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -653,6 +653,8 @@ void *QAccessibleLineEdit::interface_cast(QAccessible::InterfaceType t) { if (t == QAccessible::TextInterface) return static_cast<QAccessibleTextInterface*>(this); + if (t == QAccessible::EditableTextInterface) + return static_cast<QAccessibleEditableTextInterface*>(this); return QAccessibleWidget::interface_cast(t); } @@ -784,6 +786,21 @@ void QAccessibleLineEdit::scrollToSubstring(int startIndex, int endIndex) lineEdit()->setCursorPosition(startIndex); } +void QAccessibleLineEdit::deleteText(int startOffset, int endOffset) +{ + lineEdit()->setText(lineEdit()->text().remove(startOffset, endOffset - startOffset)); +} + +void QAccessibleLineEdit::insertText(int offset, const QString &text) +{ + lineEdit()->setText(lineEdit()->text().insert(offset, text)); +} + +void QAccessibleLineEdit::replaceText(int startOffset, int endOffset, const QString &text) +{ + lineEdit()->setText(lineEdit()->text().replace(startOffset, endOffset - startOffset, text)); +} + #endif // QT_NO_LINEEDIT #ifndef QT_NO_PROGRESSBAR diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index 7891e13c20..2e1bca88b4 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -137,7 +137,7 @@ private: #endif #ifndef QT_NO_LINEEDIT -class QAccessibleLineEdit : public QAccessibleWidget, public QAccessibleTextInterface +class QAccessibleLineEdit : public QAccessibleWidget, public QAccessibleTextInterface, public QAccessibleEditableTextInterface { public: explicit QAccessibleLineEdit(QWidget *o, const QString &name = QString()); @@ -168,6 +168,10 @@ public: int characterCount() const; void scrollToSubstring(int startIndex, int endIndex); + // QAccessibleEditableTextInterface + void deleteText(int startOffset, int endOffset); + void insertText(int offset, const QString &text); + void replaceText(int startOffset, int endOffset, const QString &text); protected: QLineEdit *lineEdit() const; }; diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 3ea5dc2d1c..ce46c46b0e 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -37,6 +37,7 @@ OBJECTIVE_SOURCES += main.mm \ qcocoainputcontext.mm \ qcocoaservices.mm \ qcocoasystemtrayicon.mm \ + qcocoaintrospection.mm \ HEADERS += qcocoaintegration.h \ qcocoatheme.h \ @@ -70,6 +71,7 @@ HEADERS += qcocoaintegration.h \ qcocoainputcontext.h \ qcocoaservices.h \ qcocoasystemtrayicon.h \ + qcocoaintrospection.h \ RESOURCES += qcocoaresources.qrc diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h index ad2267c6bf..e2a64331ac 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h @@ -44,6 +44,18 @@ #include <Cocoa/Cocoa.h> #include <QtGui> +#include <qpa/qplatformaccessibility.h> + +class QCococaAccessibility : public QPlatformAccessibility +{ +public: + QCococaAccessibility(); + ~QCococaAccessibility(); + void notifyAccessibilityUpdate(QAccessibleEvent *event); + void setRootObject(QObject *o); + void initialize(); + void cleanup(); +}; namespace QCocoaAccessible { @@ -52,9 +64,9 @@ namespace QCocoaAccessible { Cocoa accessibility is implemented in the following files: + - qcocoaaccessibility (this file) : QCocoaAccessibility "plugin", conversion and helper functions. - qnsviewaccessibility : Root accessibility implementation for QNSView - qcocoaaccessibilityelement : Cocoa accessibility protocol wrapper for QAccessibleInterface - - qcocoaaccessibility (this file) : Conversion and helper functions. The accessibility implementation wraps QAccessibleInterfaces in QCocoaAccessibleElements, which implements the cocoa accessibility protocol. The root QAccessibleInterface (the one returned @@ -70,6 +82,8 @@ bool shouldBeIgnrored(QAccessibleInterface *interface); NSString *getTranslatedAction(const QString &qtAction); NSMutableArray *createTranslatedActionsList(const QStringList &qtActions); QString translateAction(NSString *nsAction); +bool hasValueAttribute(QAccessibleInterface *interface); +id getValueAttribute(QAccessibleInterface *interface); } diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 4b897fc211..66cb979031 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -39,6 +39,60 @@ ** ****************************************************************************/ #include "qcocoaaccessibility.h" +#include "qcocoaaccessibilityelement.h" +#include <qaccessible.h> +#include <qaccessible2.h> +#include <private/qcore_mac_p.h> + +QCococaAccessibility::QCococaAccessibility() +{ + +} + +QCococaAccessibility::~QCococaAccessibility() +{ + +} + +void QCococaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) +{ + QObject *object = event->object(); + if (!object) + return; + + QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object); + if (!interface) + return; + + switch (event->type()) { + case QAccessible::ValueChanged: + case QAccessible::TextInserted : + case QAccessible::TextRemoved : + case QAccessible::TextUpdated : { + QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithInterface : interface parent : nil]; + NSAccessibilityPostNotification(element, NSAccessibilityValueChangedNotification); + break; } + + default: + delete interface; + break; + } +} + +void QCococaAccessibility::setRootObject(QObject *o) +{ + Q_UNUSED(o) +} + +void QCococaAccessibility::initialize() +{ + +} + +void QCococaAccessibility::cleanup() +{ + +} namespace QCocoaAccessible { @@ -218,4 +272,43 @@ QString translateAction(NSString *nsAction) return QString(); } +bool hasValueAttribute(QAccessibleInterface *interface) +{ + const QAccessible::Role qtrole = interface->role(); + if (qtrole == QAccessible::EditableText + || interface->valueInterface()) { + return true; + } + + return false; +} + +id getValueAttribute(QAccessibleInterface *interface) +{ + const QAccessible::Role qtrole = interface->role(); + if (qtrole == QAccessible::EditableText) { + if (QAccessibleTextInterface *textInterface = interface->textInterface()) { + // VoiceOver will read out the entire text string at once when returning + // text as a value. For large text edits the size of the returned string + // needs to be limited and text range attributes need to be used instead. + // NSTextEdit returns the first sentence as the value, Do the same here: + int begin = 0; + int end = textInterface->characterCount(); + // ### call to textAfterOffset hangs. Booo! + //if (textInterface->characterCount() > 0) + // textInterface->textAfterOffset(0, QAccessible2::SentenceBoundary, &begin, &end); + + QString text = textInterface->text(begin, end); + //qDebug() << "text" << begin << end << text; + return QCFString::toNSString(text); + } + } + + if (QAccessibleValueInterface *valueInterface = interface->valueInterface()) { + return QCFString::toNSString(QString::number(valueInterface->currentValue().toDouble())); + } + + return nil; +} + } // namespace QCocoaAccessible diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index c39290357e..cc1d393029 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -96,9 +96,9 @@ static QAccessibleInterface *acast(void *ptr) // attributes - (NSArray *)accessibilityAttributeNames { - static NSArray *attributes = nil; - if (attributes == nil) { - attributes = [[NSArray alloc] initWithObjects: + static NSArray *defaultAttributes = nil; + if (defaultAttributes == nil) { + defaultAttributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, NSAccessibilityRoleDescriptionAttribute, NSAccessibilityChildrenAttribute, @@ -112,6 +112,14 @@ static QAccessibleInterface *acast(void *ptr) NSAccessibilityEnabledAttribute, nil]; } + + NSMutableArray *attributes = [[NSMutableArray alloc] initWithCapacity : [defaultAttributes count]]; + [attributes addObjectsFromArray : defaultAttributes]; + + if (QCocoaAccessible::hasValueAttribute(acast(accessibleInterface))) { + [attributes addObject : NSAccessibilityValueAttribute]; + } + return attributes; } @@ -153,6 +161,13 @@ static QAccessibleInterface *acast(void *ptr) return QCFString::toNSString(acast(accessibleInterface)->text(QAccessible::Name)); } else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) { return [NSNumber numberWithBool:!acast(accessibleInterface)->state().disabled]; + } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + // VoiceOver asks for the value attribute for all elements. Return nil + // if we don't want the element to have a value attribute. + if (!QCocoaAccessible::hasValueAttribute(acast(accessibleInterface))) + return nil; + + return QCocoaAccessible::getValueAttribute(acast(accessibleInterface)); } return nil; diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h index 783edada77..66700281ac 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.h +++ b/src/plugins/platforms/cocoa/qcocoaapplication.h @@ -102,13 +102,14 @@ - (BOOL)qt_filterEvent:(NSEvent *)event; @end -@interface QNSApplication : NSApplication { +@interface QT_MANGLE_NAMESPACE(QNSApplication) : NSApplication { } @end QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent(); +void qt_resetNSApplicationSendEvent(); QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm index 5b646d8942..a50c480f1f 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm @@ -75,6 +75,7 @@ #include <qcocoaapplication.h> +#include <qcocoaintrospection.h> #include <qcocoaapplicationdelegate.h> #include <qcocoahelpers.h> #include <qguiapplication.h> @@ -107,8 +108,6 @@ QT_USE_NAMESPACE - (void)qt_sendPostedMessage:(NSEvent *)event { - Q_UNUSED(event); -/* // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! // That is why we need to split the address in two parts: quint64 lower = [event data1]; @@ -131,14 +130,14 @@ QT_USE_NAMESPACE } delete args; -*/ } +static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSEvent"); + - (BOOL)qt_filterEvent:(NSEvent *)event { - Q_UNUSED(event); -/* - if (qApp && qApp->macEventFilter(0, reinterpret_cast<EventRef>(event))) + if (qApp && qApp->eventDispatcher()-> + filterNativeEvent(q_macLocalEventType, static_cast<void*>(event), 0)) return true; if ([event type] == NSApplicationDefined) { @@ -150,13 +149,13 @@ QT_USE_NAMESPACE break; } } -*/ + return false; } @end -@implementation QNSApplication +@implementation QT_MANGLE_NAMESPACE(QNSApplication) - (void)qt_sendEvent_original:(NSEvent *)event { @@ -190,8 +189,7 @@ QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent() { -/* - if ([NSApp isMemberOfClass:[QNSApplication class]]) { + if ([NSApp isMemberOfClass:[QT_MANGLE_NAMESPACE(QNSApplication) class]]) { // No need to change implementation since Qt // already controls a subclass of NSApplication return; @@ -204,10 +202,16 @@ void qt_redirectNSApplicationSendEvent() qt_cocoa_change_implementation( [NSApplication class], @selector(sendEvent:), - [QNSApplication class], + [QT_MANGLE_NAMESPACE(QNSApplication) class], @selector(qt_sendEvent_replacement:), @selector(qt_sendEvent_original:)); - */ } +void qt_resetNSApplicationSendEvent() +{ + qt_cocoa_change_back_implementation([NSApplication class], + @selector(sendEvent:), + @selector(QT_MANGLE_NAMESPACE(qt_sendEvent_original):)); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 3023100d93..d44ff0fae1 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -344,12 +344,6 @@ static void cleanupCocoaApplicationDelegate() */ } -- (void)applicationDidChangeScreenParameters:(NSNotification *)notification -{ - Q_UNUSED(notification); - ((QCocoaIntegration*)QGuiApplicationPrivate::platformIntegration())->updateScreens(); -} - - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate { [oldDelegate retain]; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index eb0eb77905..ef67275208 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -73,15 +73,12 @@ void QCocoaBackingStore::flush(QWindow *widget, const QRegion ®ion, const QPo NSRect rect = NSMakeRect(geo.x(), geo.y(), geo.width(), geo.height()); QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle()); if (cocoaWindow) { - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { - // Workaround for malfunctioning displayRect on 10.8 where - // calling it seems to have no effect. Call setImage like - // resize() does. - [cocoaWindow->m_contentView setImage:m_image]; - } -#endif + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { + // Workaround for malfunctioning displayRect on 10.8 where + // calling it seems to have no effect. Call setImage like + // resize() does. + [cocoaWindow->m_contentView setImage:m_image]; + } [cocoaWindow->m_contentView displayRect:rect]; } } diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 45c35cccbf..de98d5219e 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -99,6 +99,7 @@ void qt_mac_transformProccessToForegroundApplication(); QString qt_mac_removeMnemonics(const QString &original); CGColorSpaceRef qt_mac_genericColorSpace(); CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget); +CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice); QString qt_mac_applicationName(); inline int qt_mac_flipYCoordinate(int y) @@ -129,6 +130,36 @@ bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); // accelerators. QString qt_mac_removeAmpersandEscapes(QString s); +enum { + QtCocoaEventSubTypeWakeup = SHRT_MAX, + QtCocoaEventSubTypePostMessage = SHRT_MAX-1 +}; + +class QCocoaPostMessageArgs { +public: + id target; + SEL selector; + int argCount; + id arg1; + id arg2; + QCocoaPostMessageArgs(id target, SEL selector, int argCount=0, id arg1=0, id arg2=0) + : target(target), selector(selector), argCount(argCount), arg1(arg1), arg2(arg2) + { + [target retain]; + [arg1 retain]; + [arg2 retain]; + } + + ~QCocoaPostMessageArgs() + { + [arg2 release]; + [arg1 release]; + [target release]; + } +}; + +CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); + QT_END_NAMESPACE #endif //QCOCOAHELPERS_H diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index bd89f26fca..0a8da0a956 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -48,6 +48,10 @@ #include <qpa/qplatformscreen.h> #include <private/qguiapplication_p.h> +#ifndef QT_NO_WIDGETS +#include <QtWidgets/QWidget> +#endif + QT_BEGIN_NAMESPACE // @@ -551,6 +555,17 @@ void qt_mac_cleanUpMacColorSpaces() m_displayColorSpaceHash.clear(); } +CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice) +{ +#ifdef QT_NO_WIDGETS + return qt_mac_displayColorSpace(0); +#else + bool isWidget = (paintDevice->devType() == QInternal::Widget); + return qt_mac_displayColorSpace(isWidget ? static_cast<const QWidget *>(paintDevice): 0); +#endif + +} + QString qt_mac_applicationName() { QString appName; @@ -696,4 +711,44 @@ QString qt_mac_removeAmpersandEscapes(QString s) return s.trimmed(); } +/*! \internal + + Returns the CoreGraphics CGContextRef of the paint device. 0 is + returned if it can't be obtained. It is the caller's responsibility to + CGContextRelease the context when finished using it. + + \warning This function is only available on Mac OS X. + \warning This function is duplicated in qmacstyle_mac.mm + */ +CGContextRef qt_mac_cg_context(const QPaintDevice *pdev) +{ + if (pdev->devType() == QInternal::Pixmap) { + const QPixmap *pm = static_cast<const QPixmap*>(pdev); + CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev); + uint flags = kCGImageAlphaPremultipliedFirst; + flags |= kCGBitmapByteOrder32Host; + CGContextRef ret = 0; + + QPlatformPixmap *data = const_cast<QPixmap *>(pm)->data_ptr().data(); + if (data && data->classId() == QPlatformPixmap::RasterClass) { + QImage *image = data->buffer(); + ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(), + 8, image->bytesPerLine(), colorspace, flags); + } else { + qDebug() << "qt_mac_cg_context: Unsupported pixmap class"; + } + + CGContextTranslateCTM(ret, 0, pm->height()); + CGContextScaleCTM(ret, 1, -1); + return ret; + } else if (pdev->devType() == QInternal::Widget) { + //CGContextRef ret = static_cast<CGContextRef>(static_cast<const QWidget *>(pdev)->macCGHandle()); + ///CGContextRetain(ret); + //return ret; + qDebug() << "qt_mac_cg_context: not implemented: Widget class"; + return 0; + } + return 0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 481055aae4..83c3efb2c6 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -53,6 +53,7 @@ #include "qcocoatheme.h" #include "qcocoainputcontext.h" #include "qmacmime.h" +#include "qcocoaaccessibility.h" #include <qpa/qplatformaccessibility.h> #include <QtCore/qcoreapplication.h> @@ -97,9 +98,8 @@ void QCocoaScreen::updateGeometry() CGDirectDisplayID dpy = [[devDesc objectForKey:@"NSScreenNumber"] unsignedIntValue]; CGSize size = CGDisplayScreenSize(dpy); m_physicalSize = QSizeF(size.width, size.height); - NSSize resolution = [[devDesc valueForKey:NSDeviceResolution] sizeValue]; - m_logicalDpi.first = resolution.width; - m_logicalDpi.second = resolution.height; + m_logicalDpi.first = 72; + m_logicalDpi.second = 72; m_refreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(dpy)); // Get m_name (brand/model of the monitor) @@ -110,7 +110,7 @@ void QCocoaScreen::updateGeometry() [deviceInfo release]; QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry()); - QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), resolution.width, resolution.height); + QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second); QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate); QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), availableGeometry()); } @@ -181,7 +181,7 @@ QCocoaIntegration::QCocoaIntegration() , mEventDispatcher(new QCocoaEventDispatcher()) , mInputContext(new QCocoaInputContext) #ifndef QT_NO_ACCESSIBILITY - , mAccessibility(new QPlatformAccessibility) + , mAccessibility(new QCococaAccessibility) #endif , mCocoaClipboard(new QCocoaClipboard) , mCocoaDrag(new QCocoaDrag) @@ -193,7 +193,8 @@ QCocoaIntegration::QCocoaIntegration() qApp->setAttribute(Qt::AA_DontUseNativeMenuBar, false); - NSApplication *cocoaApplication = [NSApplication sharedApplication]; + NSApplication *cocoaApplication = [QT_MANGLE_NAMESPACE(QNSApplication) sharedApplication]; + qt_redirectNSApplicationSendEvent(); if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { // Applications launched from plain executables (without an app @@ -234,6 +235,8 @@ QCocoaIntegration::QCocoaIntegration() QCocoaIntegration::~QCocoaIntegration() { + qt_resetNSApplicationSendEvent(); + QCocoaAutoReleasePool pool; if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) { // remove the apple event handlers installed by QCocoaApplicationDelegate diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.h b/src/plugins/platforms/cocoa/qcocoaintrospection.h new file mode 100644 index 0000000000..ffe3d96290 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaintrospection.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (c) 2007-2008, Apple, Inc. +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * Neither the name of Apple, Inc. nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#include <qglobal.h> +#import <objc/objc-class.h> + +QT_BEGIN_NAMESPACE + +void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel = 0, SEL backupSel = 0); +void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL backupSel); + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.mm b/src/plugins/platforms/cocoa/qcocoaintrospection.mm new file mode 100644 index 0000000000..e1af986487 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaintrospection.mm @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (c) 2007-2008, Apple, Inc. +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * Neither the name of Apple, Inc. nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#include "qcocoaintrospection.h" + +QT_BEGIN_NAMESPACE + +void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel, SEL backupSel) +{ +#ifndef QT_MAC_USE_COCOA + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) +#endif + { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + // The following code replaces the _implementation_ for the selector we want to hack + // (originalSel) with the implementation found in proxyClass. Then it creates + // a new 'backup' method inside baseClass containing the old, original, + // implementation (fakeSel). You can let the proxy implementation of originalSel + // call fakeSel if needed (similar approach to calling a super class implementation). + // fakeSel must also be implemented in proxyClass, as the signature is used + // as template for the method one we add into baseClass. + // NB: You will typically never create any instances of proxyClass; we use it + // only for stealing its contents and put it into baseClass. + if (!replacementSel) + replacementSel = originalSel; + + Method originalMethod = class_getInstanceMethod(baseClass, originalSel); + Method replacementMethod = class_getInstanceMethod(proxyClass, replacementSel); + IMP originalImp = method_setImplementation(originalMethod, method_getImplementation(replacementMethod)); + + if (backupSel) { + Method backupMethod = class_getInstanceMethod(proxyClass, backupSel); + class_addMethod(baseClass, backupSel, originalImp, method_getTypeEncoding(backupMethod)); + } +#endif + } +} + +void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL backupSel) +{ +#ifndef QT_MAC_USE_COCOA + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) +#endif + { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + Method originalMethod = class_getInstanceMethod(baseClass, originalSel); + Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel); + method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass)); +#endif + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 36d5c81f34..676f0683fa 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -45,6 +45,13 @@ #include "qcocoaautoreleasepool.h" #include <QtCore/QtDebug> +#include "qcocoaapplication.h" +#include "qcocoamenuloader.h" + +static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +{ + return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; +} @interface QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) : NSObject <NSMenuDelegate> { QCocoaMenu *m_menu; @@ -215,12 +222,19 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem) } bool wasMerged = cocoaItem->isMerged(); - NSMenuItem *oldItem = [m_nativeMenu itemWithTag:(NSInteger) cocoaItem]; + NSMenu *oldMenu = wasMerged ? [getMenuLoader() applicationMenu] : m_nativeMenu; + NSMenuItem *oldItem = [oldMenu itemWithTag:(NSInteger) cocoaItem]; if (cocoaItem->sync() != oldItem) { // native item was changed for some reason - if (!wasMerged && oldItem) - [m_nativeMenu removeItem:oldItem]; + if (oldItem) { + if (wasMerged) { + [oldItem setEnabled:NO]; + [oldItem setHidden:YES]; + } else { + [m_nativeMenu removeItem:oldItem]; + } + } QCocoaMenuItem* beforeItem = itemOrNull(m_menuItems.indexOf(cocoaItem) + 1); insertNative(cocoaItem, beforeItem); diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 8434cb75e9..bae52c91b8 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -219,7 +219,7 @@ QList<QCocoaMenuItem*> QCocoaMenuBar::merged() const bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const { - if (active && (active->window()->windowModality() == Qt::NonModal)) + if (active && (active->window()->modality() == Qt::NonModal)) return false; if (m_window == active) { @@ -232,7 +232,7 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const // the menubar should be disabled. The exception in Qt is that if the // modal window is the only window on screen, then we enable the menu bar. foreach (QWindow *w, topWindows) { - if (w->isVisible() && w->windowModality() == Qt::ApplicationModal) { + if (w->isVisible() && w->modality() == Qt::ApplicationModal) { // check for other visible windows foreach (QWindow *other, topWindows) { if ((w != other) && (other->isVisible())) { diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 2cb15b141f..8a08924bda 100755 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -79,7 +79,6 @@ #include "qcocoasystemtrayicon.h" #include <qtemporaryfile.h> #include <qimagewriter.h> -#include <qapplication.h> #include <qdebug.h> #include "qcocoamenu.h" @@ -238,7 +237,7 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess return; QPixmap notificationIconPixmap = icon.pixmap(32, 32); QTemporaryFile notificationIconFile; - QString notificationType(QLatin1String("Notification")), notificationIcon, notificationApp(QApplication::applicationName()); + QString notificationType(QLatin1String("Notification")), notificationIcon, notificationApp(qt_mac_applicationName()); if (notificationApp.isEmpty()) notificationApp = QLatin1String("Application"); if (!notificationIconPixmap.isNull() && notificationIconFile.open()) { diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index db3a20c2be..a9ea135b3e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -66,6 +66,8 @@ class QT_PREPEND_NAMESPACE(QCocoaWindow); - (BOOL)canBecomeKeyWindow; @end +@class QNSWindowDelegate; + QT_BEGIN_NAMESPACE // QCocoaWindow // @@ -157,6 +159,7 @@ public: // for QNSView QNSView *m_contentView; NSWindow *m_nsWindow; + QNSWindowDelegate *m_nsWindowDelegate; Qt::WindowFlags m_windowFlags; Qt::WindowState m_synchedWindowState; Qt::WindowModality m_windowModality; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index de6e7dc43e..d17df81011 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -148,12 +148,10 @@ static bool isMouseEvent(NSEvent *ev) - (BOOL)canBecomeKeyWindow { - // Most panels can be come the key window. Exceptions are: - if (m_cocoaPlatformWindow->window()->windowType() == Qt::ToolTip) - return NO; - if (m_cocoaPlatformWindow->window()->windowType() == Qt::SplashScreen) - return NO; - return YES; + // Only tool windows should become key for popup types: + if (m_cocoaPlatformWindow->window()->type() == Qt::Tool) + return YES; + return NO; } - (void) sendEvent: (NSEvent*) theEvent @@ -186,6 +184,7 @@ static bool isMouseEvent(NSEvent *ev) QCocoaWindow::QCocoaWindow(QWindow *tlw) : QPlatformWindow(tlw) , m_nsWindow(0) + , m_nsWindowDelegate(0) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) , m_inConstructor(true) @@ -217,6 +216,7 @@ QCocoaWindow::~QCocoaWindow() clearNSWindow(m_nsWindow); [m_contentView release]; [m_nsWindow release]; + [m_nsWindowDelegate release]; } void QCocoaWindow::setGeometry(const QRect &rect) @@ -250,7 +250,7 @@ void QCocoaWindow::setVisible(bool visible) #endif if (visible) { // We need to recreate if the modality has changed as the style mask will need updating - if (m_windowModality != window()->windowModality()) + if (m_windowModality != window()->modality()) recreateWindow(parent()); QCocoaWindow *parentCocoaWindow = 0; if (window()->transientParent()) { @@ -262,8 +262,8 @@ void QCocoaWindow::setVisible(bool visible) // Register popup windows so that the parent window can // close them when needed. - if (window()->windowType() == Qt::Popup) { - // qDebug() << "transientParent and popup" << window()->windowType() << Qt::Popup << (window()->windowType() & Qt::Popup); + if (window()->type() == Qt::Popup) { + // qDebug() << "transientParent and popup" << window()->type() << Qt::Popup << (window()->type() & Qt::Popup); parentCocoaWindow->m_activePopupWindow = window(); } @@ -279,12 +279,12 @@ void QCocoaWindow::setVisible(bool visible) syncWindowState(window()->windowState()); if (window()->windowState() != Qt::WindowMinimized) { - if ((window()->windowModality() == Qt::WindowModal - || window()->windowType() == Qt::Sheet) + if ((window()->modality() == Qt::WindowModal + || window()->type() == Qt::Sheet) && parentCocoaWindow) { // show the window as a sheet [NSApp beginSheet:m_nsWindow modalForWindow:parentCocoaWindow->m_nsWindow modalDelegate:nil didEndSelector:nil contextInfo:nil]; - } else if (window()->windowModality() != Qt::NonModal) { + } else if (window()->modality() != Qt::NonModal) { // show the window as application modal QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); Q_ASSERT(cocoaEventDispatcher != 0); @@ -298,7 +298,7 @@ void QCocoaWindow::setVisible(bool visible) } // We want the events to properly reach the popup - if (window()->windowType() == Qt::Popup) + if (window()->type() == Qt::Popup) [(NSPanel *)m_nsWindow setWorksWhenModal:YES]; } } @@ -364,7 +364,7 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; if (flags == Qt::Window) { styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); - } else if ((flags & Qt::Dialog) && (window()->windowModality() != Qt::NonModal)) { + } else if ((flags & Qt::Dialog) && (window()->modality() != Qt::NonModal)) { styleMask = NSTitledWindowMask; } else if (!(flags & Qt::FramelessWindowHint)) { if (flags & Qt::WindowMaximizeButtonHint) @@ -433,7 +433,7 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) NSButton *iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton]; if (iconButton == nil) { - NSString *title = QCFString::toNSString(window()->windowTitle()); + NSString *title = QCFString::toNSString(window()->title()); [m_nsWindow setRepresentedURL:[NSURL fileURLWithPath:title]]; iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton]; } @@ -594,7 +594,7 @@ void QCocoaWindow::windowWillClose() bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const { if (type == Qt::Widget) - type = window()->windowType(); + type = window()->type(); if (type == Qt::Tool) return false; // Qt::Tool has the Popup bit set but isn't, at least on Mac. @@ -619,6 +619,8 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) [m_nsWindow close]; [m_nsWindow release]; m_nsWindow = 0; + [m_nsWindowDelegate release]; + m_nsWindowDelegate = 0; } if (!parentWindow) { @@ -628,8 +630,8 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) // QPlatformWindow subclasses must sync up with QWindow on creation: propagateSizeHints(); - setWindowFlags(window()->windowFlags()); - setWindowTitle(window()->windowTitle()); + setWindowFlags(window()->flags()); + setWindowTitle(window()->title()); setWindowState(window()->windowState()); } else { // Child windows have no NSWindow, link the NSViews instead. @@ -644,8 +646,8 @@ NSWindow * QCocoaWindow::createNSWindow() NSRect frame = qt_mac_flipRect(window()->geometry(), window()); - Qt::WindowType type = window()->windowType(); - Qt::WindowFlags flags = window()->windowFlags(); + Qt::WindowType type = window()->type(); + Qt::WindowFlags flags = window()->flags(); NSUInteger styleMask = windowStyleMask(flags); NSWindow *createdWindow = 0; @@ -691,14 +693,14 @@ NSWindow * QCocoaWindow::createNSWindow() NSInteger level = windowLevel(flags); [createdWindow setLevel:level]; - m_windowModality = window()->windowModality(); + m_windowModality = window()->modality(); return createdWindow; } void QCocoaWindow::setNSWindow(NSWindow *window) { - QNSWindowDelegate *delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; - [window setDelegate:delegate]; + m_nsWindowDelegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; + [window setDelegate:m_nsWindowDelegate]; [window setAcceptsMouseMovedEvents:YES]; // Prevent Cocoa from releasing the window on close. Qt @@ -713,7 +715,9 @@ void QCocoaWindow::setNSWindow(NSWindow *window) name:nil // Get all notifications object:m_nsWindow]; + [m_contentView setPostsFrameChangedNotifications: NO]; [window setContentView:m_contentView]; + [m_contentView setPostsFrameChangedNotifications: YES]; } void QCocoaWindow::clearNSWindow(NSWindow *window) diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index e7c03726d6..e8d12abaed 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -193,7 +193,10 @@ QMacPasteboard::hasOSType(int c_flavor) const const int type_count = CFArrayGetCount(types); for (int i = 0; i < type_count; ++i) { CFStringRef flavor = (CFStringRef)CFArrayGetValueAtIndex(types, i); - const int os_flavor = UTGetOSTypeFromString(UTTypeCopyPreferredTagWithClass(flavor, kUTTagClassOSType)); + CFStringRef preferredTag = UTTypeCopyPreferredTagWithClass(flavor, kUTTagClassOSType); + const int os_flavor = UTGetOSTypeFromString(preferredTag); + if (preferredTag) + CFRelease(preferredTag); if (os_flavor == c_flavor) { #ifdef DEBUG_PASTEBOARD qDebug(" - Found!"); diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index d62913a7af..4fb099341e 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -263,6 +263,7 @@ static CGImageRef qt_mac_toCGImage(QImage *qImage, bool isMask, uchar **dataCopy kCGRenderingIntentDefault); CGColorSpaceRelease(cgColourSpaceRef); } + CGDataProviderRelease(cgDataProviderRef); return cgImage; } @@ -339,7 +340,7 @@ static CGImageRef qt_mac_toCGImage(QImage *qImage, bool isMask, uchar **dataCopy return YES; } -- (void)handleMouseEvent:(NSEvent *)theEvent +- (void)convertFromEvent:(NSEvent *)event toWindowPoint:(QPoint *)qtWindowPoint andScreenPoint:(QPoint *)qtScreenPoint { // Calculate the mouse position in the QWindow and Qt screen coordinate system, // starting from coordinates in the NSWindow coordinate system. @@ -359,25 +360,29 @@ static CGImageRef qt_mac_toCGImage(QImage *qImage, bool isMask, uchar **dataCopy // NSView and QWindow are equal coordinate systems: the QWindow covers the // entire NSView, and we've set the NSView's isFlipped property to true. - NSPoint nsWindowPoint = [theEvent locationInWindow]; // NSWindow coordinates + NSPoint nsWindowPoint = [event locationInWindow]; // NSWindow coordinates NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates - QPoint qtWindowPoint(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates - - QPoint qtScreenPoint; + *qtWindowPoint = QPoint(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates NSWindow *window = [self window]; // Use convertRectToScreen if available (added in 10.7). #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if ([window respondsToSelector:@selector(convertRectToScreen:)]) { NSRect screenRect = [window convertRectToScreen : NSMakeRect(nsWindowPoint.x, nsWindowPoint.y, 0, 0)]; // OS X screen coordinates - qtScreenPoint = QPoint(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y)); // Qt screen coordinates + *qtScreenPoint = QPoint(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y)); // Qt screen coordinates } else #endif { NSPoint screenPoint = [window convertBaseToScreen : NSMakePoint(nsWindowPoint.x, nsWindowPoint.y)]; - qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); + *qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); } +} + +- (void)handleMouseEvent:(NSEvent *)theEvent +{ + QPoint qtWindowPoint, qtScreenPoint; + [self convertFromEvent:theEvent toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); @@ -462,8 +467,9 @@ static CGImageRef qt_mac_toCGImage(QImage *qImage, bool isMask, uchar **dataCopy - (void)mouseEntered:(NSEvent *)theEvent { - Q_UNUSED(theEvent); - QWindowSystemInterface::handleEnterEvent(m_window); + QPoint windowPoint, screenPoint; + [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleEnterEvent(m_window, windowPoint, screenPoint); } - (void)mouseExited:(NSEvent *)theEvent diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 404c03dd30..5b83477881 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -116,13 +116,6 @@ void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig } } -CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice) -{ - bool isWidget = (paintDevice->devType() == QInternal::Widget); - return QCoreGraphicsPaintEngine::macDisplayColorSpace(isWidget ? static_cast<const QWidget *>(paintDevice) - : 0); -} - // Implemented for qt_mac_p.h QMacCGContext::QMacCGContext(QPainter *p) { @@ -206,46 +199,6 @@ CGAffineTransform qt_mac_convert_transform_to_cg(const QTransform &t) { return CGAffineTransformMake(t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy()); } -/*! \internal - - Returns the CoreGraphics CGContextRef of the paint device. 0 is - returned if it can't be obtained. It is the caller's responsibility to - CGContextRelease the context when finished using it. - - \warning This function is only available on Mac OS X. - \warning This function is duplicated in qmacstyle_mac.mm -*/ -CGContextRef qt_mac_cg_context(const QPaintDevice *pdev) -{ - if (pdev->devType() == QInternal::Pixmap) { - const QPixmap *pm = static_cast<const QPixmap*>(pdev); - CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev); - uint flags = kCGImageAlphaPremultipliedFirst; - flags |= kCGBitmapByteOrder32Host; - CGContextRef ret = 0; - - QPlatformPixmap *data = const_cast<QPixmap *>(pm)->data_ptr().data(); - if (data && data->classId() == QPlatformPixmap::RasterClass) { - QImage *image = data->buffer(); - ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(), - 8, image->bytesPerLine(), colorspace, flags); - } else { - qDebug() << "qt_mac_cg_context: Unsupported pixmap class"; - } - - CGContextTranslateCTM(ret, 0, pm->height()); - CGContextScaleCTM(ret, 1, -1); - return ret; - } else if (pdev->devType() == QInternal::Widget) { - //CGContextRef ret = static_cast<CGContextRef>(static_cast<const QWidget *>(pdev)->macCGHandle()); - ///CGContextRetain(ret); - //return ret; - qDebug() << "qt_mac_cg_context: not implemented: Widget class"; - return 0; - } - return 0; -} - inline static QCFType<CGColorRef> cgColorForQColor(const QColor &col, QPaintDevice *pdev) { CGFloat components[] = { diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index adb92741f9..d35ec935fd 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -130,6 +130,7 @@ QQnxIntegration::QQnxIntegration() #if !defined(QT_NO_CLIPBOARD) , m_clipboard(0) #endif + , m_navigator(0) #if !defined(QT_NO_DRAGANDDROP) , m_drag(new QSimpleDrag()) #endif diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 592586fde0..04fe558541 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -87,7 +87,7 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); #ifndef Q_OS_WINCE - if (rw->format().hasAlpha() && (window->windowFlags() & Qt::FramelessWindowHint)) { + if (rw->format().hasAlpha() && (window->flags() & Qt::FramelessWindowHint)) { const long wl = GetWindowLong(rw->handle(), GWL_EXSTYLE); if ((wl & WS_EX_LAYERED) == 0) SetWindowLong(rw->handle(), GWL_EXSTYLE, wl | WS_EX_LAYERED); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index a0749388f9..aaa5573899 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -374,7 +374,7 @@ void QWindowsContext::setKeyGrabber(QWindow *w) QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL) { - const Qt::WindowFlags flags = w ? w->windowFlags() : (Qt::WindowFlags)0; + const Qt::WindowFlags flags = w ? w->flags() : (Qt::WindowFlags)0; const Qt::WindowFlags type = flags & Qt::WindowType_Mask; uint style = 0; diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 323cff1646..76fe5f1a43 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -533,7 +533,7 @@ QWindowsFontEngineData::QWindowsFontEngineData() QWindowsFontEngineData::~QWindowsFontEngineData() { if (hdc) - ReleaseDC(0, hdc); + DeleteDC(hdc); #if !defined(QT_NO_DIRECTWRITE) if (directWriteGdiInterop) directWriteGdiInterop->Release(); diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 0e592aee7b..578a0cd20b 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -1110,7 +1110,7 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, SetGraphicsMode(hdc, GM_COMPATIBLE); SelectObject(hdc, old_font); - ReleaseDC(0, hdc); + DeleteDC(hdc); } #else // else wince unsigned int options = 0; @@ -1166,8 +1166,11 @@ QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xfo mask_format = QImage::Format_RGB32; QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format); - if (mask == 0) + if (mask == 0) { + if (m_fontEngineData->clearTypeEnabled) + DeleteObject(font); return QImage(); + } QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index a02f0cd494..f6011ae082 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -354,10 +354,10 @@ QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::Pixe QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const { QWindowsWindow::WindowData requested; - requested.flags = window->windowFlags(); + requested.flags = window->flags(); requested.geometry = window->geometry(); const QWindowsWindow::WindowData obtained - = QWindowsWindow::WindowData::create(window, requested, window->windowTitle()); + = QWindowsWindow::WindowData::create(window, requested, window->title()); if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) qDebug().nospace() << __FUNCTION__ << '<' << window << '\n' @@ -372,7 +372,7 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons if (!obtained.hwnd) return 0; if (requested.flags != obtained.flags) - window->setWindowFlags(obtained.flags); + window->setFlags(obtained.flags); return new QWindowsWindow(window, obtained); } diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index c11bd8c53c..5a11aee802 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -481,6 +481,14 @@ static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer, int code = 0; QChar unicodeBuffer[5]; int res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0); + // When Ctrl modifier is used ToUnicode does not return correct values. In order to assign the + // right key the control modifier is removed for just that function if the previous call failed. + if (res == 0 && kbdBuffer[VK_CONTROL]) { + const unsigned char controlState = kbdBuffer[VK_CONTROL]; + kbdBuffer[VK_CONTROL] = 0; + res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0); + kbdBuffer[VK_CONTROL] = controlState; + } if (res) code = unicodeBuffer[0].toUpper().unicode(); @@ -682,16 +690,16 @@ static void showSystemMenu(QWindow* w) #define enabled (MF_BYCOMMAND | MF_ENABLED) #define disabled (MF_BYCOMMAND | MF_GRAYED) - EnableMenuItem(menu, SC_MINIMIZE, (topLevel->windowFlags() & Qt::WindowMinimizeButtonHint)?enabled:disabled); + EnableMenuItem(menu, SC_MINIMIZE, (topLevel->flags() & Qt::WindowMinimizeButtonHint)?enabled:disabled); bool maximized = IsZoomed(topLevelHwnd); - EnableMenuItem(menu, SC_MAXIMIZE, ! (topLevel->windowFlags() & Qt::WindowMaximizeButtonHint) || maximized?disabled:enabled); + EnableMenuItem(menu, SC_MAXIMIZE, ! (topLevel->flags() & Qt::WindowMaximizeButtonHint) || maximized?disabled:enabled); EnableMenuItem(menu, SC_RESTORE, maximized?enabled:disabled); // We should _not_ check with the setFixedSize(x,y) case here, since Windows is not able to check // this and our menu here would be out-of-sync with the menu produced by mouse-click on the // System Menu, or right-click on the title bar. - EnableMenuItem(menu, SC_SIZE, (topLevel->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) || maximized?disabled:enabled); + EnableMenuItem(menu, SC_SIZE, (topLevel->flags() & Qt::MSWindowsFixedSizeDialogHint) || maximized?disabled:enabled); EnableMenuItem(menu, SC_MOVE, maximized?disabled:enabled); EnableMenuItem(menu, SC_CLOSE, enabled); // Set bold on close menu item diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 2d60c87438..d202da1d31 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -129,7 +129,9 @@ static inline void compressMouseMove(MSG *msg) QWindowsMouseHandler::QWindowsMouseHandler() : m_windowUnderMouse(0), m_trackedWindow(0), - m_touchDevice(0) + m_touchDevice(0), + m_leftButtonDown(false), + m_previousCaptureWindow(0) { } @@ -143,6 +145,10 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons() result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton; if (GetAsyncKeyState(VK_MBUTTON) < 0) result |= Qt::MidButton; + if (GetAsyncKeyState(VK_XBUTTON1) < 0) + result |= Qt::XButton1; + if (GetAsyncKeyState(VK_XBUTTON2) < 0) + result |= Qt::XButton2; return result; } @@ -164,7 +170,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, return false; // Allow further event processing (dragging of windows). } - *result = 0; if (msg.message == WM_MOUSELEAVE) { if (QWindowsContext::verboseEvents) @@ -185,6 +190,36 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + const Qt::MouseButtons buttons = keyStateToMouseButtons((int)msg.wParam); + + // If the window was recently resized via mouse doubleclick on the frame or title bar, + // we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click, + // but we will get at least one WM_MOUSEMOVE with left button down and the WM_LBUTTONUP, + // which will result undesired mouse press and release events. + // To avoid those, we ignore any events with left button down if we didn't + // get the original WM_LBUTTONDOWN/WM_LBUTTONDBLCLK. + if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONDBLCLK) { + m_leftButtonDown = true; + } else { + const bool actualLeftDown = buttons & Qt::LeftButton; + if (!m_leftButtonDown && actualLeftDown) { + // Autocapture the mouse for current window to and ignore further events until release. + // Capture is necessary so we don't get WM_MOUSELEAVEs to confuse matters. + // This autocapture is released normally when button is released. + if (!platformWindow->hasMouseCapture()) { + QWindowsWindow::baseWindowOf(window)->applyCursor(); + platformWindow->setMouseGrabEnabled(true); + platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); + if (QWindowsContext::verboseEvents) + qDebug() << "Automatic mouse capture for missing buttondown event" << window; + } + m_previousCaptureWindow = window; + return true; + } else if (m_leftButtonDown && !actualLeftDown) { + m_leftButtonDown = false; + } + } + const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition); QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ? QWindowsScreen::windowAt(globalPosition) : window; @@ -194,7 +229,9 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // any button press until release. if (!platformWindow->hasMouseCapture() && (msg.message == WM_LBUTTONDOWN || msg.message == WM_MBUTTONDOWN - || msg.message == WM_RBUTTONDOWN)) { + || msg.message == WM_RBUTTONDOWN || msg.message == WM_XBUTTONDOWN + || msg.message == WM_LBUTTONDBLCLK || msg.message == WM_MBUTTONDBLCLK + || msg.message == WM_RBUTTONDBLCLK || msg.message == WM_XBUTTONDBLCLK)) { platformWindow->setMouseGrabEnabled(true); platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); if (QWindowsContext::verboseEvents) @@ -202,27 +239,20 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } else if (platformWindow->hasMouseCapture() && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture) && (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP - || msg.message == WM_RBUTTONUP)) { + || msg.message == WM_RBUTTONUP || msg.message == WM_XBUTTONUP) + && !buttons) { platformWindow->setMouseGrabEnabled(false); if (QWindowsContext::verboseEvents) qDebug() << "Releasing automatic mouse capture " << window; } - // Eat mouse move after size grip drag. - if (msg.message == WM_MOUSEMOVE) { - if (platformWindow->testFlag(QWindowsWindow::SizeGripOperation)) { - MSG mouseMsg; - while (PeekMessage(&mouseMsg, platformWindow->handle(), WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) ; - platformWindow->clearFlag(QWindowsWindow::SizeGripOperation); - return true; - } - } + const bool hasCapture = platformWindow->hasMouseCapture(); + const bool currentNotCapturing = hasCapture && currentWindowUnderMouse != window; #ifndef Q_OS_WINCE // Enter new window: track to generate leave event. - // If there is an active capture, we must track the actual capture window instead of window - // under cursor or leaves will trigger constantly, so always track the window we got - // native mouse event for. - if (window != m_trackedWindow) { + // If there is an active capture, only track if the current window is capturing, + // so we don't get extra leave when cursor leaves the application. + if (window != m_trackedWindow && !currentNotCapturing) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; @@ -234,38 +264,53 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } #endif // !Q_OS_WINCE - // Qt expects enter/leave events for windows even when some window is capturing mouse input, - // except for automatic capture when mouse button is pressed - in that case enter/leave - // should be sent only after the last button is released. - // We need to track m_windowUnderMouse separately from m_trackedWindow, as - // Windows mouse tracking will not trigger WM_MOUSELEAVE for leaving window when - // mouse capture is set. - if (!platformWindow->hasMouseCapture() - || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) { - if (m_windowUnderMouse != currentWindowUnderMouse) { - if (m_windowUnderMouse) { - if (QWindowsContext::verboseEvents) - qDebug() << "Synthetic leave for " << m_windowUnderMouse; - QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse); - // Clear tracking if we are no longer over application, - // since we have already sent the leave. - if (!currentWindowUnderMouse) - m_trackedWindow = 0; - } - - if (currentWindowUnderMouse) { - if (QWindowsContext::verboseEvents) - qDebug() << "Entering " << currentWindowUnderMouse; - QWindowsWindow::baseWindowOf(currentWindowUnderMouse)->applyCursor(); - QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse); + // No enter or leave events are sent as long as there is an autocapturing window. + if (!hasCapture || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) { + // Leave is needed if: + // 1) There is no capture and we move from a window to another window. + // Note: Leaving the application entirely is handled in WM_MOUSELEAVE case. + // 2) There is capture and we move out of the capturing window. + // 3) There is a new capture and we were over another window. + if ((m_windowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse + && (!hasCapture || window == m_windowUnderMouse)) + || (hasCapture && m_previousCaptureWindow != window && m_windowUnderMouse + && m_windowUnderMouse != window)) { + if (QWindowsContext::verboseEvents) + qDebug() << "Synthetic leave for " << m_windowUnderMouse; + QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse); + if (currentNotCapturing) { + // Clear tracking if capturing and current window is not the capturing window + // to avoid leave when mouse actually leaves the application. + m_trackedWindow = 0; + // We are not officially in any window, but we need to set some cursor to clear + // whatever cursor the left window had, so apply the cursor of the capture window. + QWindowsWindow::baseWindowOf(window)->applyCursor(); } } + // Enter is needed if: + // 1) There is no capture and we move to a new window. + // 2) There is capture and we move into the capturing window. + // 3) The capture just ended and we are over non-capturing window. + if ((currentWindowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse + && (!hasCapture || currentWindowUnderMouse == window)) + || (m_previousCaptureWindow && window != m_previousCaptureWindow && currentWindowUnderMouse + && currentWindowUnderMouse != m_previousCaptureWindow)) { + if (QWindowsContext::verboseEvents) + qDebug() << "Entering " << currentWindowUnderMouse; + QWindowsWindow::baseWindowOf(currentWindowUnderMouse)->applyCursor(); + QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse, + currentWindowUnderMouse->mapFromGlobal(globalPosition), + globalPosition); + } + // We need to track m_windowUnderMouse separately from m_trackedWindow, as + // Windows mouse tracking will not trigger WM_MOUSELEAVE for leaving window when + // mouse capture is set. m_windowUnderMouse = currentWindowUnderMouse; } - QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, - keyStateToMouseButtons((int)msg.wParam), + QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, QWindowsKeyMapper::queryKeyboardModifiers()); + m_previousCaptureWindow = hasCapture ? window : 0; return true; } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index 1b19b34458..965deb4e0f 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -81,6 +81,8 @@ private: QPointer<QWindow> m_trackedWindow; QHash<DWORD, int> m_touchInputIDToTouchPointID; QTouchDevice *m_touchDevice; + bool m_leftButtonDown; + QWindow *m_previousCaptureWindow; }; Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam) diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 0717a8ec60..a09ab583c8 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -125,11 +125,19 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM Qt::PortraitOrientation : Qt::LandscapeOrientation; // EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only // virtual desktop screens. + data.name = QString::fromWCharArray(info.szDevice); data.flags = QWindowsScreenData::VirtualDesktop; - if (info.dwFlags & MONITORINFOF_PRIMARY) + if (info.dwFlags & MONITORINFOF_PRIMARY) { data.flags |= QWindowsScreenData::PrimaryScreen; - data.name = QString::fromWCharArray(info.szDevice); - result->append(data); + // QPlatformIntegration::screenAdded() documentation specifies that first + // added screen will be the primary screen, so order accordingly. + // Note that the side effect of this policy is that there is no way to change primary + // screen reported by Qt, unless we want to delete all existing screens and add them + // again whenever primary screen changes. + result->prepend(data); + } else { + result->append(data); + } return TRUE; } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 9aada91e73..25aae11d87 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -715,7 +715,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : setFlag(OpenGLSurface); QWindowsContext::instance()->addWindow(m_data.hwnd, this); if (aWindow->isTopLevel()) { - switch (aWindow->windowType()) { + switch (aWindow->type()) { case Qt::Window: case Qt::Dialog: case Qt::Sheet: @@ -893,8 +893,8 @@ void QWindowsWindow::show_sys() const int sm = SW_SHOWNORMAL; bool fakedMaximize = false; const QWindow *w = window(); - const Qt::WindowFlags flags = w->windowFlags(); - const Qt::WindowType type = w->windowType(); + const Qt::WindowFlags flags = w->flags(); + const Qt::WindowType type = w->type(); if (w->isTopLevel()) { const Qt::WindowState state = w->windowState(); if (state & Qt::WindowMinimized) { @@ -931,7 +931,7 @@ void QWindowsWindow::show_sys() const // partially from QWidgetPrivate::hide_sys() void QWindowsWindow::hide_sys() const { - const Qt::WindowFlags flags = window()->windowFlags(); + const Qt::WindowFlags flags = window()->flags(); if (flags != Qt::Desktop) { if (flags & Qt::Popup) ShowWindow(m_data.hwnd, SW_HIDE); @@ -979,7 +979,7 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const // to dialog frames, etc (see SetParent() ) if the top level state changes. if (wasTopLevel != isTopLevel) { const unsigned flags = isTopLevel ? unsigned(0) : unsigned(WindowCreationData::ForceChild); - setWindowFlags_sys(window()->windowFlags(), flags); + setWindowFlags_sys(window()->flags(), flags); } } } diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index 59d9ffe39b..2f666bebfd 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -1,5 +1,7 @@ Requires libxcb >= 1.5. +PACKAGE DEPENDENCIES + Required packages: libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev @@ -13,3 +15,9 @@ libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-d On Fedora, the following packages are required: libxcb libxcb-devel libXrender libXrender-devel xcb-util-wm xcb-util-wm-devel xcb-util xcb-util-devel xcb-util-image xcb-util-image-devel xcb-util-keysyms xcb-util-keysyms-devel + +REDUCING RUNTIME DEPENDENCIES + +The '-qt-xcb' configure option can be used to get rid of most xcb- dependencies. Only libxcb will +still be linked dynamically, since it will be most likely be pulled in via other dependencies anyway. +This should allow for binaries that are portable across most modern Linux distributions. diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index 8c300d6c19..10aaa5a3b5 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -86,6 +86,7 @@ static Window createDummyWindow(QXcbScreen *screen, XVisualInfo *visualInfo) 0, 0, 100, 100, 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBackPixel|CWBorderPixel|CWColormap, &a); + XFreeColormap(DISPLAY_FROM_XCB(screen), cmap); return window; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 85f6fc9213..405a16d488 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -58,6 +58,7 @@ #include <QTimer> #include <QByteArray> +#include <dlfcn.h> #include <stdio.h> #include <errno.h> #include <xcb/shm.h> @@ -281,17 +282,16 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char qFatal("QXcbConnection: Could not connect to display %s", m_displayName.constData()); m_reader = new QXcbEventReader(this); -#ifdef XCB_POLL_FOR_QUEUED_EVENT connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection); - m_reader->start(); -#else - QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents())); - - QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; - connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents())); - connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents())); -#endif + connect(m_reader, SIGNAL(finished()), this, SLOT(processXcbEvents())); + if (!m_reader->startThread()) { + QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents())); + + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents())); + connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents())); + } xcb_extension_t *extensions[] = { &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, @@ -363,10 +363,11 @@ QXcbConnection::~QXcbConnection() finalizeXInput2(); #endif -#ifdef XCB_POLL_FOR_QUEUED_EVENT - sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION); - m_reader->wait(); -#endif + if (m_reader->isRunning()) { + sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION); + m_reader->wait(); + } + delete m_reader; #ifdef XCB_USE_EGL @@ -807,14 +808,37 @@ void QXcbConnection::addPeekFunc(PeekFunc f) m_peekFuncs.append(f); } -#ifdef XCB_POLL_FOR_QUEUED_EVENT +QXcbEventReader::QXcbEventReader(QXcbConnection *connection) + : m_connection(connection) + , m_xcb_poll_for_queued_event(0) +{ +#ifdef RTLD_DEFAULT + m_xcb_poll_for_queued_event = (XcbPollForQueuedEventFunctionPointer)dlsym(RTLD_DEFAULT, "xcb_poll_for_queued_event"); +#endif + +#ifdef Q_XCB_DEBUG + if (m_xcb_poll_for_queued_event) + qDebug("Using threaded event reader with xcb_poll_for_queued_event"); +#endif +} + +bool QXcbEventReader::startThread() +{ + if (m_xcb_poll_for_queued_event) { + QThread::start(); + return true; + } + + return false; +} + void QXcbEventReader::run() { xcb_generic_event_t *event; while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) { m_mutex.lock(); addEvent(event); - while (m_connection && (event = xcb_poll_for_queued_event(m_connection->xcb_connection()))) + while (m_connection && (event = m_xcb_poll_for_queued_event(m_connection->xcb_connection()))) addEvent(event); m_mutex.unlock(); emit eventPending(); @@ -823,7 +847,6 @@ void QXcbEventReader::run() for (int i = 0; i < m_events.size(); ++i) free(m_events.at(i)); } -#endif void QXcbEventReader::addEvent(xcb_generic_event_t *event) { @@ -836,10 +859,10 @@ void QXcbEventReader::addEvent(xcb_generic_event_t *event) QXcbEventArray *QXcbEventReader::lock() { m_mutex.lock(); -#ifndef XCB_POLL_FOR_QUEUED_EVENT - while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection())) - m_events << event; -#endif + if (!m_xcb_poll_for_queued_event) { + while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection())) + m_events << event; + } return &m_events; } @@ -919,6 +942,12 @@ xcb_timestamp_t QXcbConnection::getTimestamp() void QXcbConnection::processXcbEvents() { + int connection_error = xcb_connection_has_error(xcb_connection()); + if (connection_error) { + qWarning("The X11 connection broke (error %d). Did the X11 server die?", connection_error); + exit(1); + } + QXcbEventArray *eventqueue = m_reader->lock(); for(int i = 0; i < eventqueue->size(); ++i) { @@ -932,6 +961,30 @@ void QXcbConnection::processXcbEvents() if (!response_type) { handleXcbError((xcb_generic_error_t *)event); } else { + if (response_type == XCB_MOTION_NOTIFY) { + // compress multiple motion notify events in a row + // to avoid swamping the event queue + xcb_generic_event_t *next = eventqueue->value(i+1, 0); + if (next && (next->response_type & ~0x80) == XCB_MOTION_NOTIFY) + continue; + } + + if (response_type == XCB_CONFIGURE_NOTIFY) { + // compress multiple configure notify events for the same window + bool found = false; + for (int j = i; j < eventqueue->size(); ++j) { + xcb_generic_event_t *other = eventqueue->at(j); + if (other && (other->response_type & ~0x80) == XCB_CONFIGURE_NOTIFY + && ((xcb_configure_notify_event_t *)other)->event == ((xcb_configure_notify_event_t *)event)->event) + { + found = true; + break; + } + } + if (found) + continue; + } + QVector<PeekFunc>::iterator it = m_peekFuncs.begin(); while (it != m_peekFuncs.end()) { // These callbacks return true if the event is what they were diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 8b2315c67e..c67acb3218 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -278,18 +278,15 @@ class QXcbEventReader : public QThread { Q_OBJECT public: - QXcbEventReader(QXcbConnection *connection) - : m_connection(connection) - { - } + QXcbEventReader(QXcbConnection *connection); -#ifdef XCB_POLL_FOR_QUEUED_EVENT void run(); -#endif QXcbEventArray *lock(); void unlock(); + bool startThread(); + signals: void eventPending(); @@ -299,6 +296,9 @@ private: QMutex m_mutex; QXcbEventArray m_events; QXcbConnection *m_connection; + + typedef xcb_generic_event_t * (*XcbPollForQueuedEventFunctionPointer)(xcb_connection_t *c); + XcbPollForQueuedEventFunctionPointer m_xcb_poll_for_queued_event; }; class QAbstractEventDispatcher; @@ -376,6 +376,8 @@ public: bool hasXRandr() const { return has_randr_extension; } bool hasInputShape() const { return has_input_shape; } + bool supportsThreadedRendering() const { return m_reader->isRunning(); } + xcb_timestamp_t getTimestamp(); private slots: diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 27a926eca2..cd7237e4b4 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -396,7 +396,7 @@ void QXcbDrag::move(const QMouseEvent *me) QXcbWindow *w = 0; if (target) { w = connection()->platformWindowFromId(target); - if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; } else { w = 0; @@ -507,7 +507,7 @@ void QXcbDrag::drop(const QMouseEvent *event) QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); - if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; Transaction t = { @@ -722,7 +722,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t p -= geometry.topLeft(); - if (!w || (w->windowType() == Qt::Desktop)) + if (!w || (w->type() == Qt::Desktop)) return; if (e->data.data32[0] != xdnd_dragsource) { @@ -912,7 +912,7 @@ void QXcbDrag::send_leave() QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); - if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; if (w) @@ -1157,7 +1157,7 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) DNDDEBUG << "xdndEnable" << w << on; if (on) { QXcbWindow *xdnd_widget = 0; - if ((w->window()->windowType() == Qt::Desktop)) { + if ((w->window()->type() == Qt::Desktop)) { if (desktop_proxy) // *WE* already have one. return false; @@ -1191,7 +1191,7 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) return false; } } else { - if ((w->window()->windowType() == Qt::Desktop)) { + if ((w->window()->type() == Qt::Desktop)) { xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::XdndProxy)); delete desktop_proxy; desktop_proxy = 0; @@ -1225,7 +1225,7 @@ QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type r QXcbConnection *c = drag->connection(); QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource); - if (xcb_window && drag->currentDrag() && xcb_window->window()->windowType() != Qt::Desktop) { + if (xcb_window && drag->currentDrag() && xcb_window->window()->type() != Qt::Desktop) { QMimeData *data = drag->currentDrag()->mimeData(); if (data->hasFormat(QLatin1String(format))) result = data->data(QLatin1String(format)); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 2ffe53c04b..22e5386937 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -214,7 +214,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const #else case OpenGL: return false; #endif - case ThreadedOpenGL: return false; + case ThreadedOpenGL: return m_connections.at(0)->supportsThreadedRendering(); case WindowMasks: return true; case MultipleWindows: return true; default: return QPlatformIntegration::hasCapability(cap); diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index a8542af156..d35ce181e3 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -53,6 +53,7 @@ #include <qpa/qplatforminputcontext.h> #include <qpa/qplatformintegration.h> +#include <qpa/qplatformcursor.h> #ifndef XK_ISO_Left_Tab #define XK_ISO_Left_Tab 0xFE20 @@ -1106,9 +1107,15 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod filtered = inputContext->filterEvent(&event); } - if (!filtered) + if (!filtered) { + if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu) { + const QPoint globalPos = window->screen()->handle()->cursor()->pos(); + const QPoint pos = window->mapFromGlobal(globalPos); + QWindowSystemInterface::handleContextMenuEvent(window, false, pos, globalPos, modifiers); + } QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, code, sym, state, string.left(count), isAutoRepeat); + } if (isAutoRepeat && type == QEvent::KeyRelease) { // since we removed it from the event queue using checkEvent we need to send the key press here diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index fa5f5f43d0..a44e7fb959 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -104,6 +104,25 @@ void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceSt return result; } +void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, QScreen *screen) +{ + const QXcbResourceMap::const_iterator it = qXcbResourceMap()->constFind(resource.toLower()); + if (it == qXcbResourceMap()->constEnd() || !screen->handle()) + return 0; + const QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(screen->handle()); + switch (it.value()) { + case Display: +#ifdef XCB_USE_XLIB + return xcbScreen->connection()->xlib_display(); +#else + break; +#endif + default: + break; + } + return 0; +} + void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { QByteArray lowerCaseResource = resourceString.toLower(); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index c15d00255a..a7e0a207cb 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -65,6 +65,7 @@ public: QXcbNativeInterface(); void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen); void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index eab18e2435..e0f5dbc435 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -121,13 +121,13 @@ QT_BEGIN_NAMESPACE // Returns true if we should set WM_TRANSIENT_FOR on \a w static inline bool isTransient(const QWindow *w) { - return w->windowType() == Qt::Dialog - || w->windowType() == Qt::Sheet - || w->windowType() == Qt::Tool - || w->windowType() == Qt::SplashScreen - || w->windowType() == Qt::ToolTip - || w->windowType() == Qt::Drawer - || w->windowType() == Qt::Popup; + return w->type() == Qt::Dialog + || w->type() == Qt::Sheet + || w->type() == Qt::Tool + || w->type() == Qt::SplashScreen + || w->type() == Qt::ToolTip + || w->type() == Qt::Drawer + || w->type() == Qt::Popup; } static inline QImage::Format imageFormatForDepth(int depth) @@ -175,7 +175,7 @@ void QXcbWindow::create() m_configureNotifyPending = true; m_windowState = Qt::WindowNoState; - Qt::WindowType type = window()->windowType(); + Qt::WindowType type = window()->type(); if (type == Qt::Desktop) { m_window = m_screen->root(); @@ -309,7 +309,7 @@ void QXcbWindow::create() if (m_screen->syncRequestSupported()) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); - if (window()->windowFlags() & Qt::WindowContextHelpButtonHint) + if (window()->flags() & Qt::WindowContextHelpButtonHint) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP); Q_XCB_CALL(xcb_change_property(xcb_connection(), @@ -347,7 +347,7 @@ void QXcbWindow::create() memset(&hints, 0, sizeof(hints)); xcb_wm_hints_set_normal(&hints); - xcb_wm_hints_set_input(&hints, !(window()->windowFlags() & Qt::WindowDoesNotAcceptFocus)); + xcb_wm_hints_set_input(&hints, !(window()->flags() & Qt::WindowDoesNotAcceptFocus)); xcb_set_wm_hints(xcb_connection(), m_window, &hints); @@ -375,11 +375,11 @@ void QXcbWindow::create() connection()->xi2Select(m_window); #endif - setWindowFlags(window()->windowFlags()); - setWindowTitle(window()->windowTitle()); setWindowState(window()->windowState()); + setWindowFlags(window()->flags()); + setWindowTitle(window()->title()); - if (window()->windowFlags() & Qt::WindowTransparentForInput) + if (window()->flags() & Qt::WindowTransparentForInput) setTransparentForMouseEvents(true); #ifndef QT_NO_DRAGANDDROP @@ -534,7 +534,7 @@ void QXcbWindow::show() else xcb_wm_hints_set_normal(&hints); - xcb_wm_hints_set_input(&hints, !(window()->windowFlags() & Qt::WindowDoesNotAcceptFocus)); + xcb_wm_hints_set_input(&hints, !(window()->flags() & Qt::WindowDoesNotAcceptFocus)); xcb_set_wm_hints(xcb_connection(), m_window, &hints); @@ -943,8 +943,8 @@ void QXcbWindow::updateMotifWmHintsBeforeMap() { QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window); - if (window()->windowModality() != Qt::NonModal) { - switch (window()->windowModality()) { + if (window()->modality() != Qt::NonModal) { + switch (window()->modality()) { case Qt::WindowModal: mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL; break; @@ -979,17 +979,17 @@ void QXcbWindow::updateMotifWmHintsBeforeMap() } } - if (window()->windowFlags() & Qt::WindowMinimizeButtonHint) { + if (window()->flags() & Qt::WindowMinimizeButtonHint) { mwmhints.flags |= MWM_HINTS_DECORATIONS; mwmhints.decorations |= MWM_DECOR_MINIMIZE; mwmhints.functions |= MWM_FUNC_MINIMIZE; } - if (window()->windowFlags() & Qt::WindowMaximizeButtonHint) { + if (window()->flags() & Qt::WindowMaximizeButtonHint) { mwmhints.flags |= MWM_HINTS_DECORATIONS; mwmhints.decorations |= MWM_DECOR_MAXIMIZE; mwmhints.functions |= MWM_FUNC_MAXIMIZE; } - if (window()->windowFlags() & Qt::WindowCloseButtonHint) + if (window()->flags() & Qt::WindowCloseButtonHint) mwmhints.functions |= MWM_FUNC_CLOSE; setMotifWmHints(connection(), m_window, mwmhints); @@ -999,7 +999,7 @@ void QXcbWindow::updateNetWmStateBeforeMap() { NetWmStates states(0); - const Qt::WindowFlags flags = window()->windowFlags(); + const Qt::WindowFlags flags = window()->flags(); if (flags & Qt::WindowStaysOnTopHint) { states |= NetWmStateAbove; states |= NetWmStateStaysOnTop; @@ -1015,7 +1015,7 @@ void QXcbWindow::updateNetWmStateBeforeMap() states |= NetWmStateMaximizedVert; } - if (window()->windowModality() != Qt::NonModal) + if (window()->modality() != Qt::NonModal) states |= NetWmStateModal; setNetWmStates(states); @@ -1303,6 +1303,42 @@ QXcbEGLSurface *QXcbWindow::eglSurface() const } #endif +class ExposeCompressor +{ +public: + ExposeCompressor(xcb_window_t window, QRegion *region) + : m_window(window) + , m_region(region) + , m_pending(true) + { + } + + bool checkEvent(xcb_generic_event_t *event) + { + if (!event) + return false; + if ((event->response_type & ~0x80) != XCB_EXPOSE) + return false; + xcb_expose_event_t *expose = (xcb_expose_event_t *)event; + if (expose->window != m_window) + return false; + if (expose->count == 0) + m_pending = false; + *m_region |= QRect(expose->x, expose->y, expose->width, expose->height); + return true; + } + + bool pending() const + { + return m_pending; + } + +private: + xcb_window_t m_window; + QRegion *m_region; + bool m_pending; +}; + void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { QRect rect(event->x, event->y, event->width, event->height); @@ -1312,8 +1348,15 @@ void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) else m_exposeRegion |= rect; + ExposeCompressor compressor(m_window, &m_exposeRegion); + xcb_generic_event_t *filter = 0; + do { + filter = connection()->checkEvent(compressor); + free(filter); + } while (filter); + // if count is non-zero there are more expose events pending - if (event->count == 0) { + if (event->count == 0 || !compressor.pending()) { QWindowSystemInterface::handleExposeEvent(window(), m_exposeRegion); m_exposeRegion = QRegion(); } @@ -1529,7 +1572,9 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) return; } - QWindowSystemInterface::handleEnterEvent(window()); + const QPoint local(event->event_x, event->event_y); + const QPoint global(event->root_x, event->root_y); + QWindowSystemInterface::handleEnterEvent(window(), local, global); } void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) @@ -1570,8 +1615,8 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev const long *data = (const long *)xcb_get_property_value(reply); if (reply->length != 0 && XCB_WM_STATE_ICONIC == data[0]) newState = Qt::WindowMinimized; - free(reply); } + free(reply); } // WM_STATE: Quick check for 'Minimize'. if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE. const NetWmStates states = netWmStates(); diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro new file mode 100644 index 0000000000..b7b5650eea --- /dev/null +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -0,0 +1,117 @@ +TARGET = xcb + +PLUGIN_TYPE = platforms +load(qt_plugin) + +QT += core-private gui-private platformsupport-private + + +SOURCES = \ + qxcbclipboard.cpp \ + qxcbconnection.cpp \ + qxcbintegration.cpp \ + qxcbkeyboard.cpp \ + qxcbmime.cpp \ + qxcbdrag.cpp \ + qxcbscreen.cpp \ + qxcbwindow.cpp \ + qxcbbackingstore.cpp \ + qxcbwmsupport.cpp \ + main.cpp \ + qxcbnativeinterface.cpp \ + qxcbcursor.cpp \ + qxcbimage.cpp \ + qxlibconvenience.cpp + +HEADERS = \ + qxcbclipboard.h \ + qxcbconnection.h \ + qxcbintegration.h \ + qxcbkeyboard.h \ + qxcbdrag.h \ + qxcbmime.h \ + qxcbobject.h \ + qxcbscreen.h \ + qxcbwindow.h \ + qxcbbackingstore.h \ + qxcbwmsupport.h \ + qxcbnativeinterface.h \ + qxcbcursor.h \ + qxcbimage.h \ + qxlibconvenience.h + +LIBS += -ldl + +# needed by GLX, Xcursor, XLookupString, ... +contains(QT_CONFIG, xcb-xlib) { + DEFINES += XCB_USE_XLIB + LIBS += -lX11 -lX11-xcb + + *-maemo* { + contains(QT_CONFIG, xinput2) { + # XInput2 support for Harmattan. + DEFINES += XCB_USE_XINPUT2_MAEMO + SOURCES += qxcbconnection_maemo.cpp + LIBS += -lXi + } + DEFINES += XCB_USE_MAEMO_WINDOW_PROPERTIES + } else { + contains(QT_CONFIG, xinput2) { + DEFINES += XCB_USE_XINPUT2 + SOURCES += qxcbconnection_xi2.cpp + LIBS += -lXi + } + } +} + +# to support custom cursors with depth > 1 +contains(QT_CONFIG, xcb-render) { + DEFINES += XCB_USE_RENDER + LIBS += -lxcb-render -lxcb-render-util -lXrender +} + +contains(QT_CONFIG, opengl) { + contains(QT_CONFIG, opengles2) { + DEFINES += XCB_USE_EGL + LIBS += -lEGL + HEADERS += qxcbeglsurface.h + + # EGL on MeeGo 1.2 Harmattan needs this macro to map EGLNativeDisplayType + # and other types to the correct X11 types + DEFINES += SUPPORT_X11 + } else:contains(QT_CONFIG, xcb-xlib) { + DEFINES += XCB_USE_GLX + HEADERS += qglxintegration.h + SOURCES += qglxintegration.cpp + LIBS += $$QMAKE_LIBS_DYNLOAD + contains(QT_CONFIG, xcb-glx) { + DEFINES += XCB_HAS_XCB_GLX + LIBS += -lxcb-glx + } + } +} + +DEFINES += $$QMAKE_DEFINES_XCB +LIBS += $$QMAKE_LIBS_XCB +QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB + +CONFIG += qpa/genericunixfontdatabase + +contains(QT_CONFIG, dbus) { +DEFINES += XCB_USE_IBUS +QT += dbus +LIBS += -ldbus-1 +} + +OTHER_FILES += xcb.json README + +contains(QT_CONFIG, xcb-qt) { + DEFINES += XCB_USE_RENDER + XCB_DIR = ../../../3rdparty/xcb + INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude + LIBS += -lxcb -L ./xcb-static -l xcb-static +} else { + LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr + !contains(DEFINES, QT_NO_SHAPE):LIBS += -lxcb-shape +} + diff --git a/src/plugins/platforms/xcb/xcb-static/xcb-static.pro b/src/plugins/platforms/xcb/xcb-static/xcb-static.pro new file mode 100644 index 0000000000..0257826e09 --- /dev/null +++ b/src/plugins/platforms/xcb/xcb-static/xcb-static.pro @@ -0,0 +1,70 @@ +# +# Statically compile in code for +# libxcb-fixes, libxcb-randr, libxcb-shm, libxcb-sync, libxcb-image, libxcb-keysyms, libxcb-icccm, libxcb-renderutil +# +TEMPLATE = lib +TARGET = xcb-static +CONFIG += staticlib + +XCB_DIR = ../../../../3rdparty/xcb + +INCLUDEPATH += $$XCB_DIR/include/xcb $$XCB_DIR/sysinclude + +# ignore compiler warnings in 3rdparty code +QMAKE_CFLAGS_STATIC_LIB+=-w + +# +# libxcb +# +LIBXCB_DIR = $$XCB_DIR/libxcb + +SOURCES += \ + $$LIBXCB_DIR/xfixes.c \ + $$LIBXCB_DIR/randr.c \ + $$LIBXCB_DIR/shm.c \ + $$LIBXCB_DIR/sync.c \ + $$LIBXCB_DIR/render.c \ + $$LIBXCB_DIR/shape.c + +# +# xcb-util +# +XCB_UTIL_DIR = $$XCB_DIR/xcb-util + + +SOURCES += \ + $$XCB_UTIL_DIR/xcb_aux.c \ + $$XCB_UTIL_DIR/atoms.c \ + $$XCB_UTIL_DIR/event.c + +# +# xcb-util-image +# +XCB_IMAGE_DIR = $$XCB_DIR/xcb-util-image + +SOURCES += $$XCB_IMAGE_DIR/xcb_image.c + +# +# xcb-util-keysyms +# +XCB_KEYSYMS_DIR = $$XCB_DIR/xcb-util-keysyms + +SOURCES += $$XCB_KEYSYMS_DIR/keysyms.c + +# +# xcb-util-renderutil +# + +XCB_RENDERUTIL_DIR = $$XCB_DIR/xcb-util-renderutil + +SOURCES += $$XCB_RENDERUTIL_DIR/util.c + +# +# xcb-util-wm +# +XCB_WM_DIR = $$XCB_DIR/xcb-util-wm + +SOURCES += \ + $$XCB_WM_DIR/icccm.c + +OTHER_FILES = $$XCB_DIR/README diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 34f7c74675..dab0d8cb14 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -1,112 +1,5 @@ -TARGET = xcb +TEMPLATE = subdirs +CONFIG += ordered -PLUGIN_TYPE = platforms -load(qt_plugin) - -QT += core-private gui-private platformsupport-private - - -SOURCES = \ - qxcbclipboard.cpp \ - qxcbconnection.cpp \ - qxcbintegration.cpp \ - qxcbkeyboard.cpp \ - qxcbmime.cpp \ - qxcbdrag.cpp \ - qxcbscreen.cpp \ - qxcbwindow.cpp \ - qxcbbackingstore.cpp \ - qxcbwmsupport.cpp \ - main.cpp \ - qxcbnativeinterface.cpp \ - qxcbcursor.cpp \ - qxcbimage.cpp \ - qxlibconvenience.cpp - -HEADERS = \ - qxcbclipboard.h \ - qxcbconnection.h \ - qxcbintegration.h \ - qxcbkeyboard.h \ - qxcbdrag.h \ - qxcbmime.h \ - qxcbobject.h \ - qxcbscreen.h \ - qxcbwindow.h \ - qxcbbackingstore.h \ - qxcbwmsupport.h \ - qxcbnativeinterface.h \ - qxcbcursor.h \ - qxcbimage.h \ - qxlibconvenience.h - -contains(QT_CONFIG, xcb-poll-for-queued-event) { - DEFINES += XCB_POLL_FOR_QUEUED_EVENT -} - -# needed by GLX, Xcursor, XLookupString, ... -contains(QT_CONFIG, xcb-xlib) { - DEFINES += XCB_USE_XLIB - LIBS += -lX11 -lX11-xcb - - *-maemo* { - contains(QT_CONFIG, xinput2) { - # XInput2 support for Harmattan. - DEFINES += XCB_USE_XINPUT2_MAEMO - SOURCES += qxcbconnection_maemo.cpp - LIBS += -lXi - } - DEFINES += XCB_USE_MAEMO_WINDOW_PROPERTIES - } else { - contains(QT_CONFIG, xinput2) { - DEFINES += XCB_USE_XINPUT2 - SOURCES += qxcbconnection_xi2.cpp - LIBS += -lXi - } - } -} - -# to support custom cursors with depth > 1 -contains(QT_CONFIG, xcb-render) { - DEFINES += XCB_USE_RENDER - LIBS += -lxcb-render -lxcb-render-util -lXrender -} - -!contains(DEFINES, QT_NO_SHAPE):LIBS += -lxcb-shape - -contains(QT_CONFIG, opengl) { - contains(QT_CONFIG, opengles2) { - DEFINES += XCB_USE_EGL - LIBS += -lEGL - HEADERS += qxcbeglsurface.h - - # EGL on MeeGo 1.2 Harmattan needs this macro to map EGLNativeDisplayType - # and other types to the correct X11 types - DEFINES += SUPPORT_X11 - } else:contains(QT_CONFIG, xcb-xlib) { - DEFINES += XCB_USE_GLX - HEADERS += qglxintegration.h - SOURCES += qglxintegration.cpp - LIBS += $$QMAKE_LIBS_DYNLOAD - contains(QT_CONFIG, xcb-glx) { - DEFINES += XCB_HAS_XCB_GLX - LIBS += -lxcb-glx - } - } -} - -LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shape -lxcb-shm -lxcb-randr - -DEFINES += $$QMAKE_DEFINES_XCB -LIBS += $$QMAKE_LIBS_XCB -QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB - -CONFIG += qpa/genericunixfontdatabase - -contains(QT_CONFIG, dbus) { -DEFINES += XCB_USE_IBUS -QT += dbus -LIBS += -ldbus-1 -} - -OTHER_FILES += xcb.json +contains(QT_CONFIG, xcb-qt):SUBDIRS+=xcb-static +SUBDIRS += xcb-plugin.pro diff --git a/src/plugins/printsupport/cocoa/cocoa.pro b/src/plugins/printsupport/cocoa/cocoa.pro index 4e99b4a8f5..c0206fd2bc 100644 --- a/src/plugins/printsupport/cocoa/cocoa.pro +++ b/src/plugins/printsupport/cocoa/cocoa.pro @@ -1,5 +1,5 @@ TARGET = cocoaprintersupport - +MODULE = cocoaprintersupport PLUGIN_TYPE = printsupport load(qt_plugin) diff --git a/src/plugins/printsupport/cups/cups.pro b/src/plugins/printsupport/cups/cups.pro index bd0b6af114..0ea5058c00 100644 --- a/src/plugins/printsupport/cups/cups.pro +++ b/src/plugins/printsupport/cups/cups.pro @@ -1,5 +1,5 @@ TARGET = cupsprintersupport - +MODULE = cupsprintersupport PLUGIN_TYPE = printsupport load(qt_plugin) diff --git a/src/plugins/printsupport/windows/windows.pro b/src/plugins/printsupport/windows/windows.pro index 5e8738554c..5b5dd86beb 100644 --- a/src/plugins/printsupport/windows/windows.pro +++ b/src/plugins/printsupport/windows/windows.pro @@ -1,5 +1,5 @@ TARGET = windowsprintersupport - +MODULE = windowsprintersupport PLUGIN_TYPE = printsupport load(qt_plugin) |