1/* 2 * Copyright © 2014 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Author: 24 * Adam Jackson <ajax@redhat.com> 25 */ 26 27#ifdef HAVE_DIX_CONFIG_H 28#include <dix-config.h> 29#endif 30#include "ephyr.h" 31#include "ephyrlog.h" 32#include "hostx.h" 33#include "cursorstr.h" 34#include <xcb/render.h> 35#include <xcb/xcb_renderutil.h> 36 37static DevPrivateKeyRec ephyrCursorPrivateKey; 38 39typedef struct _ephyrCursor { 40 xcb_cursor_t cursor; 41} ephyrCursorRec, *ephyrCursorPtr; 42 43static ephyrCursorPtr 44ephyrGetCursor(CursorPtr cursor) 45{ 46 return dixGetPrivateAddr(&cursor->devPrivates, &ephyrCursorPrivateKey); 47} 48 49static void 50ephyrRealizeCoreCursor(EphyrScrPriv *scr, CursorPtr cursor) 51{ 52 ephyrCursorPtr hw = ephyrGetCursor(cursor); 53 xcb_connection_t *conn = hostx_get_xcbconn(); 54 xcb_pixmap_t source, mask; 55 xcb_image_t *image; 56 xcb_gcontext_t gc; 57 int w = cursor->bits->width, h = cursor->bits->height; 58 uint32_t gcmask = XCB_GC_FUNCTION | 59 XCB_GC_PLANE_MASK | 60 XCB_GC_FOREGROUND | 61 XCB_GC_BACKGROUND | 62 XCB_GC_CLIP_MASK; 63 uint32_t val[] = { 64 XCB_GX_COPY, /* function */ 65 ~0, /* planemask */ 66 1L, /* foreground */ 67 0L, /* background */ 68 None, /* clipmask */ 69 }; 70 71 source = xcb_generate_id(conn); 72 mask = xcb_generate_id(conn); 73 xcb_create_pixmap(conn, 1, source, scr->win, w, h); 74 xcb_create_pixmap(conn, 1, mask, scr->win, w, h); 75 76 gc = xcb_generate_id(conn); 77 xcb_create_gc(conn, gc, source, gcmask, val); 78 79 image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP, 80 1, NULL, ~0, NULL); 81 image->data = cursor->bits->source; 82 xcb_image_put(conn, source, gc, image, 0, 0, 0); 83 xcb_image_destroy(image); 84 85 image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP, 86 1, NULL, ~0, NULL); 87 image->data = cursor->bits->mask; 88 xcb_image_put(conn, mask, gc, image, 0, 0, 0); 89 xcb_image_destroy(image); 90 91 xcb_free_gc(conn, gc); 92 93 hw->cursor = xcb_generate_id(conn); 94 xcb_create_cursor(conn, hw->cursor, source, mask, 95 cursor->foreRed, cursor->foreGreen, cursor->foreBlue, 96 cursor->backRed, cursor->backGreen, cursor->backBlue, 97 cursor->bits->xhot, cursor->bits->yhot); 98 99 xcb_free_pixmap(conn, source); 100 xcb_free_pixmap(conn, mask); 101} 102 103static xcb_render_pictformat_t 104get_argb_format(void) 105{ 106 static xcb_render_pictformat_t format; 107 if (format == None) { 108 xcb_connection_t *conn = hostx_get_xcbconn(); 109 xcb_render_query_pict_formats_cookie_t cookie; 110 xcb_render_query_pict_formats_reply_t *formats; 111 112 cookie = xcb_render_query_pict_formats(conn); 113 formats = 114 xcb_render_query_pict_formats_reply(conn, cookie, NULL); 115 116 format = 117 xcb_render_util_find_standard_format(formats, 118 XCB_PICT_STANDARD_ARGB_32)->id; 119 120 free(formats); 121 } 122 123 return format; 124} 125 126static void 127ephyrRealizeARGBCursor(EphyrScrPriv *scr, CursorPtr cursor) 128{ 129 ephyrCursorPtr hw = ephyrGetCursor(cursor); 130 xcb_connection_t *conn = hostx_get_xcbconn(); 131 xcb_gcontext_t gc; 132 xcb_pixmap_t source; 133 xcb_render_picture_t picture; 134 xcb_image_t *image; 135 int w = cursor->bits->width, h = cursor->bits->height; 136 137 /* dix' storage is PICT_a8r8g8b8 */ 138 source = xcb_generate_id(conn); 139 xcb_create_pixmap(conn, 32, source, scr->win, w, h); 140 141 gc = xcb_generate_id(conn); 142 xcb_create_gc(conn, gc, source, 0, NULL); 143 image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, 144 32, NULL, ~0, NULL); 145 image->data = (void *)cursor->bits->argb; 146 xcb_image_put(conn, source, gc, image, 0, 0, 0); 147 xcb_free_gc(conn, gc); 148 xcb_image_destroy(image); 149 150 picture = xcb_generate_id(conn); 151 xcb_render_create_picture(conn, picture, source, get_argb_format(), 152 0, NULL); 153 xcb_free_pixmap(conn, source); 154 155 hw->cursor = xcb_generate_id(conn); 156 xcb_render_create_cursor(conn, hw->cursor, picture, 157 cursor->bits->xhot, cursor->bits->yhot); 158 159 xcb_render_free_picture(conn, picture); 160} 161 162static Bool 163can_argb_cursor(void) 164{ 165 static const xcb_render_query_version_reply_t *v; 166 167 if (!v) 168 v = xcb_render_util_query_version(hostx_get_xcbconn()); 169 170 return v->major_version == 0 && v->minor_version >= 5; 171} 172 173static Bool 174ephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor) 175{ 176 KdScreenPriv(screen); 177 KdScreenInfo *kscr = pScreenPriv->screen; 178 EphyrScrPriv *scr = kscr->driver; 179 180 if (cursor->bits->argb && can_argb_cursor()) 181 ephyrRealizeARGBCursor(scr, cursor); 182 else 183 { 184 ephyrRealizeCoreCursor(scr, cursor); 185 } 186 return TRUE; 187} 188 189static Bool 190ephyrUnrealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor) 191{ 192 ephyrCursorPtr hw = ephyrGetCursor(cursor); 193 194 if (hw->cursor) { 195 xcb_free_cursor(hostx_get_xcbconn(), hw->cursor); 196 hw->cursor = None; 197 } 198 199 return TRUE; 200} 201 202static void 203ephyrSetCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor, int x, 204 int y) 205{ 206 KdScreenPriv(screen); 207 KdScreenInfo *kscr = pScreenPriv->screen; 208 EphyrScrPriv *scr = kscr->driver; 209 uint32_t attr = None; 210 211 if (cursor) 212 attr = ephyrGetCursor(cursor)->cursor; 213 else 214 attr = hostx_get_empty_cursor(); 215 216 xcb_change_window_attributes(hostx_get_xcbconn(), scr->win, 217 XCB_CW_CURSOR, &attr); 218 xcb_flush(hostx_get_xcbconn()); 219} 220 221static void 222ephyrMoveCursor(DeviceIntPtr dev, ScreenPtr screen, int x, int y) 223{ 224} 225 226static Bool 227ephyrDeviceCursorInitialize(DeviceIntPtr dev, ScreenPtr screen) 228{ 229 return TRUE; 230} 231 232static void 233ephyrDeviceCursorCleanup(DeviceIntPtr dev, ScreenPtr screen) 234{ 235} 236 237miPointerSpriteFuncRec EphyrPointerSpriteFuncs = { 238 ephyrRealizeCursor, 239 ephyrUnrealizeCursor, 240 ephyrSetCursor, 241 ephyrMoveCursor, 242 ephyrDeviceCursorInitialize, 243 ephyrDeviceCursorCleanup 244}; 245 246Bool 247ephyrCursorInit(ScreenPtr screen) 248{ 249 if (!dixRegisterPrivateKey(&ephyrCursorPrivateKey, PRIVATE_CURSOR, 250 sizeof(ephyrCursorRec))) 251 return FALSE; 252 253 miPointerInitialize(screen, 254 &EphyrPointerSpriteFuncs, 255 &ephyrPointerScreenFuncs, FALSE); 256 257 return TRUE; 258} 259