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