261 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			261 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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>
 | |
|  */
 | |
| 
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #include <xcb/render.h>
 | |
| #include <xcb/xcb_renderutil.h>
 | |
| 
 | |
| #include "mi/mipointer_priv.h"
 | |
| 
 | |
| #include "ephyr.h"
 | |
| #include "ephyrlog.h"
 | |
| #include "hostx.h"
 | |
| #include "cursorstr.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);
 | |
| }
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor)
 | |
| {
 | |
|     KdScreenPriv(screen);
 | |
|     KdScreenInfo *kscr = pScreenPriv->screen;
 | |
|     EphyrScrPriv *scr = kscr->driver;
 | |
| 
 | |
|     if (cursor->bits->argb && can_argb_cursor())
 | |
|         ephyrRealizeARGBCursor(scr, cursor);
 | |
|     else
 | |
|     {
 | |
|         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,
 | |
|                                sizeof(ephyrCursorRec)))
 | |
|         return FALSE;
 | |
| 
 | |
|     miPointerInitialize(screen,
 | |
|                         &EphyrPointerSpriteFuncs,
 | |
|                         &ephyrPointerScreenFuncs, FALSE);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 |