/* * Copyright 2009, 2010 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 * on the rights to use, copy, modify, merge, publish, distribute, sub * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS 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. * */ /** \file qxl_cursor.c * \author Søren Sandmann */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "qxl.h" #include static void push_cursor (qxl_screen_t *qxl, struct qxl_bo *cursor_bo) { qxl->bo_funcs->write_command (qxl, QXL_CMD_CURSOR, cursor_bo); } static struct qxl_bo * qxl_alloc_cursor_cmd(qxl_screen_t *qxl) { struct qxl_bo *bo = qxl->bo_funcs->cmd_alloc (qxl, sizeof(struct QXLCursorCmd), "cursor command"); struct QXLCursorCmd *cmd = qxl->bo_funcs->bo_map(bo); cmd->release_info.id = pointer_to_u64 (bo) | 1; qxl->bo_funcs->bo_unmap(bo); return bo; } static void qxl_set_cursor_position(ScrnInfoPtr pScrn, int x, int y) { qxl_screen_t *qxl = pScrn->driverPrivate; struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl); struct QXLCursorCmd *cmd = qxl->bo_funcs->bo_map(cmd_bo); qxl->cur_x = x; qxl->cur_y = y; cmd->type = QXL_CURSOR_MOVE; cmd->u.position.x = qxl->cur_x + qxl->hot_x; cmd->u.position.y = qxl->cur_y + qxl->hot_y; qxl->bo_funcs->bo_unmap(cmd_bo); push_cursor(qxl, cmd_bo); } static void qxl_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *bits) { } static void qxl_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg) { /* Should not be called since UseHWCursor returned FALSE */ } static void qxl_load_cursor_argb (ScrnInfoPtr pScrn, CursorPtr pCurs) { qxl_screen_t *qxl = pScrn->driverPrivate; int w = pCurs->bits->width; int h = pCurs->bits->height; int size = w * h * sizeof (CARD32); struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl); struct QXLCursorCmd *cmd; struct qxl_bo *cursor_bo = qxl->bo_funcs->bo_alloc(qxl, sizeof(struct QXLCursor) + size, "cursor data"); struct QXLCursor *cursor = qxl->bo_funcs->bo_map(cursor_bo); cursor->header.unique = 0; cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; cursor->header.width = w; cursor->header.height = h; /* I wonder if we can just tell the client that the hotspot is 0, 0 * always? The coordinates we are getting from X are for 0, 0 anyway, * so the question is if the client uses the hotspot for anything else? */ cursor->header.hot_spot_x = pCurs->bits->xhot; cursor->header.hot_spot_y = pCurs->bits->yhot; cursor->data_size = size; cursor->chunk.next_chunk = 0; cursor->chunk.prev_chunk = 0; cursor->chunk.data_size = size; memcpy (cursor->chunk.data, pCurs->bits->argb, size); #if 0 int i, j; for (j = 0; j < h; ++j) { for (i = 0; i < w; ++i) { ErrorF ("%c", (pCurs->bits->argb[j * w + i] & 0xff000000) == 0xff000000? '#' : '.'); } ErrorF ("\n"); } #endif qxl->bo_funcs->bo_unmap(cursor_bo); qxl->hot_x = pCurs->bits->xhot; qxl->hot_y = pCurs->bits->yhot; cmd = qxl->bo_funcs->bo_map(cmd_bo); cmd->type = QXL_CURSOR_SET; cmd->u.set.position.x = qxl->cur_x + qxl->hot_x; cmd->u.set.position.y = qxl->cur_y + qxl->hot_y; qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(struct QXLCursorCmd, u.set.shape), cmd_bo, cursor_bo); cmd->u.set.visible = TRUE; qxl->bo_funcs->bo_unmap(cmd_bo); push_cursor(qxl, cmd_bo); qxl->bo_funcs->bo_decref(qxl, cursor_bo); } static Bool qxl_use_hw_cursor (ScreenPtr pScrn, CursorPtr pCurs) { /* Old-school bitmap cursors are not * hardware accelerated for now. */ return FALSE; } static Bool qxl_use_hw_cursorARGB (ScreenPtr pScrn, CursorPtr pCurs) { return TRUE; } static void qxl_hide_cursor(ScrnInfoPtr pScrn) { qxl_screen_t *qxl = pScrn->driverPrivate; struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl); struct QXLCursorCmd *cursor = qxl->bo_funcs->bo_map(cmd_bo); cursor->type = QXL_CURSOR_HIDE; qxl->bo_funcs->bo_unmap(cmd_bo); push_cursor(qxl, cmd_bo); } static void qxl_show_cursor(ScrnInfoPtr pScrn) { /* * slightly hacky, but there's no QXL_CURSOR_SHOW. Could maybe do * QXL_CURSOR_SET? */ qxl_screen_t *qxl = pScrn->driverPrivate; qxl_set_cursor_position(pScrn, qxl->cur_x, qxl->cur_y); } hidden void qxl_cursor_init(ScreenPtr pScreen) { xf86CursorInfoPtr cursor; cursor = calloc(1, sizeof(xf86CursorInfoRec)); if (!cursor) return; cursor->MaxWidth = cursor->MaxHeight = 64; /* cursor->Flags; */ cursor->SetCursorPosition = qxl_set_cursor_position; cursor->LoadCursorARGB = qxl_load_cursor_argb; cursor->UseHWCursor = qxl_use_hw_cursor; cursor->UseHWCursorARGB = qxl_use_hw_cursorARGB; cursor->LoadCursorImage = qxl_load_cursor_image; cursor->SetCursorColors = qxl_set_cursor_colors; cursor->HideCursor = qxl_hide_cursor; cursor->ShowCursor = qxl_show_cursor; if (!xf86InitCursor(pScreen, cursor)) free(cursor); }