diff options
Diffstat (limited to 'src/plugins/platforms')
38 files changed, 910 insertions, 645 deletions
diff --git a/src/plugins/platforms/blackberry/qbbclipboard.cpp b/src/plugins/platforms/blackberry/qbbclipboard.cpp index fce016d5ee..293a0c771b 100644 --- a/src/plugins/platforms/blackberry/qbbclipboard.cpp +++ b/src/plugins/platforms/blackberry/qbbclipboard.cpp @@ -46,6 +46,7 @@ #include <QtGui/QColor> #include <QtCore/QDebug> +#include <QtCore/QMimeData> #include <QtCore/QStringList> #include <QtCore/QUrl> @@ -53,11 +54,131 @@ #include <errno.h> QT_BEGIN_NAMESPACE -static const char *typeList[] = {"text/html", "text/plain", "application/x-color"}; + +// null terminated array +static const char *typeList[] = {"text/html", "text/plain", "image/png", "image/jpeg", "application/x-color", 0}; + +static QByteArray readClipboardBuff(const char *type) +{ + char *pbuffer; + if (is_clipboard_format_present(type) == 0) { + int size = get_clipboard_data(type, &pbuffer); + if (size != -1 && pbuffer) { + const QByteArray result = QByteArray(pbuffer, size); + free(pbuffer); + return result; + } + } + + return QByteArray(); +} + +class QBBClipboard::MimeData : public QMimeData +{ + Q_OBJECT +public: + MimeData(QBBClipboard *clipboard) + : QMimeData(), + m_clipboard(clipboard), + m_userMimeData(0) + { + Q_ASSERT(clipboard); + + for (int i = 0; typeList[i] != 0; ++i) { + m_formatsToCheck << QString::fromUtf8(typeList[i]); + } + } + + ~MimeData() + { + delete m_userMimeData; + } + + void addFormatToCheck(const QString &format) { + m_formatsToCheck << format; + +#if defined(QBBCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "formats=" << m_formatsToCheck; +#endif + } + + bool hasFormat(const QString &mimetype) const + { + const bool result = is_clipboard_format_present(mimetype.toUtf8().constData()) == 0; +#if defined(QBBCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "mimetype=" << mimetype << "result=" << result; +#endif + return result; + } + + QStringList formats() const + { + QStringList result; + + Q_FOREACH (const QString &format, m_formatsToCheck) { + if (is_clipboard_format_present(format.toUtf8().constData()) == 0) + result << format; + } + +#if defined(QBBCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "result=" << result; +#endif + return result; + } + + void setUserMimeData(QMimeData *userMimeData) + { + delete m_userMimeData; + m_userMimeData = userMimeData; + + // system clipboard API doesn't allow detection of changes by other applications + // simulate an owner change through delayed invocation + // basically transfer ownership of data to the system clipboard once event processing resumes + if (m_userMimeData) + QMetaObject::invokeMethod(this, "releaseOwnership", Qt::QueuedConnection); + } + + QMimeData *userMimeData() + { + return m_userMimeData; + } + +protected: + QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const + { +#if defined(QBBCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "mimetype=" << mimetype << "preferredType=" << preferredType; +#endif + if (is_clipboard_format_present(mimetype.toUtf8().constData()) != 0) + return QMimeData::retrieveData(mimetype, preferredType); + + const QByteArray data = readClipboardBuff(mimetype.toUtf8().constData()); + return qVariantFromValue(data); + } + +private Q_SLOTS: + void releaseOwnership() + { + if (m_userMimeData) { +#if defined(QBBCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats(); +#endif + delete m_userMimeData; + m_userMimeData = 0; + m_clipboard->emitChanged(QClipboard::Clipboard); + } + } + +private: + QBBClipboard * const m_clipboard; + + QSet<QString> m_formatsToCheck; + QMimeData *m_userMimeData; +}; QBBClipboard::QBBClipboard() + : m_mimeData(new MimeData(this)) { - m_mimeData = 0; } QBBClipboard::~QBBClipboard() @@ -70,46 +191,37 @@ void QBBClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) if (mode != QClipboard::Clipboard) return; - if (m_mimeData != data) { - delete m_mimeData; - m_mimeData = data; - } + if (data == m_mimeData || data == m_mimeData->userMimeData()) + return; empty_clipboard(); + m_mimeData->clear(); + m_mimeData->setUserMimeData(data); + if (data == 0) return; - QStringList format = data->formats(); - for (int i = 0; i < format.size(); ++i) { - QString type = format.at(i); - QByteArray buf = data->data(type); - if (!buf.size()) - continue; - - int ret = set_clipboard_data(type.toUtf8().data(), buf.size(), buf.data()); + const QStringList formats = data->formats(); #if defined(QBBCLIPBOARD_DEBUG) - qDebug() << "QBB: set " << type.toUtf8().data() << "to clipboard, size=" << buf.size() << ";ret=" << ret; -#else - Q_UNUSED(ret); + qDebug() << Q_FUNC_INFO << "formats=" << formats; #endif - } -} -void QBBClipboard::readClipboardBuff(const char *type) -{ - char *pbuffer; - if (is_clipboard_format_present(type) == 0) { - int size = get_clipboard_data(type, &pbuffer); - if (size != -1 && pbuffer) { - QString qtype = type; + Q_FOREACH (const QString &format, formats) { + const QByteArray buf = data->data(format); + + if (buf.isEmpty()) + continue; + + int ret = set_clipboard_data(format.toUtf8().data(), buf.size(), buf.data()); #if defined(QBBCLIPBOARD_DEBUG) - qDebug() << "QBB: clipboard has " << qtype; + qDebug() << "QBB: set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret; #endif - m_mimeData->setData(qtype, QByteArray(pbuffer, size)); - delete pbuffer; - } + if (ret) + m_mimeData->addFormatToCheck(format); } + + emitChanged(QClipboard::Clipboard); } QMimeData *QBBClipboard::mimeData(QClipboard::Mode mode) @@ -117,16 +229,16 @@ QMimeData *QBBClipboard::mimeData(QClipboard::Mode mode) if (mode != QClipboard::Clipboard) return 0; - if (!m_mimeData) - m_mimeData = new QMimeData(); + if (m_mimeData->userMimeData()) + return m_mimeData->userMimeData(); m_mimeData->clear(); - for (int i = 0; i < 3; i++) - readClipboardBuff(typeList[i]); - return m_mimeData; } QT_END_NAMESPACE -#endif //QT_NO_CLIPBOAR + +#include "qbbclipboard.moc" + +#endif //QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/blackberry/qbbclipboard.h b/src/plugins/platforms/blackberry/qbbclipboard.h index b9de9b3e36..11a36ba8e5 100644 --- a/src/plugins/platforms/blackberry/qbbclipboard.h +++ b/src/plugins/platforms/blackberry/qbbclipboard.h @@ -44,7 +44,6 @@ #ifndef QT_NO_CLIPBOARD #include <QtGui/QPlatformClipboard> -#include <QMimeData> QT_BEGIN_NAMESPACE @@ -57,8 +56,8 @@ public: virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); private: - QMimeData *m_mimeData; - void readClipboardBuff(const char *type); + class MimeData; + MimeData *m_mimeData; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbscreen.cpp b/src/plugins/platforms/blackberry/qbbscreen.cpp index 39d2136b7d..11e40f6150 100644 --- a/src/plugins/platforms/blackberry/qbbscreen.cpp +++ b/src/plugins/platforms/blackberry/qbbscreen.cpp @@ -286,7 +286,7 @@ void QBBScreen::updateHierarchy() #endif QList<QBBWindow*>::iterator it; - int topZorder = 0; + int topZorder = 1; // root window is z-order 0, all "top" level windows are "above" it for (it = ms_childWindows.begin(); it != ms_childWindows.end(); it++) (*it)->updateZorder(topZorder); diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 45dd3525d5..ce87de2574 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -27,6 +27,7 @@ OBJECTIVE_SOURCES += main.mm \ qcocoafiledialoghelper.mm \ qcocoafontdialoghelper.mm \ qcocoacursor.mm \ + qcocoasystemsettings.mm \ HEADERS += qcocoaintegration.h \ qcocoatheme.h \ @@ -51,6 +52,7 @@ HEADERS += qcocoaintegration.h \ qcocoafiledialoghelper.h \ qcocoafontdialoghelper.h \ qcocoacursor.h \ + qcocoasystemsettings.h \ FORMS += $$PWD/../../../widgets/dialogs/qfiledialog.ui RESOURCES += qcocoaresources.qrc diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index be061547a9..5493b21c34 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -97,6 +97,7 @@ private: QScopedPointer<QPlatformAccessibility> mAccessibility; QScopedPointer<QPlatformTheme> mPlatformTheme; + QList<QCocoaScreen *> mScreens; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index fb8e487029..626a7fe0f9 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -134,6 +134,7 @@ QCocoaIntegration::QCocoaIntegration() NSArray *screens = [NSScreen screens]; for (uint i = 0; i < [screens count]; i++) { QCocoaScreen *screen = new QCocoaScreen(i); + mScreens.append(screen); screenAdded(screen); } @@ -142,6 +143,11 @@ QCocoaIntegration::QCocoaIntegration() QCocoaIntegration::~QCocoaIntegration() { [[NSApplication sharedApplication] setDelegate: 0]; + + // Delete screens in reverse order to avoid crash in case of multiple screens + while (!mScreens.isEmpty()) { + delete mScreens.takeLast(); + } } bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index 3a1f92fcf9..70e974161e 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -93,7 +93,6 @@ void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader) // Load and instantiate nib file from temp NSURL *nibUrl = [NSURL fileURLWithPath : QCFString::toNSString(nibDir)]; - [nibUrl autorelease]; NSNib *nib = [[NSNib alloc] initWithContentsOfURL : nibUrl]; [nib autorelease]; if(!nib) { diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.h b/src/plugins/platforms/cocoa/qcocoasystemsettings.h new file mode 100644 index 0000000000..84a66d7193 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOCOASYSTEMSETTINGS_H +#define QCOCOASYSTEMSETTINGS_H + +#include <QtCore/qglobal.h> +#include <QtGui/qpalette.h> + +QT_BEGIN_NAMESPACE + +QPalette * qt_mac_createSystemPalette(); + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm new file mode 100644 index 0000000000..5170c0bc8a --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcocoasystemsettings.h" + +#include <Carbon/Carbon.h> +#include <QtCore/private/qcore_mac_p.h> + +QColor qt_mac_colorFromCGColor(CGColorRef cgcolor) +{ + QColor pc; + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(cgcolor)); + const CGFloat *components = CGColorGetComponents(cgcolor); + if (model == kCGColorSpaceModelRGB) { + pc.setRgbF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelCMYK) { + pc.setCmykF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelMonochrome) { + pc.setRgbF(components[0], components[0], components[0], components[1]); + } else { + // Colorspace we can't deal with. + qWarning("Qt: qcolorFromCGColor: cannot convert from colorspace model: %d", model); + Q_ASSERT(false); + } + return pc; +} + +QColor qt_mac_colorForTheme(ThemeBrush brush) +{ + QCFType<CGColorRef> cgClr = 0; + HIThemeBrushCreateCGColor(brush, &cgClr); + return qt_mac_colorFromCGColor(cgClr); +} + +QColor qt_mac_colorForThemeTextColor(ThemeTextColor themeColor) +{ + // No GetThemeTextColor in 64-bit mode, use hardcoded values: + switch (themeColor) { + case kThemeTextColorAlertActive: + case kThemeTextColorTabFrontActive: + case kThemeTextColorBevelButtonActive: + case kThemeTextColorListView: + case kThemeTextColorPlacardActive: + case kThemeTextColorPopupButtonActive: + case kThemeTextColorPopupLabelActive: + case kThemeTextColorPushButtonActive: + return Qt::black; + case kThemeTextColorAlertInactive: + case kThemeTextColorDialogInactive: + case kThemeTextColorPlacardInactive: + return QColor(69, 69, 69, 255); + case kThemeTextColorPopupButtonInactive: + case kThemeTextColorPopupLabelInactive: + case kThemeTextColorPushButtonInactive: + case kThemeTextColorTabFrontInactive: + case kThemeTextColorBevelButtonInactive: + return QColor(127, 127, 127, 255); + default: + return QColor(0, 0, 0, 255); // ### TODO: Sample color like Qt 4. + } +} + +QPalette * qt_mac_createSystemPalette() +{ + QColor qc; + + // Standard palette initialization (copied from Qt 4 styles) + QColor background = QColor(0xd4, 0xd0, 0xc8); // win 2000 grey + QColor light(background.lighter()); + QColor dark(background.darker()); + QColor mid(Qt::gray); + QPalette *palette = new QPalette(Qt::black, background, light, dark, mid, Qt::black, Qt::white); + + palette->setBrush(QPalette::Disabled, QPalette::WindowText, dark); + palette->setBrush(QPalette::Disabled, QPalette::Text, dark); + palette->setBrush(QPalette::Disabled, QPalette::ButtonText, dark); + palette->setBrush(QPalette::Disabled, QPalette::Base, background); + palette->setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191)); + palette->setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191)); + palette->setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191)); + + // System palette initialization: + palette->setBrush( QPalette::Active, QPalette::Highlight, qt_mac_colorForTheme(kThemeBrushPrimaryHighlightColor) ); + palette->setBrush( QPalette::Inactive, QPalette::Highlight, qt_mac_colorForTheme(kThemeBrushSecondaryHighlightColor) ); + + palette->setBrush( QPalette::Disabled, QPalette::Highlight, qt_mac_colorForTheme(kThemeBrushSecondaryHighlightColor) ); + palette->setBrush( QPalette::Active, QPalette::Shadow, qt_mac_colorForTheme(kThemeBrushButtonActiveDarkShadow) ); + + palette->setBrush( QPalette::Inactive, QPalette::Shadow, qt_mac_colorForTheme(kThemeBrushButtonInactiveDarkShadow) ); + palette->setBrush( QPalette::Disabled, QPalette::Shadow, qt_mac_colorForTheme(kThemeBrushButtonInactiveDarkShadow) ); + + qc = qt_mac_colorForThemeTextColor(kThemeTextColorDialogActive); + palette->setColor(QPalette::Active, QPalette::Text, qc); + palette->setColor(QPalette::Active, QPalette::WindowText, qc); + palette->setColor(QPalette::Active, QPalette::HighlightedText, qc); + + qc = qt_mac_colorForThemeTextColor(kThemeTextColorDialogInactive); + palette->setColor(QPalette::Inactive, QPalette::Text, qc); + palette->setColor(QPalette::Inactive, QPalette::WindowText, qc); + palette->setColor(QPalette::Inactive, QPalette::HighlightedText, qc); + palette->setColor(QPalette::Disabled, QPalette::Text, qc); + palette->setColor(QPalette::Disabled, QPalette::WindowText, qc); + palette->setColor(QPalette::Disabled, QPalette::HighlightedText, qc); + palette->setBrush(QPalette::ToolTipBase, QColor(255, 255, 199)); + return palette; +} + diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index a7dc973937..fa235b6be0 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE +class QPalette; class QCocoaTheme : public QPlatformTheme { public: @@ -60,7 +61,11 @@ public: bool usePlatformNativeDialog(DialogType dialogType) const; QPlatformDialogHelper *createPlatformDialogHelper(DialogType dialogType) const; + const QPalette *palette(Palette type = SystemPalette) const; + QVariant themeHint(ThemeHint hint) const; +private: + mutable QPalette *m_systemPalette; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 0fef3234b4..6b0e04acf8 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -45,17 +45,19 @@ #include "qcocoacolordialoghelper.h" #include "qcocoafiledialoghelper.h" #include "qcocoafontdialoghelper.h" +#include "qcocoasystemsettings.h" QT_BEGIN_NAMESPACE QCocoaTheme::QCocoaTheme() + :m_systemPalette(0) { } QCocoaTheme::~QCocoaTheme() { - + delete m_systemPalette; } QPlatformMenu *QCocoaTheme::createPlatformMenu(QMenu *menu) const @@ -102,6 +104,17 @@ QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialo } } +const QPalette *QCocoaTheme::palette(Palette type) const +{ + if (type == SystemPalette) { + if (!m_systemPalette) + m_systemPalette = qt_mac_createSystemPalette(); + + return m_systemPalette; + } + return 0; +} + QVariant QCocoaTheme::themeHint(ThemeHint hint) const { switch (hint) { diff --git a/src/plugins/platforms/cocoa/qmacdefines_mac.h b/src/plugins/platforms/cocoa/qmacdefines_mac.h index a35df47227..d89e313bcb 100644 --- a/src/plugins/platforms/cocoa/qmacdefines_mac.h +++ b/src/plugins/platforms/cocoa/qmacdefines_mac.h @@ -93,11 +93,6 @@ Yes, it is an informative comment ;-) #include <QtCore/qglobal.h> -#ifdef qDebug -# define old_qDebug qDebug -# undef qDebug -#endif - #ifdef __LP64__ typedef signed int OSStatus; #else @@ -149,9 +144,3 @@ typedef AERecord AppleEvent; #ifdef check #undef check #endif - -#ifdef old_qDebug -# undef qDebug -# define qDebug QT_NO_QDEBUG_MACRO -# undef old_qDebug -#endif diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index f16eff5449..6d7c89e086 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -59,15 +59,15 @@ QT_BEGIN_NAMESPACE of QGuiApplication: \list - \o \c fontengine=native Indicates that the freetype font + \li \c fontengine=native Indicates that the freetype font engine should not be used. - \o \c gl=gdi Indicates that ARB Open GL functionality should not be used + \li \c gl=gdi Indicates that ARB Open GL functionality should not be used \endlist \section1 Tips \list - \o The environment variable \c QT_LIGHTHOUSE_WINDOWS_VERBOSE controls + \li The environment variable \c QT_LIGHTHOUSE_WINDOWS_VERBOSE controls the debug level. It takes the form \c{<keyword1>:<level1>,<keyword2>:<level2>}, where keyword is one of \c integration, \c windows, \c backingstore and diff --git a/src/plugins/platforms/windows/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/qwindowsaccessibility.cpp index 3ef21fa0b7..1a8f593609 100644 --- a/src/plugins/platforms/windows/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/qwindowsaccessibility.cpp @@ -88,25 +88,54 @@ QT_BEGIN_NAMESPACE -//#define DEBUG_SHOW_ATCLIENT_COMMANDS -#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS +#ifndef QT_NO_DEBUG QT_BEGIN_INCLUDE_NAMESPACE -#include <qdebug.h> +# include <qdebug.h> QT_END_INCLUDE_NAMESPACE +static inline bool debug_accessibility() +{ + static signed int debugging = -1; + if (debugging == -1) + debugging = qgetenv("QT_DEBUG_ACCESSIBILITY").toInt(); + return !!debugging; +} +# define accessibleDebug !debug_accessibility() ? (void)0 : qDebug +#else +# define accessibleDebug() +#endif -void showDebug(const char* funcName, const QAccessibleInterface *iface) +//#define DEBUG_SHOW_ATCLIENT_COMMANDS +#if defined(DEBUG_SHOW_ATCLIENT_COMMANDS) +void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleInterface *iface) { - qDebug() << "Role:" << qAccessibleRoleString(iface->role(0)) - << "Name:" << iface->text(QAccessible::Name, 0) - << "State:" << QString::number(int(iface->state(0)), 16) - << QLatin1String(funcName); + QString str; + QDebug dbg(&str); + dbg << iface << QLatin1String(funcName); + accessibleDebug("%s", qPrintable(str)); } +# define accessibleDebugClientCalls(iface) accessibleDebugClientCalls_helper(Q_FUNC_INFO, iface) #else -# define showDebug(f, iface) +# define accessibleDebugClientCalls(iface) #endif + typedef QSharedPointer<QAccessibleInterface> QAIPointer; +static bool compareAccessible(QAccessibleInterface *one, QAccessibleInterface *other) +{ + if (one == other) return true; + if (!one || !other) return false; + + if (one->object() && other->object() && (one->object() == other->object())) + return true; + QAIPointer onePar(one->parent()); + QAIPointer otherPar(other->parent()); + + if (compareAccessible(onePar.data(), otherPar.data())) + return onePar->indexOfChild(one) == otherPar->indexOfChild(other); + return false; +} + // This stuff is used for widgets/items with no window handle: typedef QMap<int, QPair<QObject*,int> > NotifyMap; Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents) @@ -595,7 +624,7 @@ IAccessible::accHitTest documents the value returned in pvarID like this: HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -635,7 +664,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -659,7 +688,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *py // moz: [important, but no need to implement up/down/left/right] HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -799,7 +828,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT v // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -853,7 +882,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, I // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -864,7 +893,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChil // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -887,7 +916,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispPa HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID) { Q_UNUSED(varID); - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -904,7 +933,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID) HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction) { Q_UNUSED(varID); - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -919,7 +948,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -944,7 +973,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -974,7 +1003,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut) { Q_UNUSED(varID); - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -1004,7 +1033,7 @@ static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAcce // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -1040,14 +1069,14 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* p HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); return DISP_E_MEMBERNOTFOUND; } // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -1075,7 +1104,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -1151,7 +1180,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIAN // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid() || varID.lVal) return E_FAIL; @@ -1172,7 +1201,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); return DISP_E_MEMBERNOTFOUND; } @@ -1181,7 +1210,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIAN { Q_UNUSED(flagsSelect); Q_UNUSED(varID); - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; @@ -1207,24 +1236,43 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIAN return res ? S_OK : S_FALSE; } -// moz: [important] +/*! + \internal + Can return: + + +-------------+------------------------------------------------------------------------------+ + | VT_EMPTY | None. Neither this object nor any of its children has the keyboard focus. | + +-------------+------------------------------------------------------------------------------+ + | VT_I4 | lVal is CHILDID_SELF. The object itself has the keyboard focus. | + +-------------+------------------------------------------------------------------------------+ + | VT_I4 | lVal contains the child ID of the child element that has the keyboard focus. | + +-------------+------------------------------------------------------------------------------+ + | VT_DISPATCH | pdispVal member is the address of the IDispatch interface for the child | + | | object that has the keyboard focus. | + +-------------+------------------------------------------------------------------------------+ + moz: [important] +*/ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; if (QAccessibleInterface *acc = accessible->focusChild()) { - QWindowsAccessible* wacc = new QWindowsAccessible(acc); - IDispatch *iface = 0; - wacc->QueryInterface(IID_IDispatch, (void**)&iface); - if (iface) { + if (compareAccessible(acc, accessible)) { + (*pvarID).vt = VT_I4; + (*pvarID).lVal = CHILDID_SELF; + delete acc; + return S_OK; + } else { + QWindowsAccessible* wacc = new QWindowsAccessible(acc); + IDispatch *iface = 0; + wacc->QueryInterface(IID_IDispatch, (void**)&iface); (*pvarID).vt = VT_DISPATCH; (*pvarID).pdispVal = iface; return S_OK; - } else { - delete wacc; } + delete acc; } (*pvarID).vt = VT_EMPTY; return S_FALSE; @@ -1232,7 +1280,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID) HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren) { - showDebug(__FUNCTION__, accessible); + accessibleDebugClientCalls(accessible); if (!accessible->isValid()) return E_FAIL; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 25b9336361..1239f3d8e2 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -366,10 +366,10 @@ void eatMouseMove() There 2 types of native dialogs: \list - \o Dialogs provided by the Comdlg32 library (ChooseColor, + \li Dialogs provided by the Comdlg32 library (ChooseColor, ChooseFont). They only provide a modal, blocking function call (with idle processing). - \o File dialogs are classes derived from IFileDialog. They + \li File dialogs are classes derived from IFileDialog. They inherit IModalWindow and their exec() method (calling IModalWindow::Show()) is similarly blocking, but methods like close() can be called on them from event handlers. diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 9f2a1dc00c..d75752bc04 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -53,8 +53,11 @@ #include <QtGui/QPixmap> #include <QtGui/QPainter> #include <QtGui/QGuiApplication> +#include <QtGui/private/qwindowsysteminterface_qpa_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <QtCore/QDebug> +#include <QtCore/QBuffer> #include <QtCore/QPoint> #include <shlobj.h> @@ -300,14 +303,13 @@ private: QWindowsDrag *m_drag; Qt::MouseButtons m_currentButtons; - Qt::DropAction m_currentAction; ActionCursorMap m_cursors; ULONG m_refs; }; QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) : - m_drag(drag), m_currentButtons(Qt::NoButton), m_currentAction(Qt::IgnoreAction), + m_drag(drag), m_currentButtons(Qt::NoButton), m_refs(1) { if (QWindowsContext::verboseOLE) @@ -321,24 +323,26 @@ QWindowsOleDropSource::~QWindowsOleDropSource() qDebug("%s", __FUNCTION__); } +/*! + \brief Blend custom pixmap with cursors. +*/ + void QWindowsOleDropSource::createCursors() { - QDragManager *manager = QDragManager::self(); - if (!manager || !manager->object) - return; - const QPixmap pixmap = manager->object->pixmap(); + const QDrag *drag = m_drag->currentDrag(); + const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); - if (!hasPixmap && manager->dragPrivate()->customCursors.isEmpty()) + if (!hasPixmap) return; QList<Qt::DropAction> actions; actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction; if (hasPixmap) actions << Qt::IgnoreAction; - const QPoint hotSpot = manager->object->hotSpot(); + const QPoint hotSpot = drag->hotSpot(); for (int cnum = 0; cnum < actions.size(); ++cnum) { const Qt::DropAction action = actions.at(cnum); - QPixmap cpm = manager->dragCursor(action); + QPixmap cpm = drag->dragCursor(action); if (cpm.isNull()) cpm = m_drag->defaultCursor(action); if (cpm.isNull()) { @@ -361,7 +365,7 @@ void QWindowsOleDropSource::createCursors() const QPoint newHotSpot = hotSpot; QPixmap newCursor(w, h); if (hasPixmap) { - newCursor.fill(QColor(0, 0, 0, 0)); + newCursor.fill(Qt::transparent); QPainter p(&newCursor); const QRect srcRect = pixmap.rect(); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); @@ -375,7 +379,7 @@ void QWindowsOleDropSource::createCursors() const int hotY = hasPixmap ? qMax(0,newHotSpot.y()) : 0; if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY)) - m_cursors.insert(action, sysCursor); + m_cursors.insert(actions.at(cnum), sysCursor); } if (QWindowsContext::verboseOLE) qDebug("%s %d cursors", __FUNCTION__, m_cursors.size()); @@ -432,7 +436,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { HRESULT hr = S_OK; do { - if (fEscapePressed || QWindowsDrag::instance()->dragBeingCancelled()) { + if (fEscapePressed) { hr = ResultFromScode(DRAGDROP_S_CANCEL); break; } @@ -461,13 +465,11 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) } while (false); - QDragManager::self()->willDrop = hr == DRAGDROP_S_DROP; - if (QWindowsContext::verboseOLE && (QWindowsContext::verboseOLE > 1 || hr != S_OK)) - qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d willDrop = %d returns 0x%x", + qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d returns 0x%x", __FUNCTION__, fEscapePressed,grfKeyState, int(m_currentButtons), - QDragManager::self()->willDrop, int(hr)); + int(hr)); return hr; } @@ -479,16 +481,12 @@ QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) { const Qt::DropAction action = translateToQDragDropAction(dwEffect); + m_drag->updateAction(action); if (QWindowsContext::verboseOLE > 2) qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action); - if (m_currentAction != action) { - m_currentAction = action; - QDragManager::self()->emitActionChanged(m_currentAction); - } - - const ActionCursorMap::const_iterator it = m_cursors.constFind(m_currentAction); + const ActionCursorMap::const_iterator it = m_cursors.constFind(action); if (it != m_cursors.constEnd()) { SetCursor(it.value()); return ResultFromScode(S_OK); @@ -510,7 +508,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) */ QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : - m_refs(1), m_window(w), m_currentWindow(0), m_chosenEffect(0), m_lastKeyState(0) + m_refs(1), m_window(w), m_chosenEffect(0), m_lastKeyState(0) { if (QWindowsContext::verboseOLE) qDebug() << __FUNCTION__ << this << w; @@ -558,6 +556,38 @@ QWindow *QWindowsOleDropTarget::findDragOverWindow(const POINTL &pt) const return m_window; } +void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, + const QPoint &point, LPDWORD pdwEffect) +{ + Q_ASSERT(window); + m_lastPoint = point; + m_lastKeyState = grfKeyState; + + QWindowsDrag *windowsDrag = QWindowsDrag::instance(); + const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); + QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState); + QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + + const QPlatformDragQtResponse response = + QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); + + m_answerRect = response.answerRect(); + const Qt::DropAction action = response.acceptedAction(); + if (response.isAccepted()) { + m_chosenEffect = translateToWinDragEffects(action); + } else { + m_chosenEffect = DROPEFFECT_NONE; + } + *pdwEffect = m_chosenEffect; + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << m_window + << windowsDrag->dropData() << " supported actions=" << actions + << " mods=" << QGuiApplicationPrivate::modifier_buttons + << " mouse=" << QGuiApplicationPrivate::mouse_buttons + << " accepted: " << response.isAccepted() << action + << m_answerRect << " effect" << *pdwEffect; +} + QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) @@ -567,124 +597,28 @@ QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindowsDrag::instance()->setDropDataObject(pDataObj); pDataObj->AddRef(); - m_currentWindow = m_window; - sendDragEnterEvent(m_window, grfKeyState, pt, pdwEffect); - *pdwEffect = m_chosenEffect; + const QPoint point = QWindowsGeometryHint::mapFromGlobal(m_window, QPoint(pt.x,pt.y)); + handleDrag(m_window, grfKeyState, point, pdwEffect); return NOERROR; } -void QWindowsOleDropTarget::sendDragEnterEvent(QWindow *dragEnterWidget, - DWORD grfKeyState, - POINTL pt, LPDWORD pdwEffect) -{ - Q_ASSERT(dragEnterWidget); - - m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dragEnterWidget, QPoint(pt.x,pt.y)); - m_lastKeyState = grfKeyState; - - m_chosenEffect = DROPEFFECT_NONE; - - QDragManager *manager = QDragManager::self(); - QMimeData *md = manager->dropData(); - const Qt::MouseButtons mouseButtons - = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); - const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); - const Qt::KeyboardModifiers keyMods = toQtKeyboardModifiers(grfKeyState); - QDragEnterEvent enterEvent(m_lastPoint, actions, md, mouseButtons, keyMods); - QGuiApplication::sendEvent(m_currentWindow, &enterEvent); - m_answerRect = enterEvent.answerRect(); - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << " sent drag enter to " << m_window - << *md << " actions=" << actions - << " mods=" << keyMods << " accepted: " - << enterEvent.isAccepted(); - - if (enterEvent.isAccepted()) - m_chosenEffect = translateToWinDragEffects(enterEvent.dropAction()); - // Documentation states that a drag move event is sent immediately after - // a drag enter event. This will honor widgets overriding dragMoveEvent only: - if (enterEvent.isAccepted()) { - QDragMoveEvent moveEvent(m_lastPoint, actions, md, mouseButtons, keyMods); - m_answerRect = enterEvent.answerRect(); - moveEvent.setDropAction(enterEvent.dropAction()); - moveEvent.accept(); // accept by default, since enter event was accepted. - - QGuiApplication::sendEvent(dragEnterWidget, &moveEvent); - if (moveEvent.isAccepted()) { - m_answerRect = moveEvent.answerRect(); - m_chosenEffect = translateToWinDragEffects(moveEvent.dropAction()); - } else { - m_chosenEffect = DROPEFFECT_NONE; - } - } -} - QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { QWindow *dragOverWindow = findDragOverWindow(pt); - + if (QWindowsContext::verboseOLE) + qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, dragOverWindow, grfKeyState, pt.x, pt.y); const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(dragOverWindow, QPoint(pt.x,pt.y)); // see if we should compress this event if ((tmpPoint == m_lastPoint || m_answerRect.contains(tmpPoint)) && m_lastKeyState == grfKeyState) { *pdwEffect = m_chosenEffect; + if (QWindowsContext::verboseOLE) + qDebug("%s: compressed event", __FUNCTION__); return NOERROR; } - if (QWindowsContext::verboseOLE > 1) - qDebug().nospace() << '>' << __FUNCTION__ << ' ' << m_window << " current " - << dragOverWindow << " key=" << grfKeyState - << " pt=" <<pt.x << ',' << pt.y; - - if (dragOverWindow != m_currentWindow) { - QPointer<QWindow> dragOverWindowGuard(dragOverWindow); - // Send drag leave event to the previous drag widget. - // Drag-Over widget might be deleted in DragLeave, - // (tasktracker 218353). - QDragLeaveEvent dragLeave; - if (m_currentWindow) - QGuiApplication::sendEvent(m_currentWindow, &dragLeave); - if (!dragOverWindowGuard) { - dragOverWindow = findDragOverWindow(pt); - } - // Send drag enter event to the current drag widget. - m_currentWindow = dragOverWindow; - sendDragEnterEvent(dragOverWindow, grfKeyState, pt, pdwEffect); - } - - QDragManager *manager = QDragManager::self(); - QMimeData *md = manager->dropData(); - - const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); - - QDragMoveEvent oldEvent(m_lastPoint, actions, md, - QWindowsMouseHandler::keyStateToMouseButtons(m_lastKeyState), - toQtKeyboardModifiers(m_lastKeyState)); - - m_lastPoint = tmpPoint; - m_lastKeyState = grfKeyState; - - QDragMoveEvent e(tmpPoint, actions, md, - QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState), - toQtKeyboardModifiers(grfKeyState)); - if (m_chosenEffect != DROPEFFECT_NONE) { - if (oldEvent.dropAction() == e.dropAction() && - oldEvent.keyboardModifiers() == e.keyboardModifiers()) - e.setDropAction(translateToQDragDropAction(m_chosenEffect)); - e.accept(); - } - QGuiApplication::sendEvent(dragOverWindow, &e); - - m_answerRect = e.answerRect(); - if (e.isAccepted()) - m_chosenEffect = translateToWinDragEffects(e.dropAction()); - else - m_chosenEffect = DROPEFFECT_NONE; - *pdwEffect = m_chosenEffect; - - if (QWindowsContext::verboseOLE > 1) - qDebug("<%s effect=0x%lx", __FUNCTION__, m_chosenEffect); + handleDrag(dragOverWindow, grfKeyState, tmpPoint, pdwEffect); return NOERROR; } @@ -694,9 +628,7 @@ QWindowsOleDropTarget::DragLeave() if (QWindowsContext::verboseOLE) qDebug().nospace() <<__FUNCTION__ << ' ' << m_window; - m_currentWindow = 0; - QDragLeaveEvent e; - QGuiApplication::sendEvent(m_window, &e); + QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction); QWindowsDrag::instance()->releaseDropDataObject(); return NOERROR; @@ -724,21 +656,15 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, m_lastKeyState = grfKeyState; QWindowsDrag *windowsDrag = QWindowsDrag::instance(); - QDragManager *manager = QDragManager::self(); - QMimeData *md = manager->dropData(); - QDropEvent e(m_lastPoint, translateToQDragDropActions(*pdwEffect), md, - QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState), - toQtKeyboardModifiers(grfKeyState)); - if (m_chosenEffect != DROPEFFECT_NONE) - e.setDropAction(translateToQDragDropAction(m_chosenEffect)); - - QGuiApplication::sendEvent(dropWindow, &e); - if (m_chosenEffect != DROPEFFECT_NONE) - e.accept(); - - if (e.isAccepted()) { - if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) { - if (e.dropAction() == Qt::MoveAction) + + const QPlatformDropQtResponse response = + QWindowSystemInterface::handleDrop(dropWindow, windowsDrag->dropData(), m_lastPoint, + translateToQDragDropActions(*pdwEffect)); + + if (response.isAccepted()) { + const Qt::DropAction action = response.acceptedAction(); + if (action == Qt::MoveAction || action == Qt::TargetMoveAction) { + if (action == Qt::MoveAction) m_chosenEffect = DROPEFFECT_MOVE; else m_chosenEffect = DROPEFFECT_COPY; @@ -760,7 +686,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, windowsDrag->dropDataObject()->SetData(&format, &medium, true); } } else { - m_chosenEffect = translateToWinDragEffects(e.dropAction()); + m_chosenEffect = translateToWinDragEffects(action); } } else { m_chosenEffect = DROPEFFECT_NONE; @@ -778,7 +704,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, \ingroup qt-lighthouse-win */ -QWindowsDrag::QWindowsDrag() : m_dropDataObject(0), m_dragBeingCancelled(false) +QWindowsDrag::QWindowsDrag() : m_dropDataObject(0) { } @@ -786,6 +712,17 @@ QWindowsDrag::~QWindowsDrag() { } +/*! + \brief Return data for a drop in process. If it stems from a current drag, use a shortcut. +*/ + +QMimeData *QWindowsDrag::dropData() +{ + if (const QDrag *drag = currentDrag()) + return drag->mimeData(); + return &m_dropData; +} + QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const { switch (action) { @@ -810,69 +747,46 @@ QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const return m_ignoreDragCursor; } -void QWindowsDrag::startDrag() +Qt::DropAction QWindowsDrag::drag(QDrag *drag) { // TODO: Accessibility handling? - QDragManager *dragManager = QDragManager::self(); - QMimeData *dropData = dragManager->dropData(); - m_dragBeingCancelled = false; + QMimeData *dropData = drag->mimeData(); + Qt::DropAction dragResult = Qt::IgnoreAction; DWORD resultEffect; QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this); windowDropSource->createCursors(); QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData); - const Qt::DropActions possibleActions = dragManager->possible_actions; + const Qt::DropActions possibleActions = drag->supportedActions(); const DWORD allowedEffects = translateToWinDragEffects(possibleActions); if (QWindowsContext::verboseOLE) qDebug(">%s possible Actions=%x, effects=0x%lx", __FUNCTION__, int(possibleActions), allowedEffects); const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect); const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect(); - Qt::DropAction ret = Qt::IgnoreAction; if (r == DRAGDROP_S_DROP) { if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) { - ret = Qt::TargetMoveAction; + dragResult = Qt::TargetMoveAction; resultEffect = DROPEFFECT_MOVE; } else { - ret = translateToQDragDropAction(resultEffect); + dragResult = translateToQDragDropAction(resultEffect); } // Force it to be a copy if an unsupported operation occurred. // This indicates a bug in the drop target. - if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects)) - ret = Qt::CopyAction; - } else { - dragManager->setCurrentTarget(0); + if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects)) { + qWarning("%s: Forcing Qt::CopyAction", __FUNCTION__); + dragResult = Qt::CopyAction; + } } - // clean up dropDataObject->releaseQt(); dropDataObject->Release(); // Will delete obj if refcount becomes 0 windowDropSource->Release(); // Will delete src if refcount becomes 0 if (QWindowsContext::verboseOLE) qDebug("<%s allowedEffects=0x%lx, reportedPerformedEffect=0x%lx, resultEffect=0x%lx, hr=0x%x, dropAction=%d", - __FUNCTION__, allowedEffects, reportedPerformedEffect, resultEffect, int(r), ret); -} - -void QWindowsDrag::move(const QMouseEvent *me) -{ - const QPoint pos = me->pos(); - if (QWindowsContext::verboseOLE) - qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y()); -} - -void QWindowsDrag::drop(const QMouseEvent *me) -{ - const QPoint pos = me->pos(); - if (QWindowsContext::verboseOLE) - qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y()); -} - -void QWindowsDrag::cancel() -{ - // TODO: Accessibility handling? - if (QWindowsContext::verboseOLE) - qDebug("%s", __FUNCTION__); - m_dragBeingCancelled = true; + __FUNCTION__, allowedEffects, reportedPerformedEffect, + resultEffect, int(r), dragResult); + return dragResult; } QWindowsDrag *QWindowsDrag::instance() diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index 86b5539f92..7b629baccc 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -45,9 +45,9 @@ #include "qwindowsinternalmimedata.h" #include <QtGui/QPlatformDrag> +#include <QtGui/QPixmap> QT_BEGIN_NAMESPACE - class QWindowsDropMimeData : public QWindowsInternalMimeData { public: QWindowsDropMimeData() {} @@ -73,11 +73,10 @@ public: private: inline QWindow *findDragOverWindow(const POINTL &pt) const; - void sendDragEnterEvent(QWindow *to, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + void handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &, LPDWORD pdwEffect); ULONG m_refs; QWindow *const m_window; - QWindow *m_currentWindow; QRect m_answerRect; QPoint m_lastPoint; DWORD m_chosenEffect; @@ -92,25 +91,20 @@ public: virtual QMimeData *platformDropData() { return &m_dropData; } - virtual void startDrag(); - virtual void move(const QMouseEvent *me); - virtual void drop(const QMouseEvent *me); - virtual void cancel(); + virtual Qt::DropAction drag(QDrag *drag); static QWindowsDrag *instance(); IDataObject *dropDataObject() const { return m_dropDataObject; } void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; } void releaseDropDataObject(); - - bool dragBeingCancelled() const { return m_dragBeingCancelled; } + QMimeData *dropData(); QPixmap defaultCursor(Qt::DropAction action) const; private: QWindowsDropMimeData m_dropData; IDataObject *m_dropDataObject; - bool m_dragBeingCancelled; mutable QPixmap m_copyDragCursor; mutable QPixmap m_moveDragCursor; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 5085dfefb7..ae5053210e 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -108,11 +108,11 @@ template <class T> \section1 Testing \list - \o Install the East Asian language support and choose Japanese (say). - \o Compile the \a mainwindows/mdi example and open a text window. - \o In the language bar, switch to Japanese and choose the + \li Install the East Asian language support and choose Japanese (say). + \li Compile the \a mainwindows/mdi example and open a text window. + \li In the language bar, switch to Japanese and choose the Input method 'Hiragana'. - \o In a text editor control, type the syllable \a 'la'. + \li In a text editor control, type the syllable \a 'la'. Underlined characters show up, indicating that there is completion available. Press the Space key two times. A completion popup occurs which shows the options. diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 3e98be4741..b43362c045 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -74,9 +74,9 @@ QT_BEGIN_NAMESPACE Currently implemented keys \list - \o handle (HWND) - \o getDC (DC) - \o releaseDC Releases the previously acquired DC and returns 0. + \li handle (HWND) + \li getDC (DC) + \li releaseDC Releases the previously acquired DC and returns 0. \endlist \ingroup qt-lighthouse-win diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 570e4b3b6b..e41db3f60f 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -413,14 +413,14 @@ static bool canGetData(int cf, IDataObject * pDataObj) Qt has predefined support for the following Windows Clipboard formats: \table - \header \o Windows Format \o Equivalent MIME type - \row \o \c CF_UNICODETEXT \o \c text/plain - \row \o \c CF_TEXT \o \c text/plain - \row \o \c CF_DIB \o \c{image/xyz}, where \c xyz is + \header \li Windows Format \li Equivalent MIME type + \row \li \c CF_UNICODETEXT \li \c text/plain + \row \li \c CF_TEXT \li \c text/plain + \row \li \c CF_DIB \li \c{image/xyz}, where \c xyz is a \l{QImageWriter::supportedImageFormats()}{Qt image format} - \row \o \c CF_HDROP \o \c text/uri-list - \row \o \c CF_INETURL \o \c text/uri-list - \row \o \c CF_HTML \o \c text/html + \row \li \c CF_HDROP \li \c text/uri-list + \row \li \c CF_INETURL \li \c text/uri-list + \row \li \c CF_HTML \li \c text/html \endtable An example use of this class would be to map the Windows Metafile diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index 3ae9fe1048..6f34967ee8 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -63,11 +63,11 @@ QT_BEGIN_NAMESPACE The following methods are NOT supported for data transfer using the clipboard or drag-drop: \list - \o IDataObject::SetData -- return E_NOTIMPL - \o IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED - \o ::DUnadvise - \o ::EnumDAdvise - \o IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL + \li IDataObject::SetData -- return E_NOTIMPL + \li IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED + \li ::DUnadvise + \li ::EnumDAdvise + \li IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL (NOTE: must set pformatetcOut->ptd = NULL) \endlist diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 436cc2c0d9..77a327a62a 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -115,7 +115,11 @@ public: QWindowsScreenManager(); - inline void clearScreens() { qDeleteAll(m_screens); m_screens.clear(); } + inline void clearScreens() { + // Delete screens in reverse order to avoid crash in case of multiple screens + while (!m_screens.isEmpty()) + delete m_screens.takeLast(); + } void handleScreenChanges(); bool handleDisplayChange(WPARAM wParam, LPARAM lParam); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 3e0bec8d46..b2ebe06a58 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -205,18 +205,18 @@ static bool shouldShowMaximizeButton(Qt::WindowFlags flags) Window creation is split in 3 steps: \list - \o fromWindow() Gather all required information - \o create() Create the system handle. - \o initialize() Post creation initialization steps. + \li fromWindow() Gather all required information + \li create() Create the system handle. + \li initialize() Post creation initialization steps. \endlist The reason for this split is to also enable changing the QWindowFlags by calling: \list - \o fromWindow() Gather information and determine new system styles - \o applyWindowFlags() to apply the new window system styles. - \o initialize() Post creation initialization steps. + \li fromWindow() Gather information and determine new system styles + \li applyWindowFlags() to apply the new window system styles. + \li initialize() Post creation initialization steps. \endlist Contains the window creation code formerly in qwidget_win.cpp. @@ -594,13 +594,13 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, \brief Raster or OpenGL Window. \list - \o Raster type: handleWmPaint() is implemented to + \li Raster type: handleWmPaint() is implemented to to bitblt the image. The DC can be accessed via getDC/Relase DC, which has a special handling when within a paint event (in that case, the DC obtained from BeginPaint() is returned). - \o Open GL: The first time QWindowsGLContext accesses + \li Open GL: The first time QWindowsGLContext accesses the handle, it sets up the pixelformat on the DC which in turn sets it on the window (see flag PixelFormatInitialized). diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index ab802ced27..17e8bb53eb 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -1,6 +1,6 @@ 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 +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 On Ubuntu 11.10 icccm1 is replaced by icccm4 and xcb-render-util is not available: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev The packages for xcb-render-util can be installed manually from http://packages.ubuntu.com/natty/libxcb-render-util0 and http://packages.ubuntu.com/natty/libxcb-render-util0-dev diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index f8d35ed4da..63ce73993f 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -74,7 +74,7 @@ public: break; default: - qWarning("QTestLiteMime: Internal error: Unsupported clipboard mode"); + qWarning("QXcbClipboardMime: Internal error: Unsupported clipboard mode"); break; } } @@ -209,7 +209,7 @@ QXcbClipboard::~QXcbClipboard() // waiting until the clipboard manager fetches the content. if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, clipboard_timeout, true)) { - qWarning("QClipboard: Unable to receive an event from the " + qWarning("QXcbClipboard: Unable to receive an event from the " "clipboard manager in a reasonable time"); } } @@ -292,7 +292,7 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time()); if (getSelectionOwner(modeAtom) != newOwner) { - qWarning("QClipboard::setData: Cannot set X11 selection owner"); + qWarning("QXcbClipboard::setData: Cannot set X11 selection owner"); } emitChanged(mode); @@ -403,7 +403,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); // (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment); - qWarning() << "not implemented INCR just YET!"; + qWarning("QXcbClipboard: INCR is unimplemented"); return property; } @@ -445,7 +445,7 @@ void QXcbClipboard::handleSelectionClearRequest(xcb_selection_clear_event_t *eve void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req) { if (requestor() && req->requestor == requestor()) { - qDebug() << "This should be caught before"; + qWarning("QXcbClipboard: Selection request should be caught before"); return; } @@ -460,7 +460,7 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req) QMimeData *d; QClipboard::Mode mode = modeForAtom(req->selection); if (mode > QClipboard::Selection) { - qWarning() << "QClipboard: Unknown selection" << connection()->atomName(req->selection); + qWarning() << "QXcbClipboard: Unknown selection" << connection()->atomName(req->selection); xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); return; } @@ -468,14 +468,14 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req) d = m_clientClipboard[mode]; if (!d) { - qWarning("QClipboard: Cannot transfer data, no data available"); + qWarning("QXcbClipboard: Cannot transfer data, no data available"); xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); return; } if (m_timestamp[mode] == XCB_CURRENT_TIME // we don't own the selection anymore || (req->time != XCB_CURRENT_TIME && req->time < m_timestamp[mode])) { - qDebug("QClipboard: SelectionRequest too old"); + qWarning("QXcbClipboard: SelectionRequest too old"); xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); return; } @@ -530,7 +530,7 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req) property, XCB_ATOM_INTEGER, 32, 1, &m_timestamp[mode]); ret = property; } else { - qWarning("QClipboard: Invalid data timestamp"); + qWarning("QXcbClipboard: Invalid data timestamp"); } } else if (target == xa_targets) { ret = sendTargetsSelection(d, req->requestor, property); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index fdc2c76fea..367b24da9d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -109,6 +109,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char , m_has_support_for_dri2(false) #endif , xfixes_first_event(0) + , has_shape_extension(false) + , has_input_shape(false) { m_primaryScreen = 0; @@ -133,7 +135,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char #endif //XCB_USE_XLIB if (!m_connection || xcb_connection_has_error(m_connection)) - qFatal("Could not connect to display %s", m_displayName.constData()); + qFatal("QXcbConnection: Could not connect to display %s", m_displayName.constData()); m_reader = new QXcbEventReader(this); #ifdef XCB_POLL_FOR_QUEUED_EVENT @@ -175,6 +177,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char #ifdef XCB_USE_XINPUT2_MAEMO initializeXInput2(); #endif + initializeXShape(); m_wmSupport.reset(new QXcbWMSupport(this)); m_keyboard = new QXcbKeyboard(this); @@ -191,7 +194,9 @@ QXcbConnection::~QXcbConnection() { delete m_clipboard; - qDeleteAll(m_screens); + // Delete screens in reverse order to avoid crash in case of multiple screens + while (!m_screens.isEmpty()) + delete m_screens.takeLast(); #ifdef XCB_USE_XINPUT2_MAEMO finalizeXInput2(); @@ -250,7 +255,7 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) #ifdef XCB_EVENT_DEBUG #define PRINT_XCB_EVENT(ev) \ case ev: \ - qDebug("%s: %d - %s - sequence: %d", message, int(ev), #ev, event->sequence); \ + qDebug("QXcbConnection: %s: %d - %s - sequence: %d", message, int(ev), #ev, event->sequence); \ break; switch (event->response_type & ~0x80) { @@ -287,7 +292,7 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE); PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY); default: - qDebug("%s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence)); + qDebug("QXcbConnection: %s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence)); } #else Q_UNUSED(message); @@ -460,7 +465,7 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); - qDebug("XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", + qWarning("QXcbConnection: XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", int(error->error_code), xcb_errors[clamped_error_code], int(error->sequence), int(error->resource_id), int(error->major_code), xcb_protocol_request_codes[clamped_major_code], @@ -552,7 +557,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; case XCB_SELECTION_NOTIFY: setTime(((xcb_selection_notify_event_t *)event)->time); - qDebug() << "XCB_SELECTION_NOTIFY"; handled = false; break; case XCB_PROPERTY_NOTIFY: @@ -714,9 +718,9 @@ void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t * return; if (event->type == atom(QXcbAtom::XdndStatus)) { - drag()->handleStatus(event, false); + drag()->handleStatus(event); } else if (event->type == atom(QXcbAtom::XdndFinished)) { - drag()->handleFinished(event, false); + drag()->handleFinished(event); } QXcbWindow *window = platformWindowFromId(event->window); @@ -1024,7 +1028,7 @@ void QXcbConnection::initializeXFixes() xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection, xfixes_query_cookie, &error); if (!xfixes_query || error || xfixes_query->major_version < 2) { - qWarning("Failed to initialize XFixes"); + qWarning("QXcbConnection: Failed to initialize XFixes"); free(error); xfixes_first_event = 0; } @@ -1041,13 +1045,32 @@ void QXcbConnection::initializeXRender() xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection, xrender_query_cookie, &error); if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) { - qWarning("Failed to initialize XRender"); + qWarning("QXcbConnection: Failed to initialize XRender"); free(error); } free(xrender_query); #endif } +void QXcbConnection::initializeXShape() +{ + const xcb_query_extension_reply_t *xshape_reply = xcb_get_extension_data(m_connection, &xcb_shape_id); + if (!xshape_reply || !xshape_reply->present) + return; + + has_shape_extension = true; + xcb_shape_query_version_cookie_t cookie = xcb_shape_query_version(m_connection); + xcb_shape_query_version_reply_t *shape_query = xcb_shape_query_version_reply(m_connection, + cookie, NULL); + if (!shape_query) { + qWarning("QXcbConnection: Failed to initialize SHAPE extension"); + } else if (shape_query->major_version > 1 || (shape_query->major_version == 1 && shape_query->minor_version >= 1)) { + // The input shape is the only thing added in SHAPE 1.1 + has_input_shape = true; + } + free(shape_query); +} + #if defined(XCB_USE_EGL) bool QXcbConnection::hasEgl() const { @@ -1066,7 +1089,7 @@ void QXcbConnection::initializeDri2() connect_cookie, NULL); if (! connect || connect->driver_name_length + connect->device_name_length == 0) { - qDebug() << "Failed to connect to dri2"; + qWarning("QXcbConnection: Failed to connect to DRI2"); return; } @@ -1076,14 +1099,14 @@ void QXcbConnection::initializeDri2() int fd = open(m_dri2_device_name.constData(), O_RDWR); if (fd < 0) { - qDebug() << "InitializeDri2: Could'nt open device << dri2DeviceName"; + qWarning() << "QXcbConnection: Couldn't open DRI2 device" << m_dri2_device_name; m_dri2_device_name = QByteArray(); return; } drm_magic_t magic; if (drmGetMagic(fd, &magic)) { - qDebug() << "Failed to get drmMagic"; + qWarning("QXcbConnection: Failed to get drmMagic"); return; } @@ -1092,7 +1115,7 @@ void QXcbConnection::initializeDri2() xcb_dri2_authenticate_reply_t *authenticate = xcb_dri2_authenticate_reply(m_connection, authenticate_cookie, NULL); if (authenticate == NULL || !authenticate->authenticated) { - qWarning("DRI2: failed to authenticate"); + qWarning("QXcbConnection: DRI2: failed to authenticate"); free(authenticate); return; } @@ -1101,14 +1124,14 @@ void QXcbConnection::initializeDri2() EGLDisplay display = eglGetDRMDisplayMESA(fd); if (!display) { - qWarning("failed to create display"); + qWarning("QXcbConnection: Failed to create EGL display using DRI2"); return; } m_egl_display = display; EGLint major,minor; if (!eglInitialize(display, &major, &minor)) { - qWarning("failed to initialize display"); + qWarning("QXcbConnection: Failed to initialize EGL display using DRI2"); return; } } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 7beb41bdd7..34943bfdef 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -354,6 +354,8 @@ public: inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; } bool hasXFixes() const { return xfixes_first_event > 0; } + bool hasXShape() const { return has_shape_extension; } + bool hasInputShape() const { return has_input_shape; } private slots: void processXcbEvents(); @@ -363,6 +365,7 @@ private: void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); void initializeXFixes(); void initializeXRender(); + void initializeXShape(); #ifdef XCB_USE_DRI2 void initializeDri2(); #endif @@ -429,6 +432,9 @@ private: QVector<PeekFunc> m_peekFuncs; uint32_t xfixes_first_event; + + bool has_shape_extension; + bool has_input_shape; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index e928fe2d0a..3aeaaba2d8 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -52,6 +52,12 @@ #include <qevent.h> #include <qguiapplication.h> #include <qrect.h> +#include <qpainter.h> + +#include <QtGui/QWindowSystemInterface> + +#include <QtPlatformSupport/private/qshapedpixmapdndwindow_p.h> +#include <QtPlatformSupport/private/qsimpledrag_p.h> QT_BEGIN_NAMESPACE @@ -109,12 +115,11 @@ static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w) return proxy; } - -class QDropData : public QXcbMime +class QXcbDropData : public QXcbMime { public: - QDropData(QXcbDrag *d); - ~QDropData(); + QXcbDropData(QXcbDrag *d); + ~QXcbDropData(); protected: bool hasFormat_sys(const QString &mimeType) const; @@ -127,10 +132,9 @@ protected: }; -QXcbDrag::QXcbDrag(QXcbConnection *c) - : QXcbObject(c) +QXcbDrag::QXcbDrag(QXcbConnection *c) : QXcbObject(c) { - dropData = new QDropData(this); + dropData = new QXcbDropData(this); init(); heartbeat = -1; @@ -147,13 +151,13 @@ void QXcbDrag::init() { currentWindow.clear(); + accepted_drop_action = Qt::IgnoreAction; + xdnd_dragsource = XCB_NONE; - last_target_accepted_action = Qt::IgnoreAction; waiting_for_status = false; current_target = XCB_NONE; current_proxy_target = XCB_NONE; - xdnd_dragging = false; source_time = XCB_CURRENT_TIME; target_time = XCB_CURRENT_TIME; @@ -169,16 +173,17 @@ QMimeData *QXcbDrag::platformDropData() void QXcbDrag::startDrag() { + // #fixme enableEventFilter(); + init(); heartbeat = startTimer(200); - xdnd_dragging = true; + xcb_set_selection_owner(xcb_connection(), connection()->clipboard()->owner(), atom(QXcbAtom::XdndSelection), connection()->time()); - QDragManager *manager = QDragManager::self(); - QStringList fmts = QXcbMime::formatsHelper(manager->dropData()); + QStringList fmts = QXcbMime::formatsHelper(drag()->mimeData()); for (int i = 0; i < fmts.size(); ++i) { QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i)); for (int j = 0; j < atoms.size(); ++j) { @@ -190,23 +195,16 @@ void QXcbDrag::startDrag() xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(), atom(QXcbAtom::XdndTypelist), XCB_ATOM_ATOM, 32, drag_types.size(), (const void *)drag_types.constData()); - - QPointF pos = QCursor::pos(); - QMouseEvent me(QEvent::MouseMove, pos, pos, pos, Qt::LeftButton, - QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); - move(&me); - -// if (!QWidget::mouseGrabber()) -// manager->shapedPixmapWindow->grabMouse(); + QBasicDrag::startDrag(); } void QXcbDrag::endDrag() { - Q_ASSERT(heartbeat != -1); - killTimer(heartbeat); - heartbeat = -1; - - xdnd_dragging = false; + if (heartbeat != -1) { + killTimer(heartbeat); + heartbeat = -1; + } + QBasicDrag::endDrag(); } static xcb_translate_coordinates_reply_t * @@ -217,9 +215,29 @@ translateCoordinates(QXcbConnection *c, xcb_window_t from, xcb_window_t to, int return xcb_translate_coordinates_reply(c->xcb_connection(), cookie, 0); } +static +bool windowInteractsWithPosition(xcb_connection_t *connection, const QPoint & pos, xcb_window_t w, xcb_shape_sk_t shapeType) +{ + bool interacts = true; + xcb_shape_get_rectangles_reply_t *reply = xcb_shape_get_rectangles_reply(connection, xcb_shape_get_rectangles(connection, w, shapeType), NULL); + if (reply) { + xcb_rectangle_t *rectangles = xcb_shape_get_rectangles_rectangles(reply); + if (rectangles) { + interacts = false; + const int nRectangles = xcb_shape_get_rectangles_rectangles_length(reply); + for (int i = 0; !interacts && i < nRectangles; ++i) { + interacts = QRect(rectangles[i].x, rectangles[i].y, rectangles[i].width, rectangles[i].height).contains(pos); + } + } + free(reply); + } + + return interacts; +} + xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md) { - if (w == QDragManager::self()->shapedPixmapWindow->handle()->winId()) + if (w == shapedPixmapWindow()->handle()->winId()) return 0; if (md) { @@ -244,22 +262,12 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md bool isAware = reply && reply->type != XCB_NONE; free(reply); if (isAware) { - xcb_xfixes_region_t region = xcb_generate_id(xcb_connection()); - xcb_xfixes_create_region_from_window(xcb_connection(), region, w, XCB_SHAPE_SK_BOUNDING); - xcb_xfixes_fetch_region_reply_t *reply = xcb_xfixes_fetch_region_reply(xcb_connection(), xcb_xfixes_fetch_region(xcb_connection(), region), NULL); - if (reply) { - xcb_rectangle_t *rectangles = xcb_xfixes_fetch_region_rectangles(reply); - if (rectangles) { - windowContainsMouse = false; - const int nRectangles = xcb_xfixes_fetch_region_rectangles_length(reply); - for (int i = 0; !windowContainsMouse && i < nRectangles; ++i) { - windowContainsMouse = QRect(rectangles[i].x, rectangles[i].y, rectangles[i].width, rectangles[i].height).contains(pos); - } - } - free(reply); - } - xcb_xfixes_destroy_region(xcb_connection(), region); - + // When ShapeInput and ShapeBounding are not set they return a single rectangle with the geometry of the window, this is why we + // need to check both here so that in the case one is set and the other is not we still get the correct result. + if (connection()->hasInputShape()) + windowContainsMouse = windowInteractsWithPosition(xcb_connection(), pos, w, XCB_SHAPE_SK_INPUT); + if (windowContainsMouse && connection()->hasXShape()) + windowContainsMouse = windowInteractsWithPosition(xcb_connection(), pos, w, XCB_SHAPE_SK_BOUNDING); if (windowContainsMouse) return w; } @@ -296,9 +304,7 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md void QXcbDrag::move(const QMouseEvent *me) { - DEBUG() << "QDragManager::move enter" << me->globalPos(); - - // ### + QBasicDrag::move(me); QPoint globalPos = me->globalPos(); if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) @@ -337,15 +343,13 @@ void QXcbDrag::move(const QMouseEvent *me) ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y()); if (!translate) return; + xcb_window_t target = translate->child; int lx = translate->dst_x; int ly = translate->dst_y; free (translate); - if (target == rootwin) { - // Ok. - } else if (target) { - //me + if (target && target != rootwin) { xcb_window_t src = rootwin; while (target != 0) { DNDDEBUG << "checking target for XdndAware" << target << lx << ly; @@ -376,7 +380,7 @@ void QXcbDrag::move(const QMouseEvent *me) target = child; } - if (!target || target == QDragManager::self()->shapedPixmapWindow->handle()->winId()) { + if (!target || target == shapedPixmapWindow()->handle()->winId()) { DNDDEBUG << "need to find real window"; target = findRealWindow(globalPos, rootwin, 6); DNDDEBUG << "real window found" << target; @@ -393,9 +397,6 @@ void QXcbDrag::move(const QMouseEvent *me) target = rootwin; } - DNDDEBUG << "and the final target is " << target; - DNDDEBUG << "the widget w is" << (w ? w->window() : 0); - xcb_window_t proxy_target = xdndProxy(connection(), target); if (!proxy_target) proxy_target = target; @@ -414,7 +415,6 @@ void QXcbDrag::move(const QMouseEvent *me) free(reply); } - DEBUG() << "target=" << target << "current_target=" << current_target; if (target != current_target) { if (current_target) send_leave(); @@ -447,11 +447,10 @@ void QXcbDrag::move(const QMouseEvent *me) waiting_for_status = false; } } + if (waiting_for_status) return; - QDragManager *m = QDragManager::self(); - if (target) { waiting_for_status = true; @@ -465,28 +464,21 @@ void QXcbDrag::move(const QMouseEvent *me) move.data.data32[1] = 0; // flags move.data.data32[2] = (globalPos.x() << 16) + globalPos.y(); move.data.data32[3] = connection()->time(); - move.data.data32[4] = toXdndAction(m->defaultAction(m->dragPrivate()->possible_actions, QGuiApplication::keyboardModifiers())); + move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers())); DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; source_time = connection()->time(); if (w) - handle_xdnd_position(w->window(), &move, false); + handle_xdnd_position(w->window(), &move); else xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); - } else { - if (m->willDrop) { - m->willDrop = false; - } } - m->updateCursor(); - DEBUG() << "QDragManager::move leave"; } -void QXcbDrag::drop(const QMouseEvent *) +void QXcbDrag::drop(const QMouseEvent *event) { - endDrag(); - + QBasicDrag::drop(event); if (!current_target) return; @@ -500,14 +492,13 @@ void QXcbDrag::drop(const QMouseEvent *) drop.data.data32[2] = connection()->time(); drop.data.data32[3] = 0; - drop.data.data32[4] = 0; + drop.data.data32[4] = currentDrag()->supportedActions(); QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; - QDragManager *manager = QDragManager::self(); Transaction t = { connection()->time(), @@ -515,21 +506,22 @@ void QXcbDrag::drop(const QMouseEvent *) current_proxy_target, (w ? w->window() : 0), // current_embedding_widget, - manager->object + currentDrag() }; transactions.append(t); restartDropExpiryTimer(); - if (w) - handleDrop(w->window(), &drop, false); - else + if (w) { + handleDrop(w->window(), &drop); + } else { xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop); + } current_target = 0; current_proxy_target = 0; source_time = 0; // current_embedding_widget = 0; - manager->object = 0; + // #fixme resetDndState(false); } Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const @@ -719,7 +711,7 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev DEBUG() << " " << connection()->atomName(xdnd_types.at(i)); } -void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e, bool passive) +void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e) { QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); Q_ASSERT(w); @@ -727,11 +719,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t p -= geometry.topLeft(); - // #### -// if (!passive && checkEmbedded(w, e)) -// return; - - if (!w || (/*!w->acceptDrops() &&*/ (w->windowType() == Qt::Desktop))) + if (!w || (w->windowType() == Qt::Desktop)) return; if (e->data.data32[0] != xdnd_dragsource) { @@ -739,12 +727,27 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t return; } + currentPosition = p; + currentWindow = w; + // timestamp from the source - if (e->data.data32[3] != XCB_NONE) - target_time /*= X11->userTime*/ = e->data.data32[3]; + if (e->data.data32[3] != XCB_NONE) { + target_time = e->data.data32[3]; + } - QDragManager *manager = QDragManager::self(); - QMimeData *dropData = manager->dropData(); + QMimeData *dropData = 0; + Qt::DropActions supported_actions = Qt::IgnoreAction; + if (currentDrag()) { + dropData = currentDrag()->mimeData(); + supported_actions = currentDrag()->supportedActions(); + } else { + dropData = platformDropData(); + supported_actions = Qt::DropActions(toDropAction(e->data.data32[4])); + } + + QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w,dropData,p,supported_actions); + QRect answerRect(p + geometry.topLeft(), QSize(1,1)); + answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry); xcb_client_message_event_t response; response.response_type = XCB_CLIENT_MESSAGE; @@ -752,83 +755,33 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t response.format = 32; response.type = atom(QXcbAtom::XdndStatus); response.data.data32[0] = xcb_window(w); - response.data.data32[1] = 0; // flags + response.data.data32[1] = qt_response.isAccepted(); // flags response.data.data32[2] = 0; // x, y response.data.data32[3] = 0; // w, h - response.data.data32[4] = 0; // action + response.data.data32[4] = toXdndAction(qt_response.acceptedAction()); // action - if (!passive) { // otherwise just reject - QRect answerRect(p + geometry.topLeft(), QSize(1,1)); - if (manager->object) { - manager->possible_actions = manager->dragPrivate()->possible_actions; - } else { - manager->possible_actions = Qt::DropActions(toDropAction(e->data.data32[4])); - } - QDragMoveEvent me(p, manager->possible_actions, dropData, - QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); - - Qt::DropAction accepted_action = Qt::IgnoreAction; - - currentPosition = p; - - if (w != currentWindow.data()) { - if (currentWindow) { - QDragLeaveEvent e; - QGuiApplication::sendEvent(currentWindow.data(), &e); - } - currentWindow = w; - - last_target_accepted_action = Qt::IgnoreAction; - QDragEnterEvent de(p, manager->possible_actions, dropData, - QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); - QGuiApplication::sendEvent(w, &de); - if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction) - last_target_accepted_action = de.dropAction(); - } - DEBUG() << "qt_handle_xdnd_position action=" << connection()->atomName(e->data.data32[4]); + if (answerRect.left() < 0) + answerRect.setLeft(0); + if (answerRect.right() > 4096) + answerRect.setRight(4096); + if (answerRect.top() < 0) + answerRect.setTop(0); + if (answerRect.bottom() > 4096) + answerRect.setBottom(4096); + if (answerRect.width() < 0) + answerRect.setWidth(0); + if (answerRect.height() < 0) + answerRect.setHeight(0); - if (last_target_accepted_action != Qt::IgnoreAction) { - me.setDropAction(last_target_accepted_action); - me.accept(); - } - QGuiApplication::sendEvent(w, &me); - if (me.isAccepted()) { - response.data.data32[1] = 1; // yes - accepted_action = me.dropAction(); - last_target_accepted_action = accepted_action; - } else { - response.data.data32[0] = 0; - last_target_accepted_action = Qt::IgnoreAction; - } - answerRect = me.answerRect().translated(geometry.topLeft()).intersected(geometry); - - if (answerRect.left() < 0) - answerRect.setLeft(0); - if (answerRect.right() > 4096) - answerRect.setRight(4096); - if (answerRect.top() < 0) - answerRect.setTop(0); - if (answerRect.bottom() > 4096) - answerRect.setBottom(4096); - if (answerRect.width() < 0) - answerRect.setWidth(0); - if (answerRect.height() < 0) - answerRect.setHeight(0); - -// response.data.data32[2] = (answerRect.x() << 16) + answerRect.y(); -// response.data.data32[3] = (answerRect.width() << 16) + answerRect.height(); - response.data.data32[4] = toXdndAction(accepted_action); - } + response.data.data32[4] = toXdndAction(qt_response.acceptedAction()); // reset target_time = XCB_CURRENT_TIME; - DEBUG() << "sending XdndStatus" << (xdnd_dragsource == connection()->clipboard()->owner()) << xdnd_dragsource - << response.data.data32[1] << connection()->atomName(response.data.data32[4]); if (xdnd_dragsource == connection()->clipboard()->owner()) - handle_xdnd_status(&response, passive); + handle_xdnd_status(&response); else Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, XCB_EVENT_MASK_NO_EVENT, (const char *)&response)); @@ -850,7 +803,7 @@ namespace }; } -void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event, bool passive) +void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event) { xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); xcb_generic_event_t *nextEvent; @@ -861,19 +814,28 @@ void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *eve lastEvent = (xcb_client_message_event_t *)nextEvent; } - handle_xdnd_position(w, lastEvent, passive); + handle_xdnd_position(w, lastEvent); if (lastEvent != event) free(lastEvent); } -void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event, bool) +void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event) { DEBUG("xdndHandleStatus"); + waiting_for_status = false; // ignore late status messages if (event->data.data32[0] && event->data.data32[0] != current_proxy_target) return; - Qt::DropAction newAction = (event->data.data32[1] & 0x1) ? toDropAction(event->data.data32[4]) : Qt::IgnoreAction; + const bool dropPossible = event->data.data32[1]; + setCanDrop(dropPossible); + + if (dropPossible) { + accepted_drop_action = toDropAction(event->data.data32[4]); + updateCursor(accepted_drop_action); + } else { + updateCursor(Qt::IgnoreAction); + } if ((event->data.data32[1] & 2) == 0) { QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff); @@ -882,18 +844,9 @@ void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event, bool) } else { source_sameanswer = QRect(); } - QDragManager *manager = QDragManager::self(); - manager->willDrop = (event->data.data32[1] & 0x1); - if (manager->global_accepted_action != newAction) { - manager->global_accepted_action = newAction; - manager->emitActionChanged(newAction); - } - DEBUG() << "willDrop=" << manager->willDrop << "action=" << newAction; - manager->updateCursor(); - waiting_for_status = false; } -void QXcbDrag::handleStatus(const xcb_client_message_event_t *event, bool passive) +void QXcbDrag::handleStatus(const xcb_client_message_event_t *event) { if (event->window != connection()->clipboard()->owner()) return; @@ -907,13 +860,13 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event, bool passiv lastEvent = (xcb_client_message_event_t *)nextEvent; } - handle_xdnd_status(lastEvent, passive); + handle_xdnd_status(lastEvent); if (lastEvent != event) free(lastEvent); DEBUG("xdndHandleStatus end"); } -void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/) +void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event) { DEBUG("xdnd leave"); if (!currentWindow || w != currentWindow.data()) @@ -931,8 +884,8 @@ void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event, DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource); } - QDragLeaveEvent e; - QGuiApplication::sendEvent(currentWindow.data(), &e); + QWindowSystemInterface::handleDrag(w,0,QPoint(),Qt::IgnoreAction); + updateAction(Qt::IgnoreAction); xdnd_dragsource = 0; xdnd_types.clear(); @@ -944,7 +897,6 @@ void QXcbDrag::send_leave() if (!current_target) return; - QDragManager *manager = QDragManager::self(); xcb_client_message_event_t leave; leave.response_type = XCB_CLIENT_MESSAGE; @@ -963,24 +915,18 @@ void QXcbDrag::send_leave() w = 0; if (w) - handleLeave(w->window(), (const xcb_client_message_event_t *)&leave, false); + handleLeave(w->window(), (const xcb_client_message_event_t *)&leave); else xcb_send_event(xcb_connection(), false,current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&leave); - // reset the drag manager state - manager->willDrop = false; - if (manager->global_accepted_action != Qt::IgnoreAction) - manager->emitActionChanged(Qt::IgnoreAction); - manager->global_accepted_action = Qt::IgnoreAction; - manager->updateCursor(); current_target = 0; current_proxy_target = 0; source_time = XCB_CURRENT_TIME; waiting_for_status = false; } -void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive) +void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event) { DEBUG("xdndHandleDrop"); if (!currentWindow) { @@ -988,16 +934,8 @@ void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bo return; // sanity } - // ### -// if (!passive && checkEmbedded(currentWindow, xe)){ -// current_embedding_widget = 0; -// xdnd_dragsource = 0; -// currentWindow = 0; -// return; -// } const uint32_t *l = event->data.data32; - QDragManager *manager = QDragManager::self(); DEBUG("xdnd drop"); if (l[0] != xdnd_dragsource) { @@ -1009,50 +947,39 @@ void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bo if (l[2] != 0) target_time = /*X11->userTime =*/ l[2]; - if (!passive) { - // this could be a same-application drop, just proxied due to - // some XEMBEDding, so try to find the real QMimeData used - // based on the timestamp for this drop. - QMimeData *dropData = 0; - // ### -// int at = findXdndDropTransactionByTime(target_time); -// if (at != -1) -// dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data; - // if we can't find it, then use the data in the drag manager - if (!dropData) - dropData = manager->dropData(); - - // Drop coming from another app? Update keyboard modifiers. -// if (!qt_xdnd_dragging) { -// QApplicationPrivate::modifier_buttons = currentKeyboardModifiers(); -// } - - QDropEvent de(currentPosition, manager->possible_actions, dropData, - QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); - QGuiApplication::sendEvent(currentWindow.data(), &de); - if (!de.isAccepted()) { - // Ignore a failed drag - manager->global_accepted_action = Qt::IgnoreAction; - } else { - manager->global_accepted_action = de.dropAction(); - } - xcb_client_message_event_t finished; - finished.response_type = XCB_CLIENT_MESSAGE; - finished.window = xdnd_dragsource; - finished.format = 32; - finished.type = atom(QXcbAtom::XdndFinished); - DNDDEBUG << "xdndHandleDrop" - << "currentWindow" << currentWindow.data() - << (currentWindow ? xcb_window(currentWindow.data()) : 0); - finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE; - finished.data.data32[1] = de.isAccepted() ? 1 : 0; // flags - finished.data.data32[2] = toXdndAction(manager->global_accepted_action); - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, - XCB_EVENT_MASK_NO_EVENT, (char *)&finished)); + // this could be a same-application drop, just proxied due to + // some XEMBEDding, so try to find the real QMimeData used + // based on the timestamp for this drop. + Qt::DropActions supported_drop_actions(l[4]); + QMimeData *dropData = 0; + if (currentDrag()) { + dropData = currentDrag()->mimeData(); } else { - QDragLeaveEvent e; - QGuiApplication::sendEvent(currentWindow.data(), &e); + dropData = platformDropData(); } + + if (!dropData) + return; + // ### + // int at = findXdndDropTransactionByTime(target_time); + // if (at != -1) + // dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data; + // if we can't find it, then use the data in the drag manager + + QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(currentWindow.data(),dropData,currentPosition,supported_drop_actions); + setExecutedDropAction(response.acceptedAction()); + + xcb_client_message_event_t finished; + finished.response_type = XCB_CLIENT_MESSAGE; + finished.window = xdnd_dragsource; + finished.format = 32; + finished.type = atom(QXcbAtom::XdndFinished); + finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE; + finished.data.data32[1] = response.isAccepted(); // flags + finished.data.data32[2] = toXdndAction(response.acceptedAction()); + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, + XCB_EVENT_MASK_NO_EVENT, (char *)&finished)); + xdnd_dragsource = 0; currentWindow.clear(); waiting_for_status = false; @@ -1062,7 +989,7 @@ void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bo } -void QXcbDrag::handleFinished(const xcb_client_message_event_t *event, bool) +void QXcbDrag::handleFinished(const xcb_client_message_event_t *event) { DEBUG("xdndHandleFinished"); if (event->window != connection()->clipboard()->owner()) @@ -1099,8 +1026,8 @@ void QXcbDrag::handleFinished(const xcb_client_message_event_t *event, bool) // current_target = 0; // current_proxy_target = 0; - if (t.object) - t.object->deleteLater(); + if (t.drag) + t.drag->deleteLater(); // current_target = target; // current_proxy_target = proxy_target; @@ -1126,7 +1053,7 @@ void QXcbDrag::timerEvent(QTimerEvent* e) // dnd within the same process, don't delete these continue; } - t.object->deleteLater(); + t.drag->deleteLater(); transactions.removeAt(i--); } @@ -1138,12 +1065,9 @@ void QXcbDrag::timerEvent(QTimerEvent* e) void QXcbDrag::cancel() { DEBUG("QXcbDrag::cancel"); - endDrag(); - + QBasicDrag::cancel(); if (current_target) send_leave(); - - current_target = 0; } @@ -1157,14 +1081,11 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event notify.property = XCB_NONE; notify.time = event->time; - QDragManager *manager = QDragManager::self(); - QDrag *currentObject = manager->object; - // which transaction do we use? (note: -2 means use current manager->object) int at = -1; // figure out which data the requestor is really interested in - if (manager->object && event->time == source_time) { + if (currentDrag() && event->time == source_time) { // requestor wants the current drag data at = -2; } else { @@ -1188,20 +1109,18 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event // } // } } + + QDrag *transactionDrag = 0; if (at >= 0) { restartDropExpiryTimer(); - // use the drag object from an XdndDrop tansaction - manager->object = transactions.at(at).object; - } else if (at != -2) { - // no transaction found, we'll have to reject the request - manager->object = 0; + transactionDrag = transactions.at(at).drag; } - if (manager->object) { + if (transactionDrag) { xcb_atom_t atomFormat = event->target; int dataFormat = 0; QByteArray data; - if (QXcbMime::mimeDataForAtom(connection(), event->target, manager->dragPrivate()->data, + if (QXcbMime::mimeDataForAtom(connection(), event->target, transactionDrag->mimeData(), &data, &atomFormat, &dataFormat)) { int dataSize = data.size() / (dataFormat / 8); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, event->requestor, event->property, @@ -1211,9 +1130,6 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event } } - // reset manager->object in case we modified it above - manager->object = currentObject; - xcb_send_event(xcb_connection(), false, event->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)¬ify); } @@ -1268,20 +1184,17 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) } } - - - -QDropData::QDropData(QXcbDrag *d) +QXcbDropData::QXcbDropData(QXcbDrag *d) : QXcbMime(), drag(d) { } -QDropData::~QDropData() +QXcbDropData::~QXcbDropData() { } -QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const +QVariant QXcbDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const { QByteArray mime = mimetype.toLatin1(); QVariant data = /*X11->motifdnd_active @@ -1290,17 +1203,16 @@ QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type req return data; } -QVariant QDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const +QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const { QByteArray result; - QDragManager *manager = QDragManager::self(); QXcbConnection *c = drag->connection(); QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource); - if (xcb_window && manager->object && xcb_window->window()->windowType() != Qt::Desktop) { - QDragPrivate *o = manager->dragPrivate(); - if (o->data->hasFormat(QLatin1String(format))) - result = o->data->data(QLatin1String(format)); + if (xcb_window && drag->currentDrag() && xcb_window->window()->windowType() != Qt::Desktop) { + QMimeData *data = drag->currentDrag()->mimeData(); + if (data->hasFormat(QLatin1String(format))) + result = data->data(QLatin1String(format)); return result; } @@ -1320,12 +1232,12 @@ QVariant QDropData::xdndObtainData(const QByteArray &format, QVariant::Type requ } -bool QDropData::hasFormat_sys(const QString &format) const +bool QXcbDropData::hasFormat_sys(const QString &format) const { return formats().contains(format); } -QStringList QDropData::formats_sys() const +QStringList QXcbDropData::formats_sys() const { QStringList formats; // if (X11->motifdnd_active) { diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index e32e630548..710a07a5a4 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -43,6 +43,7 @@ #define QXCBDRAG_H #include <qplatformdrag_qpa.h> +#include <QtPlatformSupport/private/qsimpledrag_p.h> #include <qxcbobject.h> #include <xcb/xcb.h> #include <qlist.h> @@ -51,17 +52,23 @@ #include <qsharedpointer.h> #include <qvector.h> +#include <qpixmap.h> +#include <qbackingstore.h> + +#include <QtCore/QDebug> + QT_BEGIN_NAMESPACE class QMouseEvent; class QWindow; class QXcbConnection; class QXcbWindow; -class QDropData; +class QXcbDropData; class QXcbScreen; class QDrag; +class QShapedPixmapWindow; -class QXcbDrag : public QObject, public QXcbObject, public QPlatformDrag +class QXcbDrag : public QXcbObject, public QBasicDrag { public: QXcbDrag(QXcbConnection *c); @@ -69,35 +76,36 @@ public: virtual QMimeData *platformDropData(); -// virtual Qt::DropAction drag(QDrag *); - virtual void startDrag(); - virtual void cancel(); - virtual void move(const QMouseEvent *me); - virtual void drop(const QMouseEvent *me); + void startDrag(); + void cancel(); + void move(const QMouseEvent *me); + void drop(const QMouseEvent *me); void endDrag(); void handleEnter(QWindow *window, const xcb_client_message_event_t *event); - void handlePosition(QWindow *w, const xcb_client_message_event_t *event, bool passive); - void handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/); - void handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive); + void handlePosition(QWindow *w, const xcb_client_message_event_t *event); + void handleLeave(QWindow *w, const xcb_client_message_event_t *event); + void handleDrop(QWindow *, const xcb_client_message_event_t *event); - void handleStatus(const xcb_client_message_event_t *event, bool passive); + void handleStatus(const xcb_client_message_event_t *event); void handleSelectionRequest(const xcb_selection_request_event_t *event); - void handleFinished(const xcb_client_message_event_t *event, bool passive); + void handleFinished(const xcb_client_message_event_t *event); bool dndEnable(QXcbWindow *win, bool on); + void updatePixmap(); + protected: void timerEvent(QTimerEvent* e); private: - friend class QDropData; + friend class QXcbDropData; void init(); - void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event, bool passive); - void handle_xdnd_status(const xcb_client_message_event_t *event, bool); + void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event); + void handle_xdnd_status(const xcb_client_message_event_t *event); void send_leave(); Qt::DropAction toDropAction(xcb_atom_t atom) const; @@ -106,7 +114,8 @@ private: QWeakPointer<QWindow> currentWindow; QPoint currentPosition; - QDropData *dropData; + QXcbDropData *dropData; + Qt::DropAction accepted_drop_action; QWindow *desktop_proxy; @@ -118,7 +127,6 @@ private: xcb_timestamp_t target_time; xcb_timestamp_t source_time; - Qt::DropAction last_target_accepted_action; // rectangle in which the answer will be the same QRect source_sameanswer; @@ -132,7 +140,6 @@ private: QXcbScreen *current_screen; int heartbeat; - bool xdnd_dragging; QVector<xcb_atom_t> drag_types; @@ -143,7 +150,7 @@ private: xcb_window_t proxy_target; QWindow *targetWindow; // QWidget *embedding_widget; - QDrag *object; + QDrag *drag; }; QList<Transaction> transactions; diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index 13ff8ab2a5..12979bfb68 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -201,7 +201,7 @@ xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, formatsCookie, &error); if (!formatsReply || error) { - qWarning("createCursorXRender: query_pict_formats failed"); + qWarning("qt_xcb_createCursorXRender: query_pict_formats failed"); free(formatsReply); free(error); return XCB_NONE; @@ -209,7 +209,7 @@ xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply, XCB_PICT_STANDARD_ARGB_32); if (!fmt) { - qWarning("createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32"); + qWarning("qt_xcb_createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32"); free(formatsReply); return XCB_NONE; } @@ -221,13 +221,13 @@ xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, XCB_IMAGE_ORDER_MSB_FIRST, 0, 0, 0); if (!xi) { - qWarning("createCursorXRender: xcb_image_create failed"); + qWarning("qt_xcb_createCursorXRender: xcb_image_create failed"); free(formatsReply); return XCB_NONE; } xi->data = (uint8_t *) malloc(xi->stride * h); if (!xi->data) { - qWarning("createCursorXRender: Failed to malloc() image data"); + qWarning("qt_xcb_createCursorXRender: Failed to malloc() image data"); xcb_image_destroy(xi); free(formatsReply); return XCB_NONE; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 98f69e9e16..fe33bd7153 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -101,7 +101,9 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters) m_connections << new QXcbConnection(m_nativeInterface.data()); for (int i = 0; i < parameters.size() - 1; i += 2) { - qDebug() << parameters.at(i) << parameters.at(i+1); +#ifdef Q_XCB_DEBUG + qDebug() << "QXcbIntegration: Connecting to additional display: " << parameters.at(i) << parameters.at(i+1); +#endif QString display = parameters.at(i) + ':' + parameters.at(i+1); m_connections << new QXcbConnection(m_nativeInterface.data(), display.toAscii().constData()); } @@ -185,7 +187,7 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont #elif defined(XCB_USE_DRI2) return new QDri2Context(context->format(), context->shareHandle()); #endif - qWarning("Cannot create platform GL context, none of GLX, EGL, DRI2 is enabled"); + qWarning("QXcbIntegration: Cannot create platform OpenGL context, none of GLX, EGL, or DRI2 are enabled"); return 0; } #endif diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index b682b87bc3..03156dc544 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -935,7 +935,7 @@ void QXcbKeyboard::setupModifiers() xcb_get_modifier_mapping_reply_t *modMapReply = xcb_get_modifier_mapping_reply(conn, modMapCookie, &error); if (error) { - qWarning("xcb keyboard: failed to get modifier mapping"); + qWarning("QXcbKeyboard: failed to get modifier mapping"); free(error); return; } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 406f9c24bd..f56072f9d7 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -137,7 +137,7 @@ QPlatformNativeInterface::EventFilter QXcbNativeInterface::setEventFilter(const if (eventType == QByteArrayLiteral("xcb_generic_event_t")) type = GenericEventFilter; if (type == -1) { - qWarning("%s: Attempt to set invalid event filter type '%s'.", + qWarning("QXcbNativeInterface: %s: Attempt to set invalid event filter type '%s'.", Q_FUNC_INFO, eventType.constData()); return 0; } diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index c93b4863e1..15ffc5b8ff 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -55,6 +55,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num , m_screen(screen) , m_number(number) { +#ifdef Q_XCB_DEBUG qDebug(); qDebug("Information of screen %d:", screen->root); qDebug(" width.........: %d", screen->width_in_pixels); @@ -63,6 +64,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num qDebug(" white pixel...: %x", screen->white_pixel); qDebug(" black pixel...: %x", screen->black_pixel); qDebug(); +#endif const quint32 mask = XCB_CW_EVENT_MASK; const quint32 values[] = { @@ -93,7 +95,9 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num atom(QXcbAtom::UTF8_STRING), 0, 1024), &error); if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) { m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply)); +#ifdef Q_XCB_DEBUG qDebug("Running window manager: %s", qPrintable(m_windowManagerName)); +#endif } else if (error) { connection->handleXcbError(error); free(error); diff --git a/src/plugins/platforms/xcb/qxcbsharedbuffermanager.cpp b/src/plugins/platforms/xcb/qxcbsharedbuffermanager.cpp index f9e388b662..8bd3aea259 100644 --- a/src/plugins/platforms/xcb/qxcbsharedbuffermanager.cpp +++ b/src/plugins/platforms/xcb/qxcbsharedbuffermanager.cpp @@ -581,7 +581,7 @@ QXcbSharedBufferManager::Buffer *QXcbSharedBufferManager::allocateBuffer(int wid bool ok = buffer->buffer->create(buffer->width * buffer->height * buffer->bytesPerPixel, QSharedMemory::ReadWrite); if (!ok) { - qWarning("SharedBufferManager::findAvailableBuffer: Can't create new buffer (%s)", + qWarning("QXcbSharedBufferManager::findAvailableBuffer: Can't create new buffer (%s)", qPrintable(buffer->buffer->errorString())); delete buffer; return 0; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 067cb775c8..739426a92a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -369,6 +369,14 @@ void QXcbWindow::destroy() if (m_syncCounter && m_screen->syncRequestSupported()) Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter)); if (m_window) { + if (m_netWmUserTimeWindow) { + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + // Some window managers, like metacity, do XSelectInput on the _NET_WM_USER_TIME_WINDOW window, + // without trapping BadWindow (which crashes when the user time window is destroyed). + connection()->sync(); + xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow); + m_netWmUserTimeWindow = XCB_NONE; + } connection()->removeWindow(m_window); Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); } @@ -1168,10 +1176,31 @@ void QXcbWindow::propagateSizeHints() void QXcbWindow::requestActivateWindow() { - if (m_mapped){ - updateNetWmUserTime(connection()->time()); + if (!m_mapped) + return; + + updateNetWmUserTime(connection()->time()); + + if (window()->isTopLevel() + && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_ACTIVE_WINDOW))) { + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = m_window; + event.type = atom(QXcbAtom::_NET_ACTIVE_WINDOW); + event.data.data32[0] = 1; + event.data.data32[1] = connection()->time(); + QWindow *focusWindow = QGuiApplication::focusWindow(); + event.data.data32[2] = focusWindow ? focusWindow->winId() : XCB_NONE; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); + } else { Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time())); } + connection()->sync(); } @@ -1252,18 +1281,18 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even m_syncValue.lo = event->data.data32[2]; m_syncValue.hi = event->data.data32[3]; } else { - qWarning() << "unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); + qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); } } else if (event->type == atom(QXcbAtom::XdndEnter)) { connection()->drag()->handleEnter(window(), event); } else if (event->type == atom(QXcbAtom::XdndPosition)) { - connection()->drag()->handlePosition(window(), event, false); + connection()->drag()->handlePosition(window(), event); } else if (event->type == atom(QXcbAtom::XdndLeave)) { - connection()->drag()->handleLeave(window(), event, false); + connection()->drag()->handleLeave(window(), event); } else if (event->type == atom(QXcbAtom::XdndDrop)) { - connection()->drag()->handleDrop(window(), event, false); + connection()->drag()->handleDrop(window(), event); } else { - qWarning() << "unhandled client message:" << connection()->atomName(event->type); + qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type); } } diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp index 114049f911..c9f4ca69dd 100644 --- a/src/plugins/platforms/xcb/qxcbwmsupport.cpp +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -89,11 +89,6 @@ void QXcbWMSupport::updateNetWMAtoms() free(reply); } while (remaining > 0); - -// qDebug() << "======== updateNetWMAtoms"; -// for (int i = 0; i < net_wm_atoms.size(); ++i) -// qDebug() << atomName(net_wm_atoms.at(i)); -// qDebug() << "======== updateNetWMAtoms"; } // update the virtual roots array @@ -130,10 +125,12 @@ void QXcbWMSupport::updateVirtualRoots() free(reply); } while (remaining > 0); +#ifdef Q_XCB_DEBUG qDebug() << "======== updateVirtualRoots"; for (int i = 0; i < net_virtual_roots.size(); ++i) qDebug() << connection()->atomName(net_virtual_roots.at(i)); qDebug() << "======== updateVirtualRoots"; +#endif } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 7bad2b4dad..d220766be0 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -94,7 +94,7 @@ contains(DEFINES, XCB_USE_DRI2) { } } -LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes +LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shape DEFINES += $$QMAKE_DEFINES_XCB LIBS += $$QMAKE_LIBS_XCB |