Add a PlatformCursorImage to Platform and EffectsHandler

Summary:
There are several effects (screenshot, zoom) which need access to the
cursor image and cursor hotspot. So far these effects used X11
unconditionally to get the cursor which obviously does not work on
Wayland.

This change adds a new class PlatformCursorImage to kwinglobals which
wraps what a cursor is (image and hotspot) and adds a new virtual method
to Platform to provide such a PlatformCursorImage. By default it's the
cursor image the Platform tracks. On X11/standalone platform this new
virtual method is overriden and provides a PlatformCursorImage from X11
using the code previously used in screenshot effect.

Screenshot effect and zoom are adjusted to use the new API instead of
X11.

Test Plan:
Zoom effect tested on Wayland, now gets the proper cursor icon.
X11 functionality not yet tested.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D3093
icc-effect-5.14.5
Martin Gräßlin 2016-10-17 16:12:21 +02:00
parent bef9c9c8c5
commit ea52ef9e57
12 changed files with 97 additions and 24 deletions

View File

@ -237,6 +237,10 @@ public:
m_animationsSuported = set;
}
KWin::PlatformCursorImage cursorImage() const override {
return KWin::PlatformCursorImage();
}
private:
bool m_animationsSuported = true;
};

View File

@ -1559,6 +1559,11 @@ void EffectsHandlerImpl::highlightWindows(const QVector<EffectWindow *> &windows
e->perform(Effect::HighlightWindows, QVariantList{QVariant::fromValue(windows)});
}
PlatformCursorImage EffectsHandlerImpl::cursorImage() const
{
return kwinApp()->platform()->cursorImage();
}
//****************************************
// EffectWindowImpl
//****************************************

View File

@ -228,6 +228,8 @@ public:
bool animationsSupported() const override;
PlatformCursorImage cursorImage() const override;
Scene *scene() const {
return m_scene;
}

View File

@ -369,20 +369,13 @@ QImage ScreenShotEffect::blitScreenshot(const QRect &geometry)
}
void ScreenShotEffect::grabPointerImage(QImage& snapshot, int offsetx, int offsety)
// Uses the X11_EXTENSIONS_XFIXES_H extension to grab the pointer image, and overlays it onto the snapshot.
{
QScopedPointer<xcb_xfixes_get_cursor_image_reply_t, QScopedPointerPodDeleter> cursor(
xcb_xfixes_get_cursor_image_reply(xcbConnection(),
xcb_xfixes_get_cursor_image_unchecked(xcbConnection()),
NULL));
if (cursor.isNull())
const auto cursor = effects->cursorImage();
if (cursor.image().isNull())
return;
QImage qcursorimg((uchar *) xcb_xfixes_get_cursor_image_cursor_image(cursor.data()), cursor->width, cursor->height,
QImage::Format_ARGB32_Premultiplied);
QPainter painter(&snapshot);
painter.drawImage(QPointF(cursor->x - cursor->xhot - offsetx, cursor->y - cursor ->yhot - offsety), qcursorimg);
painter.drawImage(effects->cursorPos() - cursor.hotSpot() - QPoint(offsetx, offsety), cursor.image());
}
void ScreenShotEffect::convertFromGLImage(QImage &img, int w, int h)

View File

