summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows')
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp27
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp504
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp72
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h4
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp2
-rw-r--r--src/plugins/platforms/windows/windows.pro6
8 files changed, 553 insertions, 76 deletions
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
index 6acfd6e602..03bb94db8f 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -1493,13 +1493,26 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidServic
*iface = 0;
accessibleDebug("QWindowsIA2Accessible::QS(): %s", IIDToString(riid).constData());
- if (guidService == IID_IAccessible && riid == IID_IAccessible2) {
- // The conditions for entering here should be ok (from _dicoveringInterfaces in IAccessible2.idl)
- *iface = static_cast<IAccessible2*>(this);
- } else if (guidService == IID_IAccessible && (riid == IID_IAccessible || riid == IID_IUnknown || riid == IID_IDispatch)) {
- // The above conditions works with AccProbe and NVDA.
- *iface = static_cast<IAccessible*>(this);
- } else if (riid == IID_IAccessibleApplication) {
+
+ if (guidService == IID_IAccessible) {
+ if (riid == IID_IServiceProvider) {
+ // do not end up calling QueryInterface for IID_IServiceProvider
+ *iface = 0;
+ } else if (riid == IID_IAccessible || riid == IID_IUnknown || riid == IID_IDispatch) {
+ // The above conditions works with AccProbe and NVDA.
+ *iface = static_cast<IAccessible*>(this);
+ } else {
+ // According to _dicoveringInterfaces Discovery of Interfaces, we should really only
+ // enter here if riid == IID_IAccessible2, but some screen readers does not like that,
+ // and other servers seems to have realized that. (Chrome and Mozilla for instance,
+ // calls QueryInterface more or less in the same way)
+
+ // For instance, accProbe discovers IID_IAccessibleTable2 by a QueryService only.
+ return QueryInterface(riid, iface);
+ }
+ }
+
+ if (riid == IID_IAccessibleApplication) {
*iface = new AccessibleApplication;
return S_OK;
}
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 87cb224d49..9e5578d35d 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -43,12 +43,9 @@
#include "qwindowscontext.h"
#include "qwindowswindow.h"
+#include "qwindowsintegration.h"
#include "qwindowstheme.h" // Color conversion helpers
-#include <QtWidgets/QColorDialog>
-#include <QtWidgets/QFontDialog>
-#include <QtWidgets/QFileDialog>
-
#include <QtGui/QGuiApplication>
#include <QtGui/QColor>
@@ -60,6 +57,7 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QObject>
#include <QtCore/QThread>
+#include <QtCore/QSysInfo>
#include <QtCore/private/qsystemlibrary_p.h>
#include "qtwindows_additional.h"
@@ -384,9 +382,10 @@ void eatMouseMove()
\class QWindowsNativeDialogBase
\brief Base class for Windows native dialogs.
- Base clases for native dialogs that mimick the
- behaviour of their QDialog counterparts as close as
- possible.
+ Base classes for native dialogs (using the CLSID-based
+ dialog interfaces "IFileDialog", etc. available from Windows
+ Vista on) that mimick the behaviour of their QDialog
+ counterparts as close as possible.
A major difference is that there is only an exec(), which
is a modal, blocking call; there is no non-blocking show().
@@ -862,12 +861,45 @@ int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items,
return itemCount;
}
-// Copy a string to an Utf16 buffer.
-static inline void toBuffer(const QString &what, WCHAR **ptr)
+// Split a list of name filters into description and actual filters
+struct FilterSpec
+{
+ QString description;
+ QString filter;
+};
+
+static QList<FilterSpec> filterSpecs(const QStringList &filters,
+ bool hideFilterDetails,
+ int *totalStringLength)
{
- const int length = 1 + what.size();
- memcpy(*ptr, what.utf16(), length * sizeof(WCHAR));
- *ptr += length;
+ QList<FilterSpec> result;
+ result.reserve(filters.size());
+ *totalStringLength = 0;
+
+ const QRegExp filterSeparatorRE(QStringLiteral("[;\\s]+"));
+ const QString separator = QStringLiteral(";");
+ Q_ASSERT(filterSeparatorRE.isValid());
+ // Split filter specification as 'Texts (*.txt[;] *.doc)'
+ // into description and filters specification as '*.txt;*.doc'
+ foreach (const QString &filterString, filters) {
+ const int openingParenPos = filterString.lastIndexOf(QLatin1Char('('));
+ const int closingParenPos = openingParenPos != -1 ?
+ filterString.indexOf(QLatin1Char(')'), openingParenPos + 1) : -1;
+ FilterSpec filterSpec;
+ filterSpec.filter = closingParenPos == -1 ?
+ QString(QLatin1Char('*')) :
+ filterString.mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).trimmed();
+ filterSpec.filter.replace(filterSeparatorRE, separator);
+ filterSpec.description = filterString;
+ if (hideFilterDetails && openingParenPos != -1) { // Do not show pattern in description
+ filterSpec.description.truncate(openingParenPos);
+ while (filterSpec.description.endsWith(QLatin1Char(' ')))
+ filterSpec.description.truncate(filterSpec.description.size() - 1);
+ }
+ *totalStringLength += filterSpec.filter.size() + filterSpec.description.size();
+ result.push_back(filterSpec);
+ }
+ return result;
}
void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters)
@@ -875,48 +907,30 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters)
/* Populates an array of COMDLG_FILTERSPEC from list of filters,
* store the strings in a flat, contiguous buffer. */
m_nameFilters = filters;
- const int size = filters.size();
int totalStringLength = 0;
- for (int i = 0; i < size; ++i)
- totalStringLength += filters.at(i).size();
+ const QList<FilterSpec> specs = filterSpecs(filters, m_hideFiltersDetails, &totalStringLength);
+ const int size = specs.size();
- QScopedArrayPointer<WCHAR> buffer(new WCHAR[totalStringLength * 2 + 2 * size]);
+ QScopedArrayPointer<WCHAR> buffer(new WCHAR[totalStringLength + 2 * size]);
QScopedArrayPointer<COMDLG_FILTERSPEC> comFilterSpec(new COMDLG_FILTERSPEC[size]);
const QString matchesAll = QStringLiteral(" (*)");
- const QRegExp filterSeparatorRE(QStringLiteral("[;\\s]+"));
- const QString separator = QStringLiteral(";");
- Q_ASSERT(filterSeparatorRE.isValid());
-
WCHAR *ptr = buffer.data();
// Split filter specification as 'Texts (*.txt[;] *.doc)'
// into description and filters specification as '*.txt;*.doc'
+
for (int i = 0; i < size; ++i) {
- QString filterString = filters.at(i);
- const int openingParenPos = filterString.lastIndexOf(QLatin1Char('('));
- const int closingParenPos = openingParenPos != -1 ?
- filterString.indexOf(QLatin1Char(')'), openingParenPos + 1) : -1;
- QString filterSpec = closingParenPos == -1 ?
- QString(QLatin1Char('*')) :
- filterString.mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).trimmed();
- filterSpec.replace(filterSeparatorRE, separator);
- if (m_hideFiltersDetails) {
- // Do not show pattern in description
- if (openingParenPos != -1) {
- filterString.truncate(openingParenPos);
- while (filterString.endsWith(QLatin1Char(' ')))
- filterString.truncate(filterString.size() - 1);
- }
- } else {
- // Display glitch: 'All files (*)' shows up as 'All files (*) (*)'
- if (filterString.endsWith(matchesAll))
- filterString.truncate(filterString.size() - matchesAll.size());
- }
+ // Display glitch (CLSID only): 'All files (*)' shows up as 'All files (*) (*)'
+ QString description = specs[i].description;
+ if (!m_hideFiltersDetails && description.endsWith(matchesAll))
+ description.truncate(description.size() - matchesAll.size());
// Add to buffer.
comFilterSpec[i].pszName = ptr;
- toBuffer(filterString, &ptr);
+ ptr += description.toWCharArray(ptr);
+ *ptr++ = 0;
comFilterSpec[i].pszSpec = ptr;
- toBuffer(filterSpec, &ptr);
+ ptr += specs[i].filter.toWCharArray(ptr);
+ *ptr++ = 0;
}
m_fileDialog->SetFileTypes(size, comFilterSpec.data());
@@ -947,9 +961,23 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel
}
}
+// Return the index of the selected filter, accounting for QFileDialog
+// sometimes stripping the filter specification depending on the
+// hideFilterDetails setting.
+static int indexOfNameFilter(const QStringList &filters, const QString &needle)
+{
+ const int index = filters.indexOf(needle);
+ if (index >= 0)
+ return index;
+ for (int i = 0; i < filters.size(); ++i)
+ if (filters.at(i).startsWith(needle))
+ return i;
+ return -1;
+}
+
void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter)
{
- const int index = m_nameFilters.indexOf(filter);
+ const int index = indexOfNameFilter(m_nameFilters, filter);
if (index >= 0) {
m_fileDialog->SetFileTypeIndex(index + 1); // one-based.
} else {
@@ -1270,6 +1298,380 @@ QString QWindowsFileDialogHelper::selectedNameFilter() const
return QString();
}
+#ifndef Q_OS_WINCE
+
+/*!
+ \class QWindowsXpNativeFileDialog
+ \brief Native Windows directory dialog for Windows XP using SHlib-functions.
+
+ Uses the synchronous GetOpenFileNameW(), GetSaveFileNameW() from ComDlg32
+ or SHBrowseForFolder() for directories.
+
+ \internal
+ \sa QWindowsXpFileDialogHelper
+
+ \ingroup qt-lighthouse-win
+*/
+
+class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase
+{
+ Q_OBJECT
+public:
+ typedef QSharedPointer<QFileDialogOptions> OptionsPtr;
+
+ static QWindowsXpNativeFileDialog *create(const OptionsPtr &options);
+
+ virtual void setWindowTitle(const QString &t) { m_title = t; }
+ virtual void exec(HWND owner = 0);
+ virtual QPlatformDialogHelper::DialogCode result() const { return m_result; }
+
+ void setDirectory(const QString &d) { m_directory = d; }
+ QString directory() const { return m_directory; }
+ void selectFile(const QString &f) { m_initialFile = f; }
+ QStringList selectedFiles() const { return m_selectedFiles; }
+ void setNameFilters(const QStringList &n) { m_nameFilters = n; }
+ void selectNameFilter(const QString &f);
+ QString selectedNameFilter() const { return m_selectedNameFilter; }
+
+ int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam);
+
+public slots:
+ virtual void close() {}
+
+private:
+ typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW);
+ typedef BOOL (APIENTRY *PtrGetSaveFileNameW)(LPOPENFILENAMEW);
+
+ explicit QWindowsXpNativeFileDialog(const OptionsPtr &options);
+ void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const;
+ QStringList execExistingDir(HWND owner);
+ QStringList execFileNames(HWND owner, int *selectedFilterIndex) const;
+
+ const OptionsPtr m_options;
+ QString m_title;
+ QString m_directory;
+ QString m_initialFile;
+ QStringList m_selectedFiles;
+ QString m_selectedNameFilter;
+ QStringList m_nameFilters;
+ QPlatformDialogHelper::DialogCode m_result;
+
+ static PtrGetOpenFileNameW m_getOpenFileNameW;
+ static PtrGetSaveFileNameW m_getSaveFileNameW;
+};
+
+QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = 0;
+QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = 0;
+
+QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options)
+{
+ // GetOpenFileNameW() GetSaveFileName() are resolved
+ // dynamically as not to create a dependency on Comdlg32, which
+ // is used on XP only.
+ if (!m_getOpenFileNameW) {
+ QSystemLibrary library(QStringLiteral("Comdlg32"));
+ m_getOpenFileNameW = (PtrGetOpenFileNameW)(library.resolve("GetOpenFileNameW"));
+ m_getSaveFileNameW = (PtrGetSaveFileNameW)(library.resolve("GetSaveFileNameW"));
+ }
+ if (m_getOpenFileNameW && m_getSaveFileNameW)
+ return new QWindowsXpNativeFileDialog(options);
+ return 0;
+}
+
+QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options) :
+ m_options(options), m_result(QPlatformDialogHelper::Rejected)
+{
+ const QStringList nameFilters = m_options->nameFilters();
+ if (!nameFilters.isEmpty())
+ setNameFilters(nameFilters);
+ const QString initialDirectory = m_options->initialDirectory();
+ if (!initialDirectory.isEmpty())
+ setDirectory(initialDirectory);
+ const QString initialNameFilter = m_options->initiallySelectedNameFilter();
+ if (!initialNameFilter.isEmpty())
+ selectNameFilter(initialNameFilter);
+ const QStringList selectedFiles = m_options->initiallySelectedFiles();
+ if (!selectedFiles.isEmpty())
+ selectFile(selectedFiles.front());
+ setWindowTitle(m_options->windowTitle());
+}
+
+void QWindowsXpNativeFileDialog::selectNameFilter(const QString &f)
+{
+ const int index = indexOfNameFilter(m_nameFilters, f);
+ if (index >= 0)
+ m_selectedNameFilter = m_nameFilters.at(index);
+}
+
+void QWindowsXpNativeFileDialog::exec(HWND owner)
+{
+ int selectedFilterIndex = -1;
+ m_selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ?
+ execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex);
+ QWindowsDialogs::eatMouseMove();
+ if (m_selectedFiles.isEmpty()) {
+ m_result = QPlatformDialogHelper::Rejected;
+ emit rejected();
+ } else {
+ if (selectedFilterIndex >= 0 && selectedFilterIndex < m_nameFilters.size()) {
+ m_selectedNameFilter = m_nameFilters.at(selectedFilterIndex);
+ } else {
+ m_selectedNameFilter.clear();
+ }
+ m_directory = QFileInfo(m_selectedFiles.front()).absolutePath();
+ m_result = QPlatformDialogHelper::Accepted;
+ emit accepted();
+ }
+}
+
+// Callback for QWindowsNativeXpFileDialog directory dialog.
+// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
+
+static int CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ QWindowsXpNativeFileDialog *dialog = reinterpret_cast<QWindowsXpNativeFileDialog *>(lpData);
+ return dialog->existingDirCallback(hwnd, uMsg, lParam);
+}
+
+#ifdef Q_CC_MINGW
+typedef ITEMIDLIST *qt_LpItemIdList;
+#else
+typedef PIDLIST_ABSOLUTE qt_LpItemIdList;
+#endif
+
+int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
+{
+ switch (uMsg) {
+ case BFFM_INITIALIZED:
+ if (!m_initialFile.isEmpty())
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(m_initialFile.utf16()));
+ break;
+ case BFFM_SELCHANGED: {
+ wchar_t path[MAX_PATH];
+ const bool ok = SHGetPathFromIDList(reinterpret_cast<qt_LpItemIdList>(lParam), path)
+ && path[0];
+ SendMessage(hwnd, BFFM_ENABLEOK, ok ? 1 : 0, 1);
+ }
+ break;
+ }
+ return 0;
+}
+
+QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner)
+{
+ BROWSEINFO bi;
+ wchar_t initPath[MAX_PATH];
+ initPath[0] = 0;
+ bi.hwndOwner = owner;
+ bi.pidlRoot = NULL;
+ //### This does not seem to be respected? - the dialog always displays "Browse for folder"
+ bi.lpszTitle = (wchar_t*)m_title.utf16();
+ bi.pszDisplayName = initPath;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = xpFileDialogGetExistingDirCallbackProc;
+ bi.lParam = LPARAM(this);
+ QStringList 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)));
+ IMalloc *pMalloc;
+ if (SHGetMalloc(&pMalloc) == NOERROR) {
+ pMalloc->Free(pItemIDList);
+ pMalloc->Release();
+ }
+ }
+ 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
+{
+ ZeroMemory(ofn, sizeof(OPENFILENAME));
+ ofn->lStructSize = sizeof(OPENFILENAME);
+ ofn->hwndOwner = owner;
+
+ // Create a buffer with the filter strings.
+ int totalStringLength = 0;
+ QList<FilterSpec> specs =
+ filterSpecs(m_options->nameFilters(), m_options->options() & QFileDialogOptions::HideNameFilterDetails, &totalStringLength);
+ const int size = specs.size();
+ wchar_t *ptr = new wchar_t[totalStringLength + 2 * size + 1];
+ ofn->lpstrFilter = ptr;
+ foreach (const FilterSpec &spec, specs) {
+ ptr += spec.description.toWCharArray(ptr);
+ *ptr++ = 0;
+ ptr += spec.filter.toWCharArray(ptr);
+ *ptr++ = 0;
+ }
+ *ptr = 0;
+ const int nameFilterIndex = indexOfNameFilter(m_nameFilters, m_selectedNameFilter);
+ if (nameFilterIndex >= 0)
+ ofn->nFilterIndex = nameFilterIndex + 1; // 1..n based.
+ // lpstrFile receives the initial selection and is the buffer
+ // for the target. If it contains any invalid character, the dialog
+ // will not show.
+ ofn->nMaxFile = 65535;
+ const QString initiallySelectedFile =
+ QDir::toNativeSeparators(m_initialFile).remove(QLatin1Char('<')).
+ remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|'));
+ ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile);
+ ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_directory));
+ 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
+ // if no extension was given and if the current filter does not have an
+ // extension (e.g (*)). If the current filter has an extension, use
+ // the extension of the current filter".
+ if (m_options->acceptMode() == QFileDialogOptions::AcceptSave) {
+ QString defaultSuffix = m_options->defaultSuffix();
+ if (defaultSuffix.startsWith(QLatin1Char('.')))
+ defaultSuffix.remove(0, 1);
+ if (!defaultSuffix.isEmpty())
+ ofn->lpstrDefExt = qStringToWCharArray(defaultSuffix);
+ }
+ // Flags.
+ ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST);
+ if (m_options->fileMode() == QFileDialogOptions::ExistingFile
+ || m_options->fileMode() == QFileDialogOptions::ExistingFiles)
+ ofn->Flags |= (OFN_FILEMUSTEXIST);
+ if (m_options->fileMode() == QFileDialogOptions::ExistingFiles)
+ ofn->Flags |= (OFN_ALLOWMULTISELECT);
+ if (!(m_options->options() & QFileDialogOptions::DontConfirmOverwrite))
+ ofn->Flags |= OFN_OVERWRITEPROMPT;
+}
+
+QStringList QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const
+{
+ *selectedFilterIndex = -1;
+ OPENFILENAME ofn;
+ populateOpenFileName(&ofn, owner);
+ QStringList 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)));
+ // 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;
+ if (*ptr) {
+ const QString path = result.takeAt(0) + QLatin1Char('/');
+ while (*ptr) {
+ const QString fileName = QString::fromWCharArray(ptr);
+ result.push_back(path + fileName);
+ ptr += fileName.size() + 1;
+ } // extract multiple files
+ } // has multiple files
+ } // multiple flag set
+ }
+ delete [] ofn.lpstrFile;
+ delete [] ofn.lpstrInitialDir;
+ delete [] ofn.lpstrFilter;
+ delete [] ofn.lpstrDefExt;
+ return result;
+}
+
+/*!
+ \class QWindowsXpFileDialogHelper
+ \brief Dialog helper using QWindowsXpNativeFileDialog
+
+ \sa QWindowsXpNativeFileDialog
+ \internal
+ \ingroup qt-lighthouse-win
+*/
+
+class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDialogHelper>
+{
+public:
+ QWindowsXpFileDialogHelper() {}
+ virtual bool supportsNonModalDialog() 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;
+
+private:
+ virtual QWindowsNativeDialogBase *createNativeDialog();
+ inline QWindowsXpNativeFileDialog *nativeFileDialog() const
+ { return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); }
+};
+
+QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog()
+{
+ if (QWindowsNativeDialogBase *result = QWindowsXpNativeFileDialog::create(options())) {
+ QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept()));
+ QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject()));
+ return result;
+ }
+ return 0;
+}
+
+void QWindowsXpFileDialogHelper::setDirectory(const QString &directory)
+{
+ if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
+ nfd->setDirectory(directory);
+}
+
+QString QWindowsXpFileDialogHelper::directory() const
+{
+ if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
+ return nfd->directory();
+ return QString();
+}
+
+void QWindowsXpFileDialogHelper::selectFile(const QString &filename)
+{
+ if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
+ nfd->selectFile(filename);
+}
+
+QStringList QWindowsXpFileDialogHelper::selectedFiles() const
+{
+ if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
+ return nfd->selectedFiles();
+ return QStringList();
+}
+
+void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &n)
+{
+ if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
+ nfd->setNameFilters(n);
+}
+
+void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f)
+{
+ if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
+ nfd->selectNameFilter(f);
+}
+
+QString QWindowsXpFileDialogHelper::selectedNameFilter() const
+{
+ if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
+ return nfd->selectedNameFilter();
+ return QString();
+}
+
+#endif // Q_OS_WINCE
+
/*!
\class QWindowsNativeColorDialog
\brief Native Windows color dialog.
@@ -1399,10 +1801,11 @@ namespace QWindowsDialogs {
// QWindowsDialogHelperBase creation functions
bool useHelper(QPlatformTheme::DialogType type)
{
+ if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs)
+ return false;
switch (type) {
case QPlatformTheme::FileDialog:
- return true;
- break;
+ return QSysInfo::windowsVersion() >= QSysInfo::WV_XP;
case QPlatformTheme::ColorDialog:
#ifdef USE_NATIVE_COLOR_DIALOG
return true;
@@ -1417,9 +1820,20 @@ bool useHelper(QPlatformTheme::DialogType type)
QPlatformDialogHelper *createHelper(QPlatformTheme::DialogType type)
{
+ if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs)
+ return 0;
switch (type) {
case QPlatformTheme::FileDialog:
+#ifndef Q_OS_WINCE
+ if (QWindowsIntegration::instance()->options() & QWindowsIntegration::XpNativeDialogs
+ || QSysInfo::windowsVersion() == QSysInfo::WV_XP) {
+ return new QWindowsXpFileDialogHelper();
+ }
+ if (QSysInfo::windowsVersion() > QSysInfo::WV_XP)
+ return new QWindowsFileDialogHelper();
+#else
return new QWindowsFileDialogHelper();
+#endif // Q_OS_WINCE
case QPlatformTheme::ColorDialog:
#ifdef USE_NATIVE_COLOR_DIALOG
return new QWindowsColorDialogHelper();
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index f74b2140f6..805046c715 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -301,9 +301,15 @@ public:
STDMETHOD(GiveFeedback)(DWORD dwEffect);
private:
- typedef QMap <Qt::DropAction, HCURSOR> ActionCursorMap;
-
- inline void clearCursors();
+ class DragCursorHandle {
+ Q_DISABLE_COPY(DragCursorHandle)
+ public:
+ DragCursorHandle(HCURSOR c, quint64 k) : cursor(c), cacheKey(k) {}
+ ~DragCursorHandle() { DestroyCursor(cursor); }
+ HCURSOR cursor;
+ quint64 cacheKey;
+ };
+ typedef QMap <Qt::DropAction, QSharedPointer<DragCursorHandle> > ActionCursorMap;
QWindowsDrag *m_drag;
Qt::MouseButtons m_currentButtons;
@@ -322,7 +328,7 @@ QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) :
QWindowsOleDropSource::~QWindowsOleDropSource()
{
- clearCursors();
+ m_cursors.clear();
if (QWindowsContext::verboseOLE)
qDebug("%s", __FUNCTION__);
}
@@ -347,10 +353,14 @@ void QWindowsOleDropSource::createCursors()
QPixmap cpm = drag->dragCursor(action);
if (cpm.isNull())
cpm = m_drag->defaultCursor(action);
+ QSharedPointer<DragCursorHandle> cursorHandler = m_cursors.value(action);
+ if (!cursorHandler.isNull() && cpm.cacheKey() == cursorHandler->cacheKey)
+ continue;
if (cpm.isNull()) {
qWarning("%s: Unable to obtain drag cursor for %d.", __FUNCTION__, action);
continue;
}
+
int w = cpm.width();
int h = cpm.height();
@@ -380,23 +390,14 @@ void QWindowsOleDropSource::createCursors()
const int hotX = hasPixmap ? qMax(0,newHotSpot.x()) : 0;
const int hotY = hasPixmap ? qMax(0,newHotSpot.y()) : 0;
- if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY))
- m_cursors.insert(actions.at(cnum), sysCursor);
+ if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY)) {
+ m_cursors.insert(action, QSharedPointer<DragCursorHandle>(new DragCursorHandle(sysCursor, cpm.cacheKey())));
+ }
}
if (QWindowsContext::verboseOLE)
qDebug("%s %d cursors", __FUNCTION__, m_cursors.size());
}
-void QWindowsOleDropSource::clearCursors()
-{
- if (!m_cursors.isEmpty()) {
- const ActionCursorMap::const_iterator cend = m_cursors.constEnd();
- for (ActionCursorMap::const_iterator it = m_cursors.constBegin(); it != cend; ++it)
- DestroyCursor(it.value());
- m_cursors.clear();
- }
-}
-
//---------------------------------------------------------------------
// IUnknown Methods
//---------------------------------------------------------------------
@@ -488,9 +489,14 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
if (QWindowsContext::verboseOLE > 2)
qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action);
+ QSharedPointer<DragCursorHandle> cursorHandler = m_cursors.value(action);
+ quint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey();
+ if (cursorHandler.isNull() || currentCacheKey != cursorHandler->cacheKey)
+ createCursors();
+
const ActionCursorMap::const_iterator it = m_cursors.constFind(action);
if (it != m_cursors.constEnd()) {
- SetCursor(it.value());
+ SetCursor(it.value()->cursor);
return ResultFromScode(S_OK);
}
@@ -595,6 +601,9 @@ QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
POINTL pt, LPDWORD pdwEffect)
{
+ if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper())
+ dh->DragEnter(reinterpret_cast<HWND>(m_window->winId()), pDataObj, reinterpret_cast<POINT*>(&pt), *pdwEffect);
+
if (QWindowsContext::verboseOLE)
qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, m_window, grfKeyState, pt.x, pt.y);
@@ -608,6 +617,9 @@ QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
+ if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper())
+ dh->DragOver(reinterpret_cast<POINT*>(&pt), *pdwEffect);
+
QWindow *dragOverWindow = findDragOverWindow(pt);
if (QWindowsContext::verboseOLE)
qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, dragOverWindow, grfKeyState, pt.x, pt.y);
@@ -628,6 +640,9 @@ QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropTarget::DragLeave()
{
+ if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper())
+ dh->DragLeave();
+
if (QWindowsContext::verboseOLE)
qDebug().nospace() <<__FUNCTION__ << ' ' << m_window;
@@ -640,9 +655,12 @@ QWindowsOleDropTarget::DragLeave()
#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
-QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState,
+QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
POINTL pt, LPDWORD pdwEffect)
{
+ if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper())
+ dh->Drop(pDataObj, reinterpret_cast<POINT*>(&pt), *pdwEffect);
+
QWindow *dropWindow = findDragOverWindow(pt);
if (QWindowsContext::verboseOLE)
@@ -700,6 +718,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState,
return NOERROR;
}
+
/*!
\class QWindowsDrag
\brief Windows drag implementation.
@@ -707,12 +726,15 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState,
\ingroup qt-lighthouse-win
*/
-QWindowsDrag::QWindowsDrag() : m_dropDataObject(0)
+QWindowsDrag::QWindowsDrag() :
+ m_dropDataObject(0), m_cachedDropTargetHelper(0)
{
}
QWindowsDrag::~QWindowsDrag()
{
+ if (m_cachedDropTargetHelper)
+ m_cachedDropTargetHelper->Release();
}
/*!
@@ -726,6 +748,18 @@ QMimeData *QWindowsDrag::dropData()
return &m_dropData;
}
+/*!
+ \brief May be used to handle extended cursors functionality for drags from outside the app.
+*/
+IDropTargetHelper* QWindowsDrag::dropHelper() {
+ if (!m_cachedDropTargetHelper) {
+ CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER,
+ IID_IDropTargetHelper,
+ reinterpret_cast<void**>(&m_cachedDropTargetHelper));
+ }
+ return m_cachedDropTargetHelper;
+}
+
QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const
{
switch (action) {
diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h
index ab06545884..d3bfd36955 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.h
+++ b/src/plugins/platforms/windows/qwindowsdrag.h
@@ -47,6 +47,8 @@
#include <qpa/qplatformdrag.h>
#include <QtGui/QPixmap>
+struct IDropTargetHelper;
+
QT_BEGIN_NAMESPACE
class QWindowsDropMimeData : public QWindowsInternalMimeData {
public:
@@ -100,12 +102,16 @@ public:
void releaseDropDataObject();
QMimeData *dropData();
+ IDropTargetHelper* dropHelper();
+
QPixmap defaultCursor(Qt::DropAction action) const;
private:
QWindowsDropMimeData m_dropData;
IDataObject *m_dropDataObject;
+ IDropTargetHelper* m_cachedDropTargetHelper;
+
mutable QPixmap m_copyDragCursor;
mutable QPixmap m_moveDragCursor;
mutable QPixmap m_linkDragCursor;
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index b7309c3f7c..a02f0cd494 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -279,6 +279,12 @@ static inline unsigned parseOptions(const QStringList &paramList)
} else if (param.endsWith(QLatin1String("native"))) {
options |= QWindowsIntegration::FontDatabaseNative;
}
+ } else if (param.startsWith(QLatin1String("dialogs="))) {
+ if (param.endsWith(QLatin1String("xp"))) {
+ options |= QWindowsIntegration::XpNativeDialogs;
+ } else if (param.endsWith(QLatin1String("none"))) {
+ options |= QWindowsIntegration::NoNativeDialogs;
+ }
} else if (param == QLatin1String("gl=gdi")) {
options |= QWindowsIntegration::DisableArb;
}
@@ -332,6 +338,8 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co
#endif // !QT_NO_OPENGL
case WindowMasks:
return true;
+ case MultipleWindows:
+ return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index ca47dabb4b..abf663c052 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -56,7 +56,9 @@ public:
enum Options { // Options to be passed on command line.
FontDatabaseFreeType = 0x1,
FontDatabaseNative = 0x2,
- DisableArb = 0x4
+ DisableArb = 0x4,
+ NoNativeDialogs = 0x8,
+ XpNativeDialogs = 0x10
};
explicit QWindowsIntegration(const QStringList &paramList);
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index d9de911914..2fb905d23b 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -509,6 +509,7 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con
case TrashIcon:
resourceId = 191;
break;
+#ifndef Q_OS_WINCE
case MessageBoxInformation:
iconName = IDI_INFORMATION;
break;
@@ -538,6 +539,7 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con
}
}
break;
+#endif
default:
break;
}
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index 1527f0e496..ca356e1276 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -1,4 +1,6 @@
TARGET = windows
+
+PLUGIN_TYPE = platforms
load(qt_plugin)
QT *= core-private
@@ -6,7 +8,6 @@ QT *= gui-private
QT *= platformsupport-private
INCLUDEPATH += ../../../3rdparty/harfbuzz/src
-QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
# Note: OpenGL32 must precede Gdi32 as it overwrites some functions.
LIBS *= -lole32
@@ -172,6 +173,3 @@ contains(QT_CONFIG, freetype) {
OTHER_FILES += windows.json
contains(QT_CONFIG, accessibility):include(accessible/accessible.pri)
-
-target.path += $$[QT_INSTALL_PLUGINS]/platforms
-INSTALLS += target