ephyr: Properly implement hardware cursors (v3)
When dix hands us a new cursor we proxy it through to the host server; since we keep the host XID on the cursor bits private we can switch among them with just ChangeWindowAttributes. v2: Use xcb-renderutil for argb format lookup (Uli, Keith) Fall back to core cursors for host RENDER < 0.5 (Keith) Drop useless ephyrEnableCursor Consistently create/destroy the cursor image GC on both paths Treat null cursor from dix as invisible v3: Initialize the invisible cursor's image (Keith) Signed-off-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
parent
f839caadd4
commit
670ee0757f
|
@ -2349,7 +2349,7 @@ if test "$KDRIVE" = yes; then
|
|||
AC_DEFINE(KDRIVE_MOUSE, 1, [Enable KDrive mouse driver])
|
||||
fi
|
||||
|
||||
XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms xcb-randr"
|
||||
XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms xcb-randr"
|
||||
if test "x$XV" = xyes; then
|
||||
XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv"
|
||||
fi
|
||||
|
|
|
@ -68,6 +68,7 @@ Xephyr_SOURCES = \
|
|||
ephyr_draw.c \
|
||||
os.c \
|
||||
ephyrinit.c \
|
||||
ephyrcursor.c \
|
||||
hostx.c \
|
||||
hostx.h \
|
||||
$(XV_SRCS) \
|
||||
|
|
|
@ -197,8 +197,6 @@ extern KdOsFuncs EphyrOsFuncs;
|
|||
|
||||
extern Bool ephyrCursorInit(ScreenPtr pScreen);
|
||||
|
||||
extern void ephyrCursorEnable(ScreenPtr pScreen);
|
||||
|
||||
extern int ephyrBufferHeight(KdScreenInfo * screen);
|
||||
|
||||
/* ephyr_draw.c */
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright © 2014 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author:
|
||||
* Adam Jackson <ajax@redhat.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <kdrive-config.h>
|
||||
#endif
|
||||
#include "ephyr.h"
|
||||
#include "ephyrlog.h"
|
||||
#include "hostx.h"
|
||||
#include "cursorstr.h"
|
||||
#include <xcb/render.h>
|
||||
#include <xcb/xcb_renderutil.h>
|
||||
|
||||
static DevPrivateKeyRec ephyrCursorPrivateKey;
|
||||
|
||||
typedef struct _ephyrCursor {
|
||||
xcb_cursor_t cursor;
|
||||
} ephyrCursorRec, *ephyrCursorPtr;
|
||||
|
||||
static ephyrCursorPtr
|
||||
ephyrGetCursor(CursorPtr cursor)
|
||||
{
|
||||
return dixGetPrivateAddr(&cursor->devPrivates, &ephyrCursorPrivateKey);
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrRealizeCoreCursor(EphyrScrPriv *scr, CursorPtr cursor)
|
||||
{
|
||||
ephyrCursorPtr hw = ephyrGetCursor(cursor);
|
||||
xcb_connection_t *conn = hostx_get_xcbconn();
|
||||
xcb_pixmap_t source, mask;
|
||||
xcb_image_t *image;
|
||||
xcb_gcontext_t gc;
|
||||
int w = cursor->bits->width, h = cursor->bits->height;
|
||||
uint32_t gcmask = XCB_GC_FUNCTION |
|
||||
XCB_GC_PLANE_MASK |
|
||||
XCB_GC_FOREGROUND |
|
||||
XCB_GC_BACKGROUND |
|
||||
XCB_GC_CLIP_MASK;
|
||||
uint32_t val[] = {
|
||||
XCB_GX_COPY, /* function */
|
||||
~0, /* planemask */
|
||||
1L, /* foreground */
|
||||
0L, /* background */
|
||||
None, /* clipmask */
|
||||
};
|
||||
|
||||
source = xcb_generate_id(conn);
|
||||
mask = xcb_generate_id(conn);
|
||||
xcb_create_pixmap(conn, 1, source, scr->win, w, h);
|
||||
xcb_create_pixmap(conn, 1, mask, scr->win, w, h);
|
||||
|
||||
gc = xcb_generate_id(conn);
|
||||
xcb_create_gc(conn, gc, source, gcmask, val);
|
||||
|
||||
image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP,
|
||||
1, NULL, ~0, NULL);
|
||||
image->data = cursor->bits->source;
|
||||
xcb_image_put(conn, source, gc, image, 0, 0, 0);
|
||||
xcb_image_destroy(image);
|
||||
|
||||
image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP,
|
||||
1, NULL, ~0, NULL);
|
||||
image->data = cursor->bits->mask;
|
||||
xcb_image_put(conn, mask, gc, image, 0, 0, 0);
|
||||
xcb_image_destroy(image);
|
||||
|
||||
xcb_free_gc(conn, gc);
|
||||
|
||||
hw->cursor = xcb_generate_id(conn);
|
||||
xcb_create_cursor(conn, hw->cursor, source, mask,
|
||||
cursor->foreRed, cursor->foreGreen, cursor->foreBlue,
|
||||
cursor->backRed, cursor->backGreen, cursor->backBlue,
|
||||
cursor->bits->xhot, cursor->bits->yhot);
|
||||
|
||||
xcb_free_pixmap(conn, source);
|
||||
xcb_free_pixmap(conn, mask);
|
||||
}
|
||||
|
||||
#ifdef ARGB_CURSOR
|
||||
static xcb_render_pictformat_t
|
||||
get_argb_format(void)
|
||||
{
|
||||
static xcb_render_pictformat_t format;
|
||||
if (format == None) {
|
||||
xcb_connection_t *conn = hostx_get_xcbconn();
|
||||
xcb_render_query_pict_formats_cookie_t cookie;
|
||||
xcb_render_query_pict_formats_reply_t *formats;
|
||||
|
||||
cookie = xcb_render_query_pict_formats(conn);
|
||||
formats =
|
||||
xcb_render_query_pict_formats_reply(conn, cookie, NULL);
|
||||
|
||||
format =
|
||||
xcb_render_util_find_standard_format(formats,
|
||||
XCB_PICT_STANDARD_ARGB_32)->id;
|
||||
|
||||
free(formats);
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrRealizeARGBCursor(EphyrScrPriv *scr, CursorPtr cursor)
|
||||
{
|
||||
ephyrCursorPtr hw = ephyrGetCursor(cursor);
|
||||
xcb_connection_t *conn = hostx_get_xcbconn();
|
||||
xcb_gcontext_t gc;
|
||||
xcb_pixmap_t source;
|
||||
xcb_render_picture_t picture;
|
||||
xcb_image_t *image;
|
||||
int w = cursor->bits->width, h = cursor->bits->height;
|
||||
|
||||
/* dix' storage is PICT_a8r8g8b8 */
|
||||
source = xcb_generate_id(conn);
|
||||
xcb_create_pixmap(conn, 32, source, scr->win, w, h);
|
||||
|
||||
gc = xcb_generate_id(conn);
|
||||
xcb_create_gc(conn, gc, source, 0, NULL);
|
||||
image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
|
||||
32, NULL, ~0, NULL);
|
||||
image->data = (void *)cursor->bits->argb;
|
||||
xcb_image_put(conn, source, gc, image, 0, 0, 0);
|
||||
xcb_free_gc(conn, gc);
|
||||
xcb_image_destroy(image);
|
||||
|
||||
picture = xcb_generate_id(conn);
|
||||
xcb_render_create_picture(conn, picture, source, get_argb_format(),
|
||||
0, NULL);
|
||||
xcb_free_pixmap(conn, source);
|
||||
|
||||
hw->cursor = xcb_generate_id(conn);
|
||||
xcb_render_create_cursor(conn, hw->cursor, picture,
|
||||
cursor->bits->xhot, cursor->bits->yhot);
|
||||
|
||||
xcb_render_free_picture(conn, picture);
|
||||
}
|
||||
|
||||
static Bool
|
||||
can_argb_cursor(void)
|
||||
{
|
||||
static const xcb_render_query_version_reply_t *v;
|
||||
|
||||
if (!v)
|
||||
v = xcb_render_util_query_version(hostx_get_xcbconn());
|
||||
|
||||
return v->major_version == 0 && v->minor_version >= 5;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Bool
|
||||
ephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor)
|
||||
{
|
||||
KdScreenPriv(screen);
|
||||
KdScreenInfo *kscr = pScreenPriv->screen;
|
||||
EphyrScrPriv *scr = kscr->driver;
|
||||
|
||||
#ifdef ARGB_CURSOR
|
||||
if (cursor->bits->argb && can_argb_cursor())
|
||||
ephyrRealizeARGBCursor(scr, cursor);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ephyrRealizeCoreCursor(scr, cursor);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static Bool
|
||||
ephyrUnrealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor)
|
||||
{
|
||||
ephyrCursorPtr hw = ephyrGetCursor(cursor);
|
||||
|
||||
if (hw->cursor) {
|
||||
xcb_free_cursor(hostx_get_xcbconn(), hw->cursor);
|
||||
hw->cursor = None;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrSetCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor, int x,
|
||||
int y)
|
||||
{
|
||||
KdScreenPriv(screen);
|
||||
KdScreenInfo *kscr = pScreenPriv->screen;
|
||||
EphyrScrPriv *scr = kscr->driver;
|
||||
uint32_t attr = None;
|
||||
|
||||
if (cursor)
|
||||
attr = ephyrGetCursor(cursor)->cursor;
|
||||
else
|
||||
attr = hostx_get_empty_cursor();
|
||||
|
||||
xcb_change_window_attributes(hostx_get_xcbconn(), scr->win,
|
||||
XCB_CW_CURSOR, &attr);
|
||||
xcb_flush(hostx_get_xcbconn());
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrMoveCursor(DeviceIntPtr dev, ScreenPtr screen, int x, int y)
|
||||
{
|
||||
}
|
||||
|
||||
static Bool
|
||||
ephyrDeviceCursorInitialize(DeviceIntPtr dev, ScreenPtr screen)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrDeviceCursorCleanup(DeviceIntPtr dev, ScreenPtr screen)
|
||||
{
|
||||
}
|
||||
|
||||
miPointerSpriteFuncRec EphyrPointerSpriteFuncs = {
|
||||
ephyrRealizeCursor,
|
||||
ephyrUnrealizeCursor,
|
||||
ephyrSetCursor,
|
||||
ephyrMoveCursor,
|
||||
ephyrDeviceCursorInitialize,
|
||||
ephyrDeviceCursorCleanup
|
||||
};
|
||||
|
||||
Bool
|
||||
ephyrCursorInit(ScreenPtr screen)
|
||||
{
|
||||
if (!dixRegisterPrivateKey(&ephyrCursorPrivateKey, PRIVATE_CURSOR_BITS,
|
||||
sizeof(ephyrCursorRec)))
|
||||
return FALSE;
|
||||
|
||||
miPointerInitialize(screen,
|
||||
&EphyrPointerSpriteFuncs,
|
||||
&ephyrPointerScreenFuncs, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -369,77 +369,12 @@ OsVendorInit(void)
|
|||
{
|
||||
EPHYR_DBG("mark");
|
||||
|
||||
if (hostx_want_host_cursor()) {
|
||||
if (hostx_want_host_cursor())
|
||||
ephyrFuncs.initCursor = &ephyrCursorInit;
|
||||
ephyrFuncs.enableCursor = &ephyrCursorEnable;
|
||||
}
|
||||
|
||||
KdOsInit(&EphyrOsFuncs);
|
||||
}
|
||||
|
||||
/* 'Fake' cursor stuff, could be improved */
|
||||
|
||||
static Bool
|
||||
ephyrRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static Bool
|
||||
ephyrUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x,
|
||||
int y)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static Bool
|
||||
ephyrDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
|
||||
{
|
||||
}
|
||||
|
||||
miPointerSpriteFuncRec EphyrPointerSpriteFuncs = {
|
||||
ephyrRealizeCursor,
|
||||
ephyrUnrealizeCursor,
|
||||
ephyrSetCursor,
|
||||
ephyrMoveCursor,
|
||||
ephyrDeviceCursorInitialize,
|
||||
ephyrDeviceCursorCleanup
|
||||
};
|
||||
|
||||
Bool
|
||||
ephyrCursorInit(ScreenPtr pScreen)
|
||||
{
|
||||
miPointerInitialize(pScreen,
|
||||
&EphyrPointerSpriteFuncs,
|
||||
&ephyrPointerScreenFuncs, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ephyrCursorEnable(ScreenPtr pScreen)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
KdCardFuncs ephyrFuncs = {
|
||||
ephyrCardInit, /* cardinit */
|
||||
ephyrScreenInitialize, /* scrinit */
|
||||
|
|
|
@ -71,6 +71,8 @@ struct EphyrHostXVars {
|
|||
xcb_visualtype_t *visual;
|
||||
Window winroot;
|
||||
xcb_gcontext_t gc;
|
||||
xcb_render_pictformat_t argb_format;
|
||||
xcb_cursor_t empty_cursor;
|
||||
int depth;
|
||||
Bool use_sw_cursor;
|
||||
Bool use_fullscreen;
|
||||
|
@ -202,6 +204,12 @@ hostx_use_sw_cursor(void)
|
|||
HostX.use_sw_cursor = TRUE;
|
||||
}
|
||||
|
||||
xcb_cursor_t
|
||||
hostx_get_empty_cursor(void)
|
||||
{
|
||||
return HostX.empty_cursor;
|
||||
}
|
||||
|
||||
int
|
||||
hostx_want_preexisting_window(KdScreenInfo *screen)
|
||||
{
|
||||
|
@ -408,8 +416,8 @@ hostx_init(void)
|
|||
{
|
||||
uint32_t attrs[2];
|
||||
uint32_t attr_mask = 0;
|
||||
xcb_cursor_t empty_cursor;
|
||||
xcb_pixmap_t cursor_pxm;
|
||||
xcb_gcontext_t cursor_gc;
|
||||
uint16_t red, green, blue;
|
||||
uint32_t pixel;
|
||||
int index;
|
||||
|
@ -418,6 +426,7 @@ hostx_init(void)
|
|||
size_t class_len;
|
||||
const xcb_query_extension_reply_t *shm_rep;
|
||||
xcb_screen_t *xscreen;
|
||||
xcb_rectangle_t rect = { 0, 0, 1, 1 };
|
||||
|
||||
attrs[0] =
|
||||
XCB_EVENT_MASK_BUTTON_PRESS
|
||||
|
@ -594,18 +603,25 @@ hostx_init(void)
|
|||
|
||||
xcb_change_gc(HostX.conn, HostX.gc, XCB_GC_FOREGROUND, &pixel);
|
||||
|
||||
cursor_pxm = xcb_generate_id(HostX.conn);
|
||||
xcb_create_pixmap(HostX.conn, 1, cursor_pxm, HostX.winroot, 1, 1);
|
||||
cursor_gc = xcb_generate_id(HostX.conn);
|
||||
pixel = 0;
|
||||
xcb_create_gc(HostX.conn, cursor_gc, cursor_pxm,
|
||||
XCB_GC_FOREGROUND, &pixel);
|
||||
xcb_poly_fill_rectangle(HostX.conn, cursor_pxm, cursor_gc, 1, &rect);
|
||||
xcb_free_gc(HostX.conn, cursor_gc);
|
||||
HostX.empty_cursor = xcb_generate_id(HostX.conn);
|
||||
xcb_create_cursor(HostX.conn,
|
||||
HostX.empty_cursor,
|
||||
cursor_pxm, cursor_pxm,
|
||||
0,0,0,
|
||||
0,0,0,
|
||||
1,1);
|
||||
xcb_free_pixmap(HostX.conn, cursor_pxm);
|
||||
if (!hostx_want_host_cursor ()) {
|
||||
CursorVisible = TRUE;
|
||||
/* Ditch the cursor, we provide our 'own' */
|
||||
cursor_pxm = xcb_generate_id(HostX.conn);
|
||||
xcb_create_pixmap(HostX.conn, 1, cursor_pxm, HostX.winroot, 1, 1);
|
||||
empty_cursor = xcb_generate_id(HostX.conn);
|
||||
xcb_create_cursor(HostX.conn,
|
||||
empty_cursor,
|
||||
cursor_pxm, cursor_pxm,
|
||||
0,0,0,
|
||||
0,0,0,
|
||||
1,1);
|
||||
for (index = 0; index < HostX.n_screens; index++) {
|
||||
KdScreenInfo *screen = HostX.screens[index];
|
||||
EphyrScrPriv *scrpriv = screen->driver;
|
||||
|
@ -613,9 +629,8 @@ hostx_init(void)
|
|||
xcb_change_window_attributes(HostX.conn,
|
||||
scrpriv->win,
|
||||
XCB_CW_CURSOR,
|
||||
&empty_cursor);
|
||||
&HostX.empty_cursor);
|
||||
}
|
||||
xcb_free_pixmap(HostX.conn, cursor_pxm);
|
||||
}
|
||||
|
||||
/* Try to get share memory ximages for a little bit more speed */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <X11/X.h>
|
||||
#include <X11/Xmd.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/render.h>
|
||||
#include "ephyr.h"
|
||||
|
||||
#define EPHYR_WANT_DEBUG 0
|
||||
|
@ -82,6 +83,9 @@ int
|
|||
void
|
||||
hostx_use_sw_cursor(void);
|
||||
|
||||
xcb_cursor_t
|
||||
hostx_get_empty_cursor(void);
|
||||
|
||||
void
|
||||
hostx_get_output_geometry(const char *output,
|
||||
int *x, int *y,
|
||||
|
|
Loading…
Reference in New Issue