QQuick item for live updating window thumbnails
New qquick item in PlasmaCore to render a live updating window thumbnail. The implementation uses XCB to redirect the specified window using the composite extension. This means a running compositor is not required. Through the damage extension the item tracks changes to the window and triggers updates of the texture. Furthermore the item tracks geometry changes of the window to recreate the window pixmap. If the pixmap of the window is valid, a texture is generated from it using the glx texture from pixmap extension. For this a new optional dependency for glx is added. On platform where glx is not available (e.g. Windows, Linux with OpenGL ES) this will not get compiled and the window's icon is used instead as a fallback. REVIEW: 112142
This commit is contained in:
parent
eba2125d6e
commit
91d306d2e8
@ -74,7 +74,7 @@ find_package(KDE4Support REQUIRED NO_MODULE)
|
||||
|
||||
#optional features
|
||||
find_package(X11 MODULE)
|
||||
find_package(XCB MODULE COMPONENTS XCB)
|
||||
find_package(XCB MODULE COMPONENTS XCB COMPOSITE DAMAGE)
|
||||
set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding"
|
||||
URL "http://xcb.freedesktop.org"
|
||||
TYPE RECOMMENDED
|
||||
@ -131,6 +131,17 @@ set_package_properties(LibAttica PROPERTIES DESCRIPTION "Support for Get Hot New
|
||||
TYPE REQUIRED
|
||||
)
|
||||
|
||||
find_package(OpenGL)
|
||||
set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries"
|
||||
URL "http://www.opengl.org"
|
||||
TYPE OPTIONAL
|
||||
)
|
||||
if(OPENGL_FOUND)
|
||||
set(HAVE_GLX HAVE_X11)
|
||||
else()
|
||||
set(HAVE_GLX 0)
|
||||
endif()
|
||||
|
||||
#########################################################################
|
||||
|
||||
#add_definitions(${KDE4_DEFINITIONS})
|
||||
|
@ -10,6 +10,14 @@ INCLUDE_DIRECTORIES(
|
||||
)
|
||||
|
||||
add_definitions(-DHAVE_X11=${HAVE_X11})
|
||||
if(XCB_XCB_FOUND AND XCB_COMPOSITE_FOUND AND XCB_DAMAGE_FOUND)
|
||||
add_definitions(-DHAVE_XCB_COMPOSITE=1)
|
||||
include_directories(
|
||||
${XCB_XCB_INCLUDE_DIR}
|
||||
${XCB_DAMAGE_INCLUDE_DIR}
|
||||
${XCB_COMPOSITE_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
set(corebindings_SRCS
|
||||
corebindingsplugin.cpp
|
||||
@ -26,6 +34,7 @@ set(corebindings_SRCS
|
||||
serviceoperationstatus.cpp
|
||||
dataenginebindings.cpp
|
||||
iconitem.cpp
|
||||
windowthumbnail.cpp
|
||||
)
|
||||
|
||||
add_library(corebindingsplugin SHARED ${corebindings_SRCS})
|
||||
@ -43,6 +52,17 @@ target_link_libraries(corebindingsplugin
|
||||
if(X11_FOUND)
|
||||
target_link_libraries(corebindingsplugin ${X11_LIBRARIES} ${XCB_XCB_LIBRARY} )
|
||||
target_link_libraries(corebindingsplugin Qt5::X11Extras)
|
||||
|
||||
if(XCB_COMPOSITE_FOUND AND XCB_DAMAGE_FOUND)
|
||||
target_link_libraries(corebindingsplugin
|
||||
${XCB_DAMAGE_LIBRARY}
|
||||
${XCB_COMPOSITE_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(OPENGL_FOUND)
|
||||
target_link_libraries(corebindingsplugin ${OPENGL_gl_LIBRARY})
|
||||
endif()
|
||||
endif(X11_FOUND)
|
||||
|
||||
install(TARGETS corebindingsplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/plasma/core)
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "serviceoperationstatus.h"
|
||||
|
||||
#include "tooltip.h"
|
||||
#include "windowthumbnail.h"
|
||||
|
||||
// #include "dataenginebindings_p.h"
|
||||
|
||||
@ -103,6 +104,8 @@ void CoreBindingsPlugin::registerTypes(const char *uri)
|
||||
qmlRegisterInterface<Plasma::DataSource>("DataSource");
|
||||
qRegisterMetaType<Plasma::DataSource*>("DataSource");
|
||||
|
||||
qmlRegisterType<Plasma::WindowThumbnail>(uri, 2, 0, "WindowThumbnail");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
394
src/declarativeimports/core/windowthumbnail.cpp
Normal file
394
src/declarativeimports/core/windowthumbnail.cpp
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright 2013 by Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "windowthumbnail.h"
|
||||
// KF5
|
||||
#include <KWindowSystem>
|
||||
// Qt
|
||||
#include <QGuiApplication>
|
||||
#include <QIcon>
|
||||
#include <QOpenGLContext>
|
||||
#include <QQuickWindow>
|
||||
// X11
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
#include <QX11Info>
|
||||
#include <xcb/composite.h>
|
||||
#if HAVE_GLX
|
||||
#include <GL/glx.h>
|
||||
typedef void (*glXBindTexImageEXT_func)(Display* dpy, GLXDrawable drawable,
|
||||
int buffer, const int* attrib_list);
|
||||
typedef void (*glXReleaseTexImageEXT_func)(Display* dpy, GLXDrawable drawable, int buffer);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Plasma {
|
||||
|
||||
WindowTextureNode::WindowTextureNode()
|
||||
: QSGSimpleTextureNode()
|
||||
{
|
||||
}
|
||||
|
||||
WindowTextureNode::~WindowTextureNode()
|
||||
{
|
||||
}
|
||||
|
||||
void WindowTextureNode::reset(QSGTexture *texture)
|
||||
{
|
||||
setTexture(texture);
|
||||
m_texture.reset(texture);
|
||||
}
|
||||
|
||||
WindowThumbnail::WindowThumbnail(QQuickItem* parent)
|
||||
: QQuickItem(parent)
|
||||
, QAbstractNativeEventFilter()
|
||||
, m_xcb(false)
|
||||
, m_winId(0)
|
||||
, m_damaged(false)
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
, m_openGLFunctionsResolved(false)
|
||||
, m_damageEventBase(0)
|
||||
, m_damage(XCB_NONE)
|
||||
, m_pixmap(XCB_PIXMAP_NONE)
|
||||
, m_texture(0)
|
||||
#if HAVE_GLX
|
||||
, m_glxPixmap(XCB_PIXMAP_NONE)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
setFlag(ItemHasContents);
|
||||
if (QGuiApplication *gui = dynamic_cast<QGuiApplication*>(QCoreApplication::instance())) {
|
||||
m_xcb = (gui->platformName() == QStringLiteral("xcb"));
|
||||
if (m_xcb) {
|
||||
gui->installNativeEventFilter(this);
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_connection_t *c = QX11Info::connection();
|
||||
xcb_prefetch_extension_data(c, &xcb_damage_id);
|
||||
const auto *reply = xcb_get_extension_data(c, &xcb_damage_id);
|
||||
m_damageEventBase = reply->first_event;
|
||||
if (reply->present) {
|
||||
xcb_damage_query_version_unchecked(c, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WindowThumbnail::~WindowThumbnail()
|
||||
{
|
||||
if (m_xcb) {
|
||||
QCoreApplication::instance()->removeNativeEventFilter(this);
|
||||
stopRedirecting();
|
||||
discardPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WindowThumbnail::winId() const
|
||||
{
|
||||
return m_winId;
|
||||
}
|
||||
|
||||
void WindowThumbnail::setWinId(uint32_t winId)
|
||||
{
|
||||
if (m_winId == winId) {
|
||||
return;
|
||||
}
|
||||
if (!KWindowSystem::self()->hasWId(winId)) {
|
||||
// invalid Id, don't updated
|
||||
return;
|
||||
}
|
||||
stopRedirecting();
|
||||
m_winId = winId;
|
||||
startRedirecting();
|
||||
emit winIdChanged();
|
||||
}
|
||||
|
||||
QSGNode *WindowThumbnail::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
|
||||
{
|
||||
Q_UNUSED(updatePaintNodeData)
|
||||
auto *node = static_cast<WindowTextureNode*>(oldNode);
|
||||
if (!node) {
|
||||
node = new WindowTextureNode();
|
||||
node->setFiltering(QSGTexture::Linear);
|
||||
}
|
||||
if (!m_xcb || m_winId == 0) {
|
||||
iconToTexture(node);
|
||||
} else {
|
||||
windowToTexture(node);
|
||||
}
|
||||
node->setRect(boundingRect());
|
||||
const QSize size(node->texture()->textureSize().scaled(boundingRect().size().toSize(), Qt::KeepAspectRatio));
|
||||
const qreal x = boundingRect().x() + (boundingRect().width() - size.width())/2;
|
||||
const qreal y = boundingRect().y() + (boundingRect().height() - size.height())/2;
|
||||
node->setRect(QRectF(QPointF(x, y), size));
|
||||
return node;
|
||||
}
|
||||
|
||||
bool WindowThumbnail::nativeEventFilter(const QByteArray &eventType, void *message, long int *result)
|
||||
{
|
||||
Q_UNUSED(result)
|
||||
if (!m_xcb || eventType != QByteArrayLiteral("xcb_generic_event_t")) {
|
||||
// currently we are only interested in XCB events
|
||||
return false;
|
||||
}
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_generic_event_t *event = static_cast<xcb_generic_event_t*>(message);
|
||||
const uint8_t responseType = event->response_type & ~0x80;
|
||||
if (responseType == m_damageEventBase + XCB_DAMAGE_NOTIFY) {
|
||||
if (reinterpret_cast<xcb_damage_notify_event_t*>(event)->drawable == m_winId) {
|
||||
m_damaged = true;
|
||||
update();
|
||||
}
|
||||
} else if (responseType == XCB_CONFIGURE_NOTIFY) {
|
||||
if (reinterpret_cast<xcb_configure_notify_event_t*>(event)->window == m_winId) {
|
||||
// TODO: only discard if size changes
|
||||
discardPixmap();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// do not filter out any events, there might be further WindowThumbnails for the same window
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowThumbnail::iconToTexture(WindowTextureNode *textureNode)
|
||||
{
|
||||
QIcon icon;
|
||||
if (KWindowSystem::self()->hasWId(m_winId)) {
|
||||
icon = KWindowSystem::self()->icon(m_winId);
|
||||
} else {
|
||||
// fallback to plasma icon
|
||||
icon = QIcon::fromTheme("plasma");
|
||||
}
|
||||
QImage image = icon.pixmap(boundingRect().size().toSize()).toImage();
|
||||
textureNode->reset(window()->createTextureFromImage(image));
|
||||
}
|
||||
|
||||
void WindowThumbnail::windowToTexture(WindowTextureNode *textureNode)
|
||||
{
|
||||
if (!m_damaged && textureNode->texture()) {
|
||||
return;
|
||||
}
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_connection_t *c = QX11Info::connection();
|
||||
if (m_pixmap == XCB_PIXMAP_NONE) {
|
||||
m_pixmap = pixmapForWindow();
|
||||
}
|
||||
if (m_pixmap == XCB_PIXMAP_NONE) {
|
||||
// create above failed
|
||||
iconToTexture(textureNode);
|
||||
return;
|
||||
}
|
||||
#if HAVE_GLX
|
||||
if (glXGetCurrentContext()) {
|
||||
if (!m_openGLFunctionsResolved) {
|
||||
resolveGLXFunctions();
|
||||
}
|
||||
if (!m_bindTexImage || !m_releaseTexImage) {
|
||||
iconToTexture(textureNode);
|
||||
return;
|
||||
}
|
||||
if (m_glxPixmap == XCB_PIXMAP_NONE) {
|
||||
auto geometryCookie = xcb_get_geometry_unchecked(c, m_pixmap);
|
||||
|
||||
if (!loadGLXTexture()) {
|
||||
iconToTexture(textureNode);
|
||||
return;
|
||||
}
|
||||
|
||||
QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> geo(xcb_get_geometry_reply(c, geometryCookie, Q_NULLPTR));
|
||||
QSize size;
|
||||
if (!geo.isNull()) {
|
||||
size.setWidth(geo->width);
|
||||
size.setHeight(geo->height);
|
||||
}
|
||||
textureNode->reset(window()->createTextureFromId(m_texture, size));
|
||||
}
|
||||
textureNode->texture()->bind();
|
||||
bindGLXTexture();
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
// just for safety to not crash
|
||||
iconToTexture(textureNode);
|
||||
}
|
||||
// TODO: add an egl variant
|
||||
textureNode->markDirty(QSGNode::DirtyForceUpdate);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_pixmap_t WindowThumbnail::pixmapForWindow()
|
||||
{
|
||||
xcb_connection_t *c = QX11Info::connection();
|
||||
xcb_pixmap_t pix = xcb_generate_id(c);
|
||||
auto cookie = xcb_composite_name_window_pixmap_checked(c, m_winId, pix);
|
||||
QScopedPointer<xcb_generic_error_t, QScopedPointerPodDeleter> error(xcb_request_check(c, cookie));
|
||||
if (error) {
|
||||
return XCB_PIXMAP_NONE;
|
||||
}
|
||||
return pix;
|
||||
}
|
||||
|
||||
#if HAVE_GLX
|
||||
void WindowThumbnail::resolveGLXFunctions()
|
||||
{
|
||||
auto *context = window()->openglContext();
|
||||
QList<QByteArray> extensions = QByteArray(glXQueryExtensionsString(QX11Info::display(), QX11Info::appScreen())).split(' ');
|
||||
if (extensions.contains(QByteArrayLiteral("GLX_EXT_texture_from_pixmap"))) {
|
||||
qDebug() << "Have texture from pixmap";
|
||||
m_bindTexImage = context->getProcAddress(QByteArrayLiteral("glXBindTexImageEXT"));
|
||||
m_releaseTexImage = context->getProcAddress(QByteArrayLiteral("glXReleaseTexImageEXT"));
|
||||
}
|
||||
m_openGLFunctionsResolved = true;
|
||||
}
|
||||
|
||||
void WindowThumbnail::bindGLXTexture()
|
||||
{
|
||||
Display *d = QX11Info::display();
|
||||
((glXReleaseTexImageEXT_func)(m_releaseTexImage))(d, m_glxPixmap, GLX_FRONT_LEFT_EXT);
|
||||
((glXBindTexImageEXT_func)(m_bindTexImage))(d, m_glxPixmap, GLX_FRONT_LEFT_EXT, NULL);
|
||||
resetDamaged();
|
||||
}
|
||||
|
||||
bool WindowThumbnail::loadGLXTexture()
|
||||
{
|
||||
GLXContext glxContext = glXGetCurrentContext();
|
||||
if (!glxContext) {
|
||||
return false;
|
||||
}
|
||||
Display *d = QX11Info::display();
|
||||
glGenTextures(1, &m_texture);
|
||||
int fbConfig = 0;
|
||||
glXQueryContext(d, glxContext, GLX_FBCONFIG_ID, &fbConfig);
|
||||
|
||||
int fbAttribs[] = {
|
||||
GLX_FBCONFIG_ID, fbConfig, XCB_NONE
|
||||
};
|
||||
int count = 0;
|
||||
GLXFBConfig *fbConfigs = glXChooseFBConfig(d, QX11Info::appScreen(), fbAttribs, &count);
|
||||
if (count == 0) {
|
||||
qDebug() << "Didn't get our FBConfig";
|
||||
return false;
|
||||
}
|
||||
|
||||
int bindRgb, bindRgba;
|
||||
glXGetFBConfigAttrib(d, fbConfigs[0], GLX_BIND_TO_TEXTURE_RGBA_EXT, &bindRgba);
|
||||
glXGetFBConfigAttrib(d, fbConfigs[0], GLX_BIND_TO_TEXTURE_RGB_EXT, &bindRgb);
|
||||
|
||||
XVisualInfo *vi = glXGetVisualFromFBConfig(d, fbConfigs[0]);
|
||||
int textureFormat;
|
||||
if (window()->openglContext()->format().hasAlpha())
|
||||
textureFormat = bindRgba ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
|
||||
else
|
||||
textureFormat = bindRgb ? GLX_TEXTURE_FORMAT_RGB_EXT : GLX_TEXTURE_FORMAT_RGBA_EXT;
|
||||
XFree(vi);
|
||||
|
||||
// we assume that Texture_2D is supported as we have a QtQuick OpenGL context
|
||||
int attrs[] = {
|
||||
GLX_TEXTURE_FORMAT_EXT, textureFormat,
|
||||
GLX_MIPMAP_TEXTURE_EXT, false,
|
||||
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, XCB_NONE
|
||||
};
|
||||
m_glxPixmap = glXCreatePixmap(d, fbConfigs[0], m_pixmap, attrs);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
void WindowThumbnail::resetDamaged()
|
||||
{
|
||||
m_damaged = false;
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_damage_subtract(QX11Info::connection(), m_damage, XCB_NONE, XCB_NONE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WindowThumbnail::stopRedirecting()
|
||||
{
|
||||
if (!m_xcb) {
|
||||
return;
|
||||
}
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_connection_t *c = QX11Info::connection();
|
||||
if (m_pixmap != XCB_PIXMAP_NONE) {
|
||||
xcb_free_pixmap(c, m_pixmap);
|
||||
m_pixmap = XCB_PIXMAP_NONE;
|
||||
}
|
||||
if (m_winId == XCB_WINDOW_NONE) {
|
||||
return;
|
||||
}
|
||||
xcb_composite_unredirect_window(c, m_winId, XCB_COMPOSITE_REDIRECT_AUTOMATIC);
|
||||
if (m_damage == XCB_NONE) {
|
||||
return;
|
||||
}
|
||||
xcb_damage_destroy(c, m_damage);
|
||||
m_damage = XCB_NONE;
|
||||
|
||||
const uint32_t values[] = {XCB_EVENT_MASK_NO_EVENT};
|
||||
xcb_change_window_attributes(c, m_winId, XCB_CW_EVENT_MASK, values);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WindowThumbnail::startRedirecting()
|
||||
{
|
||||
if (!m_xcb) {
|
||||
return;
|
||||
}
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_connection_t *c = QX11Info::connection();
|
||||
|
||||
// redirect the window
|
||||
xcb_composite_redirect_window(c, m_winId, XCB_COMPOSITE_REDIRECT_AUTOMATIC);
|
||||
|
||||
// generate the damage handle
|
||||
m_damage = xcb_generate_id(c);
|
||||
xcb_damage_create(c, m_damage, m_winId, XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
|
||||
|
||||
const uint32_t values[] = {XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
||||
xcb_change_window_attributes(c, m_winId, XCB_CW_EVENT_MASK, values);
|
||||
// force to update the texture
|
||||
m_damaged = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WindowThumbnail::discardPixmap()
|
||||
{
|
||||
if (!m_xcb) {
|
||||
return;
|
||||
}
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
#if HAVE_GLX
|
||||
if (m_glxPixmap != XCB_PIXMAP_NONE) {
|
||||
Display *d = QX11Info::display();
|
||||
((glXReleaseTexImageEXT_func)(m_releaseTexImage))(d, m_glxPixmap, GLX_FRONT_LEFT_EXT);
|
||||
glXDestroyPixmap(d, m_glxPixmap);
|
||||
m_glxPixmap = XCB_PIXMAP_NONE;
|
||||
glDeleteTextures(1, &m_texture);
|
||||
}
|
||||
#endif
|
||||
if (m_pixmap != XCB_WINDOW_NONE) {
|
||||
xcb_free_pixmap(QX11Info::connection(), m_pixmap);
|
||||
m_pixmap = XCB_PIXMAP_NONE;
|
||||
}
|
||||
m_damaged = true;
|
||||
update();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
124
src/declarativeimports/core/windowthumbnail.h
Normal file
124
src/declarativeimports/core/windowthumbnail.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2013 by Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef PLASMA_WINDOWTHUMBNAIL_H
|
||||
#define PLASMA_WINDOWTHUMBNAIL_H
|
||||
#include <config-plasma.h>
|
||||
// Qt
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QSGSimpleTextureNode>
|
||||
#include <QQuickItem>
|
||||
// xcb
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
#include <xcb/damage.h>
|
||||
#endif
|
||||
|
||||
class KWindowInfo;
|
||||
|
||||
namespace Plasma {
|
||||
|
||||
class WindowTextureNode;
|
||||
|
||||
/**
|
||||
* @brief Renders a thumbnail for the window specified by the @c winId property.
|
||||
*
|
||||
* This declarative item is able to render a live updating thumbnail for the
|
||||
* window specified by the given @c winId property. If it is not possible to get
|
||||
* the thumbnail, the window's icon is rendered instead or in case that the window
|
||||
* Id is invalid a generic fallback icon is used.
|
||||
*
|
||||
* The thumbnail does not necessarily fill out the complete geometry as the
|
||||
* thumbnail gets scaled keeping the aspect ratio. This means the thumbnail gets
|
||||
* rendered into the center of the item's geometry.
|
||||
*
|
||||
* Note: live updating thumbnails are only implemented on the X11 platform. On X11
|
||||
* a running compositor is not required as this item takes care of redirecting the
|
||||
* window. For technical reasons the window's frame is not included on X11.
|
||||
*
|
||||
* If the window closes, the thumbnail does not get destroyed, which allows to have
|
||||
* a window close animation.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* WindowThumbnail {
|
||||
* winId: 102760466
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
class WindowThumbnail : public QQuickItem, public QAbstractNativeEventFilter
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(uint winId READ winId WRITE setWinId NOTIFY winIdChanged)
|
||||
public:
|
||||
WindowThumbnail(QQuickItem *parent = 0);
|
||||
virtual ~WindowThumbnail();
|
||||
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long int *result);
|
||||
virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);
|
||||
|
||||
uint32_t winId() const;
|
||||
void setWinId(uint32_t winId);
|
||||
|
||||
Q_SIGNALS:
|
||||
void winIdChanged();
|
||||
|
||||
private:
|
||||
void iconToTexture(WindowTextureNode *textureNode);
|
||||
void windowToTexture(WindowTextureNode *textureNode);
|
||||
void startRedirecting();
|
||||
void stopRedirecting();
|
||||
void resetDamaged();
|
||||
void discardPixmap();
|
||||
bool m_xcb;
|
||||
uint32_t m_winId;
|
||||
bool m_damaged;
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_pixmap_t pixmapForWindow();
|
||||
bool m_openGLFunctionsResolved;
|
||||
uint8_t m_damageEventBase;
|
||||
xcb_damage_damage_t m_damage;
|
||||
xcb_pixmap_t m_pixmap;
|
||||
uint m_texture;
|
||||
#if HAVE_GLX
|
||||
void resolveGLXFunctions();
|
||||
bool loadGLXTexture();
|
||||
void bindGLXTexture();
|
||||
QFunctionPointer m_bindTexImage;
|
||||
QFunctionPointer m_releaseTexImage;
|
||||
xcb_pixmap_t m_glxPixmap;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SimpleTextureNode which cleans up the texture
|
||||
*
|
||||
*/
|
||||
class WindowTextureNode : public QSGSimpleTextureNode
|
||||
{
|
||||
public:
|
||||
WindowTextureNode();
|
||||
virtual ~WindowTextureNode();
|
||||
void reset(QSGTexture *texture);
|
||||
private:
|
||||
QScopedPointer<QSGTexture> m_texture;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PLASMA_WINDOWTHUMBNAIL_H
|
@ -4,6 +4,7 @@
|
||||
#cmakedefine01 PLASMA_NO_KUTILS
|
||||
#cmakedefine01 PLASMA_NO_GLOBAL_SHORTCUTS
|
||||
#cmakedefine01 HAVE_X11
|
||||
#cmakedefine01 HAVE_GLX
|
||||
|
||||
/*FIXME: Only used in CMakeLists.txt, to be removed ?*/
|
||||
#cmakedefine01 PLASMA_NO_KNEWSTUFF
|
||||
|
Loading…
Reference in New Issue
Block a user