From bdc2ad2a84f81a26a938e917590a054a9fceeccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 20 Jan 2014 10:11:58 +0100 Subject: [PATCH] Add outputOnly property to PlasmaCore.Dialog The outputOnly property allows to specify that the dialog should not accept any input. Thus it's an output only window which supports click through. This is obviously platform specific and so far it is only implemented for the X11 platform using the shape extension. The input shape needs to be set once the window is visible and thus the functionality is bound to the visible changed signal. The code ensures that the required shape extension version is present and only fetches it once. REVIEW: 115139 --- CMakeLists.txt | 2 +- src/declarativeimports/core/CMakeLists.txt | 7 +++ src/declarativeimports/core/dialog.cpp | 64 +++++++++++++++++++++- src/declarativeimports/core/dialog.h | 17 ++++++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef64bdc7c..8fb14bba0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ set_package_properties(KActivities PROPERTIES DESCRIPTION "The KActivities libra #optional features find_package(X11 MODULE) -find_package(XCB MODULE COMPONENTS XCB COMPOSITE DAMAGE) +find_package(XCB MODULE COMPONENTS XCB COMPOSITE DAMAGE SHAPE) set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding" URL "http://xcb.freedesktop.org" TYPE REQUIRED diff --git a/src/declarativeimports/core/CMakeLists.txt b/src/declarativeimports/core/CMakeLists.txt index 71f2cb351..f63d6e226 100644 --- a/src/declarativeimports/core/CMakeLists.txt +++ b/src/declarativeimports/core/CMakeLists.txt @@ -8,6 +8,10 @@ if(XCB_XCB_FOUND AND XCB_COMPOSITE_FOUND AND XCB_DAMAGE_FOUND) ${XCB_COMPOSITE_INCLUDE_DIR} ) endif() +if(XCB_XCB_FOUND AND XCB_SHAPE_FOUND) + add_definitions(-DHAVE_XCB_SHAPE=1) + include_directories(${XCB_SHAPE_INCLUDE_DIR}) +endif() set(corebindings_SRCS corebindingsplugin.cpp @@ -49,6 +53,9 @@ if(X11_FOUND) ${XCB_COMPOSITE_LIBRARY} ) endif() + if(XCB_SHAPE_FOUND) + target_link_libraries(corebindingsplugin ${XCB_SHAPE_LIBRARY}) + endif() if(OPENGL_FOUND) target_link_libraries(corebindingsplugin ${OPENGL_gl_LIBRARY}) diff --git a/src/declarativeimports/core/dialog.cpp b/src/declarativeimports/core/dialog.cpp index 2c15f30c1..cb5ab5057 100644 --- a/src/declarativeimports/core/dialog.cpp +++ b/src/declarativeimports/core/dialog.cpp @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright 2011 Marco Martin * * Copyright 2013 Sebastian Kügler * + * Copyright 2014 Martin Gräßlin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -38,11 +39,17 @@ #include +#if HAVE_XCB_SHAPE +#include +#include +#endif + DialogProxy::DialogProxy(QQuickItem *parent) : QQuickWindow(parent ? parent->window() : 0), m_location(Plasma::Types::BottomEdge), m_type(Normal), - m_hideOnWindowDeactivate(false) + m_hideOnWindowDeactivate(false), + m_outputOnly(false) { QSurfaceFormat format; format.setAlphaBufferSize(8); @@ -58,6 +65,8 @@ DialogProxy::DialogProxy(QQuickItem *parent) connect(this, &QWindow::xChanged, [=](){m_syncTimer->start(150);}); connect(this, &QWindow::yChanged, [=](){m_syncTimer->start(150);}); + connect(this, &QWindow::visibleChanged, this, &DialogProxy::updateInputShape); + connect(this, &DialogProxy::outputOnlyChanged, this, &DialogProxy::updateInputShape); // connect(this, &QWindow::visibleChanged, this, &DialogProxy::onVisibleChanged); //HACK: this property is invoked due to the initialization that gets done to contentItem() in the getter property("data"); @@ -485,5 +494,58 @@ void DialogProxy::setHideOnWindowDeactivate(bool hide) emit hideOnWindowDeactivateChanged(); } +bool DialogProxy::isOutputOnly() const +{ + return m_outputOnly; +} + +void DialogProxy::setOutputOnly(bool outputOnly) +{ + if (m_outputOnly == outputOnly) { + return; + } + m_outputOnly = outputOnly; + emit outputOnlyChanged(); +} + +void DialogProxy::updateInputShape() +{ + if (!isVisible()) { + return; + } +#if HAVE_XCB_SHAPE + if (QGuiApplication::platformName() == QStringLiteral("xcb")) { + xcb_connection_t *c = QX11Info::connection(); + static bool s_shapeExtensionChecked = false; + static bool s_shapeAvailable = false; + if (!s_shapeExtensionChecked) { + xcb_prefetch_extension_data(c, &xcb_shape_id); + const xcb_query_extension_reply_t *extension = xcb_get_extension_data(c, &xcb_shape_id); + if (extension->present) { + // query version + auto cookie = xcb_shape_query_version(c); + QScopedPointer version(xcb_shape_query_version_reply(c, cookie, Q_NULLPTR)); + if (!version.isNull()) { + s_shapeAvailable = (version->major_version * 0x10 + version->minor_version) >= 0x11; + } + } + s_shapeExtensionChecked = true; + } + if (!s_shapeAvailable) { + return; + } + if (m_outputOnly) { + // set input shape, so that it doesn't accept any input events + xcb_shape_rectangles(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, + XCB_CLIP_ORDERING_UNSORTED, winId(), 0, 0, 0, NULL); + } else { + // delete the shape + xcb_shape_mask(c, XCB_SHAPE_SO_INTERSECT, XCB_SHAPE_SK_INPUT, + winId(), 0, 0, XCB_PIXMAP_NONE); + } + } +#endif +} + #include "dialog.moc" diff --git a/src/declarativeimports/core/dialog.h b/src/declarativeimports/core/dialog.h index 051437c6a..b96b43c63 100644 --- a/src/declarativeimports/core/dialog.h +++ b/src/declarativeimports/core/dialog.h @@ -79,6 +79,16 @@ class DialogProxy : public QQuickWindow **/ Q_PROPERTY(bool hideOnWindowDeactivate READ hideOnWindowDeactivate WRITE setHideOnWindowDeactivate NOTIFY hideOnWindowDeactivateChanged) + /** + * Whether the dialog is output only. Default value is @c false. If it is @c true + * the dialog does not accept input and all pointer events are not accepted, thus the dialog + * is click through. + * + * This property is currently only supported on the X11 platform. On any other platform the + * property has no effect. + **/ + Q_PROPERTY(bool outputOnly READ isOutputOnly WRITE setOutputOnly NOTIFY outputOnlyChanged) + Q_CLASSINFO("DefaultProperty", "mainItem") public: @@ -123,12 +133,18 @@ public: bool hideOnWindowDeactivate() const; void setHideOnWindowDeactivate(bool hide); + void setOutputOnly(bool outputOnly); + bool isOutputOnly() const; + + void updateInputShape(); + Q_SIGNALS: void mainItemChanged(); void locationChanged(); void visualParentChanged(); void typeChanged(); void hideOnWindowDeactivateChanged(); + void outputOnlyChanged(); public Q_SLOTS: void syncMainItemToSize(); @@ -158,6 +174,7 @@ private: QRect m_cachedGeometry; WindowType m_type; bool m_hideOnWindowDeactivate; + bool m_outputOnly; }; #endif