Windows QPA: Improve handling of windows of type Qt::ForeignWindow.

Extract a base class QWindowsBaseWindow from QWindowsWindow that provides
_sys() getters for geometry and margin calculation and implements
QPlatformWindow::geometry()/ frameMargins() to be calculated from the
HWND.

Implement a QWindowsDesktopWindow class directly inheriting
QWindowsBaseWindow which does not allow any manipulation.

Add a thin QWindowsForeignWindow class that wraps a foreign window id and
always returns correct geometry/margin information when queried. Simple
reparenting and manipulation of geometry for child windows is also implemented,
allowing for embedding foreign windows into Qt. When calling other setters on
it, the unimplemented warnings of QPlatformWindow will trigger.

Remove the special casing for foreign/desktop window from QWindowsWindow.
The existing mechanism to cache the geometry/margin values in QWindowsWindow
remains as is.

Rename the existing QWindowsWindow::baseWindowOf() and add checks there.

Task-number: QTBUG-50206
Task-number: QTBUG-41186
Change-Id: Ib57cb87e3981312d32920fe3e49f0b1c4ad516a3
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
This commit is contained in:
Friedemann Kleint 2016-01-08 14:59:22 +01:00
parent 6b285de8ec
commit 14efcaa392
8 changed files with 308 additions and 132 deletions

View File

@ -84,7 +84,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
const QRect br = region.boundingRect();
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br;
QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window);
QWindowsWindow *rw = QWindowsWindow::windowsWindowOf(window);
Q_ASSERT(rw);
#ifndef Q_OS_WINCE
const bool hasAlpha = rw->format().hasAlpha();

View File

@ -1177,8 +1177,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
d->m_tabletSupport->notifyActivate();
#endif // !QT_NO_TABLETEVENT
if (platformWindow->testFlag(QWindowsWindow::BlockedByModal))
if (const QWindow *modalWindow = QGuiApplication::modalWindow())
QWindowsWindow::baseWindowOf(modalWindow)->alertWindow();
if (const QWindow *modalWindow = QGuiApplication::modalWindow()) {
QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(modalWindow);
Q_ASSERT(platformWindow);
platformWindow->alertWindow();
}
break;
case QtWindows::MouseActivateWindowEvent:
if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) {

View File

@ -648,17 +648,19 @@ QWindowsCursor::QWindowsCursor(const QPlatformScreen *screen)
void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
{
if (!window)
QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window);
if (!platformWindow) // Desktop/Foreign window.
return;
if (!cursorIn) {
QWindowsWindow::baseWindowOf(window)->setCursor(CursorHandlePtr(new CursorHandle));
platformWindow->setCursor(CursorHandlePtr(new CursorHandle));
return;
}
const CursorHandlePtr wcursor =
cursorIn->shape() == Qt::BitmapCursor ?
pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
if (wcursor->handle()) {
QWindowsWindow::baseWindowOf(window)->setCursor(wcursor);
platformWindow->setCursor(wcursor);
} else {
qWarning("%s: Unable to obtain system cursor for %d",
__FUNCTION__, cursorIn->shape());

View File

@ -233,12 +233,10 @@ void QWindowsInputContext::updateEnabled()
{
if (!QGuiApplication::focusObject())
return;
const QWindow *window = QGuiApplication::focusWindow();
if (window && window->handle()) {
QWindowsWindow *platformWindow = QWindowsWindow::baseWindowOf(window);
if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(QGuiApplication::focusWindow())) {
const bool accepted = inputMethodAccepted();
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaInputMethods) << __FUNCTION__ << window << "accepted=" << accepted;
qCDebug(lcQpaInputMethods) << __FUNCTION__ << platformWindow->window() << "accepted=" << accepted;
QWindowsInputContext::setWindowsImeEnabled(platformWindow, accepted);
}
}

View File

@ -302,6 +302,26 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co
QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const
{
if (window->type() == Qt::Desktop) {
QWindowsDesktopWindow *result = new QWindowsDesktopWindow(window);
qCDebug(lcQpaWindows) << "Desktop window:" << window
<< showbase << hex << result->winId() << noshowbase << dec << result->geometry();
return result;
}
if (window->type() == Qt::ForeignWindow) {
QWindowsForeignWindow *result = new QWindowsForeignWindow(window, reinterpret_cast<HWND>(window->winId()));
const QRect obtainedGeometry = result->geometry();
QScreen *screen = Q_NULLPTR;
if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry))
screen = pScreen->screen();
if (screen && screen != window->screen())
window->setScreen(screen);
qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex
<< result->winId() << noshowbase << dec << obtainedGeometry << screen;
return result;
}
QWindowsWindowData requested;
requested.flags = window->flags();
requested.geometry = QHighDpi::toNativePixels(window->geometry(), window);