@ -188,23 +188,17 @@ void ZoomEffect::hideCursor()
void ZoomEffect::recreateTexture()
{
effects->makeOpenGLContextCurrent();
// load the cursor-theme image from the Xcursor-library
xcb_xfixes_get_cursor_image_cookie_t keks = xcb_xfixes_get_cursor_image_unchecked(xcbConnection());
xcb_xfixes_get_cursor_image_reply_t *ximg = xcb_xfixes_get_cursor_image_reply(xcbConnection(), keks, 0);
if (ximg) {
// turn the XcursorImage into a QImage that will be used to create the GLTexture/XRenderPicture.
imageWidth = ximg->width;
imageHeight = ximg->height;
cursorHotSpot = QPoint(ximg->xhot, ximg->yhot);
uint32_t *bits = xcb_xfixes_get_cursor_image_cursor_image(ximg);
QImage img((uchar*)bits, imageWidth, imageHeight, QImage::Format_ARGB32_Premultiplied);
const auto cursor = effects->cursorImage();
if (!cursor.image().isNull()) {
imageWidth = cursor.image().width();
imageHeight = cursor.image().height();
cursorHotSpot = cursor.hotSpot();
if (effects->isOpenGLCompositing())
texture.reset(new GLTexture(img));
texture.reset(new GLTexture(cursor.image()));
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if (effects->compositingType() == XRenderCompositing)
xrenderPicture.reset(new XRenderPicture(img));
xrenderPicture.reset(new XRenderPicture(cursor.image()));
#endif
free(ximg);
}
else {
qCDebug(KWINEFFECTS) << "Falling back to proportional mouse tracking!";

View File

@ -5,7 +5,7 @@ ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX KWINEFFECTS
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kwineffects_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KWinEffectsConfigVersion.cmake"
SOVERSION 9
SOVERSION 10
)
### xrenderutils lib ###

View File

@ -1185,6 +1185,13 @@ public:
**/
virtual bool animationsSupported() const = 0;
/**
* The current cursor image of the Platform.
* @see cursorPos
* @since 5.9
**/
virtual PlatformCursorImage cursorImage() const = 0;
/**
* @return @ref KConfigGroup which holds given effect's config options
**/

View File

@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KWIN_LIB_KWINGLOBALS_H
#include <QCoreApplication>
#include <QImage>
#include <QPoint>
#include <QVariant>
#include <QtX11Extras/QX11Info>
#include <QCoreApplication>
@ -197,6 +199,36 @@ KWIN_EXPORT int displayHeight()
return screen ? screen->height_in_pixels : 0;
}
/**
* Short wrapper for a cursor image provided by the Platform.
* @since 5.9
**/
class PlatformCursorImage {
public:
explicit PlatformCursorImage()
: m_image()
, m_hotSpot()
{
}
explicit PlatformCursorImage(const QImage &image, const QPoint &hotSpot)
: m_image(image)
, m_hotSpot(hotSpot)
{
}
virtual ~PlatformCursorImage() = default;
QImage image() const {
return m_image;
}
QPoint hotSpot() const {
return m_hotSpot;
}
private:
QImage m_image;
QPoint m_hotSpot;
};
} // namespace
#define KWIN_SINGLETON_VARIABLE(ClassName, variableName) \

View File

@ -54,6 +54,11 @@ QPoint Platform::softwareCursorHotspot() const
return input()->pointer()->cursorHotSpot();
}
PlatformCursorImage Platform::cursorImage() const
{
return PlatformCursorImage(softwareCursor(), softwareCursorHotspot());
}
Screens *Platform::createScreens(QObject *parent)
{
Q_UNUSED(parent)

View File

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_PLATFORM_H
#define KWIN_PLATFORM_H
#include <kwin_export.h>
#include <kwinglobals.h>
#include <epoxy/egl.h>
#include <fixx11h.h>
#include <QImage>
@ -161,6 +162,17 @@ public:
QPoint softwareCursorHotspot() const;
void markCursorAsRendered();
/**
* Returns a PlatformCursorImage. By default this is created by softwareCursor and
* softwareCursorHotspot. An implementing subclass can use this to provide a better
* suited PlatformCursorImage.
*
* @see softwareCursor
* @see softwareCursorHotspot
* @since 5.9
**/
virtual PlatformCursorImage cursorImage() const;
bool handlesOutputs() const {
return m_handlesOutputs;
}

View File

@ -208,4 +208,21 @@ void X11StandalonePlatform::createOpenGLSafePoint(OpenGLSafePoint safePoint)
group.sync();
}
PlatformCursorImage X11StandalonePlatform::cursorImage() const
{
auto c = kwinApp()->x11Connection();
QScopedPointer<xcb_xfixes_get_cursor_image_reply_t, QScopedPointerPodDeleter> cursor(
xcb_xfixes_get_cursor_image_reply(c,
xcb_xfixes_get_cursor_image_unchecked(c),
nullptr));
if (cursor.isNull()) {
return PlatformCursorImage();
}
QImage qcursorimg((uchar *) xcb_xfixes_get_cursor_image_cursor_image(cursor.data()), cursor->width, cursor->height,
QImage::Format_ARGB32_Premultiplied);
// deep copy of image as the data is going to be freed
return PlatformCursorImage(qcursorimg.copy(), QPoint(cursor->xhot, cursor->yhot));
}
}

View File

@ -49,6 +49,8 @@ public:
bool openGLCompositingIsBroken() const override;
void createOpenGLSafePoint(OpenGLSafePoint safePoint) override;
PlatformCursorImage cursorImage() const override;
private:
/**
* Tests whether GLX is supported and returns @c true