diff options
Diffstat (limited to 'src/plugins/platforms/windows')
16 files changed, 870 insertions, 227 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/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/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 238817e85c..64bf1d71ca 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, @@ -204,6 +205,12 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI 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..132b3684e9 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) @@ -259,17 +261,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 +315,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 +642,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. @@ -866,6 +886,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, } #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 +899,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..0d3476e00f 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; @@ -135,6 +136,7 @@ public: static int verboseInputMethods; static int verboseDialogs; static int verboseTheming; + static int verboseTablet; explicit QWindowsContext(); ~QWindowsContext(); @@ -185,6 +187,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 27a7044868..328842677f 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" @@ -613,24 +615,6 @@ void QWindowsDialogHelperBase<BaseClass>::exec() } } -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()); - } - return BaseClass::styleHint(hint); -} - /*! \class QWindowsFileDialogSharedData \brief Explicitly shared file dialog parameters that are not in QFileDialogOptions. @@ -651,34 +635,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 +682,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) @@ -822,7 +806,7 @@ 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 setNameFilters(const QStringList &f); @@ -837,10 +821,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,8 +832,8 @@ 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: @@ -861,9 +845,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; } @@ -1031,9 +1015,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 +1046,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 +1080,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 +1092,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 +1254,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 +1262,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()); @@ -1338,8 +1322,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 +1358,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 +1392,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 +1468,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 +1492,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 +1515,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 +1538,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 +1573,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); @@ -1643,8 +1623,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; @@ -1683,7 +1663,7 @@ QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options void QWindowsXpNativeFileDialog::exec(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 +1675,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 +1703,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 +1719,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 +1731,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); @@ -1807,7 +1788,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 +1813,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 +1862,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 +1889,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. diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 7884f398f3..c0ee60cc1e 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -72,7 +72,6 @@ public: Qt::WindowModality windowModality, QWindow *parent); virtual void hide(); - virtual QVariant styleHint(QPlatformDialogHelper::StyleHint) const; virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index b7ccb5767e..a6bce6502b 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; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 7f97d58be4..6037c201ac 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -122,8 +122,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, @@ -304,7 +302,7 @@ 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; } 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..ab14cb49eb 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -107,8 +107,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/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 0fcd20f7bb..724ea00340 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -357,6 +357,8 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const sizes << 16 << 32; return QVariant::fromValue(sizes); } + case DialogSnapToDefaultButton: + return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false)); default: break; } @@ -404,6 +406,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); @@ -418,6 +422,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' @@ -595,7 +600,8 @@ public: void operator delete (void *) {} }; -QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +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. */ @@ -604,6 +610,8 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s static QCache<QString, FakePointer<int> > dirIconEntryCache(1000); static QMutex mx; + static int defaultFolderIIcon = 0; + const bool useDefaultFolderIcon = iconOptions & QPlatformTheme::DontUseCustomDirectoryIcons; QPixmap pixmap; const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); @@ -612,7 +620,8 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); if (cacheableDirIcon) { QMutexLocker locker(&mx); - int iIcon = **dirIconEntryCache.object(filePath); + int iIcon = (useDefaultFolderIcon && defaultFolderIIcon) ? defaultFolderIIcon + : **dirIconEntryCache.object(filePath); if (iIcon) { QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); if (pixmap.isNull()) // Let's keep both caches in sync @@ -629,13 +638,24 @@ 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) + defaultFolderIIcon = info.iIcon; + //using the unique icon index provided by windows save us from duplicate keys key = dirIconPixmapCacheKey(info.iIcon, iconSize); QPixmapCache::find(key, pixmap); 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/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 |