View File

@ -267,7 +267,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
// Capture is necessary so we don't get WM_MOUSELEAVEs to confuse matters.
// This autocapture is released normally when button is released.
if (!platformWindow->hasMouseCapture()) {
QWindowsWindow::baseWindowOf(window)->applyCursor();
platformWindow->applyCursor();
platformWindow->setMouseGrabEnabled(true);
platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
qCDebug(lcQpaEvents) << "Automatic mouse capture for missing buttondown event" << window;
@ -355,7 +355,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
m_trackedWindow = 0;
// We are not officially in any window, but we need to set some cursor to clear
// whatever cursor the left window had, so apply the cursor of the capture window.
QWindowsWindow::baseWindowOf(window)->applyCursor();
platformWindow->applyCursor();
}
}
// Enter is needed if:
@ -367,7 +367,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|| (m_previousCaptureWindow && window != m_previousCaptureWindow && currentWindowUnderMouse
&& currentWindowUnderMouse != m_previousCaptureWindow)) {
qCDebug(lcQpaEvents) << "Entering " << currentWindowUnderMouse;
QWindowsWindow::baseWindowOf(currentWindowUnderMouse)->applyCursor();
if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderMouse))
wumPlatformWindow->applyCursor();
QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse,
currentWindowUnderMouse->mapFromGlobal(globalPosition),
globalPosition);
@ -392,7 +393,7 @@ static bool isValidWheelReceiver(QWindow *candidate)
{
if (candidate) {
const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate);
if (const QWindowsWindow *ww = QWindowsWindow::baseWindowOf(toplevel))
if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel))
return !ww->testFlag(QWindowsWindow::BlockedByModal);
}

View File

@ -418,7 +418,7 @@ struct WindowCreationData
enum Flags { ForceChild = 0x1, ForceTopLevel = 0x2 };
WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0),
topLevel(false), popup(false), dialog(false), desktop(false),
topLevel(false), popup(false), dialog(false),
tool(false), embedded(false), hasAlpha(false) {}
void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0);
@ -434,7 +434,6 @@ struct WindowCreationData
bool topLevel;
bool popup;
bool dialog;
bool desktop;
bool tool;
bool embedded;
bool hasAlpha;
@ -449,7 +448,7 @@ QDebug operator<<(QDebug debug, const WindowCreationData &d)
<< "\n topLevel=" << d.topLevel;
if (d.parentHandle)
debug << " parent=" << d.parentHandle;
debug << " popup=" << d.popup << " dialog=" << d.dialog << " desktop=" << d.desktop
debug << " popup=" << d.popup << " dialog=" << d.dialog
<< " embedded=" << d.embedded << " tool=" << d.tool
<< "\n style=" << debugWinStyle(d.style);
if (d.exStyle)
@ -518,9 +517,6 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
case Qt::Popup:
popup = true;
break;
case Qt::Desktop:
desktop = true;
break;
default:
break;
}
@ -537,7 +533,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
style = WS_POPUP;
} else if (topLevel && !desktop) {
} else if (topLevel) {
if (flags & Qt::FramelessWindowHint)
style = WS_POPUP; // no border
else if (flags & Qt::WindowTitleHint)
@ -548,7 +544,6 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
style = WS_CHILD;
}
if (!desktop) {
// if (!testAttribute(Qt::WA_PaintUnclipped))
// ### Commented out for now as it causes some problems, but
// this should be correct anyway, so dig some more into this
@ -594,7 +589,6 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
if (flagsIn & Qt::WindowTransparentForInput)
exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
#endif
}
}
}
@ -606,26 +600,6 @@ QWindowsWindowData
WindowData result;
result.flags = flags;
if (desktop) { // desktop widget. No frame, hopefully?
result.hwnd = GetDesktopWindow();
result.geometry = frameGeometry(result.hwnd, true);
result.embedded = false;
qCDebug(lcQpaWindows) << "Created desktop window " << w << result.hwnd;
return result;
}
if ((flags & Qt::WindowType_Mask) == Qt::ForeignWindow) {
result.hwnd = reinterpret_cast<HWND>(w->winId());
Q_ASSERT(result.hwnd);
const LONG_PTR style = GetWindowLongPtr(result.hwnd, GWL_STYLE);
const LONG_PTR exStyle = GetWindowLongPtr(result.hwnd, GWL_EXSTYLE);
result.embedded = false;
result.frame = QWindowsGeometryHint::frame(style, exStyle);
result.geometry = frameGeometry(result.hwnd, !GetParent(result.hwnd))
.marginsRemoved(result.frame);
qCDebug(lcQpaWindows) << "Foreign window: " << w << result.hwnd << result.geometry;
return result;
}
const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
@ -697,7 +671,7 @@ void WindowCreationData::applyWindowFlags(HWND hwnd) const
void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChange, qreal opacityLevel) const
{
if (desktop || !hwnd)
if (!hwnd)
return;
UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE;
if (frameChange)
@ -848,6 +822,153 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
== QWindowPrivate::WindowFrameInclusive;
}
/*!
\class QWindowsBaseWindow
\brief Base class for QWindowsForeignWindow, QWindowsWindow
The class provides some _sys() getters for querying window
data from a HWND and some _sys() setters.
Derived classes wrapping foreign windows may use them directly
to calculate geometry, margins, etc.
Derived classes representing windows created by Qt may defer
expensive calculations until change notifications are received.
\since 5.6
\internal
\ingroup qt-lighthouse-win
*/
QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w)
{
if (w) {
if (QPlatformWindow *pw = w->handle())
return static_cast<QWindowsBaseWindow *>(pw);
}
return Q_NULLPTR;
}
HWND QWindowsBaseWindow::handleOf(const QWindow *w)
{
const QWindowsBaseWindow *bw = QWindowsBaseWindow::baseWindowOf(w);
return bw ? bw->handle() : HWND(0);
}
bool QWindowsBaseWindow::isTopLevel_sys() const
{
const HWND parent = parentHwnd();
return !parent || parent == GetDesktopWindow();
}
QRect QWindowsBaseWindow::frameGeometry_sys() const
{
return frameGeometry(handle(), isTopLevel());
}
QRect QWindowsBaseWindow::geometry_sys() const
{
return frameGeometry_sys().marginsRemoved(frameMargins());
}
QMargins QWindowsBaseWindow::frameMargins_sys() const
{
return QWindowsGeometryHint::frame(style(), exStyle());
}
void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows.
{
SetWindowPos(handle(),0 , 0, 0, 0, 0,
SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
void QWindowsBaseWindow::raise_sys()
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
void QWindowsBaseWindow::lower_sys()
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
SetWindowPos(handle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
void QWindowsBaseWindow::setWindowTitle_sys(const QString &title)
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << title;
SetWindowText(handle(), reinterpret_cast<const wchar_t *>(title.utf16()));
}
QPoint QWindowsBaseWindow::mapToGlobal(const QPoint &pos) const
{
return QWindowsGeometryHint::mapToGlobal(handle(), pos);
}
QPoint QWindowsBaseWindow::mapFromGlobal(const QPoint &pos) const
{
return QWindowsGeometryHint::mapFromGlobal(handle(), pos);
}
/*!
\class QWindowsDesktopWindow
\brief Window wrapping GetDesktopWindow not allowing any manipulation.
\since 5.6
\internal
\ingroup qt-lighthouse-win
*/
/*!
\class QWindowsForeignWindow
\brief Window wrapping a foreign native window.
QWindowsForeignWindow stores a native HWND and implements getters for
geometry, margins, etc. reparenting and geometry manipulation for use as a
child window in Qt.
\since 5.6
\internal
\ingroup qt-lighthouse-win
*/
QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
: QWindowsBaseWindow(window)
, m_hwnd(hwnd)
, m_topLevelStyle(0)
{
}
void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
{
const bool wasTopLevel = isTopLevel_sys();
const HWND newParent = newParentWindow ? reinterpret_cast<HWND>(newParentWindow->winId()) : HWND(0);
const bool isTopLevel = !newParent;
const DWORD oldStyle = style();
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << "newParent="
<< newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle);
SetParent(m_hwnd, newParent);
if (wasTopLevel != isTopLevel) { // Top level window flags need to be set/cleared manually.
DWORD newStyle = oldStyle;
if (isTopLevel) {
newStyle = m_topLevelStyle;
} else {
m_topLevelStyle = oldStyle;
newStyle &= ~(WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW);
newStyle |= WS_CHILD;
}
SetWindowLongPtr(m_hwnd, GWL_STYLE, newStyle);
}
}
void QWindowsForeignWindow::setVisible(bool visible)
{
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << visible;
if (visible)
ShowWindow(handle(), SW_SHOWNOACTIVATE);
else
hide_sys();
}
/*!
\class QWindowCreationContext
\brief Active Context for creating windows.
@ -928,7 +1049,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
*/
QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) :
QPlatformWindow(aWindow),
QWindowsBaseWindow(aWindow),
m_data(data),
m_flags(WithinCreate),
m_hdc(0),
@ -1006,7 +1127,7 @@ void QWindowsWindow::destroyWindow()
setFlag(WithinDestroy);
// Clear any transient child relationships as Windows will otherwise destroy them (QTBUG-35499, QTBUG-36666)
if (QWindow *transientChild = findTransientChild(window()))
if (QWindowsWindow *tw = QWindowsWindow::baseWindowOf(transientChild))
if (QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(transientChild))
tw->updateTransientParent();
QWindowsContext *context = QWindowsContext::instance();
if (context->windowUnderMouse() == window())
@ -1029,8 +1150,7 @@ void QWindowsWindow::destroyWindow()
}
}
#endif // !Q_OS_WINCE
if (m_data.hwnd != GetDesktopWindow() && window()->type() != Qt::ForeignWindow)
DestroyWindow(m_data.hwnd);
DestroyWindow(m_data.hwnd);
context->removeWindow(m_data.hwnd);
m_data.hwnd = 0;
}
@ -1143,7 +1263,10 @@ void QWindowsWindow::setVisible(bool visible)
} else {
if (hasMouseCapture())
setMouseGrabEnabled(false);
hide_sys();
if (window()->flags() & Qt::Popup) // from QWidgetPrivate::hide_sys(), activate other
ShowWindow(m_data.hwnd, SW_HIDE);
else
hide_sys();
fireExpose(QRegion());
}
}
@ -1219,7 +1342,7 @@ void QWindowsWindow::updateTransientParent() const
const HWND oldTransientParent = transientParentHwnd(m_data.hwnd);
HWND newTransientParent = 0;
if (const QWindow *tp = window()->transientParent())
if (const QWindowsWindow *tw = QWindowsWindow::baseWindowOf(tp))
if (const QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(tp))
if (!tw->testFlag(WithinDestroy)) // Prevent destruction by parent window (QTBUG-35499, QTBUG-36666)
newTransientParent = tw->handle();
if (newTransientParent != oldTransientParent)
@ -1283,18 +1406,6 @@ void QWindowsWindow::show_sys() const
}
}
// partially from QWidgetPrivate::hide_sys()
void QWindowsWindow::hide_sys() const
{
const Qt::WindowFlags flags = window()->flags();
if (flags != Qt::Desktop) {
if (flags & Qt::Popup)
ShowWindow(m_data.hwnd, SW_HIDE);
else
SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
}
}
void QWindowsWindow::setParent(const QPlatformWindow *newParent)
{
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << newParent;
@ -1306,7 +1417,7 @@ void QWindowsWindow::setParent(const QPlatformWindow *newParent)
void QWindowsWindow::setParent_sys(const QPlatformWindow *parent)
{
// Use GetAncestor instead of GetParent, as GetParent can return owner window for toplevels
HWND oldParentHWND = GetAncestor(m_data.hwnd, GA_PARENT);
HWND oldParentHWND = parentHwnd();
HWND newParentHWND = 0;
if (parent) {
const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
@ -1470,7 +1581,7 @@ void QWindowsWindow::handleGeometryChange()
qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry;
}
void QWindowsWindow::setGeometry_sys(const QRect &rect) const
void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
{
const QMargins margins = frameMargins();
const QRect frameGeometry = rect + margins;
@ -1482,38 +1593,28 @@ void QWindowsWindow::setGeometry_sys(const QRect &rect) const
bool result = false;
#ifndef Q_OS_WINCE
const HWND hwnd = handle();
WINDOWPLACEMENT windowPlacement;
windowPlacement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(m_data.hwnd, &windowPlacement);
GetWindowPlacement(hwnd, &windowPlacement);
// If the window is hidden and in maximized state or minimized, instead of moving the
// window, set the normal position of the window.
if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(m_data.hwnd))
if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(hwnd))
|| windowPlacement.showCmd == SW_SHOWMINIMIZED) {
windowPlacement.rcNormalPosition =
RECTfromQRect(frameGeometry.translated(-windowPlacementOffset(m_data.hwnd, frameGeometry.topLeft())));
RECTfromQRect(frameGeometry.translated(-windowPlacementOffset(hwnd, frameGeometry.topLeft())));
windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE;
result = SetWindowPlacement(m_data.hwnd, &windowPlacement);
result = SetWindowPlacement(hwnd, &windowPlacement);
} else
#endif // !Q_OS_WINCE
{
result = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(),
result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(),
frameGeometry.width(), frameGeometry.height(), true);
}
qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window()
<< "\n resulting " << result << geometry_sys();
}
QRect QWindowsWindow::frameGeometry_sys() const
{
bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded;
return frameGeometry(m_data.hwnd, isRealTopLevel);
}
QRect QWindowsWindow::geometry_sys() const
{
return frameGeometry_sys().marginsRemoved(frameMargins());
}
/*!
Allocates a HDC for the window or returns the temporary one
obtained from WinAPI BeginPaint within a WM_PAINT event.
@ -1572,11 +1673,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
void QWindowsWindow::setWindowTitle(const QString &title)
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() <<title;
if (m_data.hwnd) {
const QString fullTitle = formatWindowTitle(title, QStringLiteral(" - "));
SetWindowText(m_data.hwnd, (const wchar_t*)fullTitle.utf16());
}
setWindowTitle_sys(QWindowsWindow::formatWindowTitle(title, QStringLiteral(" - ")));
}
void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
@ -1643,8 +1740,8 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
}
foreach (QWindow *child, QGuiApplication::allWindows()) {
if (child != w && child->isVisible() && child->transientParent() == w) {
QWindowsWindow *platformWindow = QWindowsWindow::baseWindowOf(child);
if (platformWindow->isLayered()) {
QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(child);
if (platformWindow && platformWindow->isLayered()) {
platformWindow->fireExpose(QRegion(0, 0, child->width(), child->height()));
exposeEventsSent = true;
}
@ -1819,19 +1916,6 @@ void QWindowsWindow::setExStyle(unsigned s) const
SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
}
void QWindowsWindow::raise()
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
void QWindowsWindow::lower()
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
if (m_data.hwnd)
SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
void QWindowsWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
@ -2152,7 +2236,8 @@ static inline bool applyNewCursor(const QWindow *w)
for (const QWindow *p = underMouse; p ; p = p->parent()) {
if (p == w)
return true;
if (!QWindowsWindow::baseWindowOf(p)->cursor()->isNull())
const QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(p);
if (platformWindow && !platformWindow->cursor()->isNull())
return false;
}
return false;
@ -2170,7 +2255,8 @@ void QWindowsWindow::applyCursor()
#ifndef QT_NO_CURSOR
if (m_cursor->isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel.
if (const QWindow *p = window()->parent()) {
QWindowsWindow::baseWindowOf(p)->applyCursor();
if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(p))
platformWindow->applyCursor();
} else {
SetCursor(defaultCursor(window())->handle());
}
@ -2281,6 +2367,11 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon)
}
}
bool QWindowsWindow::isTopLevel() const
{
return window()->isTopLevel() && !m_data.embedded;
}
/*!
\brief Sets custom margins to be added to the default margins determined by
the windows style in the handling of the WM_NCCALCSIZE message.
@ -2345,8 +2436,7 @@ void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWind
void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
{
#ifndef Q_OS_WINCE
if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)
&& window()->type() != Qt::ForeignWindow) {
if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)) {
ULONG touchFlags = 0;
const bool ret = QWindowsContext::user32dll.isTouchWindow(m_data.hwnd, &touchFlags);
// Return if it is not a touch window or the flags are already set by a hook

View File

@ -118,7 +118,78 @@ struct QWindowsWindowData
const QString &title);
};
class QWindowsWindow : public QPlatformWindow
class QWindowsBaseWindow : public QPlatformWindow
{
public:
explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {}
WId winId() const Q_DECL_OVERRIDE { return WId(handle()); }
QRect geometry() const Q_DECL_OVERRIDE { return geometry_sys(); }
QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMargins_sys(); }
QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
using QPlatformWindow::screenForGeometry;
virtual HWND handle() const = 0;
virtual bool isTopLevel() const { return isTopLevel_sys(); }
unsigned style() const { return GetWindowLongPtr(handle(), GWL_STYLE); }
unsigned exStyle() const { return GetWindowLongPtr(handle(), GWL_EXSTYLE); }
static QWindowsBaseWindow *baseWindowOf(const QWindow *w);
static HWND handleOf(const QWindow *w);
protected:
HWND parentHwnd() const { return GetAncestor(handle(), GA_PARENT); }
bool isTopLevel_sys() const;
QRect frameGeometry_sys() const;
QRect geometry_sys() const;
void setGeometry_sys(const QRect &rect) const;
QMargins frameMargins_sys() const;
void hide_sys();
void raise_sys();
void lower_sys();
void setWindowTitle_sys(const QString &title);
};
class QWindowsDesktopWindow : public QWindowsBaseWindow
{
public:
explicit QWindowsDesktopWindow(QWindow *window)
: QWindowsBaseWindow(window), m_hwnd(GetDesktopWindow()) {}
QMargins frameMargins() const Q_DECL_OVERRIDE { return QMargins(); }
bool isTopLevel() const Q_DECL_OVERRIDE { return true; }
protected:
HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; }
private:
const HWND m_hwnd;
};
class QWindowsForeignWindow : public QWindowsBaseWindow
{
public:
explicit QWindowsForeignWindow(QWindow *window, HWND hwnd);
void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE;
void setGeometry(const QRect &rect) Q_DECL_OVERRIDE { setGeometry_sys(rect); }
void setVisible(bool visible) Q_DECL_OVERRIDE;
void raise() Q_DECL_OVERRIDE { raise_sys(); }
void lower() Q_DECL_OVERRIDE { lower_sys(); }
void setWindowTitle(const QString &title) Q_DECL_OVERRIDE { setWindowTitle_sys(title); }
protected:
HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; }
private:
const HWND m_hwnd;
DWORD m_topLevelStyle;
};
class QWindowsWindow : public QWindowsBaseWindow
{
public:
enum Flags
@ -168,14 +239,11 @@ public:
void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE;
void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE;
HWND handle() const { return m_data.hwnd; }
WId winId() const Q_DECL_OVERRIDE { return WId(m_data.hwnd); }
void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE;
void setWindowTitle(const QString &title) Q_DECL_OVERRIDE;
void raise() Q_DECL_OVERRIDE;
void lower() Q_DECL_OVERRIDE;
void raise() Q_DECL_OVERRIDE { raise_sys(); }
void lower() Q_DECL_OVERRIDE { lower_sys(); }
void windowEvent(QEvent *event) Q_DECL_OVERRIDE;
@ -198,14 +266,14 @@ public:
void setFrameStrutEventsEnabled(bool enabled) Q_DECL_OVERRIDE;
bool frameStrutEventsEnabled() const Q_DECL_OVERRIDE { return testFlag(FrameStrutEventsEnabled); }
// QWindowsBaseWindow overrides
HWND handle() const Q_DECL_OVERRIDE { return m_data.hwnd; }
bool isTopLevel() const Q_DECL_OVERRIDE;
QMargins customMargins() const { return m_data.customMargins; }
void setCustomMargins(const QMargins &m);
inline unsigned style() const
{ return GetWindowLongPtr(m_data.hwnd, GWL_STYLE); }
void setStyle(unsigned s) const;
inline unsigned exStyle() const
{ return GetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE); }
void setExStyle(unsigned s) const;
bool handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
@ -215,8 +283,7 @@ public:
void handleHidden();
void handleCompositionSettingsChanged();
static inline HWND handleOf(const QWindow *w);
static inline QWindowsWindow *baseWindowOf(const QWindow *w);
static QWindowsWindow *windowsWindowOf(const QWindow *w);
static QWindow *topLevelOf(QWindow *w);
static inline void *userDataOf(HWND hwnd);
static inline void setUserDataOf(HWND hwnd, void *ud);
@ -262,10 +329,6 @@ public:
void setHasBorderInFullScreen(bool border);
private:
inline void show_sys() const;
inline void hide_sys() const;
inline void setGeometry_sys(const QRect &rect) const;
inline QRect frameGeometry_sys() const;
inline QRect geometry_sys() const;
inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const;
inline bool isFullScreen_sys() const;
inline void setWindowState_sys(Qt::WindowState newState);
@ -334,19 +397,17 @@ QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p)
// ---------- QWindowsBaseWindow inline functions.
QWindowsWindow *QWindowsWindow::baseWindowOf(const QWindow *w)
inline QWindowsWindow *QWindowsWindow::windowsWindowOf(const QWindow *w)
{
if (w)
if (QPlatformWindow *pw = w->handle())
return static_cast<QWindowsWindow *>(pw);
return 0;
}
HWND QWindowsWindow::handleOf(const QWindow *w)
{
if (const QWindowsWindow *bw = QWindowsWindow::baseWindowOf(w))
return bw->handle();
return 0;
QWindowsWindow *result = Q_NULLPTR;
if (w) {
const Qt::WindowType type = w->type();
if (type != Qt::Desktop && type != Qt::ForeignWindow) {
if (QPlatformWindow *pw = w->handle())
result = static_cast<QWindowsWindow *>(pw);
}
}
return result;
}
void *QWindowsWindow::userDataOf(HWND hwnd)