diff options
Diffstat (limited to 'src/plugins/platforms/windows')
7 files changed, 150 insertions, 90 deletions
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index 7eb1bd30c0..ce61a8b092 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -721,22 +721,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI if (varChildID.vt != VT_I4) return E_INVALIDARG; - - int childIndex = varChildID.lVal; - - QAccessibleInterface *acc = 0; - - - if (childIndex == 0) { - // Yes, some AT clients (Active Accessibility Object Inspector) - // actually ask for the same object. As a consequence, we need to clone ourselves: - acc = accessible; - } else if (childIndex < 0) { - acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex); - } else { - acc = accessible->child(childIndex - 1); - } - + QAccessibleInterface *acc = childPointer(accessible, varChildID); if (acc) { *ppdispChild = QWindowsAccessibility::wrap(acc); return S_OK; @@ -825,7 +810,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT var QString descr; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; descr = child->text(QAccessible::Description); @@ -850,7 +835,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelp(VARIANT varID, BST QString help; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; help = child->text(QAccessible::Help); @@ -909,7 +894,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST QString name; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; name = child->text(QAccessible::Name); @@ -952,7 +937,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VAR QAccessible::Role role; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; role = child->role(); @@ -987,7 +972,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VA QAccessible::State state; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; state = child->state(); diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h index ef17acf3e9..d4f141c5d8 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h @@ -153,13 +153,23 @@ protected: return 0; } - QAccessibleInterface *childPointer(VARIANT varID) + static QAccessibleInterface *childPointer(QAccessibleInterface *parent, VARIANT varID) { // -1 since windows API always uses 1 for the first child - QAccessibleInterface *iface = accessibleInterface(); - if (iface) - return accessibleInterface()->child(varID.lVal - 1); - return 0; + Q_ASSERT(parent); + + QAccessibleInterface *acc = 0; + int childIndex = varID.lVal; + if (childIndex == 0) { + // Yes, some AT clients (Active Accessibility Object Inspector) + // actually ask for the same object. As a consequence, we need to clone ourselves: + acc = parent; + } else if (childIndex < 0) { + acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex); + } else { + acc = parent->child(childIndex - 1); + } + return acc; } private: diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index 3b2e9787a2..49ddf3106b 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -49,6 +49,10 @@ # define WM_THEMECHANGED 0x031A #endif +#ifndef GWL_HWNDPARENT +# define GWL_HWNDPARENT (-8) +#endif + /* Complement the definitions and declarations missing * when using MinGW or older Windows SDKs. */ diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 3f4555a31f..872fd07729 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -842,9 +842,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::FocusOutEvent: handleFocusEvent(et, platformWindow); return true; - case QtWindows::ShowEvent: - platformWindow->handleShown(); - return false; // Indicate transient children should be shown by windows (SW_PARENTOPENING) case QtWindows::HideEvent: platformWindow->handleHidden(); return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING) diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 5b84725edf..33b4eb4771 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -833,6 +833,7 @@ public: bool hideFiltersDetails() const { return m_hideFiltersDetails; } void setHideFiltersDetails(bool h) { m_hideFiltersDetails = h; } void setDefaultSuffix(const QString &s); + inline bool hasDefaultSuffix() const { return m_hasDefaultSuffix; } inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text); // Return the selected files for tracking in OnSelectionChanged(). @@ -857,6 +858,7 @@ public slots: protected: explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); bool init(const CLSID &clsId, const IID &iid); + void setDefaultSuffixSys(const QString &s); inline IFileDialog * fileDialog() const { return m_fileDialog; } static QString itemPath(IShellItem *item); static QStringList libraryItemFolders(IShellItem *item); @@ -873,12 +875,13 @@ private: DWORD m_cookie; QStringList m_nameFilters; bool m_hideFiltersDetails; + bool m_hasDefaultSuffix; QWindowsFileDialogSharedData m_data; }; QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) : m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false), - m_data(data) + m_hasDefaultSuffix(false), m_data(data) { } @@ -1188,6 +1191,15 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters) void QWindowsNativeFileDialogBase::setDefaultSuffix(const QString &s) { + setDefaultSuffixSys(s); + m_hasDefaultSuffix = !s.isEmpty(); +} + +void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s) +{ + // If this parameter is non-empty, it will be appended by the dialog for the 'Any files' + // filter ('*'). If this parameter is non-empty and the current filter has a suffix, + // the dialog will append the filter's suffix. wchar_t *wSuffix = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(s.utf16())); m_fileDialog->SetDefaultExtension(wSuffix); } @@ -1321,33 +1333,45 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *) class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase { + Q_OBJECT public: - explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : - QWindowsNativeFileDialogBase(data) {} + explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data); virtual QStringList selectedFiles() const; virtual QStringList dialogResult() const; + +private slots: + void slotFilterSelected(const QString &); }; -// Append a suffix from the name filter "Foo files (*.foo;*.bar)" -// unless the file name already has one. -static inline QString appendSuffix(const QString &fileName, const QString &filter) +// Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". +static inline QString suffixFromFilter(const QString &filter) { - const int lastDot = fileName.lastIndexOf(QLatin1Char('.')); - const int lastSlash = fileName.lastIndexOf(QLatin1Char('/')); - if (lastDot >= 0 && (lastSlash == -1 || lastDot > lastSlash)) - return fileName; int suffixPos = filter.indexOf(QLatin1String("(*.")); if (suffixPos < 0) - return fileName; + return QString(); suffixPos += 3; int endPos = filter.indexOf(QLatin1Char(' '), suffixPos + 1); if (endPos < 0) endPos = filter.indexOf(QLatin1Char(';'), suffixPos + 1); if (endPos < 0) endPos = filter.indexOf(QLatin1Char(')'), suffixPos + 1); - if (endPos < 0) - return fileName; - return fileName + QLatin1Char('.') + filter.mid(suffixPos, endPos - suffixPos); + return endPos >= 0 ? filter.mid(suffixPos, endPos - suffixPos) : QString(); +} + +QWindowsNativeSaveFileDialog::QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) + : QWindowsNativeFileDialogBase(data) +{ + connect(this, &QWindowsNativeFileDialogBase::filterSelected, + this, &QWindowsNativeSaveFileDialog::slotFilterSelected); +} + +void QWindowsNativeSaveFileDialog::slotFilterSelected(const QString &filter) +{ + // Cause the dialog to append the suffix of the current filter unless a default + // suffix is set (Note: Qt 4.8 sets the selected filter's suffix before + // calling GetSaveFileName()). + if (!hasDefaultSuffix()) + setDefaultSuffixSys(suffixFromFilter(filter)); } QStringList QWindowsNativeSaveFileDialog::dialogResult() const @@ -1355,7 +1379,7 @@ QStringList QWindowsNativeSaveFileDialog::dialogResult() const QStringList result; IShellItem *item = 0; if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) - result.push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter())); + result.push_back(QWindowsNativeFileDialogBase::itemPath(item)); return result; } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 2a5e08cf41..010197d6d8 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -839,6 +839,15 @@ QWindowsWindow::~QWindowsWindow() destroyIcon(); } +void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) +{ + if (region.isEmpty() && !force) + clearFlag(Exposed); + else + setFlag(Exposed); + QWindowSystemInterface::handleExposeEvent(window(), region); +} + void QWindowsWindow::destroyWindow() { if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) @@ -942,13 +951,19 @@ void QWindowsWindow::setVisible(bool visible) if (m_data.hwnd) { if (visible) { show_sys(); - QWindowSystemInterface::handleExposeEvent(window(), - QRect(QPoint(), geometry().size())); + + // When the window is layered, we won't get WM_PAINT, and "we" are in control + // over the rendering of the window + // There is nobody waiting for this, so we don't need to flush afterwards. + QWindow *w = window(); + if (w->format().hasAlpha() || qFuzzyCompare(w->opacity(), qreal(1))) + fireExpose(QRect(0, 0, w->width(), w->height())); + } else { if (hasMouseCapture()) setMouseGrabEnabled(false); hide_sys(); - QWindowSystemInterface::handleExposeEvent(window(), QRegion()); + fireExpose(QRegion()); } } } @@ -998,6 +1013,24 @@ QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const return pos; } +// Update the transient parent for a toplevel window. The concept does not +// really exist on Windows, the relationship is set by passing a parent along with !WS_CHILD +// to window creation or by setting the parent using GWL_HWNDPARENT (as opposed to +// SetParent, which would make it a real child). +void QWindowsWindow::updateTransientParent() const +{ +#ifndef Q_OS_WINCE + // Update transient parent. + const HWND oldTransientParent = + GetAncestor(m_data.hwnd, GA_PARENT) == GetDesktopWindow() ? GetAncestor(m_data.hwnd, GA_ROOTOWNER) : HWND(0); + HWND newTransientParent = 0; + if (const QWindow *tp = window()->transientParent()) + newTransientParent = QWindowsWindow::handleOf(tp); + if (newTransientParent && newTransientParent != oldTransientParent) + SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent); +#endif // !Q_OS_WINCE +} + // partially from QWidgetPrivate::show_sys() void QWindowsWindow::show_sys() const { @@ -1012,19 +1045,22 @@ void QWindowsWindow::show_sys() const sm = SW_SHOWMINIMIZED; if (!isVisible()) sm = SW_SHOWMINNOACTIVE; - } else if (state & Qt::WindowMaximized) { - sm = SW_SHOWMAXIMIZED; - // Windows will not behave correctly when we try to maximize a window which does not - // have minimize nor maximize buttons in the window frame. Windows would then ignore - // non-available geometry, and rather maximize the widget to the full screen, minus the - // window frame (caption). So, we do a trick here, by adding a maximize button before - // maximizing the widget, and then remove the maximize button afterwards. - if (flags & Qt::WindowTitleHint && - !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) { - fakedMaximize = TRUE; - setStyle(style() | WS_MAXIMIZEBOX); - } - } + } else { + updateTransientParent(); + if (state & Qt::WindowMaximized) { + sm = SW_SHOWMAXIMIZED; + // Windows will not behave correctly when we try to maximize a window which does not + // have minimize nor maximize buttons in the window frame. Windows would then ignore + // non-available geometry, and rather maximize the widget to the full screen, minus the + // window frame (caption). So, we do a trick here, by adding a maximize button before + // maximizing the widget, and then remove the maximize button afterwards. + if (flags & Qt::WindowTitleHint && + !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) { + fakedMaximize = TRUE; + setStyle(style() | WS_MAXIMIZEBOX); + } + } // Qt::WindowMaximized + } // !Qt::WindowMinimized } if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool) sm = SW_SHOWNOACTIVATE; @@ -1094,14 +1130,9 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const } } -void QWindowsWindow::handleShown() -{ - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); -} - void QWindowsWindow::handleHidden() { - QWindowSystemInterface::handleExposeEvent(window(), QRegion()); + fireExpose(QRegion()); } void QWindowsWindow::setGeometry(const QRect &rectIn) @@ -1267,28 +1298,21 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, if (message == WM_ERASEBKGND) // Backing store - ignored. return true; PAINTSTRUCT ps; - if (testFlag(OpenGLSurface)) { - // Observed painting problems with Aero style disabled (QTBUG-7865). - if (testFlag(OpenGLDoubleBuffered)) - InvalidateRect(hwnd, 0, false); - BeginPaint(hwnd, &ps); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(qrectFromRECT(ps.rcPaint))); - if (!QWindowsContext::instance()->asyncExpose()) - QWindowSystemInterface::flushWindowSystemEvents(); - EndPaint(hwnd, &ps); - } else { - BeginPaint(hwnd, &ps); - const QRect updateRect = qrectFromRECT(ps.rcPaint); + // Observed painting problems with Aero style disabled (QTBUG-7865). + if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered)) + InvalidateRect(hwnd, 0, false); - if (QWindowsContext::verboseIntegration) - qDebug() << __FUNCTION__ << this << window() << updateRect; + BeginPaint(hwnd, &ps); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(updateRect)); - if (!QWindowsContext::instance()->asyncExpose()) - QWindowSystemInterface::flushWindowSystemEvents(); - EndPaint(hwnd, &ps); - } + // If the a window is obscured by another window (such as a child window) + // we still need to send isExposed=true, for compatibility. + // Our tests depend on it. + fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true); + if (!QWindowsContext::instance()->asyncExpose()) + QWindowSystemInterface::flushWindowSystemEvents(); + + EndPaint(hwnd, &ps); return true; } @@ -1366,9 +1390,23 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) } } +// Return the effective screen for full screen mode in a virtual desktop. +static const QScreen *effectiveScreen(const QWindow *w) +{ + QPoint center = w->geometry().center(); + if (!w->isTopLevel()) + center = w->mapToGlobal(center); + const QScreen *screen = w->screen(); + if (!screen->geometry().contains(center)) + foreach (const QScreen *sibling, screen->virtualSiblings()) + if (sibling->geometry().contains(center)) + return sibling; + return screen; +} + bool QWindowsWindow::isFullScreen_sys() const { - return geometry_sys() == window()->screen()->geometry(); + return geometry_sys() == effectiveScreen(window())->geometry(); } /*! @@ -1444,7 +1482,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) newStyle |= WS_VISIBLE; setStyle(newStyle); - const QRect r = window()->screen()->geometry(); + const QRect r = effectiveScreen(window())->geometry(); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 2117ca50b8..6c735ede7d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -133,7 +133,8 @@ public: WithinSetStyle = 0x800, WithinDestroy = 0x1000, TouchRegistered = 0x2000, - AlertState = 0x4000 + AlertState = 0x4000, + Exposed = 0x08000 }; struct WindowData @@ -161,7 +162,7 @@ public: virtual void setVisible(bool visible); bool isVisible() const; - virtual bool isExposed() const { return m_windowState != Qt::WindowMinimized && isVisible(); } + virtual bool isExposed() const { return testFlag(Exposed); } virtual bool isActive() const; virtual bool isEmbedded(const QPlatformWindow *parentWindow) const; virtual QPoint mapToGlobal(const QPoint &pos) const; @@ -217,7 +218,6 @@ public: void handleMoved(); void handleResized(int wParam); - void handleShown(); void handleHidden(); static inline HWND handleOf(const QWindow *w); @@ -272,12 +272,14 @@ private: inline bool isFullScreen_sys() const; inline void setWindowState_sys(Qt::WindowState newState); inline void setParent_sys(const QPlatformWindow *parent) const; + inline void updateTransientParent() const; void destroyWindow(); void registerDropSite(); void unregisterDropSite(); void handleGeometryChange(); void handleWindowStateChange(Qt::WindowState state); inline void destroyIcon(); + void fireExpose(const QRegion ®ion, bool force=false); mutable WindowData m_data; mutable unsigned m_flags; |