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
This commit is contained in:
Martin Gräßlin 2014-01-20 10:11:58 +01:00
parent e4d4f5fc1c
commit bdc2ad2a84
4 changed files with 88 additions and 2 deletions

View File

@ -57,7 +57,7 @@ set_package_properties(KActivities PROPERTIES DESCRIPTION "The KActivities libra
#optional features #optional features
find_package(X11 MODULE) 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" set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding"
URL "http://xcb.freedesktop.org" URL "http://xcb.freedesktop.org"
TYPE REQUIRED TYPE REQUIRED

View File

@ -8,6 +8,10 @@ if(XCB_XCB_FOUND AND XCB_COMPOSITE_FOUND AND XCB_DAMAGE_FOUND)
${XCB_COMPOSITE_INCLUDE_DIR} ${XCB_COMPOSITE_INCLUDE_DIR}
) )
endif() 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 set(corebindings_SRCS
corebindingsplugin.cpp corebindingsplugin.cpp
@ -49,6 +53,9 @@ if(X11_FOUND)
${XCB_COMPOSITE_LIBRARY} ${XCB_COMPOSITE_LIBRARY}
) )
endif() endif()
if(XCB_SHAPE_FOUND)
target_link_libraries(corebindingsplugin ${XCB_SHAPE_LIBRARY})
endif()
if(OPENGL_FOUND) if(OPENGL_FOUND)
target_link_libraries(corebindingsplugin ${OPENGL_gl_LIBRARY}) target_link_libraries(corebindingsplugin ${OPENGL_gl_LIBRARY})

View File

@ -1,6 +1,7 @@
/*************************************************************************** /***************************************************************************
* Copyright 2011 Marco Martin <mart@kde.org> * * Copyright 2011 Marco Martin <mart@kde.org> *
* Copyright 2013 Sebastian Kügler <sebas@kde.org> * * Copyright 2013 Sebastian Kügler <sebas@kde.org> *
* Copyright 2014 Martin Gräßlin <mgraesslin@kde.org> *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
@ -38,11 +39,17 @@
#include <QDebug> #include <QDebug>
#if HAVE_XCB_SHAPE
#include <QX11Info>
#include <xcb/shape.h>
#endif
DialogProxy::DialogProxy(QQuickItem *parent) DialogProxy::DialogProxy(QQuickItem *parent)
: QQuickWindow(parent ? parent->window() : 0), : QQuickWindow(parent ? parent->window() : 0),
m_location(Plasma::Types::BottomEdge), m_location(Plasma::Types::BottomEdge),
m_type(Normal), m_type(Normal),
m_hideOnWindowDeactivate(false) m_hideOnWindowDeactivate(false),
m_outputOnly(false)
{ {
QSurfaceFormat format; QSurfaceFormat format;
format.setAlphaBufferSize(8); format.setAlphaBufferSize(8);
@ -58,6 +65,8 @@ DialogProxy::DialogProxy(QQuickItem *parent)
connect(this, &QWindow::xChanged, [=](){m_syncTimer->start(150);}); connect(this, &QWindow::xChanged, [=](){m_syncTimer->start(150);});
connect(this, &QWindow::yChanged, [=](){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); // connect(this, &QWindow::visibleChanged, this, &DialogProxy::onVisibleChanged);
//HACK: this property is invoked due to the initialization that gets done to contentItem() in the getter //HACK: this property is invoked due to the initialization that gets done to contentItem() in the getter
property("data"); property("data");
@ -485,5 +494,58 @@ void DialogProxy::setHideOnWindowDeactivate(bool hide)
emit hideOnWindowDeactivateChanged(); 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<xcb_shape_query_version_reply_t, QScopedPointerPodDeleter> 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" #include "dialog.moc"

View File

@ -79,6 +79,16 @@ class DialogProxy : public QQuickWindow
**/ **/
Q_PROPERTY(bool hideOnWindowDeactivate READ hideOnWindowDeactivate WRITE setHideOnWindowDeactivate NOTIFY hideOnWindowDeactivateChanged) 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") Q_CLASSINFO("DefaultProperty", "mainItem")
public: public:
@ -123,12 +133,18 @@ public:
bool hideOnWindowDeactivate() const; bool hideOnWindowDeactivate() const;
void setHideOnWindowDeactivate(bool hide); void setHideOnWindowDeactivate(bool hide);
void setOutputOnly(bool outputOnly);
bool isOutputOnly() const;
void updateInputShape();
Q_SIGNALS: Q_SIGNALS:
void mainItemChanged(); void mainItemChanged();
void locationChanged(); void locationChanged();
void visualParentChanged(); void visualParentChanged();
void typeChanged(); void typeChanged();
void hideOnWindowDeactivateChanged(); void hideOnWindowDeactivateChanged();
void outputOnlyChanged();
public Q_SLOTS: public Q_SLOTS:
void syncMainItemToSize(); void syncMainItemToSize();
@ -158,6 +174,7 @@ private:
QRect m_cachedGeometry; QRect m_cachedGeometry;
WindowType m_type; WindowType m_type;
bool m_hideOnWindowDeactivate; bool m_hideOnWindowDeactivate;
bool m_outputOnly;
}; };
#endif #endif