diff options
Diffstat (limited to 'src/plugins/platforms/windows')
27 files changed, 1278 insertions, 328 deletions
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 7a28fd9074..a0f2c1812f 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -1207,10 +1207,14 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row, { QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible) + if (!accessible || !tableCellInterface()) return E_FAIL; - tableCellInterface()->rowColumnExtents((int*)row, (int*)column, (int*)rowExtents, (int*)columnExtents, (bool*)isSelected); + *row = (long)tableCellInterface()->rowIndex(); + *column = (long)tableCellInterface()->columnIndex(); + *rowExtents = (long)tableCellInterface()->rowExtent(); + *columnExtents = (long)tableCellInterface()->columnExtent(); + *isSelected = tableCellInterface()->isSelected(); return S_OK; } diff --git a/src/plugins/platforms/windows/array.h b/src/plugins/platforms/windows/array.h index 74759231f4..9b7e3a0acb 100644 --- a/src/plugins/platforms/windows/array.h +++ b/src/plugins/platforms/windows/array.h @@ -42,7 +42,8 @@ #ifndef ARRAY_H #define ARRAY_H -#include <QtCore/QtAlgorithms> +#include <QtCore/QtGlobal> +#include <algorithm> QT_BEGIN_NAMESPACE @@ -86,7 +87,7 @@ public: const T *oldData = data; data = new T[capacity]; if (oldData) { - qCopy(oldData, oldData + m_size, data); + std::copy(oldData, oldData + m_size, data); delete [] oldData; } m_capacity = capacity; diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index e5c3269a6c..ffd87af193 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -105,12 +105,12 @@ QT_BEGIN_NAMESPACE class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "windows.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "windows.json") public: - QPlatformIntegration *create(const QString&, const QStringList&); + QPlatformIntegration *create(const QString&, const QStringList&, int &, char **); }; -QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList) +QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList, int &, char **) { if (system.compare(system, QStringLiteral("windows"), Qt::CaseInsensitive) == 0) return new QWindowsIntegration(paramList); diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index 49ddf3106b..4c08a664d8 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -49,6 +49,10 @@ # define WM_THEMECHANGED 0x031A #endif +#ifndef WM_DWMCOMPOSITIONCHANGED +# define WM_DWMCOMPOSITIONCHANGED 0x31E +#endif + #ifndef GWL_HWNDPARENT # define GWL_HWNDPARENT (-8) #endif diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 238817e85c..e9eb50799e 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -83,6 +83,7 @@ enum WindowsEventType // Simplify event types CalculateSize = WindowEventFlag + 16, FocusInEvent = WindowEventFlag + 17, FocusOutEvent = WindowEventFlag + 18, + WhatsThisEvent = WindowEventFlag + 19, MouseEvent = MouseEventFlag + 1, MouseWheelEvent = MouseEventFlag + 2, CursorEvent = MouseEventFlag + 3, @@ -104,6 +105,7 @@ enum WindowsEventType // Simplify event types InputMethodCloseCandidateWindowEvent = InputMethodEventFlag + 5, InputMethodRequest = InputMethodEventFlag + 6, ThemeChanged = ThemingEventFlag + 1, + CompositionSettingsChanged = ThemingEventFlag + 2, DisplayChangedEvent = 437, SettingChangedEvent = DisplayChangedEvent + 1, ContextMenu = 123, @@ -200,10 +202,18 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return QtWindows::DisplayChangedEvent; case WM_THEMECHANGED: return QtWindows::ThemeChanged; + case WM_DWMCOMPOSITIONCHANGED: + return QtWindows::CompositionSettingsChanged; #ifndef QT_NO_CONTEXTMENU case WM_CONTEXTMENU: return QtWindows::ContextMenu; #endif + case WM_SYSCOMMAND: +#ifndef Q_OS_WINCE + if ((wParamIn & 0xfff0) == SC_CONTEXTHELP) + return QtWindows::WhatsThisEvent; +#endif + break; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 5114e9d524..8dab1e2b1c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -47,6 +47,7 @@ #include "qtwindowsglobal.h" #include "qwindowsmime.h" #include "qwindowsinputcontext.h" +#include "qwindowstabletsupport.h" #ifndef QT_NO_ACCESSIBILITY #include "accessible/qwindowsaccessibility.h" #endif @@ -83,6 +84,7 @@ int QWindowsContext::verboseOLE = 0; int QWindowsContext::verboseInputMethods = 0; int QWindowsContext::verboseDialogs = 0; int QWindowsContext::verboseTheming = 0; +int QWindowsContext::verboseTablet = 0; // Get verbosity of components from "foo:2,bar:3" static inline int componentVerbose(const char *v, const char *keyWord) @@ -216,6 +218,7 @@ bool QWindowsUser32DLL::initTouch() QWindowsShell32DLL::QWindowsShell32DLL() : sHCreateItemFromParsingName(0) , sHGetStockIconInfo(0) + , sHGetImageList(0) { } @@ -224,6 +227,7 @@ void QWindowsShell32DLL::init() QSystemLibrary library(QStringLiteral("shell32")); sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName")); sHGetStockIconInfo = (SHGetStockIconInfo)library.resolve("SHGetStockIconInfo"); + sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList"); } QWindowsUser32DLL QWindowsContext::user32dll; @@ -259,17 +263,20 @@ struct QWindowsContextPrivate { QWindowsMimeConverter m_mimeConverter; QWindowsScreenManager m_screenManager; QSharedPointer<QWindowCreationContext> m_creationContext; +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + QScopedPointer<QWindowsTabletSupport> m_tabletSupport; +#endif const HRESULT m_oleInitializeResult; const QByteArray m_eventType; QWindow *m_lastActiveWindow; bool m_asyncExpose; }; -QWindowsContextPrivate::QWindowsContextPrivate() : - m_systemInfo(0), - m_oleInitializeResult(OleInitialize(NULL)), - m_eventType(QByteArrayLiteral("windows_generic_MSG")), - m_lastActiveWindow(0), m_asyncExpose(0) +QWindowsContextPrivate::QWindowsContextPrivate() + : m_systemInfo(0) + , m_oleInitializeResult(OleInitialize(NULL)) + , m_eventType(QByteArrayLiteral("windows_generic_MSG")) + , m_lastActiveWindow(0), m_asyncExpose(0) { const QSysInfo::WinVersion ver = QSysInfo::windowsVersion(); #ifndef Q_OS_WINCE @@ -310,7 +317,13 @@ QWindowsContext::QWindowsContext() : QWindowsContext::verboseInputMethods = componentVerbose(v, "im"); QWindowsContext::verboseDialogs = componentVerbose(v, "dialogs"); QWindowsContext::verboseTheming = componentVerbose(v, "theming"); + QWindowsContext::verboseTablet = componentVerbose(v, "tablet"); } +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + d->m_tabletSupport.reset(QWindowsTabletSupport::create()); + if (QWindowsContext::verboseTablet) + qDebug() << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description()); +#endif } QWindowsContext::~QWindowsContext() @@ -631,6 +644,15 @@ QWindowsScreenManager &QWindowsContext::screenManager() return d->m_screenManager; } +QWindowsTabletSupport *QWindowsContext::tabletSupport() const +{ +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + return d->m_tabletSupport.data(); +#else + return 0; +#endif +} + /*! \brief Convenience to create a non-visible, message-only dummy window for example used as clipboard watcher or for GL. @@ -864,8 +886,15 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, theme->windowsThemeChanged(platformWindow->window()); return true; } + case QtWindows::CompositionSettingsChanged: + platformWindow->handleCompositionSettingsChanged(); + return true; #ifndef Q_OS_WINCE case QtWindows::ActivateWindowEvent: +#ifndef QT_NO_TABLETEVENT + if (!d->m_tabletSupport.isNull()) + d->m_tabletSupport->notifyActivate(); +#endif // !QT_NO_TABLETEVENT if (platformWindow->testFlag(QWindowsWindow::BlockedByModal)) if (const QWindow *modalWindow = QGuiApplication::modalWindow()) QWindowsWindow::baseWindowOf(modalWindow)->alertWindow(); @@ -875,6 +904,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::ContextMenu: return handleContextMenuEvent(platformWindow->window(), msg); #endif + case QtWindows::WhatsThisEvent: { +#ifndef QT_NO_WHATSTHIS + QWindowSystemInterface::handleEnterWhatsThisEvent(); + return true; +#endif + } break; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 6b80075379..173df58570 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE class QWindow; class QPlatformScreen; class QWindowsScreenManager; +class QWindowsTabletSupport; class QWindowsWindow; class QWindowsMimeConverter; struct QWindowCreationContext; @@ -107,9 +108,11 @@ struct QWindowsShell32DLL typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); + typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); SHCreateItemFromParsingName sHCreateItemFromParsingName; SHGetStockIconInfo sHGetStockIconInfo; + SHGetImageList sHGetImageList; }; #endif // Q_OS_WINCE @@ -135,6 +138,7 @@ public: static int verboseInputMethods; static int verboseDialogs; static int verboseTheming; + static int verboseTablet; explicit QWindowsContext(); ~QWindowsContext(); @@ -185,6 +189,7 @@ public: QWindowsMimeConverter &mimeConverter() const; QWindowsScreenManager &screenManager(); + QWindowsTabletSupport *tabletSupport() const; #ifndef Q_OS_WINCE static QWindowsUser32DLL user32dll; static QWindowsShell32DLL shell32dll; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 9a7d03c0c2..4add6cd634 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#define QT_NO_URL_CAST_FROM_STRING 1 + #include "qwindowsdialoghelpers.h" #include "qwindowscontext.h" @@ -64,6 +66,8 @@ #include <QtCore/QMutexLocker> #include <QtCore/private/qsystemlibrary_p.h> +#include <algorithm> + #include "qtwindows_additional.h" #define STRICT_TYPED_ITEMIDS @@ -385,6 +389,16 @@ static inline QString guidToString(const GUID &g) inline QDebug operator<<(QDebug d, const GUID &g) { d.nospace() << guidToString(g); return d; } +// Return an allocated wchar_t array from a QString, reserve more memory if desired. +static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0) +{ + const size_t stringSize = s.size(); + wchar_t *result = new wchar_t[qMax(stringSize + 1, reserveSize)]; + s.toWCharArray(result); + result[stringSize] = 0; + return result; +} + namespace QWindowsDialogs { /*! @@ -448,7 +462,8 @@ class QWindowsNativeDialogBase : public QObject Q_OBJECT public: virtual void setWindowTitle(const QString &title) = 0; - virtual void exec(HWND owner = 0) = 0; + bool executed() const { return m_executed; } + void exec(HWND owner = 0) { doExec(owner); m_executed = true; } signals: void accepted(); @@ -458,7 +473,12 @@ public slots: virtual void close() = 0; protected: - QWindowsNativeDialogBase() {} + QWindowsNativeDialogBase() : m_executed(false) {} + +private: + virtual void doExec(HWND owner = 0) = 0; + + bool m_executed; }; /*! @@ -488,18 +508,11 @@ QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() : template <class BaseClass> QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() const { - if (!m_nativeDialog) { + if (m_nativeDialog.isNull()) { qWarning("%s invoked with no native dialog present.", __FUNCTION__); return 0; } - return m_nativeDialog; -} - -template <class BaseClass> -void QWindowsDialogHelperBase<BaseClass>::deleteNativeDialog() -{ - delete m_nativeDialog; - m_nativeDialog = 0; + return m_nativeDialog.data(); } template <class BaseClass> @@ -511,10 +524,11 @@ void QWindowsDialogHelperBase<BaseClass>::timerEvent(QTimerEvent *) template <class BaseClass> QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialog() { - // Create dialog and apply common settings. - if (!m_nativeDialog) - m_nativeDialog = createNativeDialog(); - return m_nativeDialog; + // Create dialog and apply common settings. Check "executed" flag as well + // since for example IFileDialog::Show() works only once. + if (m_nativeDialog.isNull() || m_nativeDialog->executed()) + m_nativeDialog = QWindowsNativeDialogBasePtr(createNativeDialog()); + return m_nativeDialog.data(); } /*! @@ -529,18 +543,22 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo class QWindowsDialogThread : public QThread { public: - QWindowsDialogThread(QPlatformDialogHelper *h) : m_helper(h) {} + typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; + + explicit QWindowsDialogThread(const QWindowsNativeDialogBasePtr &d, HWND owner) + : m_dialog(d), m_owner(owner) {} void run(); private: - QPlatformDialogHelper *m_helper; + const QWindowsNativeDialogBasePtr m_dialog; + const HWND m_owner; }; void QWindowsDialogThread::run() { if (QWindowsContext::verboseDialogs) qDebug(">%s" , __FUNCTION__); - m_helper->exec(); + m_dialog->exec(m_owner); deleteLater(); if (QWindowsContext::verboseDialogs) qDebug("<%s" , __FUNCTION__); @@ -559,7 +577,7 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags, } if (QWindowsContext::verboseDialogs) qDebug("%s modal=%d native=%p parent=%p" , - __FUNCTION__, modal, m_nativeDialog, m_ownerWindow); + __FUNCTION__, modal, m_nativeDialog.data(), m_ownerWindow); if (!modal && !supportsNonModalDialog(parent)) return false; // Was it changed in-between? if (!ensureNativeDialog()) @@ -579,7 +597,8 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags, template <class BaseClass> void QWindowsDialogHelperBase<BaseClass>::startDialogThread() { - QWindowsDialogThread *thread = new QWindowsDialogThread(this); + Q_ASSERT(!m_nativeDialog.isNull()); + QWindowsDialogThread *thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow); thread->start(); stopTimer(); } @@ -593,6 +612,44 @@ void QWindowsDialogHelperBase<BaseClass>::stopTimer() } } +#ifndef Q_OS_WINCE +// Find a file dialog window created by IFileDialog by process id, window +// title and class, which starts with a hash '#'. + +struct FindDialogContext +{ + explicit FindDialogContext(const QString &titleIn) + : title(qStringToWCharArray(titleIn)), processId(GetCurrentProcessId()), hwnd(0) {} + + const QScopedArrayPointer<wchar_t> title; + const DWORD processId; + HWND hwnd; // contains the HWND of the window found. +}; + +static BOOL CALLBACK findDialogEnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + FindDialogContext *context = reinterpret_cast<FindDialogContext *>(lParam); + DWORD winPid = 0; + GetWindowThreadProcessId(hwnd, &winPid); + if (winPid != context->processId) + return TRUE; + wchar_t buf[256]; + if (!RealGetWindowClass(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || buf[0] != L'#') + return TRUE; + if (!GetWindowTextW(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || wcscmp(buf, context->title.data())) + return TRUE; + context->hwnd = hwnd; + return FALSE; +} + +static inline HWND findDialogWindow(const QString &title) +{ + FindDialogContext context(title); + EnumWindows(findDialogEnumWindowsProc, reinterpret_cast<LPARAM>(&context)); + return context.hwnd; +} +#endif // !Q_OS_WINCE + template <class BaseClass> void QWindowsDialogHelperBase<BaseClass>::hide() { @@ -609,26 +666,8 @@ void QWindowsDialogHelperBase<BaseClass>::exec() stopTimer(); if (QWindowsNativeDialogBase *nd = nativeDialog()) { nd->exec(m_ownerWindow); - deleteNativeDialog(); - } -} - -static inline bool snapToDefaultButtonHint() -{ - BOOL snapToDefault = false; - if (SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &snapToDefault, 0)) - return snapToDefault; - return false; -} - -template <class BaseClass> -QVariant QWindowsDialogHelperBase<BaseClass>::styleHint(QPlatformDialogHelper::StyleHint hint) const -{ - switch (hint) { - case QPlatformDialogHelper::SnapToDefaultButton: - return QVariant(snapToDefaultButtonHint()); + m_nativeDialog.clear(); } - return BaseClass::styleHint(hint); } /*! @@ -651,34 +690,34 @@ public: QWindowsFileDialogSharedData() : m_data(new Data) {} void fromOptions(const QSharedPointer<QFileDialogOptions> &o); - QString directory() const; - void setDirectory(const QString &); + QUrl directory() const; + void setDirectory(const QUrl &); QString selectedNameFilter() const; void setSelectedNameFilter(const QString &); - QStringList selectedFiles() const; - void setSelectedFiles(const QStringList &); + QList<QUrl> selectedFiles() const; + void setSelectedFiles(const QList<QUrl> &); QString selectedFile() const; private: class Data : public QSharedData { public: - QString directory; + QUrl directory; QString selectedNameFilter; - QStringList selectedFiles; + QList<QUrl> selectedFiles; QMutex mutex; }; QExplicitlySharedDataPointer<Data> m_data; }; -inline QString QWindowsFileDialogSharedData::directory() const +inline QUrl QWindowsFileDialogSharedData::directory() const { m_data->mutex.lock(); - const QString result = m_data->directory; + const QUrl result = m_data->directory; m_data->mutex.unlock(); return result; } -inline void QWindowsFileDialogSharedData::setDirectory(const QString &d) +inline void QWindowsFileDialogSharedData::setDirectory(const QUrl &d) { QMutexLocker (&m_data->mutex); m_data->directory = d; @@ -698,24 +737,24 @@ inline void QWindowsFileDialogSharedData::setSelectedNameFilter(const QString &f m_data->selectedNameFilter = f; } -inline QStringList QWindowsFileDialogSharedData::selectedFiles() const +inline QList<QUrl> QWindowsFileDialogSharedData::selectedFiles() const { m_data->mutex.lock(); - const QStringList result = m_data->selectedFiles; + const QList<QUrl> result = m_data->selectedFiles; m_data->mutex.unlock(); return result; } inline QString QWindowsFileDialogSharedData::selectedFile() const { - const QStringList files = selectedFiles(); - return files.isEmpty() ? QString() : files.front(); + const QList<QUrl> files = selectedFiles(); + return files.isEmpty() ? QString() : files.front().toLocalFile(); } -inline void QWindowsFileDialogSharedData::setSelectedFiles(const QStringList &f) +inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList<QUrl> &urls) { QMutexLocker (&m_data->mutex); - m_data->selectedFiles = f; + m_data->selectedFiles = urls; } inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFileDialogOptions> &o) @@ -779,7 +818,7 @@ public: QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog) : m_ref(1), m_nativeFileDialog(nativeFileDialog) {} - ~QWindowsNativeFileDialogEventHandler() {} + virtual ~QWindowsNativeFileDialogEventHandler() {} private: long m_ref; @@ -822,9 +861,9 @@ public: virtual void setWindowTitle(const QString &title); inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::FileDialogOptions options); inline void setDirectory(const QString &directory); - inline void updateDirectory() { setDirectory(m_data.directory()); } + inline void updateDirectory() { setDirectory(m_data.directory().toLocalFile()); } inline QString directory() const; - virtual void exec(HWND owner = 0); + virtual void doExec(HWND owner = 0); virtual void setNameFilters(const QStringList &f); inline void selectNameFilter(const QString &filter); inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); } @@ -837,10 +876,10 @@ public: inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text); // Return the selected files for tracking in OnSelectionChanged(). - virtual QStringList selectedFiles() const = 0; + virtual QList<QUrl> selectedFiles() const = 0; // Return the result for tracking in OnFileOk(). Differs from selection for // example by appended default suffixes, etc. - virtual QStringList dialogResult() const = 0; + virtual QList<QUrl> dialogResult() const = 0; inline void onFolderChange(IShellItem *); inline void onSelectionChange(); @@ -848,12 +887,12 @@ public: inline bool onFileOk(); signals: - void directoryEntered(const QString& directory); - void currentChanged(const QString& file); + void directoryEntered(const QUrl &directory); + void currentChanged(const QUrl &file); void filterSelected(const QString & filter); public slots: - virtual void close() { m_fileDialog->Close(S_OK); } + virtual void close(); protected: explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); @@ -861,9 +900,9 @@ protected: void setDefaultSuffixSys(const QString &s); inline IFileDialog * fileDialog() const { return m_fileDialog; } static QString itemPath(IShellItem *item); - static QStringList libraryItemFolders(IShellItem *item); + static QList<QUrl> libraryItemFolders(IShellItem *item); static QString libraryItemDefaultSaveFolder(IShellItem *item); - static int itemPaths(IShellItemArray *items, QStringList *fileResult = 0); + static int itemPaths(IShellItemArray *items, QList<QUrl> *fileResult = 0); static IShellItem *shellItem(const QString &path); const QWindowsFileDialogSharedData &data() const { return m_data; } @@ -877,6 +916,7 @@ private: bool m_hideFiltersDetails; bool m_hasDefaultSuffix; QWindowsFileDialogSharedData m_data; + QString m_title; }; QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) : @@ -920,6 +960,7 @@ bool QWindowsNativeFileDialogBase::init(const CLSID &clsId, const IID &iid) void QWindowsNativeFileDialogBase::setWindowTitle(const QString &title) { + m_title = title; m_fileDialog->SetTitle(reinterpret_cast<const wchar_t *>(title.utf16())); } @@ -961,10 +1002,12 @@ QString QWindowsNativeFileDialogBase::directory() const return QString(); } -void QWindowsNativeFileDialogBase::exec(HWND owner) +void QWindowsNativeFileDialogBase::doExec(HWND owner) { if (QWindowsContext::verboseDialogs) qDebug(">%s on %p", __FUNCTION__, (void *)owner); + // Show() blocks until the user closes the dialog, the dialog window + // gets a WM_CLOSE or the parent window is destroyed. const HRESULT hr = m_fileDialog->Show(owner); QWindowsDialogs::eatMouseMove(); if (QWindowsContext::verboseDialogs) @@ -1031,9 +1074,9 @@ static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) } // Return all folders of a library-type item. -QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) +QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) { - QStringList result; + QList<QUrl> result; if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { IShellItemArray *itemArray = 0; if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) { @@ -1062,9 +1105,9 @@ QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *i #else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__ -QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) +QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) { - return QStringList(); + return QList<QUrl>(); } QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *) @@ -1096,7 +1139,7 @@ QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item) } int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, - QStringList *result /* = 0 */) + QList<QUrl> *result /* = 0 */) { DWORD itemCount = 0; if (result) @@ -1108,7 +1151,7 @@ int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, for (DWORD i = 0; i < itemCount; ++i) { IShellItem *item = 0; if (SUCCEEDED(items->GetItemAt(i, &item))) - result->push_back(QWindowsNativeFileDialogBase::itemPath(item)); + result->push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); } } return itemCount; @@ -1270,7 +1313,7 @@ QString QWindowsNativeFileDialogBase::selectedNameFilter() const void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) { if (item) { - const QString directory = QWindowsNativeFileDialogBase::itemPath(item); + const QUrl directory = QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item)); m_data.setDirectory(directory); emit directoryEntered(directory); } @@ -1278,7 +1321,7 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) void QWindowsNativeFileDialogBase::onSelectionChange() { - const QStringList current = selectedFiles(); + const QList<QUrl> current = selectedFiles(); m_data.setSelectedFiles(current); if (current.size() == 1) emit currentChanged(current.front()); @@ -1298,6 +1341,20 @@ bool QWindowsNativeFileDialogBase::onFileOk() return true; } +void QWindowsNativeFileDialogBase::close() +{ + m_fileDialog->Close(S_OK); +#ifndef Q_OS_WINCE + // IFileDialog::Close() does not work unless invoked from a callback. + // Try to find the window and send it a WM_CLOSE in addition. + const HWND hwnd = findDialogWindow(m_title); + if (QWindowsContext::verboseDialogs) + qDebug() << __FUNCTION__ << "closing" << hwnd; + if (hwnd && IsWindowVisible(hwnd)) + PostMessageW(hwnd, WM_CLOSE, 0, 0); +#endif // !Q_OS_WINCE +} + HRESULT QWindowsNativeFileDialogEventHandler::OnFolderChanging(IFileDialog *, IShellItem *item) { m_nativeFileDialog->onFolderChange(item); @@ -1338,8 +1395,8 @@ public: explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} virtual void setNameFilters(const QStringList &f); - virtual QStringList selectedFiles() const; - virtual QStringList dialogResult() const; + virtual QList<QUrl> selectedFiles() const; + virtual QList<QUrl> dialogResult() const; }; // Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". @@ -1374,22 +1431,22 @@ void QWindowsNativeSaveFileDialog::setNameFilters(const QStringList &f) } // m_hasDefaultSuffix } -QStringList QWindowsNativeSaveFileDialog::dialogResult() const +QList<QUrl> QWindowsNativeSaveFileDialog::dialogResult() const { - QStringList result; + QList<QUrl> result; IShellItem *item = 0; if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) - result.push_back(QWindowsNativeFileDialogBase::itemPath(item)); + result.push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); return result; } -QStringList QWindowsNativeSaveFileDialog::selectedFiles() const +QList<QUrl> QWindowsNativeSaveFileDialog::selectedFiles() const { - QStringList result; + QList<QUrl> result; IShellItem *item = 0; const HRESULT hr = fileDialog()->GetCurrentSelection(&item); if (SUCCEEDED(hr) && item) - result.push_back(QWindowsNativeSaveFileDialog::itemPath(item)); + result.push_back(QUrl::fromLocalFile(QWindowsNativeSaveFileDialog::itemPath(item))); return result; } @@ -1408,26 +1465,26 @@ class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase public: explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} - virtual QStringList selectedFiles() const; - virtual QStringList dialogResult() const; + virtual QList<QUrl> selectedFiles() const; + virtual QList<QUrl> dialogResult() const; private: inline IFileOpenDialog *openFileDialog() const { return static_cast<IFileOpenDialog *>(fileDialog()); } }; -QStringList QWindowsNativeOpenFileDialog::dialogResult() const +QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const { - QStringList result; + QList<QUrl> result; IShellItemArray *items = 0; if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) QWindowsNativeFileDialogBase::itemPaths(items, &result); return result; } -QStringList QWindowsNativeOpenFileDialog::selectedFiles() const +QList<QUrl> QWindowsNativeOpenFileDialog::selectedFiles() const { - QStringList result; + QList<QUrl> result; IShellItemArray *items = 0; const HRESULT hr = openFileDialog()->GetSelectedItems(&items); if (SUCCEEDED(hr) && items) @@ -1484,14 +1541,13 @@ public: virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } - virtual void setDirectory(const QString &directory); - virtual QString directory() const; - virtual void selectFile(const QString &filename); - virtual QStringList selectedFiles() const; - virtual void setFilter(); - virtual void setNameFilters(const QStringList &filters); - virtual void selectNameFilter(const QString &filter); - virtual QString selectedNameFilter() const; + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE; + virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; private: virtual QWindowsNativeDialogBase *createNativeDialog(); @@ -1509,10 +1565,10 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() return 0; QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept())); QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject())); - QObject::connect(result, SIGNAL(directoryEntered(QString)), - this, SIGNAL(directoryEntered(QString))); - QObject::connect(result, SIGNAL(currentChanged(QString)), - this, SIGNAL(currentChanged(QString))); + QObject::connect(result, SIGNAL(directoryEntered(QUrl)), + this, SIGNAL(directoryEntered(QUrl))); + QObject::connect(result, SIGNAL(currentChanged(QUrl)), + this, SIGNAL(currentChanged(QUrl))); QObject::connect(result, SIGNAL(filterSelected(QString)), this, SIGNAL(filterSelected(QString))); @@ -1532,11 +1588,16 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept)); result->updateDirectory(); result->updateSelectedNameFilter(); - const QStringList initialSelection = opts->initiallySelectedFiles(); + const QList<QUrl> initialSelection = opts->initiallySelectedFiles(); if (initialSelection.size() > 0) { - QFileInfo info(initialSelection.front()); - if (!info.isDir()) - result->selectFile(info.fileName()); + const QUrl url = initialSelection.front(); + if (url.isLocalFile()) { + QFileInfo info(url.toLocalFile()); + if (!info.isDir()) + result->selectFile(info.fileName()); + } else { + result->selectFile(url.path()); // TODO url.fileName() once it exists + } } // No need to select initialNameFilter if mode is Dir if (mode != QFileDialogOptions::Directory && mode != QFileDialogOptions::DirectoryOnly) { @@ -1550,31 +1611,31 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() return result; } -void QWindowsFileDialogHelper::setDirectory(const QString &directory) +void QWindowsFileDialogHelper::setDirectory(const QUrl &directory) { if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(directory)); + qDebug("%s %s" , __FUNCTION__, qPrintable(directory.toString())); m_data.setDirectory(directory); if (hasNativeDialog()) nativeFileDialog()->updateDirectory(); } -QString QWindowsFileDialogHelper::directory() const +QUrl QWindowsFileDialogHelper::directory() const { return m_data.directory(); } -void QWindowsFileDialogHelper::selectFile(const QString &fileName) +void QWindowsFileDialogHelper::selectFile(const QUrl &fileName) { if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(fileName)); + qDebug("%s %s" , __FUNCTION__, qPrintable(fileName.toString())); if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->selectFile(fileName); + nfd->selectFile(fileName.toLocalFile()); // ## should use QUrl::fileName() once it exists } -QStringList QWindowsFileDialogHelper::selectedFiles() const +QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const { return m_data.selectedFiles(); } @@ -1585,14 +1646,6 @@ void QWindowsFileDialogHelper::setFilter() qDebug("%s" , __FUNCTION__); } -void QWindowsFileDialogHelper::setNameFilters(const QStringList &filters) -{ - if (QWindowsContext::verboseDialogs) - qDebug("%s" , __FUNCTION__); - if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->setNameFilters(filters); -} - void QWindowsFileDialogHelper::selectNameFilter(const QString &filter) { m_data.setSelectedNameFilter(filter); @@ -1629,7 +1682,7 @@ public: static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); virtual void setWindowTitle(const QString &t) { m_title = t; } - virtual void exec(HWND owner = 0); + virtual void doExec(HWND owner = 0); virtual QPlatformDialogHelper::DialogCode result() const { return m_result; } int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam); @@ -1643,8 +1696,8 @@ private: explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const; - QStringList execExistingDir(HWND owner); - QStringList execFileNames(HWND owner, int *selectedFilterIndex) const; + QList<QUrl> execExistingDir(HWND owner); + QList<QUrl> execFileNames(HWND owner, int *selectedFilterIndex) const; const OptionsPtr m_options; QString m_title; @@ -1680,10 +1733,10 @@ QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options setWindowTitle(m_options->windowTitle()); } -void QWindowsXpNativeFileDialog::exec(HWND owner) +void QWindowsXpNativeFileDialog::doExec(HWND owner) { int selectedFilterIndex = -1; - const QStringList selectedFiles = + const QList<QUrl> selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ? execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex); m_data.setSelectedFiles(selectedFiles); @@ -1695,7 +1748,8 @@ void QWindowsXpNativeFileDialog::exec(HWND owner) const QStringList nameFilters = m_options->nameFilters(); if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size()) m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex)); - m_data.setDirectory(QFileInfo(selectedFiles.front()).absolutePath()); + QUrl firstFile = selectedFiles.front(); + m_data.setDirectory(firstFile.adjusted(QUrl::RemoveFilename)); m_result = QPlatformDialogHelper::Accepted; emit accepted(); } @@ -1722,7 +1776,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM case BFFM_INITIALIZED: { if (!m_title.isEmpty()) SetWindowText(hwnd, (wchar_t *)m_title.utf16()); - const QString initialFile = QDir::toNativeSeparators(m_data.directory()); + const QString initialFile = QDir::toNativeSeparators(m_data.directory().toLocalFile()); if (!initialFile.isEmpty()) SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16())); } @@ -1738,7 +1792,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM return 0; } -QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) +QList<QUrl> QWindowsXpNativeFileDialog::execExistingDir(HWND owner) { BROWSEINFO bi; wchar_t initPath[MAX_PATH]; @@ -1750,12 +1804,12 @@ QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE; bi.lpfn = xpFileDialogGetExistingDirCallbackProc; bi.lParam = LPARAM(this); - QStringList selectedFiles; + QList<QUrl> selectedFiles; if (qt_LpItemIdList pItemIDList = SHBrowseForFolder(&bi)) { wchar_t path[MAX_PATH]; path[0] = 0; if (SHGetPathFromIDList(pItemIDList, path) && path[0]) - selectedFiles.push_back(QDir::cleanPath(QString::fromWCharArray(path))); + selectedFiles.push_back(QUrl::fromLocalFile(QDir::cleanPath(QString::fromWCharArray(path)))); IMalloc *pMalloc; if (SHGetMalloc(&pMalloc) == NOERROR) { pMalloc->Free(pItemIDList); @@ -1765,16 +1819,6 @@ QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) return selectedFiles; } -// Return an allocated wchar_t array from a QString, reserve more memory if desired. -static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0) -{ - const size_t stringSize = s.size(); - wchar_t *result = new wchar_t[qMax(stringSize + 1, reserveSize)]; - s.toWCharArray(result); - result[stringSize] = 0; - return result; -} - // Open/Save files void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND owner) const { @@ -1807,7 +1851,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')). remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|')); ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile); - ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory())); + ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory().toLocalFile())); ofn->lpstrTitle = (wchar_t*)m_title.utf16(); // Determine lpstrDefExt. Note that the current MSDN docs document this // member wrong. It should rather be documented as "the default extension @@ -1832,25 +1876,27 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow ofn->Flags |= OFN_OVERWRITEPROMPT; } -QStringList QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const +QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const { *selectedFilterIndex = -1; OPENFILENAME ofn; populateOpenFileName(&ofn, owner); - QStringList result; + QList<QUrl> result; const bool isSave = m_options->acceptMode() == QFileDialogOptions::AcceptSave; if (isSave ? m_getSaveFileNameW(&ofn) : m_getOpenFileNameW(&ofn)) { *selectedFilterIndex = ofn.nFilterIndex - 1; - result.push_back(QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile))); + const QString dir = QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile)); + result.push_back(QUrl::fromLocalFile(dir)); // For multiselection, the first item is the path followed // by "\0<file1>\0<file2>\0\0". if (ofn.Flags & (OFN_ALLOWMULTISELECT)) { - wchar_t *ptr = ofn.lpstrFile + result.front().size() + 1; + wchar_t *ptr = ofn.lpstrFile + dir.size() + 1; if (*ptr) { - const QString path = result.takeAt(0) + QLatin1Char('/'); + result.pop_front(); + const QString path = dir + QLatin1Char('/'); while (*ptr) { const QString fileName = QString::fromWCharArray(ptr); - result.push_back(path + fileName); + result.push_back(QUrl::fromLocalFile(path + fileName)); ptr += fileName.size() + 1; } // extract multiple files } // has multiple files @@ -1879,14 +1925,13 @@ public: virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } - virtual void setDirectory(const QString &directory); - virtual QString directory() const; - virtual void selectFile(const QString &filename); - virtual QStringList selectedFiles() const; - virtual void setFilter() {} - virtual void setNameFilters(const QStringList &); - virtual void selectNameFilter(const QString &); - virtual QString selectedNameFilter() const; + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &url) Q_DECL_OVERRIDE; + virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE {} + virtual void selectNameFilter(const QString &) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; private: virtual QWindowsNativeDialogBase *createNativeDialog(); @@ -1907,31 +1952,26 @@ QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog() return 0; } -void QWindowsXpFileDialogHelper::setDirectory(const QString &directory) +void QWindowsXpFileDialogHelper::setDirectory(const QUrl &directory) { m_data.setDirectory(directory); // Dialog cannot be updated at run-time. } -QString QWindowsXpFileDialogHelper::directory() const +QUrl QWindowsXpFileDialogHelper::directory() const { return m_data.directory(); } -void QWindowsXpFileDialogHelper::selectFile(const QString &filename) +void QWindowsXpFileDialogHelper::selectFile(const QUrl &url) { - m_data.setSelectedFiles(QStringList(filename)); // Dialog cannot be updated at run-time. + m_data.setSelectedFiles(QList<QUrl>() << url); // Dialog cannot be updated at run-time. } -QStringList QWindowsXpFileDialogHelper::selectedFiles() const +QList<QUrl> QWindowsXpFileDialogHelper::selectedFiles() const { return m_data.selectedFiles(); } -void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &) -{ - // Dialog cannot be updated at run-time. -} - void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f) { m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time. @@ -1969,13 +2009,14 @@ public: explicit QWindowsNativeColorDialog(const SharedPointerColor &color); virtual void setWindowTitle(const QString &) {} - virtual void exec(HWND owner = 0); virtual QPlatformDialogHelper::DialogCode result() const { return m_code; } public slots: virtual void close() {} private: + virtual void doExec(HWND owner = 0); + COLORREF m_customColors[CustomColorCount]; QPlatformDialogHelper::DialogCode m_code; SharedPointerColor m_color; @@ -1984,10 +2025,10 @@ private: QWindowsNativeColorDialog::QWindowsNativeColorDialog(const SharedPointerColor &color) : m_code(QPlatformDialogHelper::Rejected), m_color(color) { - qFill(m_customColors, m_customColors + 16, COLORREF(0)); + std::fill(m_customColors, m_customColors + 16, COLORREF(0)); } -void QWindowsNativeColorDialog::exec(HWND owner) +void QWindowsNativeColorDialog::doExec(HWND owner) { typedef BOOL (WINAPI *ChooseColorWType)(LPCHOOSECOLORW); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 7884f398f3..1501b02bd9 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -46,6 +46,7 @@ #include <qpa/qplatformdialoghelper.h> #include <qpa/qplatformtheme.h> #include <QtCore/QStringList> +#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE @@ -64,15 +65,15 @@ namespace QWindowsDialogs template <class BaseClass> class QWindowsDialogHelperBase : public BaseClass { + Q_DISABLE_COPY(QWindowsDialogHelperBase) public: - ~QWindowsDialogHelperBase() { deleteNativeDialog(); } + typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; virtual void exec(); virtual bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); virtual void hide(); - virtual QVariant styleHint(QPlatformDialogHelper::StyleHint) const; virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } @@ -80,7 +81,6 @@ protected: QWindowsDialogHelperBase(); QWindowsNativeDialogBase *nativeDialog() const; inline bool hasNativeDialog() const { return m_nativeDialog; } - void deleteNativeDialog(); void timerEvent(QTimerEvent *); private: @@ -89,7 +89,7 @@ private: inline void startDialogThread(); inline void stopTimer(); - QWindowsNativeDialogBase *m_nativeDialog; + QWindowsNativeDialogBasePtr m_nativeDialog; HWND m_ownerWindow; int m_timerId; }; diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index b7ccb5767e..c2c8c15a30 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -838,8 +838,6 @@ error: return i18n_name; } -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); - static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, @@ -932,7 +930,7 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0); if (!englishName.isEmpty()) - qt_registerAliasToFontFamily(familyName, englishName); + QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); return true; } @@ -1409,12 +1407,6 @@ HFONT QWindowsFontDatabase::systemFont() // Creation functions -static inline bool scriptRequiresOpenType(int script) -{ - return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala) - || script == QChar::Script_Khmer || script == QChar::Script_Nko); -} - static const char *other_tryFonts[] = { "Arial", "MS UI Gothic", @@ -1761,20 +1753,14 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ QFontEngine *fe = 0; if (!useDirectWrite) { QWindowsFontEngine *few = new QWindowsFontEngine(request.family, hfont, stockFont, lf, data); - few->setObjectName(QStringLiteral("QWindowsFontEngine_") + request.family); if (preferClearTypeAA) few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask; // Also check for OpenType tables when using complex scripts - // ### TODO: This only works for scripts that require OpenType. More generally - // for scripts that do not require OpenType we should just look at the list of - // supported writing systems in the font's OS/2 table. - if (scriptRequiresOpenType(script)) { - if (!few->supportsScript(QChar::Script(script))) { - qWarning(" OpenType support missing for script\n"); - delete few; - return 0; - } + if (!few->supportsScript(QChar::Script(script))) { + qWarning(" OpenType support missing for script %d", int(script)); + delete few; + return 0; } few->initFontInfo(request, fontHdc, dpi); @@ -1790,7 +1776,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ request.pixelSize, data); fedw->initFontInfo(request, dpi, directWriteFont); - fedw->setObjectName(QStringLiteral("QWindowsFontEngineDirectWrite_") + request.family); fe = fedw; } else { qErrnoWarning("%s: CreateFontFace failed", __FUNCTION__); @@ -1808,7 +1793,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ QStringList list = family_list; list.append(extraFonts); QFontEngine *mfe = new QWindowsMultiFontEngine(fe, list); - mfe->setObjectName(QStringLiteral("QWindowsMultiFontEngine_") + request.family); mfe->fontDef = fe->fontDef; fe = mfe; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 7f97d58be4..9be0ff9d55 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -54,6 +54,9 @@ #include <QtGui/QFontDatabase> #include <wchar.h> +#ifdef Q_OS_WINCE +#include <QtEndian> +#endif QT_BEGIN_NAMESPACE @@ -122,8 +125,6 @@ static FontFile * createFontFile(const QString &fileName, int index) extern bool localizedName(const QString &name); extern QString getEnglishName(const QString &familyName); -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); - static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, @@ -273,6 +274,12 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, continue; fontCache.insert(fontName, fontFile); settings.setValue(fontName, fontFile); + + if (localizedName(fontName)) { + QString englishFontName = getEnglishName(fontName); + fontCache.insert(englishFontName, fontFile); + settings.setValue(englishFontName, fontFile); + } } value = fontCache.value(faceName); @@ -285,7 +292,11 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, return false; if (!QDir::isAbsolutePath(value)) +#ifndef Q_OS_WINCE value.prepend(QFile::decodeName(qgetenv("windir") + "\\Fonts\\")); +#else + value.prepend(QFile::decodeName("/Windows/")); +#endif QPlatformFontDatabase::registerFont(faceName, QString(), foundryName, weight, style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); @@ -304,11 +315,29 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); if (!englishName.isEmpty()) - qt_registerAliasToFontFamily(faceName, englishName); + QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); return true; } +#ifdef Q_OS_WINCE +static QByteArray getFntTable(HFONT hfont, uint tag) +{ + HDC hdc = GetDC(0); + HGDIOBJ oldFont = SelectObject(hdc, hfont); + quint32 t = qFromBigEndian<quint32>(tag); + QByteArray buffer; + + DWORD length = GetFontData(hdc, t, 0, NULL, 0); + if (length != GDI_ERROR) { + buffer.resize(length); + GetFontData(hdc, t, 0, reinterpret_cast<uchar *>(buffer.data()), length); + } + SelectObject(hdc, oldFont); + return buffer; +} +#endif + static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, int type, LPARAM namesSetIn) { @@ -318,7 +347,33 @@ static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, + QString::fromWCharArray(f->elfFullName); const uchar charSet = f->elfLogFont.lfCharSet; +#ifndef Q_OS_WINCE const FONTSIGNATURE signature = textmetric->ntmFontSig; +#else + FONTSIGNATURE signature; + QByteArray table; + + if (type & TRUETYPE_FONTTYPE) { + HFONT hfont = CreateFontIndirect(&f->elfLogFont); + table = getFntTable(hfont, MAKE_TAG('O', 'S', '/', '2')); + DeleteObject((HGDIOBJ)hfont); + } + + if (table.length() >= 86) { + // See also qfontdatabase_mac.cpp, offsets taken from OS/2 table in the TrueType spec + uchar *tableData = reinterpret_cast<uchar *>(table.data()); + + signature.fsUsb[0] = qFromBigEndian<quint32>(tableData + 42); + signature.fsUsb[1] = qFromBigEndian<quint32>(tableData + 46); + signature.fsUsb[2] = qFromBigEndian<quint32>(tableData + 50); + signature.fsUsb[3] = qFromBigEndian<quint32>(tableData + 54); + + signature.fsCsb[0] = qFromBigEndian<quint32>(tableData + 78); + signature.fsCsb[1] = qFromBigEndian<quint32>(tableData + 82); + } else { + memset(&signature, 0, sizeof(signature)); + } +#endif // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is // identical to a TEXTMETRIC except for the last four members, which we don't use @@ -503,6 +558,17 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF default: result << QString::fromLatin1("Arial"); } + +#ifdef Q_OS_WINCE + QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\FontLink\\SystemLink"), QSettings::NativeFormat); + const QStringList fontList = settings.value(family).toStringList(); + foreach (const QString &fallback, fontList) { + const int sep = fallback.indexOf(QLatin1Char(',')); + if (sep > 0) + result << fallback.mid(sep + 1); + } +#endif + if (QWindowsContext::verboseFonts) qDebug() << __FUNCTION__ << family << style << styleHint << script << result << m_families; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 33ddcaffc5..ac57a1b396 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -336,6 +336,13 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name, if (!resolvedGetCharWidthI) resolveGetCharWidthI(); + + // ### Properties accessed by QWin32PrintEngine (QtPrintSupport) + QVariantMap userData; + userData.insert(QStringLiteral("logFont"), QVariant::fromValue(m_logfont)); + userData.insert(QStringLiteral("hFont"), QVariant::fromValue(hfont)); + userData.insert(QStringLiteral("trueType"), QVariant(bool(ttf))); + setUserData(userData); } QWindowsFontEngine::~QWindowsFontEngine() @@ -1133,8 +1140,10 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, << "If you need them anyway, start your application with -platform windows:fontengine=freetype."; } #endif // wince - QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin + 4, - ih + 2 * margin + 4, + + // The padding here needs to be kept in sync with the values in alphaMapBoundingBox. + QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin, + ih + 2 * margin, QWindowsNativeImage::systemFormat()); /*If cleartype is enabled we use the standard system format even on Windows CE @@ -1167,6 +1176,17 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, return ni; } +glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat format) +{ + int margin = 0; + if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB) + margin = glyphMargin(QFontEngineGlyphCache::Raster_RGBMask); + glyph_metrics_t gm = boundingBox(glyph, matrix); + gm.width += margin * 2; + gm.height += margin * 2; + return gm; +} + QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) { HFONT font = hfont; @@ -1353,7 +1373,7 @@ void QWindowsMultiFontEngine::loadEngine(int at) #endif { QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(fontEngine); - lf = fe->logFont(); + lf = fe->m_logfont; data = fe->fontEngineData(); } @@ -1378,8 +1398,6 @@ void QWindowsMultiFontEngine::loadEngine(int at) QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, fontEngine->fontDef.pixelSize, data); - fedw->setObjectName(QStringLiteral("QWindowsFontEngineDirectWrite_") + fontEngine->fontDef.family); - fedw->fontDef = fontDef; fedw->ref.ref(); engines[at] = fedw; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 9e92a8fbff..d783b6048c 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -68,10 +68,7 @@ class QWindowsFontEngineData; class QWindowsFontEngine : public QFontEngine { - Q_OBJECT - Q_PROPERTY(HFONT hFont READ hFont STORED false) - Q_PROPERTY(LOGFONT logFont READ logFont STORED false) - Q_PROPERTY(bool trueType READ trueType STORED false) + friend class QWindowsMultiFontEngine; public: QWindowsFontEngine(const QString &name, HFONT, bool, LOGFONT, @@ -121,6 +118,7 @@ public: virtual QImage alphaMapForGlyph(glyph_t t) { return alphaMapForGlyph(t, QTransform()); } virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform); virtual QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform); + virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat); virtual QFontEngine *cloneWithSize(qreal pixelSize) const; virtual bool supportsTransformation(const QTransform &transform) const; @@ -136,11 +134,6 @@ public: const QSharedPointer<QWindowsFontEngineData> &fontEngineData() const { return m_fontEngineData; } - // Properties accessed by QWin32PrintEngine (Qt Print Support) - LOGFONT logFont() const { return m_logfont; } - HFONT hFont() const { return hfont; } - bool trueType() const { return ttf; } - void setUniqueFamilyName(const QString &newName) { uniqueFamilyName = newName; } private: diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index c0f1b3a000..7407d88f8b 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -215,7 +215,9 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di if (QWindowsContext::verboseFonts) qDebug("%s %g", __FUNCTION__, pixelSize); - d->directWriteFactory->AddRef(); + Q_ASSERT(m_directWriteFontFace); + + m_fontEngineData->directWriteFactory->AddRef(); m_directWriteFontFace->AddRef(); fontDef.pixelSize = pixelSize; @@ -237,19 +239,17 @@ QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() void QWindowsFontEngineDirectWrite::collectMetrics() { - if (m_directWriteFontFace != 0) { - DWRITE_FONT_METRICS metrics; - - m_directWriteFontFace->GetMetrics(&metrics); - m_unitsPerEm = metrics.designUnitsPerEm; - - m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); - m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); - m_descent = DESIGN_TO_LOGICAL(metrics.descent); - m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); - m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); - m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); - } + DWRITE_FONT_METRICS metrics; + + m_directWriteFontFace->GetMetrics(&metrics); + m_unitsPerEm = metrics.designUnitsPerEm; + + m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); + m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); + m_descent = DESIGN_TO_LOGICAL(metrics.descent); + m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); + m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); + m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); } QFixed QWindowsFontEngineDirectWrite::underlinePosition() const @@ -272,31 +272,24 @@ bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, ui { bool ret = false; - if (m_directWriteFontFace) { - DWORD t = qbswap<quint32>(tag); - - const void *tableData = 0; - void *tableContext = 0; - UINT32 tableSize; - BOOL exists; - HRESULT hr = m_directWriteFontFace->TryGetFontTable( - t, &tableData, &tableSize, &tableContext, &exists - ); - - if (SUCCEEDED(hr)) { - if (exists) { - if (!buffer) { - *length = tableSize; - ret = true; - } else if (*length >= tableSize) { - memcpy(buffer, tableData, tableSize); - ret = true; - } - } - m_directWriteFontFace->ReleaseFontTable(tableContext); - } else { - qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); + const void *tableData = 0; + UINT32 tableSize; + void *tableContext = 0; + BOOL exists; + HRESULT hr = m_directWriteFontFace->TryGetFontTable(qbswap<quint32>(tag) + &tableData, &tableSize, + &tableContext, &exists); + if (SUCCEEDED(hr)) { + if (exists) { + ret = true; + if (buffer && *length >= tableSize) + memcpy(buffer, tableData, tableSize); + else + *length = tableSize; } + m_directWriteFontFace->ReleaseFontTable(tableContext); + } else { + qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); } return ret; @@ -327,43 +320,43 @@ inline unsigned int getChar(const QChar *str, int &i, const int len) bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { - if (m_directWriteFontFace != 0) { - QVarLengthArray<UINT32> codePoints(len); - for (int i=0; i<len; ++i) { - codePoints[i] = getChar(str, i, len); - if (flags & QFontEngine::RightToLeft) - codePoints[i] = QChar::mirroredChar(codePoints[i]); - } + if (*nglyphs < len) { + *nglyphs = len; + return false; + } - QVarLengthArray<UINT16> glyphIndices(len); - HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), - len, - glyphIndices.data()); + QVarLengthArray<UINT32> codePoints(len); + int actualLength = 0; + if (flags & QFontEngine::RightToLeft) { + for (int i = 0; i < len; ++i) + codePoints[actualLength++] = QChar::mirroredChar(getChar(str, i, len)); + } else { + for (int i = 0; i < len; ++i) + codePoints[actualLength++] = getChar(str, i, len); + } - if (SUCCEEDED(hr)) { - for (int i=0; i<len; ++i) - glyphs->glyphs[i] = glyphIndices[i]; + QVarLengthArray<UINT16> glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); + return false; + } - *nglyphs = len; - glyphs->numGlyphs = len; + for (int i = 0; i < actualLength; ++i) + glyphs->glyphs[i] = glyphIndices.at(i); - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, 0); + *nglyphs = actualLength; + glyphs->numGlyphs = actualLength; - return true; - } else { - qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); - } - } + if (!(flags & GlyphIndicesOnly)) + recalcAdvances(glyphs, 0); - return false; + return true; } void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const { - if (m_directWriteFontFace == 0) - return; - QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs); // ### Caching? @@ -391,9 +384,6 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags) { - if (m_directWriteFontFace == 0) - return; - QVarLengthArray<UINT16> glyphIndices(nglyphs); QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs); QVarLengthArray<FLOAT> glyphAdvances(nglyphs); @@ -439,9 +429,6 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &g glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) { - if (m_directWriteFontFace == 0) - return glyph_metrics_t(); - UINT16 glyphIndex = g; DWRITE_GLYPH_METRICS glyphMetrics; @@ -668,14 +655,14 @@ bool QWindowsFontEngineDirectWrite::canRender(const QChar *string, int len) if (FAILED(hr)) { qErrnoWarning("%s: GetGlyphIndices failed", __FUNCTION__); return false; - } else { - for (int i=0; i<glyphIndices.size(); ++i) { - if (glyphIndices.at(i) == 0) - return false; - } + } - return true; + for (int i = 0; i < actualLength; ++i) { + if (glyphIndices.at(i) == 0) + return false; } + + return true; } QFontEngine::Type QWindowsFontEngineDirectWrite::type() const diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 106087f757..57a6a3ba1d 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -61,7 +61,6 @@ QT_BEGIN_NAMESPACE class QWindowsFontEngineDirectWrite : public QFontEngine { - Q_OBJECT public: explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, qreal pixelSize, @@ -107,8 +106,6 @@ public: static QString fontNameSubstitute(const QString &familyName); private: - friend class QRawFontPrivate; - QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); void collectMetrics(); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index f6dda04c13..d1ede39549 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -49,6 +49,8 @@ #include <QtGui/QGuiApplication> #include <qpa/qplatformnativeinterface.h> +#include <algorithm> + #include <wingdi.h> #include <GL/gl.h> @@ -377,7 +379,7 @@ static int choosePixelFormat(HDC hdc, return 0; int iAttributes[attribSize]; - qFill(iAttributes, iAttributes + attribSize, int(0)); + std::fill(iAttributes, iAttributes + attribSize, int(0)); int i = 0; iAttributes[i++] = WGL_ACCELERATION_ARB; iAttributes[i++] = testFlag(additional.formatFlags, QWindowsGLDirectRendering) ? @@ -505,8 +507,8 @@ static QSurfaceFormat return result; int iAttributes[attribSize]; int iValues[attribSize]; - qFill(iAttributes, iAttributes + attribSize, int(0)); - qFill(iValues, iValues + attribSize, int(0)); + std::fill(iAttributes, iAttributes + attribSize, int(0)); + std::fill(iValues, iValues + attribSize, int(0)); int i = 0; const bool hasSampleBuffers = testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers); @@ -567,7 +569,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, return 0; int attributes[attribSize]; int attribIndex = 0; - qFill(attributes, attributes + attribSize, int(0)); + std::fill(attributes, attributes + attribSize, int(0)); // We limit the requested version by the version of the static context as // wglCreateContextAttribsARB fails and returns NULL if the requested context diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 5287b79ac3..a84d30de0f 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -56,6 +56,8 @@ #include <QtGui/QPalette> #include <QtGui/QGuiApplication> +#include <algorithm> + QT_BEGIN_NAMESPACE static inline QByteArray debugComposition(int lParam) @@ -583,8 +585,8 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) reconv->dwTargetStrLen = reconv->dwCompStrLen; reconv->dwTargetStrOffset = reconv->dwCompStrOffset; ushort *pastReconv = reinterpret_cast<ushort *>(reconv + 1); - qCopy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(), - pastReconv); + std::copy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(), + pastReconv); return memSize; } diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 754d7a0288..5f1f9cf149 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -342,6 +342,8 @@ static inline unsigned parseOptions(const QStringList ¶mList) } } else if (param == QLatin1String("gl=gdi")) { options |= QWindowsIntegration::DisableArb; + } else if (param == QLatin1String("mousefromtouch")) { + options |= QWindowsIntegration::PassOsMouseEventsSynthesizedFromTouch; } } return options; @@ -557,13 +559,15 @@ QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) co break; case QPlatformIntegration::UseRtlExtensions: return QVariant(d->m_context.useRTLExtensions()); -#ifdef Q_OS_WINCE case QPlatformIntegration::SynthesizeMouseFromTouchEvents: +#ifdef Q_OS_WINCE // We do not want Qt to synthesize mouse events as Windows also does that. // Alternatively, Windows-generated touch mouse events can be identified and // ignored by checking GetMessageExtraInfo() for MI_WP_SIGNATURE (0xFF515700). return false; -#endif // Q_OS_WINCE +#else // Q_OS_WINCE + return QVariant(!(d->m_options & PassOsMouseEventsSynthesizedFromTouch)); +#endif // !Q_OS_WINCE default: break; } diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index ca484415be..b3854d673a 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -58,7 +58,8 @@ public: FontDatabaseNative = 0x2, DisableArb = 0x4, NoNativeDialogs = 0x8, - XpNativeDialogs = 0x10 + XpNativeDialogs = 0x10, + PassOsMouseEventsSynthesizedFromTouch = 0x20 // Pass OS-generated mouse events from touch. }; explicit QWindowsIntegration(const QStringList ¶mList); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 43286eadf3..3782b7e020 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -169,10 +169,13 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, #ifndef Q_OS_WINCE // Check for events synthesized from touch. Lower byte is touch index, 0 means pen. - const quint64 extraInfo = GetMessageExtraInfo(); - const bool fromTouch = (extraInfo & signatureMask) == miWpSignature && (extraInfo & 0xff); - if (fromTouch) - return false; + static const bool passSynthesizedMouseEvents = QWindowsIntegration::instance()->options() & QWindowsIntegration::PassOsMouseEventsSynthesizedFromTouch; + if (!passSynthesizedMouseEvents) { + const quint64 extraInfo = GetMessageExtraInfo(); + const bool fromTouch = (extraInfo & signatureMask) == miWpSignature && (extraInfo & 0xff); + if (fromTouch) + return false; + } #endif // !Q_OS_WINCE const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp new file mode 100644 index 0000000000..4a5d7b5a78 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -0,0 +1,473 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowstabletsupport.h" + +#ifndef QT_NO_TABLETEVENT + +#include "qwindowscontext.h" +#include "qwindowskeymapper.h" +#include "qwindowswindow.h" + +#include <qpa/qwindowsysteminterface.h> + +#include <QtGui/QTabletEvent> +#include <QtGui/QScreen> +#include <QtGui/QGuiApplication> +#include <QtGui/QWindow> +#include <QtCore/QDebug> +#include <QtCore/QScopedArrayPointer> +#include <QtCore/QtMath> + +#include <private/qguiapplication_p.h> +#include <QtCore/private/qsystemlibrary_p.h> + +// Note: The definition of the PACKET structure in pktdef.h depends on this define. +#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z) +#include <pktdef.h> + +QT_BEGIN_NAMESPACE + +enum { + PacketMode = 0, + TabletPacketQSize = 128, + DeviceIdMask = 0xFF6, // device type mask && device color mask + CursorTypeBitMask = 0x0F06 // bitmask to find the specific cursor type (see Wacom FAQ) +}; + +extern "C" LRESULT QT_WIN_CALLBACK qWindowsTabletSupportWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WT_PROXIMITY: + if (QWindowsContext::instance()->tabletSupport()->translateTabletProximityEvent(wParam, lParam)) + return 0; + break; + case WT_PACKET: + if (QWindowsContext::instance()->tabletSupport()->translateTabletPacketEvent()) + return 0; + break; + } + return DefWindowProc(hwnd, message, wParam, lParam); +} + + +// Scale tablet coordinates to screen coordinates. + +static inline int sign(int x) +{ + return x >= 0 ? 1 : -1; +} + +inline QPointF QWindowsTabletDeviceData::scaleCoordinates(int coordX, int coordY, const QRect &targetArea) const +{ + const int targetX = targetArea.x(); + const int targetY = targetArea.y(); + const int targetWidth = targetArea.width(); + const int targetHeight = targetArea.height(); + + const qreal x = sign(targetWidth) == sign(maxX) ? + ((coordX - minX) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX : + ((qAbs(maxX) - (coordX - minX)) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX; + + const qreal y = sign(targetHeight) == sign(maxY) ? + ((coordY - minY) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY : + ((qAbs(maxY) - (coordY - minY)) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY; + + return QPointF(x, y); +} + +QWindowsWinTab32DLL QWindowsTabletSupport::m_winTab32DLL; + +/*! + \class QWindowsWinTab32DLL QWindowsTabletSupport + \brief Functions from wintabl32.dll shipped with WACOM tablets used by QWindowsTabletSupport. + + \internal + \ingroup qt-lighthouse-win +*/ + +bool QWindowsWinTab32DLL::init() +{ + if (wTInfo) + return true; + QSystemLibrary library(QStringLiteral("wintab32")); + if (!library.load()) + return false; + wTOpen = (PtrWTOpen)library.resolve("WTOpenW"); + wTClose = (PtrWTClose)library.resolve("WTClose"); + wTInfo = (PtrWTInfo)library.resolve("WTInfoW"); + wTEnable = (PtrWTEnable)library.resolve("WTEnable"); + wTOverlap = (PtrWTEnable)library.resolve("WTOverlap"); + wTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet"); + wTGet = (PtrWTGet)library.resolve("WTGetW"); + wTQueueSizeGet = (PtrWTQueueSizeGet)library.resolve("WTQueueSizeGet"); + wTQueueSizeSet = (PtrWTQueueSizeSet)library.resolve("WTQueueSizeSet"); + return wTOpen && wTClose && wTInfo && wTEnable && wTOverlap && wTPacketsGet && wTQueueSizeGet && wTQueueSizeSet; +} + +/*! + \class QWindowsTabletSupport + \brief Tablet support for Windows. + + Support for WACOM tablets. + + \sa http://www.wacomeng.com/windows/docs/Wintab_v140.htm + + \internal + \since 5.2 + \ingroup qt-lighthouse-win +*/ + +QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context) + : m_window(window) + , m_context(context) + , m_tiltSupport(false) + , m_currentDevice(-1) +{ + AXIS orientation[3]; + // Some tablets don't support tilt, check if it is possible, + if (QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_ORIENTATION, &orientation)) + m_tiltSupport = orientation[0].axResolution && orientation[1].axResolution; +} + +QWindowsTabletSupport::~QWindowsTabletSupport() +{ + QWindowsTabletSupport::m_winTab32DLL.wTClose(m_context); + DestroyWindow(m_window); +} + +QWindowsTabletSupport *QWindowsTabletSupport::create() +{ + if (!m_winTab32DLL.init()) + return 0; + const HWND window = QWindowsContext::instance()->createDummyWindow(QStringLiteral("TabletDummyWindow"), + L"TabletDummyWindow", + qWindowsTabletSupportWndProc); + if (!window) { + if (QWindowsContext::verboseTablet) + qWarning() << __FUNCTION__ << "Unable to create window for tablet."; + return 0; + } + LOGCONTEXT lcMine; + // build our context from the default context + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFSYSCTX, 0, &lcMine); + // Go for the raw coordinates, the tablet event will return good stuff + lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES; + lcMine.lcPktData = lcMine.lcMoveMask = PACKETDATA; + lcMine.lcPktMode = PacketMode; + lcMine.lcOutOrgX = 0; + lcMine.lcOutExtX = lcMine.lcInExtX; + lcMine.lcOutOrgY = 0; + lcMine.lcOutExtY = -lcMine.lcInExtY; + const HCTX context = QWindowsTabletSupport::m_winTab32DLL.wTOpen(window, &lcMine, true); + if (!context) { + if (QWindowsContext::verboseTablet) + qWarning() << __FUNCTION__ << "Unable to open tablet."; + DestroyWindow(window); + return 0; + + } + // Set the size of the Packet Queue to the correct size + const int currentQueueSize = QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeGet(context); + if (currentQueueSize != TabletPacketQSize) { + if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, TabletPacketQSize)) { + if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, currentQueueSize)) { + qWarning() << "Unable to set queue size on tablet. The tablet will not work."; + QWindowsTabletSupport::m_winTab32DLL.wTClose(context); + DestroyWindow(window); + return 0; + } // cannot restore old size + } // cannot set + } // mismatch + if (QWindowsContext::verboseTablet) + qDebug("Opened tablet context %p on window %p, changed packet queue size %d -> %d", + context, window, currentQueueSize, TabletPacketQSize); + return new QWindowsTabletSupport(window, context); +} + +unsigned QWindowsTabletSupport::options() const +{ + UINT result = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_CTXOPTIONS, &result); + return result; +} + +QString QWindowsTabletSupport::description() const +{ + const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0); + if (!size) + return QString(); + QScopedPointer<TCHAR> winTabId(new TCHAR[size + 1]); + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data()); + WORD implementationVersion = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion); + WORD specificationVersion = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_SPECVERSION, &specificationVersion); + const unsigned opts = options(); + QString result = QString::fromLatin1("%1 specification: v%2.%3 implementation: v%4.%5 options: 0x%6") + .arg(QString::fromWCharArray(winTabId.data())) + .arg(specificationVersion >> 8).arg(specificationVersion & 0xFF) + .arg(implementationVersion >> 8).arg(implementationVersion & 0xFF) + .arg(opts, 0, 16); + if (opts & CXO_MESSAGES) + result += QStringLiteral(" CXO_MESSAGES"); + if (opts & CXO_CSRMESSAGES) + result += QStringLiteral(" CXO_CSRMESSAGES"); + if (m_tiltSupport) + result += QStringLiteral(" tilt"); + return result; +} + +void QWindowsTabletSupport::notifyActivate() +{ + // Cooperate with other tablet applications, but when we get focus, I want to use the tablet. + const bool result = QWindowsTabletSupport::m_winTab32DLL.wTEnable(m_context, true) + && QWindowsTabletSupport::m_winTab32DLL.wTOverlap(m_context, true); + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << result; +} + +static inline int indexOfDevice(const QVector<QWindowsTabletDeviceData> &devices, qint64 uniqueId) +{ + for (int i = 0; i < devices.size(); ++i) + if (devices.at(i).uniqueId == uniqueId) + return i; + return -1; +} + +static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType) +{ + if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902)) + return QTabletEvent::Stylus; + switch (cursorType & CursorTypeBitMask) { + case 0x0802: + return QTabletEvent::Stylus; + case 0x0902: + return QTabletEvent::Airbrush; + case 0x0004: + return QTabletEvent::FourDMouse; + case 0x0006: + return QTabletEvent::Puck; + case 0x0804: + return QTabletEvent::RotationStylus; + default: + break; + } + return QTabletEvent::NoDevice; +} + +static inline QTabletEvent::PointerType pointerType(unsigned currentCursor) +{ + switch (currentCursor % 3) { // %3 for dual track + case 0: + return QTabletEvent::Cursor; + case 1: + return QTabletEvent::Pen; + case 2: + return QTabletEvent::Eraser; + default: + break; + } + return QTabletEvent::UnknownPointer; +} + +QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t) +{ + d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure + << ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".." + << t.maxTanPressure << " area:" << t.minX << t.minY <<t.minZ + << ".." << t.maxX << t.maxY << t.maxZ << " device " << t.currentDevice + << " pointer " << t.currentPointerType; + return d; +} + +QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(const quint64 uniqueId, const UINT cursorType) const +{ + QWindowsTabletDeviceData result; + result.uniqueId = uniqueId; + /* browse WinTab's many info items to discover pressure handling. */ + AXIS axis; + LOGCONTEXT lc; + /* get the current context for its device variable. */ + QWindowsTabletSupport::m_winTab32DLL.wTGet(m_context, &lc); + /* get the size of the pressure axis. */ + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &axis); + result.minPressure = int(axis.axMin); + result.maxPressure = int(axis.axMax); + + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &axis); + result.minTanPressure = int(axis.axMin); + result.maxTanPressure = int(axis.axMax); + + LOGCONTEXT defaultLc; + /* get default region */ + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFCONTEXT, 0, &defaultLc); + result.maxX = int(defaultLc.lcInExtX) - int(defaultLc.lcInOrgX); + result.maxY = int(defaultLc.lcInExtY) - int(defaultLc.lcInOrgY); + result.maxZ = int(defaultLc.lcInExtZ) - int(defaultLc.lcInOrgZ); + result.currentDevice = deviceType(cursorType); + return result; +} + +bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam) +{ + const bool enteredProximity = LOWORD(lParam) != 0; + PACKET proximityBuffer[1]; // we are only interested in the first packet in this case + const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); + if (!totalPacks) + return false; + const UINT currentCursor = proximityBuffer[0].pkCursor; + UINT physicalCursorId; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId); + UINT cursorType; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &cursorType); + const qint64 uniqueId = (qint64(cursorType & DeviceIdMask) << 32L) | qint64(physicalCursorId); + // initializing and updating the cursor should be done in response to + // WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send + // the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES + m_currentDevice = indexOfDevice(m_devices, uniqueId); + if (m_currentDevice < 0) { + m_currentDevice = m_devices.size(); + m_devices.push_back(tabletInit(uniqueId, cursorType)); + } + m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor); + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << (enteredProximity ? "enter" : "leave") + << " proximity for device #" + << m_currentDevice << m_devices.at(m_currentDevice); + if (enteredProximity) { + QWindowSystemInterface::handleTabletEnterProximityEvent(m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + } else { + QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + } + return true; +} + +bool QWindowsTabletSupport::translateTabletPacketEvent() +{ + static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue. + const int packetCount = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, TabletPacketQSize, &localPacketBuf); + if (!packetCount || m_currentDevice < 0) + return false; + + const int currentDevice = m_devices.at(m_currentDevice).currentDevice; + const int currentPointer = m_devices.at(m_currentDevice).currentPointerType; + + // When entering proximity, the tablet driver snaps the mouse pointer to the + // tablet position scaled to the virtual desktop and keeps it in sync. + const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); + + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << "processing " << packetCount + << "target:" << QGuiApplicationPrivate::tabletPressTarget; + + const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); + + for (int i = 0; i < packetCount ; ++i) { + const PACKET &packet = localPacketBuf[i]; + + const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0; + const QPointF globalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea); + + QWindow *target = QGuiApplicationPrivate::tabletPressTarget; // Pass to window that grabbed it. + const QPoint globalPos = globalPosF.toPoint(); + if (!target) + if (QPlatformWindow *pw = QWindowsContext::instance()->findPlatformWindowAt(GetDesktopWindow(), globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT)) + target = pw->window(); + if (!target) + continue; + + const QPoint localPos = target->mapFromGlobal(globalPos); + + const qreal pressureNew = packet.pkButtons && (currentPointer == QTabletEvent::Pen || currentPointer == QTabletEvent::Eraser) ? + m_devices.at(m_currentDevice).scalePressure(packet.pkNormalPressure) : + qreal(0); + const qreal tangentialPressure = currentDevice == QTabletEvent::Airbrush ? + m_devices.at(m_currentDevice).scaleTangentialPressure(packet.pkTangentPressure) : + qreal(0); + + int tiltX = 0; + int tiltY = 0; + qreal rotation = 0; + if (m_tiltSupport) { + // Convert from azimuth and altitude to x tilt and y tilt. What + // follows is the optimized version. Here are the equations used: + // X = sin(azimuth) * cos(altitude) + // Y = cos(azimuth) * cos(altitude) + // Z = sin(altitude) + // X Tilt = arctan(X / Z) + // Y Tilt = arctan(Y / Z) + const double radAzim = (packet.pkOrientation.orAzimuth / 10) * (M_PI / 180); + const double tanAlt = tan((abs(packet.pkOrientation.orAltitude / 10)) * (M_PI / 180)); + + const double degX = atan(sin(radAzim) / tanAlt); + const double degY = atan(cos(radAzim) / tanAlt); + tiltX = int(degX * (180 / M_PI)); + tiltY = int(-degY * (180 / M_PI)); + rotation = packet.pkOrientation.orTwist; + } + + if (QWindowsContext::verboseTablet > 1) { + qDebug() + << "Packet #" << i << '/' << packetCount << "button:" << packet.pkButtons + << globalPosF << z << "to:" << target << localPos << "(packet" << packet.pkX + << packet.pkY << ") dev:" << currentDevice << "pointer:" + << currentPointer << "P:" << pressureNew << "tilt:" << tiltX << ',' + << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; + } + + QWindowSystemInterface::handleTabletEvent(target, packet.pkButtons, localPos, globalPosF, + currentDevice, currentPointer, + pressureNew, tiltX, tiltY, + tangentialPressure, rotation, z, + m_devices.at(m_currentDevice).uniqueId, + keyboardModifiers); + } + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_TABLETEVENT diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h new file mode 100644 index 0000000000..12f96b618d --- /dev/null +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSTABLETSUPPORT_H +#define QWINDOWSTABLETSUPPORT_H + +#include "qtwindowsglobal.h" + +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + +#include <QtCore/QVector> +#include <QtCore/QPointF> + +#include <wintab.h> + +QT_BEGIN_NAMESPACE + +class QDebug; +class QWindow; +class QRect; + +struct QWindowsWinTab32DLL +{ + QWindowsWinTab32DLL() : wTOpen(0), wTClose(0), wTInfo(0), wTEnable(0), wTOverlap(0), wTPacketsGet(0), wTGet(0), + wTQueueSizeGet(0), wTQueueSizeSet(0) {} + + bool init(); + + typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL); + typedef BOOL (API *PtrWTClose)(HCTX); + typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID); + typedef BOOL (API *PtrWTEnable)(HCTX, BOOL); + typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL); + typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID); + typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT); + typedef int (API *PtrWTQueueSizeGet)(HCTX); + typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int); + + PtrWTOpen wTOpen; + PtrWTClose wTClose; + PtrWTInfo wTInfo; + PtrWTEnable wTEnable; + PtrWTOverlap wTOverlap; + PtrWTPacketsGet wTPacketsGet; + PtrWTGet wTGet; + PtrWTQueueSizeGet wTQueueSizeGet; + PtrWTQueueSizeSet wTQueueSizeSet; +}; + +struct QWindowsTabletDeviceData +{ + QWindowsTabletDeviceData() : minPressure(0), maxPressure(0), minTanPressure(0), + maxTanPressure(0), minX(0), maxX(0), minY(0), maxY(0), minZ(0), maxZ(0), + uniqueId(0), currentDevice(0), currentPointerType(0) {} + + QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const; + qreal scalePressure(qreal p) const { return p / qreal(maxPressure - minPressure); } + qreal scaleTangentialPressure(qreal p) const { return p / qreal(maxTanPressure - minTanPressure); } + + int minPressure; + int maxPressure; + int minTanPressure; + int maxTanPressure; + int minX, maxX, minY, maxY, minZ, maxZ; + qint64 uniqueId; + int currentDevice; + int currentPointerType; +}; + +QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t); + +class QWindowsTabletSupport +{ + Q_DISABLE_COPY(QWindowsTabletSupport) + + explicit QWindowsTabletSupport(HWND window, HCTX context); + +public: + ~QWindowsTabletSupport(); + + static QWindowsTabletSupport *create(); + + void notifyActivate(); + QString description() const; + + bool translateTabletProximityEvent(WPARAM wParam, LPARAM lParam); + bool translateTabletPacketEvent(); + +private: + unsigned options() const; + QWindowsTabletDeviceData tabletInit(const quint64 uniqueId, const UINT cursorType) const; + + static QWindowsWinTab32DLL m_winTab32DLL; + const HWND m_window; + const HCTX m_context; + bool m_tiltSupport; + QVector<QWindowsTabletDeviceData> m_devices; + int m_currentDevice; +}; + +QT_END_NAMESPACE + +#endif // !QT_NO_TABLETEVENT && !Q_OS_WINCE +#endif // QWINDOWSTABLETSUPPORT_H diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 9f6e6b18e7..eb1bbd1ab0 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -54,6 +54,13 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" # include "winuser.h" +#else +# include <commctrl.h> +# include <objbase.h> +# ifndef Q_CC_MINGW +# include <commoncontrols.h> +# endif +# include <shellapi.h> #endif #include <QtCore/QVariant> @@ -69,6 +76,12 @@ #include <qpa/qwindowsysteminterface.h> #include <private/qsystemlibrary_p.h> +#include <algorithm> + +#if defined(__IImageList_INTERFACE_DEFINED__) && defined(__IID_DEFINED__) +# define USE_IIMAGELIST +#endif + QT_BEGIN_NAMESPACE static inline QTextStream& operator<<(QTextStream &str, const QColor &c) @@ -290,8 +303,8 @@ QWindowsTheme *QWindowsTheme::m_instance = 0; QWindowsTheme::QWindowsTheme() { m_instance = this; - qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); - qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); + std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); + std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); refresh(); } @@ -361,8 +374,15 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const case IconPixmapSizes: { QList<int> sizes; sizes << 16 << 32; +#ifdef USE_IIMAGELIST + sizes << 48; // sHIL_EXTRALARGE + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) + sizes << 256; // SHIL_JUMBO +#endif // USE_IIMAGELIST return QVariant::fromValue(sizes); } + case DialogSnapToDefaultButton: + return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false)); default: break; } @@ -372,7 +392,7 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const void QWindowsTheme::clearPalettes() { qDeleteAll(m_palettes, m_palettes + NPalettes); - qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); + std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); } void QWindowsTheme::refreshPalettes() @@ -393,7 +413,7 @@ void QWindowsTheme::refreshPalettes() void QWindowsTheme::clearFonts() { qDeleteAll(m_fonts, m_fonts + NFonts); - qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); + std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); } void QWindowsTheme::refreshFonts() @@ -410,6 +430,8 @@ void QWindowsTheme::refreshFonts() const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont); const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont); + QFont fixedFont(QStringLiteral("Courier New"), messageBoxFont.pointSize()); + fixedFont.setStyleHint(QFont::TypeWriter); LOGFONT lfIconTitleFont; SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); @@ -424,6 +446,7 @@ void QWindowsTheme::refreshFonts() m_fonts[MdiSubWindowTitleFont] = new QFont(titleFont); m_fonts[DockWidgetTitleFont] = new QFont(titleFont); m_fonts[ItemViewFont] = new QFont(iconTitleFont); + m_fonts[FixedFont] = new QFont(fixedFont); if (QWindowsContext::verboseTheming) qDebug() << __FUNCTION__ << '\n' @@ -573,11 +596,24 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con return QPlatformTheme::standardPixmap(sp, size); } -static QString dirIconPixmapCacheKey(int iIcon, int iconSize) +enum { // Shell image list ids + sHIL_EXTRALARGE = 0x2, // 48x48 or user-defined + sHIL_JUMBO = 0x4 // 256x256 (Vista or later) +}; + +static QString dirIconPixmapCacheKey(int iIcon, int iconSize, int imageListSize) { QString key = QLatin1String("qt_dir_") + QString::number(iIcon); if (iconSize == SHGFI_LARGEICON) key += QLatin1Char('l'); + switch (imageListSize) { + case sHIL_EXTRALARGE: + key += QLatin1Char('e'); + break; + case sHIL_JUMBO: + key += QLatin1Char('j'); + break; + } return key; } @@ -601,7 +637,40 @@ public: void operator delete (void *) {} }; -QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +// Shell image list helper functions. + +static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info) +{ + QPixmap result; +#ifdef USE_IIMAGELIST + // For MinGW: + static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}}; + + if (!QWindowsContext::shell32dll.sHGetImageList) + return result; + if (iImageList == sHIL_JUMBO && QSysInfo::WindowsVersion < QSysInfo::WV_VISTA) + return result; + + IImageList *imageList = 0; + HRESULT hr = QWindowsContext::shell32dll.sHGetImageList(iImageList, iID_IImageList, (void **)&imageList); + if (hr != S_OK) + return result; + HICON hIcon; + hr = imageList->GetIcon(info.iIcon, ILD_TRANSPARENT, &hIcon); + if (hr == S_OK) { + result = qt_pixmapFromWinHICON(hIcon); + DestroyIcon(hIcon); + } + imageList->Release(); +#else + Q_UNUSED(iImageList) + Q_UNUSED(info) +#endif // USE_IIMAGELIST + return result; +} + +QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { /* We don't use the variable, but by storing it statically, we * ensure CoInitialize is only called once. */ @@ -610,17 +679,26 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s static QCache<QString, FakePointer<int> > dirIconEntryCache(1000); static QMutex mx; + static int defaultFolderIIcon = -1; + const bool useDefaultFolderIcon = iconOptions & QPlatformTheme::DontUseCustomDirectoryIcons; QPixmap pixmap; const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); - int iconSize = size.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; - + const int width = size.width(); + const int iconSize = width > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; + const int requestedImageListSize = +#ifdef USE_IIMAGELIST + width > 48 ? sHIL_JUMBO : (width > 32 ? sHIL_EXTRALARGE : 0); +#else + 0; +#endif // !USE_IIMAGELIST bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); if (cacheableDirIcon) { QMutexLocker locker(&mx); - int iIcon = **dirIconEntryCache.object(filePath); + int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? defaultFolderIIcon + : **dirIconEntryCache.object(filePath); if (iIcon) { - QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); + QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize), pixmap); if (pixmap.isNull()) // Let's keep both caches in sync dirIconEntryCache.remove(filePath); else @@ -635,15 +713,26 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s #else iconSize|SHGFI_SYSICONINDEX; #endif // Q_OS_WINCE - unsigned long val = SHGetFileInfo((const wchar_t *)filePath.utf16(), 0, - &info, sizeof(SHFILEINFO), flags); + unsigned long val = 0; + if (cacheableDirIcon && useDefaultFolderIcon) { + flags |= SHGFI_USEFILEATTRIBUTES; + val = SHGetFileInfo(L"dummy", + FILE_ATTRIBUTE_DIRECTORY, + &info, sizeof(SHFILEINFO), flags); + } else { + val = SHGetFileInfo(reinterpret_cast<const wchar_t *>(filePath.utf16()), 0, + &info, sizeof(SHFILEINFO), flags); + } // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases if (val && info.hIcon) { QString key; if (cacheableDirIcon) { + if (useDefaultFolderIcon && defaultFolderIIcon < 0) + defaultFolderIIcon = info.iIcon; + //using the unique icon index provided by windows save us from duplicate keys - key = dirIconPixmapCacheKey(info.iIcon, iconSize); + key = dirIconPixmapCacheKey(info.iIcon, iconSize, requestedImageListSize); QPixmapCache::find(key, pixmap); if (!pixmap.isNull()) { QMutexLocker locker(&mx); @@ -652,7 +741,13 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s } if (pixmap.isNull()) { - pixmap = qt_pixmapFromWinHICON(info.hIcon); + if (requestedImageListSize) { + pixmap = pixmapFromShellImageList(requestedImageListSize, info); + if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO) + pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, info); + } + if (pixmap.isNull()) + pixmap = qt_pixmapFromWinHICON(info.hIcon); if (!pixmap.isNull()) { if (cacheableDirIcon) { QMutexLocker locker(&mx); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index bbd7f4623f..9346621d59 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -68,7 +68,8 @@ public: { return m_fonts[type]; } virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const; void windowsThemeChanged(QWindow *window); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 9d87eaa110..7077eaf4b0 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -56,6 +56,7 @@ #include <QtGui/QScreen> #include <QtGui/QWindow> #include <QtGui/QRegion> +#include <private/qsystemlibrary_p.h> #include <private/qwindow_p.h> #include <private/qguiapplication_p.h> #include <qpa/qwindowsysteminterface.h> @@ -203,6 +204,69 @@ static inline QSize clientSize(HWND hwnd) return qSizeOfRect(rect); } +static bool applyBlurBehindWindow(HWND hwnd) +{ +#ifdef Q_OS_WINCE + Q_UNUSED(hwnd); + return false; +#else + enum { dwmBbEnable = 0x1, dwmBbBlurRegion = 0x2 }; + + struct DwmBlurBehind { + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; + }; + + typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND, const DwmBlurBehind*); + typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL *); + + // DWM API is available only from Windows Vista + if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA) + return false; + + static bool functionPointersResolved = false; + static PtrDwmEnableBlurBehindWindow dwmBlurBehind = 0; + static PtrDwmIsCompositionEnabled dwmIsCompositionEnabled = 0; + + if (Q_UNLIKELY(!functionPointersResolved)) { + QSystemLibrary library(QStringLiteral("dwmapi")); + if (library.load()) { + dwmBlurBehind = (PtrDwmEnableBlurBehindWindow)(library.resolve("DwmEnableBlurBehindWindow")); + dwmIsCompositionEnabled = (PtrDwmIsCompositionEnabled)(library.resolve("DwmIsCompositionEnabled")); + } + + functionPointersResolved = true; + } + + if (Q_UNLIKELY(!dwmBlurBehind || !dwmIsCompositionEnabled)) + return false; + + BOOL compositionEnabled; + if (dwmIsCompositionEnabled(&compositionEnabled) != S_OK) + return false; + + DwmBlurBehind blurBehind = {0, 0, 0, 0}; + + if (compositionEnabled) { + blurBehind.dwFlags = dwmBbEnable | dwmBbBlurRegion; + blurBehind.fEnable = TRUE; + blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1); + } else { + blurBehind.dwFlags = dwmBbEnable; + blurBehind.fEnable = FALSE; + } + + const bool result = dwmBlurBehind(hwnd, &blurBehind) == S_OK; + + if (blurBehind.hRgnBlur) + DeleteObject(blurBehind.hRgnBlur); + + return result; +#endif // Q_OS_WINCE +} + // from qwidget_win.cpp, pass flags separately in case they have been "autofixed". static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags) { @@ -544,6 +608,10 @@ QWindowsWindow::WindowData result.frame = context->margins; result.embedded = embedded; result.customMargins = context->customMargins; + + if (isGL && hasAlpha) + applyBlurBehindWindow(result.hwnd); + return result; } @@ -1168,6 +1236,13 @@ void QWindowsWindow::handleHidden() fireExpose(QRegion()); } +void QWindowsWindow::handleCompositionSettingsChanged() +{ + const QWindow *w = window(); + if (w->surfaceType() == QWindow::OpenGLSurface && w->format().hasAlpha()) + applyBlurBehindWindow(handle()); +} + void QWindowsWindow::setGeometry(const QRect &rectIn) { QRect rect = rectIn; diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index afcfa8b821..f055864482 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -221,6 +221,7 @@ public: void handleMoved(); void handleResized(int wParam); void handleHidden(); + void handleCompositionSettingsChanged(); static inline HWND handleOf(const QWindow *w); static inline QWindowsWindow *baseWindowOf(const QWindow *w); diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 3aa9caaa0f..d4e6e558ed 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -102,6 +102,12 @@ contains(QT_CONFIG, opengles2) { } } +!wince*:!contains( DEFINES, QT_NO_TABLETEVENT ) { + INCLUDEPATH += ../../../3rdparty/wintab + HEADERS += qwindowstabletsupport.h + SOURCES += qwindowstabletsupport.cpp +} + contains(QT_CONFIG, freetype) { DEFINES *= QT_NO_FONTCONFIG QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype |