From 8e280d1e187b09651c7036bd76272342d52ce401 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 25 Jun 2012 13:58:41 +0200 Subject: QPlatformWindow: Add Window masks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add functionality for window masks to QPlatformWindow, which is required to implement QWidget::setMask() in order to fix the regression in functionality from Qt 4.8. Change-Id: I2c2d5629f0b4c6d90e52595ad70b13559aab1f41 Reviewed-by: Samuel Rødal --- src/gui/kernel/qplatformintegration.h | 4 +- src/gui/kernel/qplatformwindow.h | 2 + src/gui/kernel/qplatformwindow_qpa.cpp | 10 ++++ .../platforms/windows/qwindowsintegration.cpp | 2 + src/plugins/platforms/windows/qwindowswindow.cpp | 44 ++++++++++++++++++ src/plugins/platforms/windows/qwindowswindow.h | 1 + src/plugins/platforms/xcb/qxcbintegration.cpp | 1 + src/plugins/platforms/xcb/qxcbwindow.cpp | 54 ++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbwindow.h | 4 ++ src/plugins/platforms/xcb/xcb.pro | 1 + src/widgets/kernel/qwidget_qpa.cpp | 21 +++++++-- 11 files changed, 139 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index 3990adb3fe..ea13a25bab 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -85,8 +85,8 @@ public: OpenGL = 2, ThreadedOpenGL = 3, SharedGraphicsCache = 4, - BufferQueueingOpenGL = 5 - + BufferQueueingOpenGL = 5, + WindowMasks = 6 }; virtual ~QPlatformIntegration() { } diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 604398909d..d9f79f25eb 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -68,6 +68,7 @@ class QPlatformScreen; class QPlatformWindowPrivate; class QWindow; class QIcon; +class QRegion; class Q_GUI_EXPORT QPlatformWindow : public QPlatformSurface { @@ -105,6 +106,7 @@ public: virtual void propagateSizeHints(); virtual void setOpacity(qreal level); + virtual void setMask(const QRegion ®ion); virtual void requestActivateWindow(); virtual void handleContentOrientationChange(Qt::ScreenOrientation orientation); diff --git a/src/gui/kernel/qplatformwindow_qpa.cpp b/src/gui/kernel/qplatformwindow_qpa.cpp index 2380c6db75..88f2a6481e 100644 --- a/src/gui/kernel/qplatformwindow_qpa.cpp +++ b/src/gui/kernel/qplatformwindow_qpa.cpp @@ -241,6 +241,16 @@ void QPlatformWindow::setOpacity(qreal level) qWarning("This plugin does not support setting window opacity"); } +/*! + Reimplement to be able to let Qt set the mask of a window +*/ + +void QPlatformWindow::setMask(const QRegion ®ion) +{ + Q_UNUSED(region); + qWarning("This plugin does not support setting window masks"); +} + /*! Reimplement to let Qt be able to request activation/focus for a window diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 52950ecde5..7d4308d578 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -265,6 +265,8 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; # endif // QT_OPENGL_ES_2 #endif // !QT_NO_OPENGL + case WindowMasks: + return true; default: return QPlatformIntegration::hasCapability(cap); } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index e49b215422..aabea04c20 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -1344,6 +1345,49 @@ void QWindowsWindow::setOpacity(qreal level) } } +static inline HRGN createRectRegion(const QRect &r) +{ + return CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height()); +} + +static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion) +{ + if (const HRGN rectRegion = createRectRegion(rect)) { + HRGN result = CreateRectRgn(0, 0, 0, 0); + if (CombineRgn(result, *winRegion, rectRegion, RGN_OR)) { + DeleteObject(winRegion); + *winRegion = result; + } + DeleteObject(rectRegion); + } +} + +static HRGN qRegionToWinRegion(const QRegion ®ion) +{ + const QVector rects = region.rects(); + if (rects.isEmpty()) + return NULL; + const int rectCount = rects.size(); + if (rectCount == 1) + return createRectRegion(region.boundingRect()); + HRGN hRegion = createRectRegion(rects.front()); + for (int i = 1; i < rectCount; ++i) + addRectToWinRegion(rects.at(i), &hRegion); + return hRegion; +} + +void QWindowsWindow::setMask(const QRegion ®ion) +{ + if (region.isEmpty()) { + SetWindowRgn(m_data.hwnd, 0, true); + return; + } + const HRGN winRegion = qRegionToWinRegion(region); + // SetWindowRgn takes ownership. + if (!SetWindowRgn(m_data.hwnd, winRegion, true)) + DeleteObject(winRegion); +} + void QWindowsWindow::requestActivateWindow() { if (QWindowsContext::verboseWindows) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 2fd401029e..743e10dff9 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -168,6 +168,7 @@ public: virtual QMargins frameMargins() const; virtual void setOpacity(qreal level); + virtual void setMask(const QRegion ®ion); qreal opacity() const { return m_opacity; } virtual void requestActivateWindow(); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index c40ebe47bc..f7576fe19b 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -203,6 +203,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const case ThreadedPixmaps: return true; case OpenGL: return true; case ThreadedOpenGL: return false; + case WindowMasks: return true; default: return QPlatformIntegration::hasCapability(cap); } } diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 59e805fd0e..a4ee2a461c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include "qxcbconnection.h" #include "qxcbscreen.h" @@ -97,6 +98,9 @@ #ifdef XCB_USE_XLIB #include #include +#ifndef QT_NO_SHAPE +# include +#endif // QT_NO_SHAPE #endif #ifdef XCB_USE_XINPUT2_MAEMO @@ -1698,4 +1702,54 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) return true; } +#if defined(XCB_USE_XLIB) && !defined(QT_NO_SHAPE) + +static inline XRectangle qRectToX11Rectangle(const QRect &r) +{ + XRectangle result; + result.x = qMax(SHRT_MIN, r.x()); + result.y = qMax(SHRT_MIN, r.y()); + result.width = qMin((int)USHRT_MAX, r.width()); + result.height = qMin((int)USHRT_MAX, r.height()); + return result; +} + +static inline Region qRegionToX11Region(const QRegion ®ion) +{ + if (region.isEmpty()) + return None; + Region result = XCreateRegion(); + if (!result) + return None; + const QVector rects = region.rects(); + if (rects.size() == 1) { + XRectangle xrect = qRectToX11Rectangle(region.boundingRect()); + XUnionRectWithRegion(&xrect, result, result); + } else { + foreach (const QRect &r, rects) { + XRectangle xrect = qRectToX11Rectangle(r); + XUnionRectWithRegion(&xrect, result, result); + } + } + return result; +} + + +void QXcbWindow::setMask(const QRegion ®ion) +{ + + Display *display = (Display *)connection()->xlib_display(); + if (region.isEmpty()) { + XShapeCombineMask(display, xcb_window(), + ShapeBounding, 0, 0, + None, ShapeSet); + } else { + XShapeCombineRegion(display, xcb_window(), + ShapeBounding, 0, 0, + qRegionToX11Region(region), ShapeSet); + } +} + +#endif // XCB_USE_XLIB && !QT_NO_SHAPE + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index d383248428..0c4ec34269 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -109,6 +109,10 @@ public: bool startSystemResize(const QPoint &pos, Qt::Corner corner); +#if defined(XCB_USE_XLIB) && !defined(QT_NO_SHAPE) + void setMask(const QRegion ®ion); +#endif // XCB_USE_XLIB && !QT_NO_SHAPE + xcb_window_t xcb_window() const { return m_window; } uint depth() const { return m_depth; } QImage::Format imageFormat() const { return m_imageFormat; } diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 210b770a51..8e6fbc6c63 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -45,6 +45,7 @@ contains(QT_CONFIG, xcb-poll-for-queued-event) { # needed by GLX, Xcursor, XLookupString, ... contains(QT_CONFIG, xcb-xlib) { DEFINES += XCB_USE_XLIB + !contains(DEFINES, QT_NO_SHAPE):LIBS += -lXext LIBS += -lX11 -lX11-xcb linux-g++-maemo { diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index 04bf0be27f..387ed2e79a 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -50,6 +50,7 @@ #include #include "QtGui/qsurfaceformat.h" #include +#include #include "QtGui/private/qwindow_p.h" #include @@ -929,10 +930,24 @@ void QWidgetPrivate::registerDropSite(bool on) Q_UNUSED(on); } -void QWidgetPrivate::setMask_sys(const QRegion ®ion) +void QWidgetPrivate::setMask_sys(const QRegion ®ionIn) { - Q_UNUSED(region); - // XXX + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowMasks)) { + qWarning("%s: Not supported on %s.", Q_FUNC_INFO, qPrintable(QGuiApplication::platformName())); + return; + } + Q_Q(QWidget); + QRegion region = regionIn; + QWindow *window = q->windowHandle(); + if (!window) { + if (QWidget *nativeParent = q->nativeParentWidget()) { + window = nativeParent->windowHandle(); + region.translate(q->mapTo(nativeParent, QPoint(0, 0))); + } + } + if (window) + if (QPlatformWindow *platformWindow = window->handle()) + platformWindow->setMask(region); } void QWidgetPrivate::updateFrameStrut() -- cgit v1.2.3