Commit 584129bc authored by Jeremy White's avatar Jeremy White

Add support for cursors.

parent 1c9085af
......@@ -65,6 +65,37 @@ static int bits_per_pixel(display_t *d)
}
static void handle_cursor_notify(display_t *display, xcb_xfixes_cursor_notify_event_t *cev)
{
xcb_xfixes_get_cursor_image_cookie_t icookie;
xcb_xfixes_get_cursor_image_reply_t *ir;
xcb_generic_error_t *error;
int imglen;
uint32_t *imgdata;
g_debug("Cursor Notify [seq %d|subtype %d|serial %u]",
cev->sequence, cev->subtype, cev->cursor_serial);
icookie = xcb_xfixes_get_cursor_image(display->c);
ir = xcb_xfixes_get_cursor_image_reply(display->c, icookie, &error);
if (error)
{
g_error("Could not get cursor_image_reply; type %d; code %d; major %d; minor %d\n",
error->response_type, error->error_code, error->major_code, error->minor_code);
return;
}
imglen = xcb_xfixes_get_cursor_image_cursor_image_length(ir);
imgdata = xcb_xfixes_get_cursor_image_cursor_image(ir);
session_push_cursor_image(display->session,
ir->x, ir->y, ir->width, ir->height, ir->xhot, ir->yhot,
imglen * sizeof(*imgdata), (uint8_t *) imgdata);
free(ir);
}
static void handle_damage_notify(display_t *display, xcb_damage_notify_event_t *dev, pixman_region16_t *damage_region)
{
int i, n;
......@@ -106,7 +137,10 @@ static void * handle_xevents(void *opaque)
// FIXME - we do not have a good way to cause this thread to exit gracefully
while ((ev = xcb_wait_for_event(display->c)))
{
if (ev->response_type == display->damage_ext->first_event + XCB_DAMAGE_NOTIFY)
if (ev->response_type == display->xfixes_ext->first_event + XCB_XFIXES_CURSOR_NOTIFY)
handle_cursor_notify(display, (xcb_xfixes_cursor_notify_event_t *) ev);
else if (ev->response_type == display->damage_ext->first_event + XCB_DAMAGE_NOTIFY)
handle_damage_notify(display, (xcb_damage_notify_event_t *) ev, &damage_region);
else
......@@ -186,6 +220,24 @@ int display_open(display_t *d, options_t *options)
return X11SPICE_ERR_NOSHM;
}
d->xfixes_ext = xcb_get_extension_data(d->c, &xcb_xfixes_id);
if (! d->xfixes_ext)
{
fprintf(stderr, "Error: XFIXES not found on display %s\n", options->display ? options->display : "");
return X11SPICE_ERR_NOXFIXES;
}
xcb_xfixes_query_version(d->c, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
cookie = xcb_xfixes_select_cursor_input_checked(d->c, d->screen->root, XCB_XFIXES_CURSOR_NOTIFY_MASK_DISPLAY_CURSOR);
error = xcb_request_check(d->c, cookie);
if (error)
{
fprintf(stderr, "Error: Could not select cursor input; type %d; code %d; major %d; minor %d\n",
error->response_type, error->error_code, error->major_code, error->minor_code);
return X11SPICE_ERR_NOXFIXES;
}
rc = display_create_fullscreen(d);
g_message("Display %s opened", options->display ? options->display : "");
......
......@@ -52,6 +52,8 @@ typedef struct
const xcb_query_extension_reply_t *shm_ext;
const xcb_query_extension_reply_t *xfixes_ext;
shm_image_t *fullscreen;
pthread_t event_thread;
......
......@@ -49,6 +49,15 @@ typedef struct
session_t *session;
} spice_t;
typedef enum { RELEASE_SHMI, RELEASE_MEMORY } release_type_t;
typedef struct
{
release_type_t type;
void *data;
spice_t *s;
} spice_release_t;
/*----------------------------------------------------------------------------
** Prototypes
**--------------------------------------------------------------------------*/
......@@ -57,4 +66,8 @@ void spice_end(spice_t *s);
int spice_create_primary(spice_t *s, int w, int h, int bytes_per_line, void *shmaddr);
void spice_destroy_primary(spice_t *s);
spice_release_t *spice_create_release(spice_t *s, release_type_t type, void *data);
void spice_free_release(spice_release_t *r);
#endif
......@@ -27,7 +27,7 @@
#include <glib.h>
// FIXME - refactor and move this...
static QXLDrawable *shm_image_to_drawable(shm_image_t *shmi, int x, int y)
static QXLDrawable *shm_image_to_drawable(spice_t *s, shm_image_t *shmi, int x, int y)
{
QXLDrawable *drawable;
QXLImage *qxl_image;
......@@ -38,7 +38,7 @@ static QXLDrawable *shm_image_to_drawable(shm_image_t *shmi, int x, int y)
return NULL;
qxl_image = (QXLImage *) (drawable + 1);
drawable->release_info.id = (uint64_t) shmi;
drawable->release_info.id = (uint64_t) spice_create_release(s, RELEASE_SHMI, shmi);
shmi->drawable_ptr = drawable;
drawable->surface_id = 0;
......@@ -139,7 +139,7 @@ static void handle_damage_report(session_t *session, scan_report_t *r)
if (read_shm_image(&session->display, shmi, r->x, r->y) == 0)
{
//save_ximage_pnm(shmi);
QXLDrawable *drawable = shm_image_to_drawable(shmi, r->x, r->y);
QXLDrawable *drawable = shm_image_to_drawable(&session->spice, shmi, r->x, r->y);
if (drawable)
{
g_async_queue_push(session->draw_queue, drawable);
......
......@@ -32,12 +32,14 @@
void free_cursor_queue_item(gpointer data)
{
// FIXME
QXLCursorCmd *ccmd = (QXLCursorCmd *) data;
spice_free_release((spice_release_t *) ccmd->release_info.id);
}
void free_draw_queue_item(gpointer data)
{
// FIXME
QXLDrawable *drawable = (QXLDrawable *) data;
spice_free_release((spice_release_t *) drawable->release_info.id);
}
void *session_pop_draw(session_t *session)
......@@ -56,6 +58,22 @@ int session_draw_waiting(session_t *session)
return g_async_queue_length(session->draw_queue);
}
void *session_pop_cursor(session_t *session)
{
if (! session || ! session->running)
return NULL;
return g_async_queue_try_pop(session->cursor_queue);
}
int session_cursor_waiting(session_t *session)
{
if (! session || ! session->running)
return 0;
return g_async_queue_length(session->cursor_queue);
}
void session_handle_key(session_t *session, uint8_t keycode, int is_press)
{
xcb_test_fake_input(session->display.c, is_press ? XCB_KEY_PRESS : XCB_KEY_RELEASE,
......@@ -168,3 +186,45 @@ int session_alive(session_t *s)
{
return s->running;
}
int session_push_cursor_image(session_t *s,
int x, int y, int w, int h, int xhot, int yhot,
int imglen, uint8_t *imgdata)
{
QXLCursorCmd *ccmd;
QXLCursor *cursor;
ccmd = calloc(1, sizeof(*ccmd) + sizeof(*cursor) + imglen);
if (! ccmd)
return X11SPICE_ERR_MALLOC;;
cursor = (QXLCursor *) (ccmd + 1);
cursor->header.unique = 0;
cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
cursor->header.width = w;
cursor->header.height = h;
cursor->header.hot_spot_x = xhot;
cursor->header.hot_spot_y = yhot;
cursor->data_size = imglen;
cursor->chunk.next_chunk = 0;
cursor->chunk.prev_chunk = 0;
cursor->chunk.data_size = imglen;
memcpy(cursor->chunk.data, imgdata, imglen);
ccmd->type = QXL_CURSOR_SET;
ccmd->u.set.position.x = x + xhot;
ccmd->u.set.position.y = y + yhot;
ccmd->u.set.shape = (QXLPHYSICAL) cursor;
ccmd->u.set.visible = TRUE;
ccmd->release_info.id = (uint64_t) spice_create_release(&s->spice, RELEASE_MEMORY, ccmd);
g_async_queue_push(s->cursor_queue, ccmd);
return 0;
}
......@@ -54,8 +54,17 @@ int session_alive(session_t *s);
void *session_pop_draw(session_t *session);
int session_draw_waiting(session_t *session);
void *session_pop_cursor(session_t *session);
int session_cursor_waiting(session_t *session);
void session_handle_key(session_t *session, uint8_t keycode, int is_press);
void session_handle_mouse_position(session_t *session, int x, int y, uint32_t buttons_state);
void session_handle_mouse_buttons(session_t *session, uint32_t buttons_state);
void session_handle_mouse_wheel(session_t *session, int wheel_motion, uint32_t buttons_state);
int session_push_cursor_image(session_t *s,
int x, int y, int w, int h, int xhot, int yhot,
int imglen, uint8_t *imgdata);
#endif
......@@ -250,19 +250,34 @@ static int req_cmd_notification(QXLInstance *qin)
static void release_resource(QXLInstance *qin, struct QXLReleaseInfoExt release_info)
{
spice_t *s = SPICE_CONTAINEROF(qin, spice_t, display_sin);
destroy_shm_image(&s->session->display, (shm_image_t *) release_info.info->id);
spice_free_release((spice_release_t *) release_info.info->id);
}
static int get_cursor_command(QXLInstance *qin, struct QXLCommandExt *cmd)
{
g_debug("FIXME! UNIMPLEMENTED! %s", __func__);
return 0;
spice_t *s = SPICE_CONTAINEROF(qin, spice_t, display_sin);
struct QXLCursorCmd *cursor;
cursor = session_pop_cursor(s->session);
if (! cursor)
return 0;
cmd->group_id = 0;
cmd->flags = 0;
cmd->cmd.type = QXL_CMD_CURSOR;
cmd->cmd.padding = 0;
cmd->cmd.data = (QXLPHYSICAL) cursor;
return 1;
}
static int req_cursor_notification(QXLInstance *qin)
{
g_debug("FIXME! UNIMPLEMENTED! %s", __func__);
spice_t *s = SPICE_CONTAINEROF(qin, spice_t, display_sin);
if (session_cursor_waiting(s->session) > 0)
return 0;
return 1;
}
......@@ -584,3 +599,35 @@ void spice_end(spice_t *s)
// FIXME - can't always destroy...
spice_destroy_primary(s);
}
spice_release_t *spice_create_release(spice_t *s, release_type_t type, void *data)
{
spice_release_t *r = malloc(sizeof(*r));
if (r)
{
r->s = s;
r->type = type;
r->data = data;
}
return r;
}
void spice_free_release(spice_release_t *r)
{
if (!r)
return;
switch (r->type)
{
case RELEASE_SHMI:
destroy_shm_image(&r->s->session->display, (shm_image_t *) r->data);
break;
case RELEASE_MEMORY:
free(r->data);
break;
}
free(r);
}
......@@ -35,5 +35,7 @@
#define X11SPICE_ERR_PARSE 8
#define X11SPICE_ERR_AUTO_FAILED 9
#define X11SPICE_ERR_SHUTTING_DOWN 10
#define X11SPICE_ERR_NOXFIXES 11
#define X11SPICE_ERR_NOEVENTS 12
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment