Commit f3138bfb authored by Jeremy White's avatar Jeremy White

Switch to using xcb instead of Xlib.

parent d9b150f4
AC_INIT([x11spice], 1.0)
AM_INIT_AUTOMAKE
PKG_CHECK_MODULES(X11, x11)
PKG_CHECK_MODULES(XTST, xtst)
PKG_CHECK_MODULES(XDAMAGE, xdamage)
PKG_CHECK_MODULES(XEXT, xext)
PKG_CHECK_MODULES(XCB, xcb)
PKG_CHECK_MODULES(DAMAGE, xcb-damage)
PKG_CHECK_MODULES(XTEST, xcb-xtest)
PKG_CHECK_MODULES(SHM, xcb-shm)
PKG_CHECK_MODULES(UTIL, xcb-util)
PKG_CHECK_MODULES(GTK2, gtk+-2.0)
PKG_CHECK_MODULES(SPICE, spice-server)
PKG_CHECK_MODULES(SPICE_PROTOCOL, spice-protocol)
PKG_CHECK_MODULES(GLIB2, glib-2.0)
AC_PROG_CC
......
bin_PROGRAMS = x11spice
AM_CFLAGS = -Wall $(X11_CFLAGS) $(GTK2_CFLAGS) $(SPICE_CFLAGS) $(GLIB2_CFLAGS) $(XDAMAGE_CFLAGS) $(XEXT_CFLAGS) $(XTST_CFLAGS)
x11spice_LDADD = $(X11_LIBS) $(GTK2_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS) $(XDAMAGE_LIBS) $(XEXT_LIBS) $(XTST_LIBS)
ALL_XCB_CFLAGS=$(XCB_CFLAGS) $(DAMAGE_CFLAGS) $(XTEST_CFLAGS) $(SHM_CFLAGS) $(UTIL_CFLAGS)
ALL_XCB_LIBS=$(XCB_LIBS) $(DAMAGE_LIBS) $(XTEST_LIBS) $(SHM_LIBS) $(UTIL_LIBS)
AM_CFLAGS = -Wall $(ALL_XCB_CFLAGS) $(GTK2_CFLAGS) $(SPICE_CFLAGS) $(SPICE_PROTOCOL_CFLAGS) $(GLIB2_CFLAGS)
x11spice_LDADD = $(ALL_XCB_LIBS) $(GTK2_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS)
x11spice_SOURCES = \
display.c \
gui.c \
......
......@@ -21,56 +21,102 @@
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <glib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include "x11spice.h"
#include "options.h"
#include "display.h"
static xcb_screen_t *screen_of_display (xcb_connection_t *c, int screen)
{
xcb_screen_iterator_t iter;
iter = xcb_setup_roots_iterator(xcb_get_setup(c));
for (; iter.rem; --screen, xcb_screen_next(&iter))
if (screen == 0)
return iter.data;
return NULL;
}
static int bits_per_pixel(display_t *d)
{
xcb_format_iterator_t fmt;
for (fmt = xcb_setup_pixmap_formats_iterator(xcb_get_setup(d->c));
fmt.rem;
xcb_format_next(&fmt))
if (fmt.data->depth == d->screen->root_depth)
return fmt.data->bits_per_pixel;
return 0;
}
int display_open(display_t *d, options_t *options)
{
static int xinitthreads = 0;
int scr;
xcb_damage_query_version_cookie_t dcookie;
if (!xinitthreads)
{
if (! XInitThreads())
xcb_void_cookie_t cookie;
xcb_generic_error_t *error;
d->c = xcb_connect(options->display, &scr);
if (! d->c)
{
fprintf(stderr, "Error: could not initialize X Threads\n");
fprintf(stderr, "Error: could not open display %s\n", options->display ? options->display : "");
return X11SPICE_ERR_NODISPLAY;
}
xinitthreads = 1;
}
d->xdisplay = XOpenDisplay(options->display);
// FIXME - do we care? - g_x_error_handler = XSetErrorHandler(handle_xerrors);
if (! d->xdisplay)
d->screen = screen_of_display(d->c, scr);
if (!d->screen)
{
fprintf(stderr, "Error: could not open display %s\n", options->display ? options->display : "");
fprintf(stderr, "Error: could not get screen for display %s\n", options->display ? options->display : "");
return X11SPICE_ERR_NODISPLAY;
}
if (! XDamageQueryExtension(d->xdisplay, &d->xd_event_base, &d->xd_error_base))
d->damage_ext = xcb_get_extension_data(d->c, &xcb_damage_id);
if (! d->damage_ext)
{
fprintf(stderr, "Error: XDAMAGE not found on display %s\n", options->display ? options->display : "");
return X11SPICE_ERR_NODAMAGE;
}
if (! XShmQueryExtension(d->xdisplay))
dcookie = xcb_damage_query_version(d->c, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION);
xcb_damage_query_version_reply(d->c, dcookie, &error);
if (error)
{
fprintf(stderr, "Error: Could not query damage; type %d; code %d; major %d; minor %d\n",
error->response_type, error->error_code, error->major_code, error->minor_code);
return X11SPICE_ERR_NODAMAGE;
}
d->damage = xcb_generate_id(d->c);
cookie = xcb_damage_create_checked(d->c, d->damage, d->screen->root, XCB_DAMAGE_REPORT_LEVEL_RAW_RECTANGLES);
error = xcb_request_check(d->c, cookie);
if (error)
{
fprintf(stderr, "Error: Could not create damage; type %d; code %d; major %d; minor %d\n",
error->response_type, error->error_code, error->major_code, error->minor_code);
return X11SPICE_ERR_NODAMAGE;
}
d->shm_ext = xcb_get_extension_data(d->c, &xcb_shm_id);
if (! d->shm_ext)
{
fprintf(stderr, "Error: XSHM not found on display %s\n", options->display ? options->display : "");
return X11SPICE_ERR_NOSHM;
}
d->xdamage = XDamageCreate(d->xdisplay, DefaultRootWindow(d->xdisplay), XDamageReportRawRectangles);
g_info("Display %s opened", options->display ? options->display : "");
g_message("Display %s opened", options->display ? options->display : "");
return 0;
}
......@@ -78,47 +124,48 @@ int display_open(display_t *d, options_t *options)
shm_image_t * create_shm_image(display_t *d, int w, int h)
{
shm_image_t *shmi;
int scr = DefaultScreen(d->xdisplay);
int imgsize;
xcb_void_cookie_t cookie;
xcb_generic_error_t *error;
shmi = calloc(1, sizeof(*shmi));
if (! shmi)
return shmi;
shmi->img = XShmCreateImage(d->xdisplay,
DefaultVisual(d->xdisplay, scr),
DefaultDepth(d->xdisplay, scr),
ZPixmap /* FIXME - format we want? */, NULL /* data? */,
&shmi->info,
w ? w : DisplayWidth(d->xdisplay, scr),
h ? h : DisplayHeight(d->xdisplay, scr));
if (! shmi->img)
{
free(shmi);
return NULL;
}
shmi->w = w ? w : d->screen->width_in_pixels;
shmi->h = h ? h : d->screen->height_in_pixels;
imgsize = shmi->img->bytes_per_line * shmi->img->height;
shmi->bytes_per_line = (bits_per_pixel(d) / 8) * shmi->w;
imgsize = shmi->bytes_per_line * shmi->h;
shmi->info.shmid = shmget(IPC_PRIVATE, imgsize, IPC_CREAT | 0700);
if (shmi->info.shmid == -1)
shmi->shmid = shmget(IPC_PRIVATE, imgsize, IPC_CREAT | 0700);
if (shmi->shmid != -1)
shmi->shmaddr = shmat(shmi->shmid, 0, 0);
if (shmi->shmid == -1 || shmi->shmaddr == (void *) -1)
{
g_error("Cannot get shared memory of size %d", imgsize);
XDestroyImage(shmi->img);
free(shmi);
return NULL;
}
shmi->info.shmaddr = shmi->img->data = shmat(shmi->info.shmid, 0, 0);
shmi->info.readOnly = False;
shmi->shmseg = xcb_generate_id(d->c);
cookie = xcb_shm_attach_checked(d->c, shmi->shmseg, shmi->shmid, 0);
error = xcb_request_check(d->c, cookie);
if (error)
{
g_error("Could not attach; type %d; code %d; major %d; minor %d\n",
error->response_type, error->error_code, error->major_code, error->minor_code);
return NULL;
}
if (!XShmAttach(d->xdisplay, &shmi->info))
shmi->pid = xcb_generate_id(d->c);
cookie = xcb_shm_create_pixmap_checked(d->c, shmi->pid, d->screen->root,
shmi->w, shmi->h, d->screen->root_depth, shmi->shmseg, 0);
error = xcb_request_check(d->c, cookie);
if (error)
{
g_error("Failed to attach shared memory");
shmdt(shmi->info.shmaddr);
shmctl(shmi->info.shmid, IPC_RMID, NULL);
XDestroyImage(shmi->img);
free(shmi);
g_error("Could not create pixmap; type %d; code %d; major %d; minor %d\n",
error->response_type, error->error_code, error->major_code, error->minor_code);
return NULL;
}
......@@ -127,34 +174,40 @@ shm_image_t * create_shm_image(display_t *d, int w, int h)
int read_shm_image(display_t *d, shm_image_t *shmi, int x, int y)
{
if (!XShmGetImage(d->xdisplay, DefaultRootWindow(d->xdisplay), shmi->img,
x, y, AllPlanes))
xcb_shm_get_image_cookie_t cookie;
xcb_generic_error_t *e;
cookie = xcb_shm_get_image(d->c, d->screen->root, x, y, shmi->w, shmi->h,
~0, XCB_IMAGE_FORMAT_Z_PIXMAP, shmi->shmseg, 0);
xcb_shm_get_image_reply(d->c, cookie, &e);
if (e)
{
g_error("XShmGetImage from %dx%d into size %dx%d failed",
x, y, shmi->img->width, shmi->img->height);
g_error("xcb_shm_get_image from %dx%d into size %dx%d failed", x, y, shmi->w, shmi->h);
return X11SPICE_ERR_NOSHM;
}
return 0;
}
void destroy_shm_image(display_t *d, shm_image_t *shmi)
{
XShmDetach(d->xdisplay, &shmi->info);
shmdt(shmi->info.shmaddr);
shmctl(shmi->info.shmid, IPC_RMID, NULL);
XDestroyImage(shmi->img);
xcb_free_pixmap(d->c, shmi->pid);
xcb_shm_detach(d->c, shmi->shmseg);
shmdt(shmi->shmaddr);
shmctl(shmi->shmid, IPC_RMID, NULL);
if (shmi->drawable_ptr)
free(shmi->drawable_ptr);
}
void display_close(display_t *d)
{
XDamageDestroy(d->xdisplay, d->xdamage);
XCloseDisplay(d->xdisplay);
xcb_damage_destroy(d->c, d->damage);
if (d->fullscreen)
{
destroy_shm_image(d, d->fullscreen);
d->fullscreen = NULL;
}
xcb_disconnect(d->c);
}
......@@ -21,26 +21,35 @@
#ifndef DISPLAY_H_
#define DISPLAY_H_
#include <X11/Xlib.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/XShm.h>
#include <xcb/xcb.h>
#include <xcb/damage.h>
#include <xcb/shm.h>
/*----------------------------------------------------------------------------
** Structure definitions
**--------------------------------------------------------------------------*/
typedef struct
{
XImage *img;
XShmSegmentInfo info;
xcb_pixmap_t pid;
int shmid;
int w;
int h;
int bytes_per_line;
xcb_shm_seg_t shmseg;
void *shmaddr;
void *drawable_ptr;
}shm_image_t;
typedef struct
{
Display *xdisplay;
Damage xdamage;
int xd_event_base;
int xd_error_base;
xcb_connection_t *c;
xcb_screen_t *screen;
const xcb_query_extension_reply_t *damage_ext;
xcb_damage_damage_t damage;
const xcb_query_extension_reply_t *shm_ext;
shm_image_t *fullscreen;
} display_t;
......
......@@ -20,36 +20,15 @@
#include <stdio.h>
#include <string.h>
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
#include <xcb/xcb.h>
#include <xcb/xtest.h>
#include <xcb/xcb_aux.h>
#include "x11spice.h"
#include "session.h"
static void save_ximage_pnm(XImage *img)
{
int x,y;
unsigned long pixel;
static int count = 0;
char fname[200];
FILE *fp;
sprintf(fname, "ximage%04d.ppm", count++);
fp = fopen(fname, "w");
fprintf(fp,"P3\n%d %d\n255\n",img->width, img->height);
for (y=0; y<img->height; y++)
{
for (x=0; x<img->width; x++)
{
pixel=XGetPixel(img,x,y);
fprintf(fp,"%ld %ld %ld\n",
pixel>>16,(pixel&0x00ff00)>>8,pixel&0x0000ff);
}
}
fclose(fp);
}
static QXLDrawable *shm_image_to_drawable(shm_image_t *shmi, int x, int y)
{
QXLDrawable *drawable;
......@@ -70,8 +49,8 @@ static QXLDrawable *shm_image_to_drawable(shm_image_t *shmi, int x, int y)
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
drawable->bbox.left = x;
drawable->bbox.top = y;
drawable->bbox.right = x + shmi->img->width;
drawable->bbox.bottom = y + shmi->img->height;
drawable->bbox.right = x + shmi->w;
drawable->bbox.bottom = y + shmi->h;
/*
* surfaces_dest[i] should apparently be filled out with the
......@@ -92,17 +71,17 @@ static QXLDrawable *shm_image_to_drawable(shm_image_t *shmi, int x, int y)
qxl_image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
qxl_image->descriptor.flags = 0;
qxl_image->descriptor.width = shmi->img->width;
qxl_image->descriptor.height = shmi->img->height;
qxl_image->descriptor.width = shmi->w;
qxl_image->descriptor.height = shmi->h;
// FIXME - be a bit more dynamic...
qxl_image->bitmap.format = SPICE_BITMAP_FMT_RGBA;
qxl_image->bitmap.flags = SPICE_BITMAP_FLAGS_TOP_DOWN | QXL_BITMAP_DIRECT;
qxl_image->bitmap.x = shmi->img->width;
qxl_image->bitmap.y = shmi->img->height;
qxl_image->bitmap.stride = shmi->img->bytes_per_line;
qxl_image->bitmap.x = shmi->w;
qxl_image->bitmap.y = shmi->h;
qxl_image->bitmap.stride = shmi->bytes_per_line;
qxl_image->bitmap.palette = 0;
qxl_image->bitmap.data = (QXLPHYSICAL) shmi->img->data;
qxl_image->bitmap.data = (QXLPHYSICAL) shmi->shmaddr;
// FIXME - cache images at all?
......@@ -112,23 +91,23 @@ static QXLDrawable *shm_image_to_drawable(shm_image_t *shmi, int x, int y)
static void session_handle_xevent(int fd, int event, void *opaque)
{
session_t *s = (session_t *) opaque;
XEvent xev;
int rc;
XDamageNotifyEvent *dev = (XDamageNotifyEvent *) &xev;;
xcb_generic_event_t *ev;
shm_image_t *shmi = NULL;
rc = XNextEvent(s->display.xdisplay, &xev);
if (rc)
return;
while ((ev = xcb_poll_for_event(s->display.c)))
{
xcb_damage_notify_event_t *dev;
if (xev.type != s->display.xd_event_base + XDamageNotify)
if (ev->response_type != s->display.damage_ext->first_event + XCB_DAMAGE_NOTIFY)
{
g_debug("Unexpected X event %d", xev.type);
g_debug("Unexpected X event %d", ev->response_type);
return;
}
dev = (xcb_damage_notify_event_t *) ev;
g_debug("XDamageNotify [ser %ld|send_event %d|level %d|more %d|area (%dx%d)@%dx%d|geo (%dx%d)@%dx%d",
dev->serial, dev->send_event, dev->level, dev->more,
g_debug("Damage Notify [seq %d|level %d|area (%dx%d)@%dx%d|geo (%dx%d)@%dx%d",
dev->sequence, dev->level,
dev->area.width, dev->area.height, dev->area.x, dev->area.y,
dev->geometry.width, dev->geometry.height, dev->geometry.x, dev->geometry.y);
......@@ -137,8 +116,8 @@ static void session_handle_xevent(int fd, int event, void *opaque)
if (! hackme)
{
// FIXME - HACK!
dev->area.width = s->display.fullscreen->img->width;
dev->area.height = s->display.fullscreen->img->height;
dev->area.width = s->display.fullscreen->w;
dev->area.height = s->display.fullscreen->h;
dev->area.x = dev->area.y = 0;
hackme++;
}
......@@ -171,6 +150,7 @@ static void session_handle_xevent(int fd, int event, void *opaque)
if (shmi)
destroy_shm_image(&s->display, shmi);
}
}
......@@ -179,7 +159,6 @@ static void session_handle_xevent(int fd, int event, void *opaque)
// access to the display info if it can.
static int create_primary(session_t *s)
{
int scr = DefaultScreen(s->display.xdisplay);
QXLDevSurfaceCreate surface;
s->display.fullscreen = create_shm_image(&s->display, 0, 0);
......@@ -187,10 +166,10 @@ static int create_primary(session_t *s)
return X11SPICE_ERR_NOSHM;
memset(&surface, 0, sizeof(surface));
surface.height = DisplayHeight(s->display.xdisplay, scr);
surface.width = DisplayWidth(s->display.xdisplay, scr);
surface.height = s->display.fullscreen->h;
surface.width = s->display.fullscreen->w;
// FIXME - negative stride?
surface.stride = s->display.fullscreen->img->bytes_per_line;
surface.stride = s->display.fullscreen->bytes_per_line;
surface.type = QXL_SURF_TYPE_PRIMARY;
surface.flags = 0;
surface.group_id = 0;
......@@ -201,7 +180,7 @@ static int create_primary(session_t *s)
// FIXME - compute this dynamically?
surface.format = SPICE_SURFACE_FMT_32_xRGB;
surface.mem = (QXLPHYSICAL) s->display.fullscreen->img->data;
surface.mem = (QXLPHYSICAL) s->display.fullscreen->shmaddr;
spice_qxl_create_primary_surface(&s->spice.display_sin, 0, &surface);
......@@ -234,21 +213,21 @@ int session_draw_waiting(void *session_ptr)
void session_handle_key(void *session_ptr, uint8_t keycode, int is_press)
{
int rc;
session_t *s = (session_t *) session_ptr;
rc = XTestFakeKeyEvent(s->display.xdisplay, keycode, is_press ? True : False, CurrentTime);
g_debug("key 0x%x, press %d, rc %d (t %d, f %d)", keycode, is_press, rc, True, False);
XFlush(s->display.xdisplay);
xcb_test_fake_input(s->display.c, is_press ? XCB_KEY_PRESS : XCB_KEY_RELEASE,
keycode, XCB_CURRENT_TIME, XCB_NONE, 0, 0, 0);
g_debug("key 0x%x, press %d", keycode, is_press);
// FIXME - and maybe a sync too... xcb_flush(s->display.c);
xcb_flush(s->display.c);
}
void session_handle_mouse_position(void *session_ptr, int x, int y, uint32_t buttons_state)
{
session_t *s = (session_t *) session_ptr;
int scr = DefaultScreen(s->display.xdisplay);
XFlush(s->display.xdisplay);
xcb_test_fake_input(s->display.c, XCB_MOTION_NOTIFY, 0, XCB_CURRENT_TIME,
s->display.screen->root, x, y, 0);
g_debug("mouse position: x %d, y %d, buttons 0x%x", x, y, buttons_state);
XTestFakeMotionEvent(s->display.xdisplay, scr, x, y, CurrentTime);
XFlush(s->display.xdisplay);
xcb_flush(s->display.c);
}
#define BUTTONS 5
......@@ -258,11 +237,11 @@ static void session_handle_button_change(session_t *s, uint32_t buttons_state)
for (i = 0; i < BUTTONS; i++) {
if ((buttons_state ^ s->spice.buttons_state) & (1 << i)) {
int action = (buttons_state & (1 << i));
XTestFakeButtonEvent(s->display.xdisplay, i + 1, action, CurrentTime);
xcb_test_fake_input(s->display.c, action ? XCB_BUTTON_PRESS : XCB_BUTTON_RELEASE,
i + 1, XCB_CURRENT_TIME, s->display.screen->root, 0, 0, 0);
}
}
s->spice.buttons_state = buttons_state;
XFlush(s->display.xdisplay);
}
static uint32_t convert_spice_buttons(int wheel, uint32_t buttons_state)
......@@ -299,7 +278,7 @@ int session_start(session_t *s)
int rc = 0;
s->spice.session_ptr = s;
s->xwatch = s->spice.core->watch_add(ConnectionNumber(s->display.xdisplay),
s->xwatch = s->spice.core->watch_add(xcb_get_file_descriptor(s->display.c),
SPICE_WATCH_EVENT_READ, session_handle_xevent, s);
if (! s->xwatch)
return(X11SPICE_ERR_NOWATCH);
......@@ -307,15 +286,15 @@ int session_start(session_t *s)
s->cursor_queue = g_async_queue_new_full(free_cursor_queue_item);
s->draw_queue = g_async_queue_new_full(free_draw_queue_item);
/* In order for the watch to function,
we seem to have to request at least one event */
// FIXME - not sure I know why...
XPending(s->display.xdisplay);
rc = create_primary(s);
if (rc)
session_end(s);
/* In order for the watch to function,
we seem to have to request at least one event */
// FIXME - still true with xcb?
session_handle_xevent(xcb_get_file_descriptor(s->display.c), 0, s);
return rc;
}
......
......@@ -183,7 +183,7 @@ static void attach_worker(QXLInstance *qin, QXLWorker *qxl_worker)
if (++count > 1)
{
g_info("Ignoring worker %d", count);
g_message("Ignoring worker %d", count);
return;
}
......
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