diff options
Diffstat (limited to 'src/plugins/platforms')
48 files changed, 2438 insertions, 203 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index ce87de2574..b953210720 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -27,6 +27,9 @@ OBJECTIVE_SOURCES += main.mm \ qcocoafiledialoghelper.mm \ qcocoafontdialoghelper.mm \ qcocoacursor.mm \ + qcocoadrag.mm \ + qmacclipboard.mm \ + qmacmime.mm \ qcocoasystemsettings.mm \ HEADERS += qcocoaintegration.h \ @@ -52,6 +55,9 @@ HEADERS += qcocoaintegration.h \ qcocoafiledialoghelper.h \ qcocoafontdialoghelper.h \ qcocoacursor.h \ + qcocoadrag.h \ + qmacclipboard.h \ + qmacmime.h \ qcocoasystemsettings.h \ FORMS += $$PWD/../../../widgets/dialogs/qfiledialog.ui diff --git a/src/plugins/platforms/cocoa/qcocoacursor.h b/src/plugins/platforms/cocoa/qcocoacursor.h index bccaa1e06b..85892ee820 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.h +++ b/src/plugins/platforms/cocoa/qcocoacursor.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QCocoaCursor : public QPlatformCursor { public: - explicit QCocoaCursor(QPlatformScreen *); + QCocoaCursor(); virtual void changeCursor(QCursor * widgetCursor, QWindow * widget); virtual QPoint pos() const; diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index bddfaa752e..56f0dcf72e 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -47,8 +47,7 @@ QT_BEGIN_NAMESPACE -QCocoaCursor::QCocoaCursor(QPlatformScreen *s) : - QPlatformCursor(s) +QCocoaCursor::QCocoaCursor() { // release cursors QHash<Qt::CursorShape, NSCursor *>::const_iterator i = m_cursors.constBegin(); diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h new file mode 100644 index 0000000000..17df54f748 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoadrag.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 QCOCOADRAG_H +#define QCOCOADRAG_H + +#include <Cocoa/Cocoa.h> +#include <QtGui> +#include <qplatformdrag_qpa.h> +#include <QtPlatformSupport/private/qsimpledrag_p.h> + +#include <QtGui/private/qdnd_p.h> + +QT_BEGIN_NAMESPACE + +class QCocoaDrag : public QSimpleDrag +{ +public: +private: +}; + +class QCocoaDropData : public QInternalMimeData +{ +public: + QCocoaDropData(NSPasteboard *pasteboard); + ~QCocoaDropData(); +protected: + bool hasFormat_sys(const QString &mimeType) const; + QStringList formats_sys() const; + QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const; +public: + CFStringRef dropPasteboard; +}; + + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm new file mode 100644 index 0000000000..c596e3fdbb --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 "qcocoadrag.h" +#include "qmacmime.h" +#include "qmacclipboard.h" + +QT_BEGIN_NAMESPACE + +QCocoaDropData::QCocoaDropData(NSPasteboard *pasteboard) +{ + dropPasteboard = reinterpret_cast<CFStringRef>(const_cast<const NSString *>([pasteboard name])); + CFRetain(dropPasteboard); +} + +QCocoaDropData::~QCocoaDropData() +{ + CFRelease(dropPasteboard); +} + +QStringList QCocoaDropData::formats_sys() const +{ + QStringList formats; + PasteboardRef board; + if (PasteboardCreate(dropPasteboard, &board) != noErr) { + qDebug("DnD: Cannot get PasteBoard!"); + return formats; + } + formats = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).formats(); + return formats; +} + +QVariant QCocoaDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const +{ + QVariant data; + PasteboardRef board; + if (PasteboardCreate(dropPasteboard, &board) != noErr) { + qDebug("DnD: Cannot get PasteBoard!"); + return data; + } + data = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).retrieveData(mimeType, type); + CFRelease(board); + return data; +} + +bool QCocoaDropData::hasFormat_sys(const QString &mimeType) const +{ + bool has = false; + PasteboardRef board; + if (PasteboardCreate(dropPasteboard, &board) != noErr) { + qDebug("DnD: Cannot get PasteBoard!"); + return has; + } + has = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).hasFormat(mimeType); + CFRelease(board); + return has; +} + + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 7b1247b739..3e3e8fa507 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -77,6 +77,11 @@ NSSize qt_mac_toNSSize(const QSize &qtSize); QChar qt_mac_qtKey2CocoaKey(Qt::Key key); Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode); +NSDragOperation qt_mac_mapDropAction(Qt::DropAction action); +NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions); +Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions); +Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions); + // Misc void qt_mac_transformProccessToForegroundApplication(); QString qt_mac_removeMnemonics(const QString &original); diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 29c505e1ab..ec4399b66c 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -270,6 +270,64 @@ Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode) return i->qtKey; } +struct dndenum_mapper +{ + NSDragOperation mac_code; + Qt::DropAction qt_code; + bool Qt2Mac; +}; + +static dndenum_mapper dnd_enums[] = { + { NSDragOperationLink, Qt::LinkAction, true }, + { NSDragOperationMove, Qt::MoveAction, true }, + { NSDragOperationCopy, Qt::CopyAction, true }, + { NSDragOperationGeneric, Qt::CopyAction, false }, + { NSDragOperationEvery, Qt::ActionMask, false }, + { NSDragOperationNone, Qt::IgnoreAction, false } +}; + +NSDragOperation qt_mac_mapDropAction(Qt::DropAction action) +{ + for (int i=0; dnd_enums[i].qt_code; i++) { + if (dnd_enums[i].Qt2Mac && (action & dnd_enums[i].qt_code)) { + return dnd_enums[i].mac_code; + } + } + return NSDragOperationNone; +} + +NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions) +{ + NSDragOperation nsActions = NSDragOperationNone; + for (int i=0; dnd_enums[i].qt_code; i++) { + if (dnd_enums[i].Qt2Mac && (actions & dnd_enums[i].qt_code)) + nsActions |= dnd_enums[i].mac_code; + } + return nsActions; +} + +Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions) +{ + Qt::DropAction action = Qt::IgnoreAction; + for (int i=0; dnd_enums[i].mac_code; i++) { + if (nsActions & dnd_enums[i].mac_code) + return dnd_enums[i].qt_code; + } + return action; +} + +Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions) +{ + Qt::DropActions actions = Qt::IgnoreAction; + for (int i=0; dnd_enums[i].mac_code; i++) { + if (nsActions & dnd_enums[i].mac_code) + actions |= dnd_enums[i].qt_code; + } + return actions; +} + + + // // Misc // diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 5493b21c34..bf54915365 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -46,6 +46,7 @@ #include "qcocoaautoreleasepool.h" #include "qcocoacursor.h" +#include "qcocoadrag.h" #include <QtCore/QScopedPointer> #include <QtGui/QPlatformIntegration> @@ -62,6 +63,7 @@ public: int depth() const { return m_depth; } QImage::Format format() const { return m_format; } QSizeF physicalSize() const { return m_physicalSize; } + QPlatformCursor *cursor() const { return m_cursor; } public: NSScreen *m_screen; @@ -88,6 +90,7 @@ public: QPlatformNativeInterface *nativeInterface() const; QPlatformAccessibility *accessibility() const; + QPlatformDrag *drag() const; QPlatformTheme *platformTheme() const; private: @@ -98,6 +101,7 @@ private: QScopedPointer<QPlatformAccessibility> mAccessibility; QScopedPointer<QPlatformTheme> mPlatformTheme; QList<QCocoaScreen *> mScreens; + QScopedPointer<QCocoaDrag> mCocoaDrag; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 626a7fe0f9..8411a795c1 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -52,6 +52,7 @@ #include "qmenu_mac.h" #include "qcocoafiledialoghelper.h" #include "qcocoatheme.h" +#include "qmacmime.h" #include <QtGui/qplatformaccessibility_qpa.h> #include <QtCore/qcoreapplication.h> @@ -78,7 +79,7 @@ QCocoaScreen::QCocoaScreen(int screenIndex) const qreal inch = 25.4; m_physicalSize = QSizeF(m_geometry.size()) * inch / dpi; - m_cursor = new QCocoaCursor(this); + m_cursor = new QCocoaCursor; }; QCocoaScreen::~QCocoaScreen() @@ -91,7 +92,7 @@ QCocoaIntegration::QCocoaIntegration() , mEventDispatcher(new QCocoaEventDispatcher()) , mAccessibility(new QPlatformAccessibility) , mPlatformTheme(new QCocoaTheme) - + , mCocoaDrag(new QCocoaDrag) { QCocoaAutoReleasePool pool; @@ -138,6 +139,7 @@ QCocoaIntegration::QCocoaIntegration() screenAdded(screen); } + QMacPasteboardMime::initialize(); } QCocoaIntegration::~QCocoaIntegration() @@ -198,6 +200,11 @@ QPlatformAccessibility *QCocoaIntegration::accessibility() const return mAccessibility.data(); } +QPlatformDrag *QCocoaIntegration::drag() const +{ + return mCocoaDrag.data(); +} + QPlatformTheme *QCocoaIntegration::platformTheme() const { return mPlatformTheme.data(); diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.h b/src/plugins/platforms/cocoa/qcocoasystemsettings.h index 84a66d7193..10cac27dcd 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.h +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.h @@ -42,12 +42,15 @@ #ifndef QCOCOASYSTEMSETTINGS_H #define QCOCOASYSTEMSETTINGS_H -#include <QtCore/qglobal.h> +#include <QtCore/qhash.h> #include <QtGui/qpalette.h> +#include <QtGui/qplatformtheme_qpa.h> QT_BEGIN_NAMESPACE QPalette * qt_mac_createSystemPalette(); +QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes(); +QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts(); QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index 5170c0bc8a..c2f5df4d38 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -41,8 +41,12 @@ #include "qcocoasystemsettings.h" -#include <Carbon/Carbon.h> #include <QtCore/private/qcore_mac_p.h> +#include <QtGui/qfont.h> + +#include <Carbon/Carbon.h> + +QT_BEGIN_NAMESPACE QColor qt_mac_colorFromCGColor(CGColorRef cgcolor) { @@ -143,3 +147,126 @@ QPalette * qt_mac_createSystemPalette() return palette; } +struct QMacPaletteMap { + inline QMacPaletteMap(QPlatformTheme::Palette p, ThemeBrush a, ThemeBrush i) : + paletteRole(p), active(a), inactive(i) { } + + QPlatformTheme::Palette paletteRole; + ThemeBrush active, inactive; +}; + +static QMacPaletteMap mac_widget_colors[] = { +// TODO (msorvig): Fix/match palette behavior with Qt 4 and enable. +// +// QMacPaletteMap(QPlatformTheme::ToolButtonPalette, kThemeTextColorBevelButtonActive, kThemeTextColorBevelButtonInactive), +// QMacPaletteMap(QPlatformTheme::ButtonPalette, kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive), +// QMacPaletteMap(QPlatformTheme::HeaderPalette, kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive), +// QMacPaletteMap(QPlatformTheme::ComboBoxPalette, kThemeTextColorPopupButtonActive, kThemeTextColorPopupButtonInactive), +// QMacPaletteMap(QPlatformTheme::ItemViewPalette, kThemeTextColorListView, kThemeTextColorDialogInactive), +// QMacPaletteMap(QPlatformTheme::MessageBoxLabelPelette, kThemeTextColorAlertActive, kThemeTextColorAlertInactive), +// QMacPaletteMap(QPlatformTheme::TabBarPalette, kThemeTextColorTabFrontActive, kThemeTextColorTabFrontInactive), +// QMacPaletteMap(QPlatformTheme::LabelPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive), +// QMacPaletteMap(QPlatformTheme::GroupBoxPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive), +// QMacPaletteMap(QPlatformTheme::MenuPalette, kThemeTextColorPopupLabelActive, kThemeTextColorPopupLabelInactive), +// ### TODO: The zeros below gives white-on-black text. +// QMacPaletteMap(QPlatformTheme::TextEditPalette, 0, 0), +// QMacPaletteMap(QPlatformTheme::TextLineEditPalette, 0, 0), + QMacPaletteMap(QPlatformTheme::NPalettes, 0, 0) }; + +QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes() +{ + QHash<QPlatformTheme::Palette, QPalette*> palettes; + QColor qc; + for (int i = 0; mac_widget_colors[i].paletteRole != QPlatformTheme::NPalettes; i++) { + QPalette pal; + if (mac_widget_colors[i].active != 0) { + qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].active); + pal.setColor(QPalette::Active, QPalette::Text, qc); + pal.setColor(QPalette::Active, QPalette::WindowText, qc); + pal.setColor(QPalette::Active, QPalette::HighlightedText, qc); + qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].inactive); + pal.setColor(QPalette::Inactive, QPalette::Text, qc); + pal.setColor(QPalette::Disabled, QPalette::Text, qc); + pal.setColor(QPalette::Inactive, QPalette::WindowText, qc); + pal.setColor(QPalette::Disabled, QPalette::WindowText, qc); + pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc); + pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc); + } + if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette) { + qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemActive); + pal.setBrush(QPalette::ButtonText, qc); + qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemSelected); + pal.setBrush(QPalette::HighlightedText, qc); + qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemDisabled); + pal.setBrush(QPalette::Disabled, QPalette::Text, qc); + } else if ((mac_widget_colors[i].paletteRole == QPlatformTheme::ButtonPalette) + || (mac_widget_colors[i].paletteRole == QPlatformTheme::HeaderPalette)) { + pal.setColor(QPalette::Disabled, QPalette::ButtonText, + pal.color(QPalette::Disabled, QPalette::Text)); + pal.setColor(QPalette::Inactive, QPalette::ButtonText, + pal.color(QPalette::Inactive, QPalette::Text)); + pal.setColor(QPalette::Active, QPalette::ButtonText, + pal.color(QPalette::Active, QPalette::Text)); + } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::ItemViewPalette) { + pal.setBrush(QPalette::Active, QPalette::Highlight, + qt_mac_colorForTheme(kThemeBrushAlternatePrimaryHighlightColor)); + qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemSelected); + pal.setBrush(QPalette::Active, QPalette::HighlightedText, qc); + pal.setBrush(QPalette::Inactive, QPalette::Text, + pal.brush(QPalette::Active, QPalette::Text)); + pal.setBrush(QPalette::Inactive, QPalette::HighlightedText, + pal.brush(QPalette::Active, QPalette::Text)); + } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::TextEditPalette) { + pal.setBrush(QPalette::Inactive, QPalette::Text, + pal.brush(QPalette::Active, QPalette::Text)); + pal.setBrush(QPalette::Inactive, QPalette::HighlightedText, + pal.brush(QPalette::Active, QPalette::Text)); + } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::TextLineEditPalette) { + pal.setBrush(QPalette::Disabled, QPalette::Base, + pal.brush(QPalette::Active, QPalette::Base)); + } + palettes.insert(mac_widget_colors[i].paletteRole, new QPalette(pal)); + } + return palettes; +} + +QFont *qt_mac_qfontForThemeFont(ThemeFontID themeID) +{ + CTFontUIFontType ctID = HIThemeGetUIFontType(themeID); + QCFType<CTFontRef> ctfont = CTFontCreateUIFontForLanguage(ctID, 0, 0); + QString familyName = QCFString(CTFontCopyFamilyName(ctfont)); + QCFType<CFDictionaryRef> dict = CTFontCopyTraits(ctfont); + CFNumberRef num = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kCTFontWeightTrait)); + float fW; + CFNumberGetValue(num, kCFNumberFloat32Type, &fW); + QFont::Weight wght = fW > 0. ? QFont::Bold : QFont::Normal; + num = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kCTFontSlantTrait)); + CFNumberGetValue(num, kCFNumberFloatType, &fW); + bool italic = (fW != 0.0); + return new QFont(familyName, CTFontGetSize(ctfont), wght, italic); +} + +QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts() +{ + QHash<QPlatformTheme::Font, QFont *> fonts; + + fonts.insert(QPlatformTheme::SystemFont, qt_mac_qfontForThemeFont(kThemeApplicationFont)); + fonts.insert(QPlatformTheme::PushButtonFont, qt_mac_qfontForThemeFont(kThemePushButtonFont)); + fonts.insert(QPlatformTheme::ListViewFont, qt_mac_qfontForThemeFont(kThemeViewsFont)); + fonts.insert(QPlatformTheme::ListBoxFont, qt_mac_qfontForThemeFont(kThemeViewsFont)); + fonts.insert(QPlatformTheme::TitleBarFont, qt_mac_qfontForThemeFont(kThemeWindowTitleFont)); + fonts.insert(QPlatformTheme::MenuFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont)); + fonts.insert(QPlatformTheme::ComboMenuItemFont, qt_mac_qfontForThemeFont(kThemeSystemFont)); + fonts.insert(QPlatformTheme::HeaderViewFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); + fonts.insert(QPlatformTheme::TipLabelFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); + fonts.insert(QPlatformTheme::LabelFont, qt_mac_qfontForThemeFont(kThemeSystemFont)); + fonts.insert(QPlatformTheme::ToolButtonFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); + fonts.insert(QPlatformTheme::MenuItemFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont)); + fonts.insert(QPlatformTheme::ComboLineEditFont, qt_mac_qfontForThemeFont(kThemeViewsFont)); + fonts.insert(QPlatformTheme::SmallFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); + fonts.insert(QPlatformTheme::MiniFont, qt_mac_qfontForThemeFont(kThemeMiniSystemFont)); + + return fonts; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index fa235b6be0..030db1822c 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -42,8 +42,7 @@ #ifndef QPLATFORMTHEME_COCOA_H #define QPLATFORMTHEME_COCOA_H -#include <Cocoa/Cocoa.h> - +#include <QtCore/QHash> #include <QtGui/QPlatformTheme> QT_BEGIN_NAMESPACE @@ -62,10 +61,13 @@ public: QPlatformDialogHelper *createPlatformDialogHelper(DialogType dialogType) const; const QPalette *palette(Palette type = SystemPalette) const; + const QFont *font(Font type = SystemFont) const; QVariant themeHint(ThemeHint hint) const; private: mutable QPalette *m_systemPalette; + mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes; + mutable QHash<QPlatformTheme::Font, QFont*> m_fonts; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 6b0e04acf8..8ec6e3801e 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -109,12 +109,23 @@ const QPalette *QCocoaTheme::palette(Palette type) const if (type == SystemPalette) { if (!m_systemPalette) m_systemPalette = qt_mac_createSystemPalette(); - return m_systemPalette; + } else { + if (m_palettes.isEmpty()) + m_palettes = qt_mac_createRolePalettes(); + return m_palettes.value(type, 0); } return 0; } +const QFont *QCocoaTheme::font(Font type) const +{ + if (m_fonts.isEmpty()) { + m_fonts = qt_mac_createRoleFonts(); + } + return m_fonts.value(type, 0); +} + QVariant QCocoaTheme::themeHint(ThemeHint hint) const { switch (hint) { diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index b2e93470c9..3f566ccb44 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -201,7 +201,7 @@ void QCocoaWindow::propagateSizeHints() [m_nsWindow setResizeIncrements : qt_mac_toNSSize(window()->sizeIncrement())]; QSize baseSize = window()->baseSize(); - if (!baseSize.isNull()) { + if (!baseSize.isNull() && baseSize.isValid()) { [m_nsWindow setFrameSize : NSMakeSize(baseSize.width(), baseSize.height()) display : YES]; } } diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h new file mode 100644 index 0000000000..9371aca459 --- /dev/null +++ b/src/plugins/platforms/cocoa/qmacclipboard.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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 QMACCLIPBOARD_H +#define QMACCLIPBOARD_H + +#include <QtGui> +#include "qmacmime.h" + +#undef slots + +#import <Cocoa/Cocoa.h> + +class QMacPasteboard +{ + struct Promise { + Promise() : itemId(0), convertor(0) { } + Promise(int itemId, QMacPasteboardMime *c, QString m, QVariant d, int o=0) : itemId(itemId), offset(o), convertor(c), mime(m), data(d) { } + int itemId, offset; + QMacPasteboardMime *convertor; + QString mime; + QVariant data; + }; + QList<Promise> promises; + + PasteboardRef paste; + uchar mime_type; + mutable QPointer<QMimeData> mime; + mutable bool mac_mime_source; + static OSStatus promiseKeeper(PasteboardRef, PasteboardItemID, CFStringRef, void *); + void clear_helper(); +public: + QMacPasteboard(PasteboardRef p, uchar mime_type=0); + QMacPasteboard(uchar mime_type); + QMacPasteboard(CFStringRef name=0, uchar mime_type=0); + ~QMacPasteboard(); + + bool hasFlavor(QString flavor) const; + bool hasOSType(int c_flavor) const; + + PasteboardRef pasteBoard() const; + QMimeData *mimeData() const; + void setMimeData(QMimeData *mime); + + QStringList formats() const; + bool hasFormat(const QString &format) const; + QVariant retrieveData(const QString &format, QVariant::Type) const; + + void clear(); + bool sync() const; +}; + +QString qt_mac_get_pasteboardString(PasteboardRef paste); + +#endif diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm new file mode 100644 index 0000000000..d5af6de69c --- /dev/null +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -0,0 +1,653 @@ +/**************************************************************************** +** +** 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 "qmacclipboard.h" +#include "qclipboard.h" +#include "qapplication.h" +#include "qbitmap.h" +#include "qdatetime.h" +#include "qdebug.h" +#include "qguiapplication.h" +#include "qevent.h" +#include "qurl.h" +#include <stdlib.h> +#include <string.h> +#include "qcocoahelpers.h" +#include "qmacmime.h" +#include "qcocoaautoreleasepool.h" + +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +/***************************************************************************** + QClipboard debug facilities + *****************************************************************************/ +//#define DEBUG_PASTEBOARD + +#ifndef QT_NO_CLIPBOARD + +/***************************************************************************** + QClipboard member functions for mac. + *****************************************************************************/ + +static QMacPasteboard *qt_mac_pasteboards[2] = {0, 0}; + +static inline QMacPasteboard *qt_mac_pasteboard(QClipboard::Mode mode) +{ + Q_ASSERT(mode == QClipboard::Clipboard || mode == QClipboard::FindBuffer); + if (mode == QClipboard::Clipboard) + return qt_mac_pasteboards[0]; + else + return qt_mac_pasteboards[1]; +} + +static void qt_mac_cleanupPasteboard() { + delete qt_mac_pasteboards[0]; + delete qt_mac_pasteboards[1]; + qt_mac_pasteboards[0] = 0; + qt_mac_pasteboards[1] = 0; +} + +static bool qt_mac_updateScrap(QClipboard::Mode mode) +{ + if (!qt_mac_pasteboards[0]) { + qt_mac_pasteboards[0] = new QMacPasteboard(kPasteboardClipboard, QMacPasteboardMime::MIME_CLIP); + qt_mac_pasteboards[1] = new QMacPasteboard(kPasteboardFind, QMacPasteboardMime::MIME_CLIP); + qAddPostRoutine(qt_mac_cleanupPasteboard); + return true; + } + return qt_mac_pasteboard(mode)->sync(); +} + +void QClipboard::clear(Mode mode) +{ + if (!supportsMode(mode)) + return; + qt_mac_updateScrap(mode); + qt_mac_pasteboard(mode)->clear(); + setMimeData(0, mode); +} + +void QClipboard::ownerDestroyed() +{ +} + + +void QClipboard::connectNotify(const char *signal) +{ + Q_UNUSED(signal); +} + +bool QClipboard::event(QEvent *e) +{ + if (e->type() != QEvent::Clipboard) + return QObject::event(e); + + if (qt_mac_updateScrap(QClipboard::Clipboard)) { + emitChanged(QClipboard::Clipboard); + } + + if (qt_mac_updateScrap(QClipboard::FindBuffer)) { + emitChanged(QClipboard::FindBuffer); + } + + return QObject::event(e); +} + +const QMimeData *QClipboard::mimeData(Mode mode) const +{ + if (!supportsMode(mode)) + return 0; + qt_mac_updateScrap(mode); + return qt_mac_pasteboard(mode)->mimeData(); +} + +void QClipboard::setMimeData(QMimeData *src, Mode mode) +{ + if (!supportsMode(mode)) + return; + qt_mac_updateScrap(mode); + qt_mac_pasteboard(mode)->setMimeData(src); + emitChanged(mode); +} + +bool QClipboard::supportsMode(Mode mode) const +{ + return (mode == Clipboard || mode == FindBuffer); +} + +bool QClipboard::ownsMode(Mode mode) const +{ + Q_UNUSED(mode); + return false; +} + +#endif // QT_NO_CLIPBOARD + +/***************************************************************************** + QMacPasteboard code +*****************************************************************************/ + +QMacPasteboard::QMacPasteboard(PasteboardRef p, uchar mt) +{ + mac_mime_source = false; + mime_type = mt ? mt : uchar(QMacPasteboardMime::MIME_ALL); + paste = p; + CFRetain(paste); +} + +QMacPasteboard::QMacPasteboard(uchar mt) +{ + mac_mime_source = false; + mime_type = mt ? mt : uchar(QMacPasteboardMime::MIME_ALL); + paste = 0; + OSStatus err = PasteboardCreate(0, &paste); + if (err == noErr) { + PasteboardSetPromiseKeeper(paste, promiseKeeper, this); + } else { + qDebug("PasteBoard: Error creating pasteboard: [%d]", (int)err); + } +} + +QMacPasteboard::QMacPasteboard(CFStringRef name, uchar mt) +{ + mac_mime_source = false; + mime_type = mt ? mt : uchar(QMacPasteboardMime::MIME_ALL); + paste = 0; + OSStatus err = PasteboardCreate(name, &paste); + if (err == noErr) { + PasteboardSetPromiseKeeper(paste, promiseKeeper, this); + } else { + qDebug("PasteBoard: Error creating pasteboard: %s [%d]", QCFString::toQString(name).toLatin1().constData(), (int)err); + } +} + +QMacPasteboard::~QMacPasteboard() +{ + // commit all promises for paste after exit close + for (int i = 0; i < promises.count(); ++i) { + const Promise &promise = promises.at(i); + QCFString flavor = QCFString(promise.convertor->flavorFor(promise.mime)); + promiseKeeper(paste, (PasteboardItemID)promise.itemId, flavor, this); + } + + if (paste) + CFRelease(paste); +} + +PasteboardRef +QMacPasteboard::pasteBoard() const +{ + return paste; +} + +OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id, CFStringRef flavor, void *_qpaste) +{ + QMacPasteboard *qpaste = (QMacPasteboard*)_qpaste; + const long promise_id = (long)id; + + // Find the kept promise + const QString flavorAsQString = QCFString::toQString(flavor); + QMacPasteboard::Promise promise; + for (int i = 0; i < qpaste->promises.size(); i++){ + QMacPasteboard::Promise tmp = qpaste->promises[i]; + if (tmp.itemId == promise_id && tmp.convertor->canConvert(tmp.mime, flavorAsQString)){ + promise = tmp; + break; + } + } + + if (!promise.itemId && flavorAsQString == QLatin1String("com.trolltech.qt.MimeTypeName")) { + // we have promised this data, but wont be able to convert, so return null data. + // This helps in making the application/x-qt-mime-type-name hidden from normal use. + QByteArray ba; + QCFType<CFDataRef> data = CFDataCreate(0, (UInt8*)ba.constData(), ba.size()); + PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags); + return noErr; + } + + if (!promise.itemId) { + // There was no promise that could deliver data for the + // given id and flavor. This should not happend. + qDebug("Pasteboard: %d: Request for %ld, %s, but no promise found!", __LINE__, promise_id, qPrintable(flavorAsQString)); + return cantGetFlavorErr; + } + +#ifdef DEBUG_PASTEBOARD + qDebug("PasteBoard: Calling in promise for %s[%ld] [%s] (%s) [%d]", qPrintable(promise.mime), promise_id, + qPrintable(flavorAsQString), qPrintable(promise.convertor->convertorName()), promise.offset); +#endif + + QList<QByteArray> md = promise.convertor->convertFromMime(promise.mime, promise.data, flavorAsQString); + if (md.size() <= promise.offset) + return cantGetFlavorErr; + const QByteArray &ba = md[promise.offset]; + QCFType<CFDataRef> data = CFDataCreate(0, (UInt8*)ba.constData(), ba.size()); + PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags); + return noErr; +} + +bool +QMacPasteboard::hasOSType(int c_flavor) const +{ + if (!paste) + return false; + + sync(); + + ItemCount cnt = 0; + if (PasteboardGetItemCount(paste, &cnt) || !cnt) + return false; + +#ifdef DEBUG_PASTEBOARD + qDebug("PasteBoard: hasOSType [%c%c%c%c]", (c_flavor>>24)&0xFF, (c_flavor>>16)&0xFF, + (c_flavor>>8)&0xFF, (c_flavor>>0)&0xFF); +#endif + for (uint index = 1; index <= cnt; ++index) { + + PasteboardItemID id; + if (PasteboardGetItemIdentifier(paste, index, &id) != noErr) + return false; + + QCFType<CFArrayRef> types; + if (PasteboardCopyItemFlavors(paste, id, &types ) != noErr) + return false; + + const int type_count = CFArrayGetCount(types); + for (int i = 0; i < type_count; ++i) { + CFStringRef flavor = (CFStringRef)CFArrayGetValueAtIndex(types, i); + const int os_flavor = UTGetOSTypeFromString(UTTypeCopyPreferredTagWithClass(flavor, kUTTagClassOSType)); + if (os_flavor == c_flavor) { +#ifdef DEBUG_PASTEBOARD + qDebug(" - Found!"); +#endif + return true; + } + } + } +#ifdef DEBUG_PASTEBOARD + qDebug(" - NotFound!"); +#endif + return false; +} + +bool +QMacPasteboard::hasFlavor(QString c_flavor) const +{ + if (!paste) + return false; + + sync(); + + ItemCount cnt = 0; + if (PasteboardGetItemCount(paste, &cnt) || !cnt) + return false; + +#ifdef DEBUG_PASTEBOARD + qDebug("PasteBoard: hasFlavor [%s]", qPrintable(c_flavor)); +#endif + for (uint index = 1; index <= cnt; ++index) { + + PasteboardItemID id; + if (PasteboardGetItemIdentifier(paste, index, &id) != noErr) + return false; + + PasteboardFlavorFlags flags; + if (PasteboardGetItemFlavorFlags(paste, id, QCFString(c_flavor), &flags) == noErr) { +#ifdef DEBUG_PASTEBOARD + qDebug(" - Found!"); +#endif + return true; + } + } +#ifdef DEBUG_PASTEBOARD + qDebug(" - NotFound!"); +#endif + return false; +} + +class QMacPasteboardMimeSource : public QMimeData { + const QMacPasteboard *paste; +public: + QMacPasteboardMimeSource(const QMacPasteboard *p) : QMimeData(), paste(p) { } + ~QMacPasteboardMimeSource() { } + virtual QStringList formats() const { return paste->formats(); } + virtual QVariant retrieveData(const QString &format, QVariant::Type type) const { return paste->retrieveData(format, type); } +}; + +QMimeData +*QMacPasteboard::mimeData() const +{ + if (!mime) { + mac_mime_source = true; + mime = new QMacPasteboardMimeSource(this); + + } + return mime; +} + +class QMacMimeData : public QMimeData +{ +public: + QVariant variantData(const QString &mime) { return retrieveData(mime, QVariant::Invalid); } +private: + QMacMimeData(); +}; + +void +QMacPasteboard::setMimeData(QMimeData *mime_src) +{ + if (!paste) + return; + + if (mime == mime_src || (!mime_src && mime && mac_mime_source)) + return; + mac_mime_source = false; + delete mime; + mime = mime_src; + + QList<QMacPasteboardMime*> availableConverters = QMacPasteboardMime::all(mime_type); + if (mime != 0) { + clear_helper(); + QStringList formats = mime_src->formats(); + + // QMimeData sub classes reimplementing the formats() might not expose the + // temporary "application/x-qt-mime-type-name" mimetype. So check the existence + // of this mime type while doing drag and drop. + QString dummyMimeType(QLatin1String("application/x-qt-mime-type-name")); + if (!formats.contains(dummyMimeType)) { + QByteArray dummyType = mime_src->data(dummyMimeType); + if (!dummyType.isEmpty()) { + formats.append(dummyMimeType); + } + } + for (int f = 0; f < formats.size(); ++f) { + QString mimeType = formats.at(f); + for (QList<QMacPasteboardMime *>::Iterator it = availableConverters.begin(); it != availableConverters.end(); ++it) { + QMacPasteboardMime *c = (*it); + QString flavor(c->flavorFor(mimeType)); + if (!flavor.isEmpty()) { + QVariant mimeData = static_cast<QMacMimeData*>(mime_src)->variantData(mimeType); +#if 0 + //### Grrr, why didn't I put in a virtual int QMacPasteboardMime::count()? --Sam + const int numItems = c->convertFromMime(mimeType, mimeData, flavor).size(); +#else + int numItems = 1; //this is a hack but it is much faster than allowing conversion above + if (c->convertorName() == QLatin1String("FileURL")) + numItems = mime_src->urls().count(); +#endif + for (int item = 0; item < numItems; ++item) { + const int itemID = item+1; //id starts at 1 + promises.append(QMacPasteboard::Promise(itemID, c, mimeType, mimeData, item)); + PasteboardPutItemFlavor(paste, (PasteboardItemID)itemID, QCFString(flavor), 0, kPasteboardFlavorNoFlags); +#ifdef DEBUG_PASTEBOARD + qDebug(" - adding %d %s [%s] <%s> [%d]", + itemID, qPrintable(mimeType), qPrintable(flavor), qPrintable(c->convertorName()), item); +#endif + } + } + } + } + } +} + +QStringList +QMacPasteboard::formats() const +{ + if (!paste) + return QStringList(); + + sync(); + + QStringList ret; + ItemCount cnt = 0; + if (PasteboardGetItemCount(paste, &cnt) || !cnt) + return ret; + +#ifdef DEBUG_PASTEBOARD + qDebug("PasteBoard: Formats [%d]", (int)cnt); +#endif + for (uint index = 1; index <= cnt; ++index) { + + PasteboardItemID id; + if (PasteboardGetItemIdentifier(paste, index, &id) != noErr) + continue; + + QCFType<CFArrayRef> types; + if (PasteboardCopyItemFlavors(paste, id, &types ) != noErr) + continue; + + const int type_count = CFArrayGetCount(types); + for (int i = 0; i < type_count; ++i) { + const QString flavor = QCFString::toQString((CFStringRef)CFArrayGetValueAtIndex(types, i)); +#ifdef DEBUG_PASTEBOARD + qDebug(" -%s", qPrintable(QString(flavor))); +#endif + QString mimeType = QMacPasteboardMime::flavorToMime(mime_type, flavor); + if (!mimeType.isEmpty() && !ret.contains(mimeType)) { +#ifdef DEBUG_PASTEBOARD + qDebug(" -<%d> %s [%s]", ret.size(), qPrintable(mimeType), qPrintable(QString(flavor))); +#endif + ret << mimeType; + } + } + } + return ret; +} + +bool +QMacPasteboard::hasFormat(const QString &format) const +{ + if (!paste) + return false; + + sync(); + + ItemCount cnt = 0; + if (PasteboardGetItemCount(paste, &cnt) || !cnt) + return false; + +#ifdef DEBUG_PASTEBOARD + qDebug("PasteBoard: hasFormat [%s]", qPrintable(format)); +#endif + for (uint index = 1; index <= cnt; ++index) { + + PasteboardItemID id; + if (PasteboardGetItemIdentifier(paste, index, &id) != noErr) + continue; + + QCFType<CFArrayRef> types; + if (PasteboardCopyItemFlavors(paste, id, &types ) != noErr) + continue; + + const int type_count = CFArrayGetCount(types); + for (int i = 0; i < type_count; ++i) { + const QString flavor = QCFString::toQString((CFStringRef)CFArrayGetValueAtIndex(types, i)); +#ifdef DEBUG_PASTEBOARD + qDebug(" -%s [0x%x]", qPrintable(QString(flavor)), mime_type); +#endif + QString mimeType = QMacPasteboardMime::flavorToMime(mime_type, flavor); +#ifdef DEBUG_PASTEBOARD + if (!mimeType.isEmpty()) + qDebug(" - %s", qPrintable(mimeType)); +#endif + if (mimeType == format) + return true; + } + } + return false; +} + +QVariant +QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const +{ + if (!paste) + return QVariant(); + + sync(); + + ItemCount cnt = 0; + if (PasteboardGetItemCount(paste, &cnt) || !cnt) + return QByteArray(); + +#ifdef DEBUG_PASTEBOARD + qDebug("Pasteboard: retrieveData [%s]", qPrintable(format)); +#endif + const QList<QMacPasteboardMime *> mimes = QMacPasteboardMime::all(mime_type); + for (int mime = 0; mime < mimes.size(); ++mime) { + QMacPasteboardMime *c = mimes.at(mime); + QString c_flavor = c->flavorFor(format); + if (!c_flavor.isEmpty()) { + // Handle text/plain a little differently. Try handling Unicode first. + bool checkForUtf16 = (c_flavor == QLatin1String("com.apple.traditional-mac-plain-text") + || c_flavor == QLatin1String("public.utf8-plain-text")); + if (checkForUtf16 || c_flavor == QLatin1String("public.utf16-plain-text")) { + // Try to get the NSStringPboardType from NSPasteboard, newlines are mapped + // correctly (as '\n') in this data. The 'public.utf16-plain-text' type + // usually maps newlines to '\r' instead. + QString str = qt_mac_get_pasteboardString(paste); + if (!str.isEmpty()) + return str; + } + if (checkForUtf16 && hasFlavor(QLatin1String("public.utf16-plain-text"))) + c_flavor = QLatin1String("public.utf16-plain-text"); + + QVariant ret; + QList<QByteArray> retList; + for (uint index = 1; index <= cnt; ++index) { + PasteboardItemID id; + if (PasteboardGetItemIdentifier(paste, index, &id) != noErr) + continue; + + QCFType<CFArrayRef> types; + if (PasteboardCopyItemFlavors(paste, id, &types ) != noErr) + continue; + + const int type_count = CFArrayGetCount(types); + for (int i = 0; i < type_count; ++i) { + CFStringRef flavor = static_cast<CFStringRef>(CFArrayGetValueAtIndex(types, i)); + if (c_flavor == QCFString::toQString(flavor)) { + QCFType<CFDataRef> macBuffer; + if (PasteboardCopyItemFlavorData(paste, id, flavor, &macBuffer) == noErr) { + QByteArray buffer((const char *)CFDataGetBytePtr(macBuffer), CFDataGetLength(macBuffer)); + if (!buffer.isEmpty()) { +#ifdef DEBUG_PASTEBOARD + qDebug(" - %s [%s] (%s)", qPrintable(format), qPrintable(QCFString::toQString(flavor)), qPrintable(c->convertorName())); +#endif + buffer.detach(); //detach since we release the macBuffer + retList.append(buffer); + break; //skip to next element + } + } + } else { +#ifdef DEBUG_PASTEBOARD + qDebug(" - NoMatch %s [%s] (%s)", qPrintable(c_flavor), qPrintable(QCFString::toQString(flavor)), qPrintable(c->convertorName())); +#endif + } + } + } + + if (!retList.isEmpty()) { + ret = c->convertToMime(format, retList, c_flavor); + return ret; + } + } + } + return QVariant(); +} + +void QMacPasteboard::clear_helper() +{ + if (paste) + PasteboardClear(paste); + promises.clear(); +} + +void +QMacPasteboard::clear() +{ +#ifdef DEBUG_PASTEBOARD + qDebug("PasteBoard: clear!"); +#endif + clear_helper(); +} + +bool +QMacPasteboard::sync() const +{ + if (!paste) + return false; + const bool fromGlobal = PasteboardSynchronize(paste) & kPasteboardModified; + + if (fromGlobal) + const_cast<QMacPasteboard *>(this)->setMimeData(0); + +#ifdef DEBUG_PASTEBOARD + if (fromGlobal) + qDebug("Pasteboard: Synchronize!"); +#endif + return fromGlobal; +} + + +QString qt_mac_get_pasteboardString(PasteboardRef paste) +{ + QCocoaAutoReleasePool pool; + NSPasteboard *pb = nil; + CFStringRef pbname; + if (PasteboardCopyName(paste, &pbname) == noErr) { + pb = [NSPasteboard pasteboardWithName:const_cast<NSString *>(reinterpret_cast<const NSString *>(pbname))]; + CFRelease(pbname); + } else { + pb = [NSPasteboard generalPasteboard]; + } + if (pb) { + NSString *text = [pb stringForType:NSStringPboardType]; + if (text) + return QCFString::toQString(text); + } + return QString(); +} + + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qmacmime.h b/src/plugins/platforms/cocoa/qmacmime.h new file mode 100644 index 0000000000..842caa5f2f --- /dev/null +++ b/src/plugins/platforms/cocoa/qmacmime.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 QMACMIME_H +#define QMACMIME_H + +#include <QtCore> + +#include <CoreFoundation/CoreFoundation.h> + +class Q_GUI_EXPORT QMacPasteboardMime { + char type; +public: + enum QMacPasteboardMimeType { MIME_DND=0x01, + MIME_CLIP=0x02, + MIME_QT_CONVERTOR=0x04, + MIME_QT3_CONVERTOR=0x08, + MIME_ALL=MIME_DND|MIME_CLIP + }; + explicit QMacPasteboardMime(char); + virtual ~QMacPasteboardMime(); + + static void initialize(); + + static QList<QMacPasteboardMime*> all(uchar); + static QMacPasteboardMime *convertor(uchar, const QString &mime, QString flav); + static QString flavorToMime(uchar, QString flav); + + virtual QString convertorName() = 0; + + virtual bool canConvert(const QString &mime, QString flav) = 0; + virtual QString mimeFor(QString flav) = 0; + virtual QString flavorFor(const QString &mime) = 0; + virtual QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav) = 0; + virtual QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav) = 0; +}; + +#endif + diff --git a/src/plugins/platforms/cocoa/qmacmime.mm b/src/plugins/platforms/cocoa/qmacmime.mm new file mode 100644 index 0000000000..db86deb91c --- /dev/null +++ b/src/plugins/platforms/cocoa/qmacmime.mm @@ -0,0 +1,938 @@ +/**************************************************************************** +** +** 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 "qmacmime.h" +#include "qcocoahelpers.h" +#include "qmacclipboard.h" + +#include "qdebug.h" +#include "qpixmap.h" +#include "qimagewriter.h" +#include "qimagereader.h" +#include "qdatastream.h" +#include "qbuffer.h" +#include "qdatetime.h" +#include "qguiapplication.h" +#include "qtextcodec.h" +#include "qregexp.h" +#include "qurl.h" +#include "qmap.h" + +#include <Cocoa/Cocoa.h> + +QT_BEGIN_NAMESPACE + +extern CGImageRef qt_mac_createCGImageFromQImage(const QImage &img, const QImage **imagePtr = 0); // qpaintengine_mac.cpp + +typedef QList<QMacPasteboardMime*> MimeList; +Q_GLOBAL_STATIC(MimeList, globalMimeList) + +static void cleanup_mimes() +{ + MimeList *mimes = globalMimeList(); + while (!mimes->isEmpty()) + delete mimes->takeFirst(); +} + +Q_GLOBAL_STATIC(QStringList, globalDraggedTypesList) + +/*! + \fn void qRegisterDraggedTypes(const QStringList &types) + \relates QMacPasteboardMime + + Registers the given \a types as custom pasteboard types. + + This function should be called to enable the Drag and Drop events + for custom pasteboard types on Cocoa implementations. This is required + in addition to a QMacPasteboardMime subclass implementation. By default + drag and drop is enabled for all standard pasteboard types. + + \sa QMacPasteboardMime +*/ +Q_WIDGETS_EXPORT void qRegisterDraggedTypes(const QStringList &types) +{ + (*globalDraggedTypesList()) += types; +} + +const QStringList& qEnabledDraggedTypes() +{ + return (*globalDraggedTypesList()); +} + + +/***************************************************************************** + QDnD debug facilities + *****************************************************************************/ +//#define DEBUG_MIME_MAPS + +//functions +extern QString qt_mac_from_pascal_string(const Str255); //qglobal.cpp +extern void qt_mac_from_pascal_string(QString, Str255, TextEncoding encoding=0, int len=-1); //qglobal.cpp + +ScrapFlavorType qt_mac_mime_type = 'CUTE'; +CFStringRef qt_mac_mime_typeUTI = CFSTR("com.pasteboard.trolltech.marker"); + +/*! + \class QMacPasteboardMime + \brief The QMacPasteboardMime class converts between a MIME type and a + \l{http://developer.apple.com/macosx/uniformtypeidentifiers.html}{Uniform + Type Identifier (UTI)} format. + \since 4.2 + + \ingroup draganddrop + \inmodule QtWidgets + + Qt's drag and drop and clipboard facilities use the MIME + standard. On X11, this maps trivially to the Xdnd protocol. On + Mac, although some applications use MIME to describe clipboard + contents, it is more common to use Apple's UTI format. + + QMacPasteboardMime's role is to bridge the gap between MIME and UTI; + By subclasses this class, one can extend Qt's drag and drop + and clipboard handling to convert to and from unsupported, or proprietary, UTI formats. + + A subclass of QMacPasteboardMime will automatically be registered, and active, upon instantiation. + + Qt has predefined support for the following UTIs: + \list + \i public.utf8-plain-text - converts to "text/plain" + \i public.utf16-plain-text - converts to "text/plain" + \i public.html - converts to "text/html" + \i public.url - converts to "text/uri-list" + \i public.file-url - converts to "text/uri-list" + \i public.tiff - converts to "application/x-qt-image" + \i public.vcard - converts to "text/plain" + \i com.apple.traditional-mac-plain-text - converts to "text/plain" + \i com.apple.pict - converts to "application/x-qt-image" + \endlist + + When working with MIME data, Qt will interate through all instances of QMacPasteboardMime to + find an instance that can convert to, or from, a specific MIME type. It will do this by calling + canConvert() on each instance, starting with (and choosing) the last created instance first. + The actual conversions will be done by using convertToMime() and convertFromMime(). + + \note The API uses the term "flavor" in some cases. This is for backwards + compatibility reasons, and should now be understood as UTIs. +*/ + +/*! \enum QMacPasteboardMime::QMacPasteboardMimeType + \internal +*/ + +/*! + Constructs a new conversion object of type \a t, adding it to the + globally accessed list of available convertors. +*/ +QMacPasteboardMime::QMacPasteboardMime(char t) : type(t) +{ + globalMimeList()->append(this); +} + +/*! + Destroys a conversion object, removing it from the global + list of available convertors. +*/ +QMacPasteboardMime::~QMacPasteboardMime() +{ + if (!QGuiApplication::closingDown()) + globalMimeList()->removeAll(this); +} + +class QMacPasteboardMimeAny : public QMacPasteboardMime { +private: + +public: + QMacPasteboardMimeAny() : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) { + } + ~QMacPasteboardMimeAny() { + } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeAny::convertorName() +{ + return QLatin1String("Any-Mime"); +} + +QString QMacPasteboardMimeAny::flavorFor(const QString &mime) +{ + // do not handle the mime type name in the drag pasteboard + if (mime == QLatin1String("application/x-qt-mime-type-name")) + return QString(); + QString ret = QLatin1String("com.trolltech.anymime.") + mime; + return ret.replace(QLatin1Char('/'), QLatin1String("--")); +} + +QString QMacPasteboardMimeAny::mimeFor(QString flav) +{ + const QString any_prefix = QLatin1String("com.trolltech.anymime."); + if (flav.size() > any_prefix.length() && flav.startsWith(any_prefix)) + return flav.mid(any_prefix.length()).replace(QLatin1String("--"), QLatin1String("/")); + return QString(); +} + +bool QMacPasteboardMimeAny::canConvert(const QString &mime, QString flav) +{ + return mimeFor(flav) == mime; +} + +QVariant QMacPasteboardMimeAny::convertToMime(const QString &mime, QList<QByteArray> data, QString) +{ + if (data.count() > 1) + qWarning("QMacPasteboardMimeAny: Cannot handle multiple member data"); + QVariant ret; + if (mime == QLatin1String("text/plain")) + ret = QString::fromUtf8(data.first()); + else + ret = data.first(); + return ret; +} + +QList<QByteArray> QMacPasteboardMimeAny::convertFromMime(const QString &mime, QVariant data, QString) +{ + QList<QByteArray> ret; + if (mime == QLatin1String("text/plain")) + ret.append(data.toString().toUtf8()); + else + ret.append(data.toByteArray()); + return ret; +} + +class QMacPasteboardMimeTypeName : public QMacPasteboardMime { +private: + +public: + QMacPasteboardMimeTypeName() : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) { + } + ~QMacPasteboardMimeTypeName() { + } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeTypeName::convertorName() +{ + return QLatin1String("Qt-Mime-Type"); +} + +QString QMacPasteboardMimeTypeName::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("application/x-qt-mime-type-name")) + return QLatin1String("com.trolltech.qt.MimeTypeName"); + return QString(); +} + +QString QMacPasteboardMimeTypeName::mimeFor(QString) +{ + return QString(); +} + +bool QMacPasteboardMimeTypeName::canConvert(const QString &, QString) +{ + return false; +} + +QVariant QMacPasteboardMimeTypeName::convertToMime(const QString &, QList<QByteArray>, QString) +{ + QVariant ret; + return ret; +} + +QList<QByteArray> QMacPasteboardMimeTypeName::convertFromMime(const QString &, QVariant, QString) +{ + QList<QByteArray> ret; + ret.append(QString("x-qt-mime-type-name").toUtf8()); + return ret; +} + +class QMacPasteboardMimePlainText : public QMacPasteboardMime { +public: + QMacPasteboardMimePlainText() : QMacPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimePlainText::convertorName() +{ + return QLatin1String("PlainText"); +} + +QString QMacPasteboardMimePlainText::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/plain")) + return QLatin1String("com.apple.traditional-mac-plain-text"); + return QString(); +} + +QString QMacPasteboardMimePlainText::mimeFor(QString flav) +{ + if (flav == QLatin1String("com.apple.traditional-mac-plain-text")) + return QLatin1String("text/plain"); + return QString(); +} + +bool QMacPasteboardMimePlainText::canConvert(const QString &mime, QString flav) +{ + return flavorFor(mime) == flav; +} + +QVariant QMacPasteboardMimePlainText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor) +{ + if (data.count() > 1) + qWarning("QMacPasteboardMimePlainText: Cannot handle multiple member data"); + const QByteArray &firstData = data.first(); + QVariant ret; + if (flavor == QCFString(QLatin1String("com.apple.traditional-mac-plain-text"))) { + QCFString str(CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(firstData.constData()), + firstData.size(), CFStringGetSystemEncoding(), false)); + ret = QString(str); + } else { + qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); + } + return ret; +} + +QList<QByteArray> QMacPasteboardMimePlainText::convertFromMime(const QString &, QVariant data, QString flavor) +{ + QList<QByteArray> ret; + QString string = data.toString(); + if (flavor == QCFString(QLatin1String("com.apple.traditional-mac-plain-text"))) + ret.append(string.toLatin1()); + return ret; +} + +class QMacPasteboardMimeUnicodeText : public QMacPasteboardMime { +public: + QMacPasteboardMimeUnicodeText() : QMacPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeUnicodeText::convertorName() +{ + return QLatin1String("UnicodeText"); +} + +QString QMacPasteboardMimeUnicodeText::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/plain")) + return QLatin1String("public.utf16-plain-text"); + int i = mime.indexOf(QLatin1String("charset=")); + if (i >= 0) { + QString cs(mime.mid(i+8).toLower()); + i = cs.indexOf(QLatin1Char(';')); + if (i>=0) + cs = cs.left(i); + if (cs == QLatin1String("system")) + return QLatin1String("public.utf8-plain-text"); + else if (cs == QLatin1String("iso-10646-ucs-2") + || cs == QLatin1String("utf16")) + return QLatin1String("public.utf16-plain-text"); + } + return QString(); +} + +QString QMacPasteboardMimeUnicodeText::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.utf16-plain-text") || flav == QLatin1String("public.utf8-plain-text")) + return QLatin1String("text/plain"); + return QString(); +} + +bool QMacPasteboardMimeUnicodeText::canConvert(const QString &mime, QString flav) +{ + return flavorFor(mime) == flav; +} + +QVariant QMacPasteboardMimeUnicodeText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor) +{ + if (data.count() > 1) + qWarning("QMacPasteboardMimeUnicodeText: Cannot handle multiple member data"); + const QByteArray &firstData = data.first(); + // I can only handle two types (system and unicode) so deal with them that way + QVariant ret; + if (flavor == QLatin1String("public.utf8-plain-text")) { + QCFString str(CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(firstData.constData()), + firstData.size(), CFStringGetSystemEncoding(), false)); + ret = QString(str); + } else if (flavor == QLatin1String("public.utf16-plain-text")) { + ret = QString(reinterpret_cast<const QChar *>(firstData.constData()), + firstData.size() / sizeof(QChar)); + } else { + qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); + } + return ret; +} + +QList<QByteArray> QMacPasteboardMimeUnicodeText::convertFromMime(const QString &, QVariant data, QString flavor) +{ + QList<QByteArray> ret; + QString string = data.toString(); + if (flavor == QLatin1String("public.utf8-plain-text")) + ret.append(string.toUtf8()); + else if (flavor == QLatin1String("public.utf16-plain-text")) + ret.append(QByteArray((char*)string.utf16(), string.length()*2)); + return ret; +} + +class QMacPasteboardMimeHTMLText : public QMacPasteboardMime { +public: + QMacPasteboardMimeHTMLText() : QMacPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeHTMLText::convertorName() +{ + return QLatin1String("HTML"); +} + +QString QMacPasteboardMimeHTMLText::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/html")) + return QLatin1String("public.html"); + return QString(); +} + +QString QMacPasteboardMimeHTMLText::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.html")) + return QLatin1String("text/html"); + return QString(); +} + +bool QMacPasteboardMimeHTMLText::canConvert(const QString &mime, QString flav) +{ + return flavorFor(mime) == flav; +} + +QVariant QMacPasteboardMimeHTMLText::convertToMime(const QString &mimeType, QList<QByteArray> data, QString flavor) +{ + if (!canConvert(mimeType, flavor)) + return QVariant(); + if (data.count() > 1) + qWarning("QMacPasteboardMimeHTMLText: Cannot handle multiple member data"); + return data.first(); +} + +QList<QByteArray> QMacPasteboardMimeHTMLText::convertFromMime(const QString &mime, QVariant data, QString flavor) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flavor)) + return ret; + ret.append(data.toByteArray()); + return ret; +} + +class QMacPasteboardMimeTiff : public QMacPasteboardMime { +public: + QMacPasteboardMimeTiff() : QMacPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeTiff::convertorName() +{ + return QLatin1String("Tiff"); +} + +QString QMacPasteboardMimeTiff::flavorFor(const QString &mime) +{ + if (mime.startsWith(QLatin1String("application/x-qt-image"))) + return QLatin1String("public.tiff"); + return QString(); +} + +QString QMacPasteboardMimeTiff::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.tiff")) + return QLatin1String("application/x-qt-image"); + return QString(); +} + +bool QMacPasteboardMimeTiff::canConvert(const QString &mime, QString flav) +{ + return flav == QLatin1String("public.tiff") && mime == QLatin1String("application/x-qt-image"); +} + +QVariant QMacPasteboardMimeTiff::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) +{ + if (data.count() > 1) + qWarning("QMacPasteboardMimeTiff: Cannot handle multiple member data"); + QVariant ret; + if (!canConvert(mime, flav)) + return ret; + const QByteArray &a = data.first(); + QCFType<CGImageRef> image; + QCFType<CFDataRef> tiffData = CFDataCreateWithBytesNoCopy(0, + reinterpret_cast<const UInt8 *>(a.constData()), + a.size(), kCFAllocatorNull); + QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithData(tiffData, 0); + image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0); + + // ### TODO (msorvig) QPixmap conversion + //if (image != 0) + // ret = QVariant(QPixmap::fromMacCGImageRef(image).toImage()); + return ret; +} + +QList<QByteArray> QMacPasteboardMimeTiff::convertFromMime(const QString &mime, QVariant variant, QString flav) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flav)) + return ret; + + QImage img = qvariant_cast<QImage>(variant); + QCFType<CGImageRef> cgimage = qt_mac_image_to_cgimage(img); + + QCFType<CFMutableDataRef> data = CFDataCreateMutable(0, 0); + QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data, kUTTypeTIFF, 1, 0); + if (imageDestination != 0) { + CFTypeRef keys[2]; + QCFType<CFTypeRef> values[2]; + QCFType<CFDictionaryRef> options; + keys[0] = kCGImagePropertyPixelWidth; + keys[1] = kCGImagePropertyPixelHeight; + int width = img.width(); + int height = img.height(); + values[0] = CFNumberCreate(0, kCFNumberIntType, &width); + values[1] = CFNumberCreate(0, kCFNumberIntType, &height); + options = CFDictionaryCreate(0, reinterpret_cast<const void **>(keys), + reinterpret_cast<const void **>(values), 2, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CGImageDestinationAddImage(imageDestination, cgimage, options); + CGImageDestinationFinalize(imageDestination); + } + QByteArray ar(CFDataGetLength(data), 0); + CFDataGetBytes(data, + CFRangeMake(0, ar.size()), + reinterpret_cast<UInt8 *>(ar.data())); + ret.append(ar); + return ret; +} + + +class QMacPasteboardMimeFileUri : public QMacPasteboardMime { +public: + QMacPasteboardMimeFileUri() : QMacPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeFileUri::convertorName() +{ + return QLatin1String("FileURL"); +} + +QString QMacPasteboardMimeFileUri::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/uri-list")) + return QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0)); + return QString(); +} + +QString QMacPasteboardMimeFileUri::mimeFor(QString flav) +{ + if (flav == QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0))) + return QLatin1String("text/uri-list"); + return QString(); +} + +bool QMacPasteboardMimeFileUri::canConvert(const QString &mime, QString flav) +{ + return mime == QLatin1String("text/uri-list") + && flav == QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0)); +} + +QVariant QMacPasteboardMimeFileUri::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) +{ + if (!canConvert(mime, flav)) + return QVariant(); + QList<QVariant> ret; + for (int i = 0; i < data.size(); ++i) { + QUrl url = QUrl::fromEncoded(data.at(i)); + if (url.host().toLower() == QLatin1String("localhost")) + url.setHost(QString()); + url.setPath(url.path().normalized(QString::NormalizationForm_C)); + ret.append(url); + } + return QVariant(ret); +} + +QList<QByteArray> QMacPasteboardMimeFileUri::convertFromMime(const QString &mime, QVariant data, QString flav) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flav)) + return ret; + QList<QVariant> urls = data.toList(); + for (int i = 0; i < urls.size(); ++i) { + QUrl url = urls.at(i).toUrl(); + if (url.scheme().isEmpty()) + url.setScheme(QLatin1String("file")); + if (url.scheme().toLower() == QLatin1String("file")) { + if (url.host().isEmpty()) + url.setHost(QLatin1String("localhost")); + url.setPath(url.path().normalized(QString::NormalizationForm_D)); + } + ret.append(url.toEncoded()); + } + return ret; +} + +class QMacPasteboardMimeUrl : public QMacPasteboardMime { +public: + QMacPasteboardMimeUrl() : QMacPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeUrl::convertorName() +{ + return QLatin1String("URL"); +} + +QString QMacPasteboardMimeUrl::flavorFor(const QString &mime) +{ + if (mime.startsWith(QLatin1String("text/uri-list"))) + return QLatin1String("public.url"); + return QString(); +} + +QString QMacPasteboardMimeUrl::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.url")) + return QLatin1String("text/uri-list"); + return QString(); +} + +bool QMacPasteboardMimeUrl::canConvert(const QString &mime, QString flav) +{ + return flav == QLatin1String("public.url") + && mime == QLatin1String("text/uri-list"); +} + +QVariant QMacPasteboardMimeUrl::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) +{ + if (!canConvert(mime, flav)) + return QVariant(); + + QList<QVariant> ret; + for (int i=0; i<data.size(); ++i) { + QUrl url = QUrl::fromEncoded(data.at(i)); + if (url.host().toLower() == QLatin1String("localhost")) + url.setHost(QString()); + url.setPath(url.path().normalized(QString::NormalizationForm_C)); + ret.append(url); + } + return QVariant(ret); +} + +QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QVariant data, QString flav) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flav)) + return ret; + + QList<QVariant> urls = data.toList(); + for (int i=0; i<urls.size(); ++i) { + QUrl url = urls.at(i).toUrl(); + if (url.scheme().isEmpty()) + url.setScheme(QLatin1String("file")); + if (url.scheme().toLower() == QLatin1String("file")) { + if (url.host().isEmpty()) + url.setHost(QLatin1String("localhost")); + url.setPath(url.path().normalized(QString::NormalizationForm_D)); + } + ret.append(url.toEncoded()); + } + return ret; +} + +class QMacPasteboardMimeVCard : public QMacPasteboardMime +{ +public: + QMacPasteboardMimeVCard() : QMacPasteboardMime(MIME_ALL){ } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeVCard::convertorName() +{ + return QString("VCard"); +} + +bool QMacPasteboardMimeVCard::canConvert(const QString &mime, QString flav) +{ + return mimeFor(flav) == mime; +} + +QString QMacPasteboardMimeVCard::flavorFor(const QString &mime) +{ + if (mime.startsWith(QLatin1String("text/plain"))) + return QLatin1String("public.vcard"); + return QString(); +} + +QString QMacPasteboardMimeVCard::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.vcard")) + return QLatin1String("text/plain"); + return QString(); +} + +QVariant QMacPasteboardMimeVCard::convertToMime(const QString &mime, QList<QByteArray> data, QString) +{ + QByteArray cards; + if (mime == QLatin1String("text/plain")) { + for (int i=0; i<data.size(); ++i) + cards += data[i]; + } + return QVariant(cards); +} + +QList<QByteArray> QMacPasteboardMimeVCard::convertFromMime(const QString &mime, QVariant data, QString) +{ + QList<QByteArray> ret; + if (mime == QLatin1String("text/plain")) + ret.append(data.toString().toUtf8()); + return ret; +} + + +/*! + \internal + + This is an internal function. +*/ +void QMacPasteboardMime::initialize() +{ + if (globalMimeList()->isEmpty()) { + qAddPostRoutine(cleanup_mimes); + + //standard types that we wrap + new QMacPasteboardMimeTiff; + new QMacPasteboardMimeUnicodeText; + new QMacPasteboardMimePlainText; + new QMacPasteboardMimeHTMLText; + new QMacPasteboardMimeFileUri; + new QMacPasteboardMimeUrl; + new QMacPasteboardMimeTypeName; + new QMacPasteboardMimeVCard; + //make sure our "non-standard" types are always last! --Sam + new QMacPasteboardMimeAny; + } +} + +/*! + Returns the most-recently created QMacPasteboardMime of type \a t that can convert + between the \a mime and \a flav formats. Returns 0 if no such convertor + exists. +*/ +QMacPasteboardMime* +QMacPasteboardMime::convertor(uchar t, const QString &mime, QString flav) +{ + MimeList *mimes = globalMimeList(); + for (MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) { +#ifdef DEBUG_MIME_MAPS + qDebug("QMacPasteboardMime::convertor: seeing if %s (%d) can convert %s to %d[%c%c%c%c] [%d]", + (*it)->convertorName().toLatin1().constData(), + (*it)->type & t, mime.toLatin1().constData(), + flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF, + (*it)->canConvert(mime,flav)); + for (int i = 0; i < (*it)->countFlavors(); ++i) { + int f = (*it)->flavor(i); + qDebug(" %d) %d[%c%c%c%c] [%s]", i, f, + (f >> 24) & 0xFF, (f >> 16) & 0xFF, (f >> 8) & 0xFF, (f) & 0xFF, + (*it)->convertorName().toLatin1().constData()); + } +#endif + if (((*it)->type & t) && (*it)->canConvert(mime, flav)) + return (*it); + } + return 0; +} +/*! + Returns a MIME type of type \a t for \a flav, or 0 if none exists. +*/ +QString QMacPasteboardMime::flavorToMime(uchar t, QString flav) +{ + MimeList *mimes = globalMimeList(); + for (MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) { +#ifdef DEBUG_MIME_MAPS + qDebug("QMacMIme::flavorToMime: attempting %s (%d) for flavor %d[%c%c%c%c] [%s]", + (*it)->convertorName().toLatin1().constData(), + (*it)->type & t, flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF, + (*it)->mimeFor(flav).toLatin1().constData()); + +#endif + if ((*it)->type & t) { + QString mimeType = (*it)->mimeFor(flav); + if (!mimeType.isNull()) + return mimeType; + } + } + return QString(); +} + +/*! + Returns a list of all currently defined QMacPasteboardMime objects of type \a t. +*/ +QList<QMacPasteboardMime*> QMacPasteboardMime::all(uchar t) +{ + MimeList ret; + MimeList *mimes = globalMimeList(); + for (MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) { + if ((*it)->type & t) + ret.append((*it)); + } + return ret; +} + + +/*! + \fn QString QMacPasteboardMime::convertorName() + + Returns a name for the convertor. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn bool QMacPasteboardMime::canConvert(const QString &mime, QString flav) + + Returns true if the convertor can convert (both ways) between + \a mime and \a flav; otherwise returns false. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QString QMacPasteboardMime::mimeFor(QString flav) + + Returns the MIME UTI used for Mac flavor \a flav, or 0 if this + convertor does not support \a flav. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QString QMacPasteboardMime::flavorFor(const QString &mime) + + Returns the Mac UTI used for MIME type \a mime, or 0 if this + convertor does not support \a mime. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QVariant QMacPasteboardMime::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) + + Returns \a data converted from Mac UTI \a flav to MIME type \a + mime. + + Note that Mac flavors must all be self-terminating. The input \a + data may contain trailing data. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QList<QByteArray> QMacPasteboardMime::convertFromMime(const QString &mime, QVariant data, QString flav) + + Returns \a data converted from MIME type \a mime + to Mac UTI \a flav. + + Note that Mac flavors must all be self-terminating. The return + value may contain trailing data. + + All subclasses must reimplement this pure virtual function. +*/ + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index c61ff2bd02..1a1a1cd3b9 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -57,6 +57,7 @@ QT_END_NAMESPACE QCocoaWindow *m_platformWindow; Qt::MouseButtons m_buttons; QAccessibleInterface *m_accessibleRoot; + QStringList *currentCustomDragTypes; } - (id)init; @@ -91,6 +92,9 @@ QT_END_NAMESPACE - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; +- (void)registerDragTypes; +- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender; + @end #endif //QNSVIEW_H diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index a43b3fe893..9ed3332ba5 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -46,7 +46,9 @@ #include "qnsview.h" #include "qcocoawindow.h" #include "qcocoahelpers.h" +#include "qcocoaautoreleasepool.h" #include "qmultitouch_mac_p.h" +#include "qcocoadrag.h" #include <QtGui/QWindowSystemInterface> #include <QtCore/QDebug> @@ -72,6 +74,7 @@ static QTouchDevice *touchDevice = 0; m_cgImage = 0; m_window = 0; m_buttons = Qt::NoButton; + currentCustomDragTypes = 0; if (!touchDevice) { touchDevice = new QTouchDevice; touchDevice->setType(QTouchDevice::TouchPad); @@ -109,6 +112,7 @@ static QTouchDevice *touchDevice = 0; m_accessibleRoot = window->accessibleRoot(); #endif + [self registerDragTypes]; [self setPostsFrameChangedNotifications : YES]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateGeometry) @@ -471,4 +475,74 @@ static QTouchDevice *touchDevice = 0; [self handleKeyEvent : theEvent eventType :int(QEvent::KeyRelease)]; } +-(void)registerDragTypes +{ + QCocoaAutoReleasePool pool; + // ### Custom types disabled. + QStringList customTypes; // = qEnabledDraggedTypes(); + if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) { + if (currentCustomDragTypes == 0) + currentCustomDragTypes = new QStringList(); + *currentCustomDragTypes = customTypes; + const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName"; + NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType, + NSFilenamesPboardType, NSStringPboardType, + NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType, + NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType, + NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType, + NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType, + NSURLPboardType, NSPDFPboardType, NSVCardPboardType, + NSFilesPromisePboardType, NSInkTextPboardType, + NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil]; + // Add custom types supported by the application. + for (int i = 0; i < customTypes.size(); i++) { + [supportedTypes addObject:QCFString::toNSString(customTypes[i])]; + } + [self registerForDraggedTypes:supportedTypes]; + } +} + +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender +{ + return [self handleDrag : sender]; +} + +- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender +{ + return [self handleDrag : sender]; +} + +// Sends drag update to Qt, return the action +- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender +{ + NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; + QPoint qt_windowPoint(windowPoint.x, windowPoint.y); + Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); + QCocoaDropData mimeData([sender draggingPasteboard]); + + QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_window, &mimeData, qt_windowPoint, qtAllowed); + return qt_mac_mapDropAction(response.acceptedAction()); +} + +- (void)draggingExited:(id <NSDraggingInfo>)sender +{ + NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; + QPoint qt_windowPoint(windowPoint.x, windowPoint.y); + + // Send 0 mime data to indicate drag exit + QWindowSystemInterface::handleDrag(m_window, 0 ,qt_windowPoint, Qt::IgnoreAction); +} + +// called on drop, send the drop to Qt and return if it was accepted. +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender +{ + NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; + QPoint qt_windowPoint(windowPoint.x, windowPoint.y); + Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); + QCocoaDropData mimeData([sender draggingPasteboard]); + + QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_window, &mimeData, qt_windowPoint, qtAllowed); + return response.isAccepted(); +} + @end diff --git a/src/plugins/platforms/cocoa/qt_mac_p.h b/src/plugins/platforms/cocoa/qt_mac_p.h index 8e94880c5a..b75e6e2bcb 100644 --- a/src/plugins/platforms/cocoa/qt_mac_p.h +++ b/src/plugins/platforms/cocoa/qt_mac_p.h @@ -196,44 +196,6 @@ public: class QMacPasteboardMime; class QMimeData; -class QMacPasteboard -{ - struct Promise { - Promise() : itemId(0), convertor(0) { } - Promise(int itemId, QMacPasteboardMime *c, QString m, QVariant d, int o=0) : itemId(itemId), offset(o), convertor(c), mime(m), data(d) { } - int itemId, offset; - QMacPasteboardMime *convertor; - QString mime; - QVariant data; - }; - QList<Promise> promises; - - OSPasteboardRef paste; - uchar mime_type; - mutable QPointer<QMimeData> mime; - mutable bool mac_mime_source; - static OSStatus promiseKeeper(OSPasteboardRef, PasteboardItemID, CFStringRef, void *); - void clear_helper(); -public: - QMacPasteboard(OSPasteboardRef p, uchar mime_type=0); - QMacPasteboard(uchar mime_type); - QMacPasteboard(CFStringRef name=0, uchar mime_type=0); - ~QMacPasteboard(); - - bool hasFlavor(QString flavor) const; - bool hasOSType(int c_flavor) const; - - OSPasteboardRef pasteBoard() const; - QMimeData *mimeData() const; - void setMimeData(QMimeData *mime); - - QStringList formats() const; - bool hasFormat(const QString &format) const; - QVariant retrieveData(const QString &format, QVariant::Type) const; - - void clear(); - bool sync() const; -}; extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.cpp b/src/plugins/platforms/directfb/qdirectfbcursor.cpp index e1660a998a..a63bc48133 100644 --- a/src/plugins/platforms/directfb/qdirectfbcursor.cpp +++ b/src/plugins/platforms/directfb/qdirectfbcursor.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE QDirectFBCursor::QDirectFBCursor(QPlatformScreen *screen) - : QPlatformCursor(screen) + : m_screen(screen) { m_image.reset(new QPlatformCursorImage(0, 0, 0, 0, 0, 0)); } @@ -70,7 +70,7 @@ void QDirectFBCursor::changeCursor(QCursor *cursor, QWindow *) } DFBResult res; - IDirectFBDisplayLayer *layer = toDfbLayer(screen); + IDirectFBDisplayLayer *layer = toDfbLayer(m_screen); IDirectFBSurface* surface(QDirectFbConvenience::dfbSurfaceForPlatformPixmap(map.handle())); res = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.h b/src/plugins/platforms/directfb/qdirectfbcursor.h index 3cc2825b28..f28e225dc7 100644 --- a/src/plugins/platforms/directfb/qdirectfbcursor.h +++ b/src/plugins/platforms/directfb/qdirectfbcursor.h @@ -60,6 +60,7 @@ public: private: QScopedPointer<QPlatformCursorImage> m_image; + QPlatformScreen *m_screen; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbscreen.h b/src/plugins/platforms/directfb/qdirectfbscreen.h index ad80576c8f..8535239088 100644 --- a/src/plugins/platforms/directfb/qdirectfbscreen.h +++ b/src/plugins/platforms/directfb/qdirectfbscreen.h @@ -61,6 +61,7 @@ public: int depth() const { return m_depth; } QImage::Format format() const { return m_format; } QSizeF physicalSize() const { return m_physicalSize; } + QPlatformCursor *cursor() const { return m_cursor.data(); } // DirectFb helpers IDirectFBDisplayLayer *dfbLayer() const; diff --git a/src/plugins/platforms/kms/qkmscursor.cpp b/src/plugins/platforms/kms/qkmscursor.cpp index a38f66bd02..37817af39d 100644 --- a/src/plugins/platforms/kms/qkmscursor.cpp +++ b/src/plugins/platforms/kms/qkmscursor.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE QKmsCursor::QKmsCursor(QKmsScreen *screen) - : QPlatformCursor(screen), m_screen(screen), + : m_screen(screen), m_graphicsBufferManager(screen->device()->gbmDevice()) { gbm_bo *bo = gbm_bo_create(m_graphicsBufferManager, 64, 64, diff --git a/src/plugins/platforms/kms/qkmsscreen.cpp b/src/plugins/platforms/kms/qkmsscreen.cpp index f1b9baf120..76b9bce28f 100644 --- a/src/plugins/platforms/kms/qkmsscreen.cpp +++ b/src/plugins/platforms/kms/qkmsscreen.cpp @@ -96,6 +96,11 @@ QSizeF QKmsScreen::physicalSize() const return m_physicalSize; } +QPlatformCursor *QKmsScreen::cursor() const +{ + return m_cursor; +} + GLuint QKmsScreen::framebufferObject() const { return m_bufferManager.framebufferObject(); diff --git a/src/plugins/platforms/kms/qkmsscreen.h b/src/plugins/platforms/kms/qkmsscreen.h index 4cb547b424..058314a515 100644 --- a/src/plugins/platforms/kms/qkmsscreen.h +++ b/src/plugins/platforms/kms/qkmsscreen.h @@ -61,6 +61,7 @@ public: int depth() const; QImage::Format format() const; QSizeF physicalSize() const; + QPlatformCursor *cursor() const; GLuint framebufferObject() const; quint32 crtcId() const { return m_crtcId; } diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index d82240255e..ac768e2dab 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -61,7 +61,8 @@ # define FE_FONTSMOOTHINGCLEARTYPE 0x0002 # define CLEARTYPE_QUALITY 5 # define SPI_GETDROPSHADOW 0x1024 - +# define COLOR_MENUHILIGHT 29 +# define COLOR_MENUBAR 30 # define CF_DIBV5 17 #define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) diff --git a/src/plugins/platforms/windows/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/qwindowsaccessibility.cpp index 1a8f593609..134b1c81ce 100644 --- a/src/plugins/platforms/windows/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/qwindowsaccessibility.cpp @@ -844,14 +844,12 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, I QPair<QObject*, int> ref = qAccessibleRecentSentEvents()->value(entry); if (ref.first) { acc = QAccessible::queryAccessibleInterface(ref.first); - if (acc && ref.second) { - if (ref.second) { - QAccessibleInterface *res = acc->child(ref.second - 1); - delete acc; - if (!res) - return E_INVALIDARG; - acc = res; - } + if (acc && ref.second >= 0) { + QAccessibleInterface *res = acc->child(ref.second); + delete acc; + if (!res) + return E_INVALIDARG; + acc = res; } } } else { diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index f75cbeb078..337ba9ab27 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -72,11 +72,6 @@ Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap); \sa QWindowsWindowCursor */ -QWindowsCursor::QWindowsCursor(QPlatformScreen *s) : - QPlatformCursor(s) -{ -} - HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY) { HCURSOR cur = 0; diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index a03c77a3b6..61c43dc4d2 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -70,7 +70,7 @@ private: class QWindowsCursor : public QPlatformCursor { public: - explicit QWindowsCursor(QPlatformScreen *); + QWindowsCursor() {} virtual void changeCursor(QCursor * widgetCursor, QWindow * widget); virtual QPoint pos() const { return mousePosition(); } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index fba7794a12..5094ad9dc3 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qwindowsfontdatabase.h" +#include "qwindowsfontdatabase_ft.h" // for default font #include "qwindowscontext.h" #include "qwindowsfontengine.h" #include "qwindowsfontenginedirectwrite.h" @@ -1066,53 +1067,7 @@ static inline int verticalDPI() QFont QWindowsFontDatabase::defaultFont() const { - LOGFONT lf; - GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); - QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(lf); - // "MS Shell Dlg 2" is the correct system font >= Win2k - if (systemFont.family() == QStringLiteral("MS Shell Dlg")) - systemFont.setFamily(QStringLiteral("MS Shell Dlg 2")); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << systemFont; - return systemFont; -} - -QHash<QByteArray, QFont> QWindowsFontDatabase::defaultFonts() const -{ - QHash<QByteArray, QFont> result; - NONCLIENTMETRICS ncm; - ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); - - const int verticalRes = verticalDPI(); - - const QFont menuFont = LOGFONT_to_QFont(ncm.lfMenuFont, verticalRes); - const QFont messageFont = LOGFONT_to_QFont(ncm.lfMessageFont, verticalRes); - const QFont statusFont = LOGFONT_to_QFont(ncm.lfStatusFont, verticalRes); - const QFont titleFont = LOGFONT_to_QFont(ncm.lfCaptionFont, verticalRes); - - LOGFONT lfIconTitleFont; - SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); - const QFont iconTitleFont = LOGFONT_to_QFont(lfIconTitleFont, verticalRes); - - result.insert(QByteArray("QMenu"), menuFont); - result.insert(QByteArray("QMenuBar"), menuFont); - result.insert(QByteArray("QMessageBox"), messageFont); - result.insert(QByteArray("QTipLabel"), statusFont); - result.insert(QByteArray("QStatusBar"), statusFont); - result.insert(QByteArray("Q3TitleBar"), titleFont); - result.insert(QByteArray("QWorkspaceTitleBar"), titleFont); - result.insert(QByteArray("QAbstractItemView"), iconTitleFont); - result.insert(QByteArray("QDockWidgetTitle"), iconTitleFont); - if (QWindowsContext::verboseFonts) { - typedef QHash<QByteArray, QFont>::const_iterator CIT; - QDebug nsp = qDebug().nospace(); - nsp << __FUNCTION__ << " DPI=" << verticalRes << "\n"; - const CIT cend = result.constEnd(); - for (CIT it = result.constBegin(); it != cend; ++it) - nsp << it.key() << ' ' << it.value() << '\n'; - } - return result; + return QWindowsFontDatabaseFT::systemDefaultFont(); } QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index b08b682991..04d6ccdd91 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -86,7 +86,6 @@ public: virtual QString fontDir() const; virtual QFont defaultFont() const; - virtual QHash<QByteArray, QFont> defaultFonts() const; static QFontEngine *createEngine(int script, const QFontDef &request, HDC fontHdc, int dpi, bool rawMode, diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index e972ae23ee..fcce87d0bd 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -460,7 +460,7 @@ static inline int verticalDPI() return GetDeviceCaps(QWindowsContext::instance()->displayContext(), LOGPIXELSY); } -QFont QWindowsFontDatabaseFT::defaultFont() const +QFont QWindowsFontDatabaseFT::systemDefaultFont() { LOGFONT lf; GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); @@ -473,44 +473,6 @@ QFont QWindowsFontDatabaseFT::defaultFont() const return systemFont; } -QHash<QByteArray, QFont> QWindowsFontDatabaseFT::defaultFonts() const -{ - QHash<QByteArray, QFont> result; - NONCLIENTMETRICS ncm; - ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); - - const int verticalRes = verticalDPI(); - - const QFont menuFont = LOGFONT_to_QFont(ncm.lfMenuFont, verticalRes); - const QFont messageFont = LOGFONT_to_QFont(ncm.lfMessageFont, verticalRes); - const QFont statusFont = LOGFONT_to_QFont(ncm.lfStatusFont, verticalRes); - const QFont titleFont = LOGFONT_to_QFont(ncm.lfCaptionFont, verticalRes); - - LOGFONT lfIconTitleFont; - SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); - const QFont iconTitleFont = LOGFONT_to_QFont(lfIconTitleFont, verticalRes); - - result.insert(QByteArray("QMenu"), menuFont); - result.insert(QByteArray("QMenuBar"), menuFont); - result.insert(QByteArray("QMessageBox"), messageFont); - result.insert(QByteArray("QTipLabel"), statusFont); - result.insert(QByteArray("QStatusBar"), statusFont); - result.insert(QByteArray("Q3TitleBar"), titleFont); - result.insert(QByteArray("QWorkspaceTitleBar"), titleFont); - result.insert(QByteArray("QAbstractItemView"), iconTitleFont); - result.insert(QByteArray("QDockWidgetTitle"), iconTitleFont); - if (QWindowsContext::verboseFonts) { - typedef QHash<QByteArray, QFont>::const_iterator CIT; - QDebug nsp = qDebug().nospace(); - nsp << __FUNCTION__ << " DPI=" << verticalRes << "\n"; - const CIT cend = result.constEnd(); - for (CIT it = result.constBegin(); it != cend; ++it) - nsp << it.key() << ' ' << it.value() << '\n'; - } - return result; -} - QFont QWindowsFontDatabaseFT::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) { if (verticalDPI_In <= 0) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index 5a0c4c6377..4136b75dd8 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -59,8 +59,9 @@ public: QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); virtual QString fontDir() const; - virtual QFont defaultFont() const; - virtual QHash<QByteArray, QFont> defaultFonts() const; + virtual QFont defaultFont() const { return systemDefaultFont(); } + static QFont systemDefaultFont(); + static HFONT systemFont(); static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0); diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 1dc5175515..2476e15169 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -147,6 +147,14 @@ static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d) return dbg; } +// Return the cursor to be shared by all screens (virtual desktop). +static inline QSharedPointer<QWindowsCursor> sharedCursor() +{ + if (const QScreen *primaryScreen = QGuiApplication::primaryScreen()) + return static_cast<const QWindowsScreen *>(primaryScreen->handle())->windowsCursor(); + return QSharedPointer<QWindowsCursor>(new QWindowsCursor); +} + /*! \class QWindowsScreen \brief Windows screen. @@ -155,7 +163,7 @@ static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d) */ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) : - m_data(data), m_cursor(this) + m_data(data), m_cursor(sharedCursor()) { } diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 77a327a62a..5b9a50b2ab 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -46,6 +46,7 @@ #include <QtCore/QList> #include <QtCore/QPair> +#include <QtCore/QSharedPointer> #include <QtGui/QPlatformScreen> QT_BEGIN_NAMESPACE @@ -74,6 +75,8 @@ struct QWindowsScreenData class QWindowsScreen : public QPlatformScreen { public: + typedef QSharedPointer<QWindowsCursor> WindowsCursorPtr; + explicit QWindowsScreen(const QWindowsScreenData &data); static QWindowsScreen *screenOf(const QWindow *w = 0); @@ -98,14 +101,14 @@ public: inline void handleChanges(const QWindowsScreenData &newData); - const QWindowsCursor &cursor() const { return m_cursor; } - QWindowsCursor &cursor() { return m_cursor; } + QPlatformCursor *cursor() const { return m_cursor.data(); } + const WindowsCursorPtr &windowsCursor() const { return m_cursor; } const QWindowsScreenData &data() const { return m_data; } private: QWindowsScreenData m_data; - QWindowsCursor m_cursor; + const WindowsCursorPtr m_cursor; }; class QWindowsScreenManager diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 5350b3ca3f..10b4682ad8 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -44,6 +44,7 @@ #include "qwindowscontext.h" #include "qwindowsintegration.h" #include "qt_windows.h" +#include "qwindowsfontdatabase_ft.h" #include <QtCore/QVariant> #include <QtCore/QCoreApplication> @@ -76,6 +77,22 @@ static inline QString paletteToString(const QPalette &palette) return result; } +static inline bool booleanSystemParametersInfo(UINT what, bool defaultValue) +{ + BOOL result; + if (SystemParametersInfo(what, 0, &result, 0)) + return result ? true : false; + return defaultValue; +} + +static inline bool dWordSystemParametersInfo(UINT what, DWORD defaultValue) +{ + DWORD result; + if (SystemParametersInfo(what, 0, &result, 0)) + return result; + return defaultValue; +} + static inline QColor mixColors(const QColor &c1, const QColor &c2) { return QColor ((c1.red() + c2.red()) / 2, @@ -138,7 +155,7 @@ static inline QPalette systemPalette() return result; } -QPalette toolTipPalette(const QPalette &systemPalette) +static inline QPalette toolTipPalette(const QPalette &systemPalette) { QPalette result(systemPalette); const QColor tipBgColor(getSysColor(COLOR_INFOBK)); @@ -163,24 +180,58 @@ QPalette toolTipPalette(const QPalette &systemPalette) return result; } -static inline bool booleanSystemParametersInfo(UINT what, bool defaultValue) +static inline QPalette menuPalette(const QPalette &systemPalette) { - BOOL result; - if (SystemParametersInfo(what, 0, &result, 0)) - return result ? true : false; - return defaultValue; + QPalette result(systemPalette); + const QColor menuColor(getSysColor(COLOR_INFOBK)); + const QColor menuTextColor(getSysColor(COLOR_MENUTEXT)); + const QColor disabled(getSysColor(COLOR_GRAYTEXT)); + const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false); + // we might need a special color group for the result. + result.setColor(QPalette::Active, QPalette::Button, menuColor); + result.setColor(QPalette::Active, QPalette::Text, menuTextColor); + result.setColor(QPalette::Active, QPalette::WindowText, menuTextColor); + result.setColor(QPalette::Active, QPalette::ButtonText, menuTextColor); + result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); + result.setColor(QPalette::Disabled, QPalette::Text, disabled); + result.setColor(QPalette::Disabled, QPalette::Highlight, + getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)); + result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled); + result.setColor(QPalette::Disabled, QPalette::Button, + result.color(QPalette::Active, QPalette::Button)); + result.setColor(QPalette::Inactive, QPalette::Button, + result.color(QPalette::Active, QPalette::Button)); + result.setColor(QPalette::Inactive, QPalette::Text, + result.color(QPalette::Active, QPalette::Text)); + result.setColor(QPalette::Inactive, QPalette::WindowText, + result.color(QPalette::Active, QPalette::WindowText)); + result.setColor(QPalette::Inactive, QPalette::ButtonText, + result.color(QPalette::Active, QPalette::ButtonText)); + result.setColor(QPalette::Inactive, QPalette::Highlight, + result.color(QPalette::Active, QPalette::Highlight)); + result.setColor(QPalette::Inactive, QPalette::HighlightedText, + result.color(QPalette::Active, QPalette::HighlightedText)); + result.setColor(QPalette::Inactive, QPalette::ButtonText, + systemPalette.color(QPalette::Inactive, QPalette::Dark)); + return result; } -static inline bool dWordSystemParametersInfo(UINT what, DWORD defaultValue) +static inline QPalette *menuBarPalette(const QPalette &menuPalette) { - DWORD result; - if (SystemParametersInfo(what, 0, &result, 0)) - return result; - return defaultValue; + QPalette *result = 0; + if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) { + result = new QPalette(menuPalette); + const QColor menubar(getSysColor(COLOR_MENUBAR)); + result->setColor(QPalette::Active, QPalette::Button, menubar); + result->setColor(QPalette::Disabled, QPalette::Button, menubar); + result->setColor(QPalette::Inactive, QPalette::Button, menubar); + } + return result; } QWindowsTheme::QWindowsTheme() { + qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); refresh(); } @@ -188,12 +239,7 @@ QWindowsTheme::QWindowsTheme() QWindowsTheme::~QWindowsTheme() { clearPalettes(); -} - -void QWindowsTheme::clearPalettes() -{ - qDeleteAll(m_palettes, m_palettes + NPalettes); - qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); + clearFonts(); } QWindowsTheme *QWindowsTheme::instance() @@ -243,17 +289,65 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const return QPlatformTheme::themeHint(hint); } -void QWindowsTheme::refresh() +void QWindowsTheme::clearPalettes() { - clearPalettes(); - if (QGuiApplication::desktopSettingsAware()) { - m_palettes[SystemPalette] = new QPalette(systemPalette()); - m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette])); - if (QWindowsContext::verboseTheming) - qDebug() << __FUNCTION__ << '\n' - << " system=" << paletteToString(*m_palettes[SystemPalette]) - << " tooltip=" << paletteToString(*m_palettes[ToolTipPalette]); - } + qDeleteAll(m_palettes, m_palettes + NPalettes); + qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); +} + +void QWindowsTheme::refreshPalettes() +{ + + if (!QGuiApplication::desktopSettingsAware()) + return; + m_palettes[SystemPalette] = new QPalette(systemPalette()); + m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette])); + m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette])); + m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette]); + if (QWindowsContext::verboseTheming) + qDebug() << __FUNCTION__ << '\n' + << " system=" << paletteToString(*m_palettes[SystemPalette]) + << " tooltip=" << paletteToString(*m_palettes[ToolTipPalette]); +} + +void QWindowsTheme::clearFonts() +{ + qDeleteAll(m_fonts, m_fonts + NFonts); + qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); +} + +void QWindowsTheme::refreshFonts() +{ + clearFonts(); + if (!QGuiApplication::desktopSettingsAware()) + return; + NONCLIENTMETRICS ncm; + ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); + + const QFont menuFont = QWindowsFontDatabaseFT::LOGFONT_to_QFont(ncm.lfMenuFont); + const QFont messageBoxFont = QWindowsFontDatabaseFT::LOGFONT_to_QFont(ncm.lfMessageFont); + const QFont statusFont = QWindowsFontDatabaseFT::LOGFONT_to_QFont(ncm.lfStatusFont); + const QFont titleFont = QWindowsFontDatabaseFT::LOGFONT_to_QFont(ncm.lfCaptionFont); + + LOGFONT lfIconTitleFont; + SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); + const QFont iconTitleFont = QWindowsFontDatabaseFT::LOGFONT_to_QFont(lfIconTitleFont); + + m_fonts[SystemFont] = new QFont(QWindowsFontDatabaseFT::systemDefaultFont()); + m_fonts[MenuFont] = new QFont(menuFont); + m_fonts[MenuBarFont] = new QFont(menuFont); + m_fonts[MessageBoxFont] = new QFont(messageBoxFont); + m_fonts[TipLabelFont] = new QFont(statusFont); + m_fonts[StatusBarFont] = new QFont(statusFont); + m_fonts[MdiSubWindowTitleFont] = new QFont(titleFont); + m_fonts[DockWidgetTitleFont] = new QFont(titleFont); + m_fonts[ItemViewFont] = new QFont(iconTitleFont); + + if (QWindowsContext::verboseTheming) + qDebug() << __FUNCTION__ << '\n' + << " menuFont=" << menuFont + << " messageBox=" << MessageBoxFont; } bool QWindowsTheme::usePlatformNativeDialog(DialogType type) const diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 950c380737..37346eed3a 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -64,14 +64,20 @@ public: virtual QVariant themeHint(ThemeHint) const; virtual const QPalette *palette(Palette type = SystemPalette) const { return m_palettes[type]; } + virtual const QFont *font(Font type = SystemFont) const + { return m_fonts[type]; } void windowsThemeChanged(QWindow *window); private: - void refresh(); + void refresh() { refreshPalettes(); refreshFonts(); } void clearPalettes(); + void refreshPalettes(); + void clearFonts(); + void refreshFonts(); QPalette *m_palettes[NPalettes]; + QFont *m_fonts[NFonts]; }; static inline COLORREF qColorToCOLORREF(const QColor &color) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index b2ebe06a58..1edb243f4e 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -618,7 +618,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : m_windowState(aWindow->windowState()), m_opacity(1.0), m_mouseGrab(false), - m_cursor(QWindowsScreen::screenOf(aWindow)->cursor().standardWindowCursor()), + m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()), m_dropTarget(0), m_savedStyle(0) { @@ -1309,16 +1309,14 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const } /*! - \brief Applies to cursor property set on the window to the global cursor - unless there is an override cursor. + \brief Applies to cursor property set on the window to the global cursor. \sa QWindowsCursor */ void QWindowsWindow::applyCursor() { - if (!QGuiApplication::overrideCursor()) - SetCursor(m_cursor.handle()); + SetCursor(m_cursor.handle()); } void QWindowsWindow::setCursor(const QWindowsWindowCursor &c) diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index ed7c22b1e6..7e1b66829a 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -261,7 +261,7 @@ static const char * const cursorNames[] = { }; QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen) - : QXcbObject(conn), QPlatformCursor(screen), m_screen(screen) + : QXcbObject(conn), m_screen(screen) { if (cursorCount++) return; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 15ffc5b8ff..8b66ef4603 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -237,6 +237,11 @@ QSizeF QXcbScreen::physicalSize() const return QSizeF(m_screen->width_in_millimeters, m_screen->height_in_millimeters); } +QPlatformCursor *QXcbScreen::cursor() const +{ + return m_cursor; +} + int QXcbScreen::screenNumber() const { return m_number; diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 870d4d5662..ac4ecb1c8d 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -68,6 +68,7 @@ public: int depth() const; QImage::Format format() const; QSizeF physicalSize() const; + QPlatformCursor *cursor() const; int screenNumber() const; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 739426a92a..542d7ab69f 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -548,6 +548,8 @@ void QXcbWindow::show() updateNetWmStateBeforeMap(); } + updateNetWmUserTime(connection()->time()); + Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); xcb_flush(xcb_connection()); diff --git a/src/plugins/platforms/xlib/qxlibcursor.cpp b/src/plugins/platforms/xlib/qxlibcursor.cpp index 8ab40e31ef..a714f82371 100644 --- a/src/plugins/platforms/xlib/qxlibcursor.cpp +++ b/src/plugins/platforms/xlib/qxlibcursor.cpp @@ -52,8 +52,7 @@ QT_BEGIN_NAMESPACE -QXlibCursor::QXlibCursor(QXlibScreen *screen) - : QPlatformCursor(screen) +QXlibCursor::QXlibCursor(QXlibScreen *screen) : m_screen(screen) { } @@ -191,9 +190,4 @@ Cursor QXlibCursor::createCursorShape(int cshape) return cursor; } -QXlibScreen * QXlibCursor::testLiteScreen() const -{ - return static_cast<QXlibScreen *>(screen); -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qxlibcursor.h b/src/plugins/platforms/xlib/qxlibcursor.h index 92e42ac7a1..0056aa9554 100644 --- a/src/plugins/platforms/xlib/qxlibcursor.h +++ b/src/plugins/platforms/xlib/qxlibcursor.h @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -class QXlibCursor : QPlatformCursor +class QXlibCursor : public QPlatformCursor { public: QXlibCursor(QXlibScreen *screen); @@ -59,8 +59,9 @@ private: Cursor createCursorBitmap(QCursor * cursor); Cursor createCursorShape(int cshape); - QXlibScreen *testLiteScreen() const; + QXlibScreen *testLiteScreen() const { return m_screen; } QMap<int, Cursor> cursorMap; + QXlibScreen *m_screen; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qxlibscreen.cpp b/src/plugins/platforms/xlib/qxlibscreen.cpp index fc903708b3..62c80b6ad4 100644 --- a/src/plugins/platforms/xlib/qxlibscreen.cpp +++ b/src/plugins/platforms/xlib/qxlibscreen.cpp @@ -241,6 +241,11 @@ QXlibScreen::~QXlibScreen() delete mDisplay; } +QPlatformCursor *QXlibScreen::cursor() const +{ + return mCursor; +} + Window QXlibScreen::rootWindow() { return RootWindow(mDisplay->nativeDisplay(), mScreen); diff --git a/src/plugins/platforms/xlib/qxlibscreen.h b/src/plugins/platforms/xlib/qxlibscreen.h index c6672c3540..5bb6cc7735 100644 --- a/src/plugins/platforms/xlib/qxlibscreen.h +++ b/src/plugins/platforms/xlib/qxlibscreen.h @@ -63,6 +63,7 @@ public: int depth() const { return mDepth; } QImage::Format format() const { return mFormat; } QSizeF physicalSize() const { return mPhysicalSize; } + QPlatformCursor *cursor() const; Window rootWindow(); unsigned long blackPixel(); |