1/*
2 * Copyright 2009, 2010 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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23/** \file qxl_cursor.c
24 * \author Søren Sandmann <sandmann@redhat.com>
25 */
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include <string.h>
31#include "qxl.h"
32#include <cursorstr.h>
33
34static void
35push_cursor (qxl_screen_t *qxl, struct qxl_bo *cursor_bo)
36{
37    qxl->bo_funcs->write_command (qxl, QXL_CMD_CURSOR, cursor_bo);
38}
39
40static struct qxl_bo *
41qxl_alloc_cursor_cmd(qxl_screen_t *qxl)
42{
43    struct qxl_bo *bo = qxl->bo_funcs->cmd_alloc (qxl, sizeof(struct QXLCursorCmd), "cursor command");
44    struct QXLCursorCmd *cmd = qxl->bo_funcs->bo_map(bo);
45
46    cmd->release_info.id = pointer_to_u64 (bo) | 1;
47
48    qxl->bo_funcs->bo_unmap(bo);
49    return bo;
50}
51
52static void
53qxl_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
54{
55    qxl_screen_t *qxl = pScrn->driverPrivate;
56    struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl);
57    struct QXLCursorCmd *cmd = qxl->bo_funcs->bo_map(cmd_bo);
58
59    qxl->cur_x = x;
60    qxl->cur_y = y;
61
62    cmd->type = QXL_CURSOR_MOVE;
63    cmd->u.position.x = qxl->cur_x + qxl->hot_x;
64    cmd->u.position.y = qxl->cur_y + qxl->hot_y;
65
66    qxl->bo_funcs->bo_unmap(cmd_bo);
67    push_cursor(qxl, cmd_bo);
68}
69
70static void
71qxl_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *bits)
72{
73}
74
75static void
76qxl_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
77{
78    /* Should not be called since UseHWCursor returned FALSE */
79}
80
81static void
82qxl_load_cursor_argb (ScrnInfoPtr pScrn, CursorPtr pCurs)
83{
84    qxl_screen_t *qxl = pScrn->driverPrivate;
85    int w = pCurs->bits->width;
86    int h = pCurs->bits->height;
87    int size = w * h * sizeof (CARD32);
88
89    struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl);
90    struct QXLCursorCmd *cmd;
91    struct qxl_bo *cursor_bo = qxl->bo_funcs->bo_alloc(qxl, sizeof(struct QXLCursor) + size, "cursor data");
92    struct QXLCursor *cursor = qxl->bo_funcs->bo_map(cursor_bo);
93
94    cursor->header.unique = 0;
95    cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
96    cursor->header.width = w;
97    cursor->header.height = h;
98    /* I wonder if we can just tell the client that the hotspot is 0, 0
99     * always? The coordinates we are getting from X are for 0, 0 anyway,
100     * so the question is if the client uses the hotspot for anything else?
101     */
102    cursor->header.hot_spot_x = pCurs->bits->xhot;
103    cursor->header.hot_spot_y = pCurs->bits->yhot;
104
105    cursor->data_size = size;
106
107    cursor->chunk.next_chunk = 0;
108    cursor->chunk.prev_chunk = 0;
109    cursor->chunk.data_size = size;
110
111    memcpy (cursor->chunk.data, pCurs->bits->argb, size);
112
113#if 0
114    int i, j;
115    for (j = 0; j < h; ++j)
116    {
117	for (i = 0; i < w; ++i)
118	{
119	    ErrorF ("%c", (pCurs->bits->argb[j * w + i] & 0xff000000) == 0xff000000? '#' : '.');
120	}
121
122	ErrorF ("\n");
123    }
124#endif
125
126    qxl->bo_funcs->bo_unmap(cursor_bo);
127
128    qxl->hot_x = pCurs->bits->xhot;
129    qxl->hot_y = pCurs->bits->yhot;
130
131    cmd = qxl->bo_funcs->bo_map(cmd_bo);
132    cmd->type = QXL_CURSOR_SET;
133    cmd->u.set.position.x = qxl->cur_x + qxl->hot_x;
134    cmd->u.set.position.y = qxl->cur_y + qxl->hot_y;
135    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(struct QXLCursorCmd, u.set.shape), cmd_bo, cursor_bo);
136
137    cmd->u.set.visible = TRUE;
138    qxl->bo_funcs->bo_unmap(cmd_bo);
139
140    push_cursor(qxl, cmd_bo);
141    qxl->bo_funcs->bo_decref(qxl, cursor_bo);
142}
143
144static Bool
145qxl_use_hw_cursor (ScreenPtr pScrn, CursorPtr pCurs)
146{
147    /* Old-school bitmap cursors are not
148     * hardware accelerated for now.
149     */
150    return FALSE;
151}
152
153static Bool
154qxl_use_hw_cursorARGB (ScreenPtr pScrn, CursorPtr pCurs)
155{
156    return TRUE;
157}
158
159static void
160qxl_hide_cursor(ScrnInfoPtr pScrn)
161{
162    qxl_screen_t *qxl = pScrn->driverPrivate;
163    struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl);
164    struct QXLCursorCmd *cursor = qxl->bo_funcs->bo_map(cmd_bo);
165
166    cursor->type = QXL_CURSOR_HIDE;
167
168    qxl->bo_funcs->bo_unmap(cmd_bo);
169    push_cursor(qxl, cmd_bo);
170}
171
172static void
173qxl_show_cursor(ScrnInfoPtr pScrn)
174{
175    /*
176     * slightly hacky, but there's no QXL_CURSOR_SHOW.  Could maybe do
177     * QXL_CURSOR_SET?
178     */
179    qxl_screen_t *qxl = pScrn->driverPrivate;
180
181    qxl_set_cursor_position(pScrn, qxl->cur_x, qxl->cur_y);
182}
183
184hidden void
185qxl_cursor_init(ScreenPtr pScreen)
186{
187    xf86CursorInfoPtr cursor;
188
189    cursor = calloc(1, sizeof(xf86CursorInfoRec));
190    if (!cursor)
191	return;
192
193    cursor->MaxWidth = cursor->MaxHeight = 64;
194    /* cursor->Flags; */
195    cursor->SetCursorPosition = qxl_set_cursor_position;
196    cursor->LoadCursorARGB = qxl_load_cursor_argb;
197    cursor->UseHWCursor = qxl_use_hw_cursor;
198    cursor->UseHWCursorARGB = qxl_use_hw_cursorARGB;
199    cursor->LoadCursorImage = qxl_load_cursor_image;
200    cursor->SetCursorColors = qxl_set_cursor_colors;
201    cursor->HideCursor = qxl_hide_cursor;
202    cursor->ShowCursor = qxl_show_cursor;
203
204    if (!xf86InitCursor(pScreen, cursor))
205      free(cursor);
206}
207