From 31360bf6bcdc388c8546fefd495163a30b0918e5 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 19 Aug 2014 14:22:30 -0400 Subject: [PATCH] ephyr: Properly implement hardware cursors Technique is basically the same as in Xnest, just create a new cursor on the host server every time. Could be optimized to remember cursors on the host and merely switch among them, if someone's feeling adventurous. Signed-off-by: Adam Jackson --- configure.ac | 2 +- hw/kdrive/ephyr/Makefile.am | 1 + hw/kdrive/ephyr/ephyrcursor.c | 216 ++++++++++++++++++++++++++++++++++++++++++ hw/kdrive/ephyr/ephyrinit.c | 63 ------------ hw/kdrive/ephyr/hostx.c | 74 +++++++++++++++ hw/kdrive/ephyr/hostx.h | 5 + 6 files changed, 297 insertions(+), 64 deletions(-) create mode 100644 hw/kdrive/ephyr/ephyrcursor.c diff --git a/configure.ac b/configure.ac index f3d9654..e83949d 100644 --- a/configure.ac +++ b/configure.ac @@ -2364,7 +2364,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" + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" fi diff --git a/hw/kdrive/ephyr/Makefile.am b/hw/kdrive/ephyr/Makefile.am index 10c5917..155e11e 100644 --- a/hw/kdrive/ephyr/Makefile.am +++ b/hw/kdrive/ephyr/Makefile.am @@ -68,6 +68,7 @@ Xephyr_SOURCES = \ ephyr_draw.c \ os.c \ ephyrinit.c \ + ephyrcursor.c \ hostx.c \ hostx.h \ $(XV_SRCS) \ diff --git a/hw/kdrive/ephyr/ephyrcursor.c b/hw/kdrive/ephyr/ephyrcursor.c new file mode 100644 index 0000000..b19e301 --- /dev/null +++ b/hw/kdrive/ephyr/ephyrcursor.c @@ -0,0 +1,216 @@ +/* + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "ephyr.h" +#include "ephyrlog.h" +#include "hostx.h" +#include "cursorstr.h" +#include + +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 = hostx_get_cursor_gc(); + int w = cursor->bits->width, h = cursor->bits->height; + + 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); + + 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); + + 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 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, hostx_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); +} +#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) + 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; + + /* XXX really? */ + if (cursor) + attr = ephyrGetCursor(cursor)->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; +} + +void +ephyrCursorEnable(ScreenPtr screen) +{ +} + diff --git a/hw/kdrive/ephyr/ephyrinit.c b/hw/kdrive/ephyr/ephyrinit.c index fc00010..e823eb8 100644 --- a/hw/kdrive/ephyr/ephyrinit.c +++ b/hw/kdrive/ephyr/ephyrinit.c @@ -350,69 +350,6 @@ OsVendorInit(void) 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 */ diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c index 1c75974..f995fc0 100644 --- a/hw/kdrive/ephyr/hostx.c +++ b/hw/kdrive/ephyr/hostx.c @@ -70,6 +70,8 @@ struct EphyrHostXVars { xcb_visualtype_t *visual; Window winroot; xcb_gcontext_t gc; + xcb_gcontext_t curgc; + xcb_render_pictformat_t argb_format; int depth; Bool use_sw_cursor; Bool use_fullscreen; @@ -1157,6 +1159,78 @@ out: return is_ok; } +xcb_gcontext_t +hostx_get_cursor_gc(void) +{ + uint32_t mask = 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 */ + }; + + if (HostX.curgc == None) { + xcb_pixmap_t p = xcb_generate_id(HostX.conn); + HostX.curgc = xcb_generate_id(HostX.conn); + + xcb_create_pixmap(HostX.conn, 1, p, HostX.winroot /* XXX */, + 1, 1); + xcb_create_gc(HostX.conn, HostX.curgc, p, mask, val); + xcb_free_pixmap(HostX.conn, p); + } + + return HostX.curgc; +} + +xcb_render_pictformat_t +hostx_get_argb_format(void) +{ + if (HostX.argb_format == None) { + xcb_render_query_pict_formats_reply_t *formats; + xcb_render_pictforminfo_iterator_t i; + + formats = xcb_render_query_pict_formats_reply(HostX.conn, + xcb_render_query_pict_formats(HostX.conn), + NULL); + + for (i = xcb_render_query_pict_formats_formats_iterator(formats); + i.rem; + xcb_render_pictforminfo_next(&i)) { + + if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT) + continue; + + if (i.data->depth != 32) + continue; + + if (i.data->direct.red_mask != 0xff || + i.data->direct.green_mask != 0xff || + i.data->direct.blue_mask != 0xff || + i.data->direct.alpha_mask != 0xff) + continue; + + if (i.data->direct.red_shift != 16 || + i.data->direct.green_shift != 8 || + i.data->direct.blue_shift != 0 || + i.data->direct.alpha_shift != 24) + continue; + + HostX.argb_format = i.data->id; + break; + } + + free(formats); + } + + return HostX.argb_format; +} + #ifdef XF86DRI typedef struct { int is_valid; diff --git a/hw/kdrive/ephyr/hostx.h b/hw/kdrive/ephyr/hostx.h index e83323a..de488a4 100644 --- a/hw/kdrive/ephyr/hostx.h +++ b/hw/kdrive/ephyr/hostx.h @@ -29,6 +29,7 @@ #include #include #include +#include #include "ephyr.h" #define EPHYR_WANT_DEBUG 0 @@ -174,6 +175,10 @@ int hostx_set_window_bounding_rectangles(int a_window, int host_has_extension(xcb_extension_t *extension); +xcb_gcontext_t hostx_get_cursor_gc(void); + +xcb_render_pictformat_t hostx_get_argb_format(void); + #ifdef XF86DRI int hostx_lookup_peer_window(void *a_local_window, int *a_host_peer /*out parameter */ ); -- 1.9.3