aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkraxel <kraxel>2006-10-25 14:47:11 +0000
committerkraxel <kraxel>2006-10-25 14:47:11 +0000
commit397fcd38d34e02a73dc0d05e41562a82e608e203 (patch)
tree051bfb9d033634e8d6832cfb754a1be6a777c2e6
parent75e722fc76c56c56a14546ba2dc7418fec08a558 (diff)
downloadxenwatch-397fcd38d34e02a73dc0d05e41562a82e608e203.tar.gz
add cvs viewer
-rw-r--r--.cvsignore1
-rw-r--r--GNUmakefile13
-rw-r--r--vnc-client.c64
-rw-r--r--vnc.c410
-rw-r--r--vnc.h21
-rw-r--r--x11.c226
-rw-r--r--x11.h27
-rw-r--r--xd_view.c5
8 files changed, 765 insertions, 2 deletions
diff --git a/.cvsignore b/.cvsignore
index 4e0d4ad..e5974df 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -5,3 +5,4 @@ xenscreenrc
xenwatch
mdns-browser
mdns-publish-xendom
+vnc-client
diff --git a/GNUmakefile b/GNUmakefile
index 37dfbe5..8cb6a52 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -9,10 +9,12 @@ CFLAGS += -DVERSION='"$(VERSION)"' -DLIB='"$(LIB)"'
TARGETS := xenlog xenscreen xenscreenrc
BUILD_GTK := xenwatch mdns-browser
BUILD_MDNS := mdns-publish-xendom
+BUILD_VNC := vnc-client
NEEDS_XENSTORE := xenlog xenscreen xenwatch mdns-publish-xendom
-NEEDS_GTK := xenwatch mdns-browser
+NEEDS_GTK := xenwatch mdns-browser vnc-client
NEEDS_MDNS := xenwatch mdns-browser mdns-publish-xendom
+NEEDS_VNC := xenwatch vnc-client
# default target
all: build
@@ -27,6 +29,7 @@ define make-config
LIB := $(LIB)
HAVE_GTK := $(call ac_pkg_config,gtk+-x11-2.0)
HAVE_AVAHI := $(call ac_pkg_config,avahi-glib)
+HAVE_VNCCLIENT := $(call ac_lib,rfbGetClient,vncclient,-lz -ljpeg)
endef
# gtk stuff
@@ -34,6 +37,11 @@ ifeq ($(HAVE_GTK),yes)
$(NEEDS_GTK) : CFLAGS += -Wno-strict-prototypes
$(NEEDS_GTK) : pkglst += gtk+-x11-2.0
TARGETS += $(BUILD_GTK)
+ ifeq ($(HAVE_VNCCLIENT),yes)
+ TARGETS += $(BUILD_VNC)
+ $(NEEDS_VNC) : CFLAGS += -DHAVE_VNC=1
+ $(NEEDS_VNC) : LDLIBS += -lvncclient -lz -ljpeg
+ endif
endif
# avahi stuff
@@ -78,9 +86,10 @@ realclean distclean: clean
xenlog: xenlog.o xenstore.o
xenscreen: xenscreen.o xenstore.o apps.o
xenwatch: xenwatch.o xs_view.o xs_store.o xd_view.o xd_store.o \
- apps.o apps-x11.o tcp.o mdns.o
+ apps.o apps-x11.o tcp.o mdns.o vnc.o x11.o
mdns-browser: mdns-browser.o mdns.o apps.o apps-x11.o
mdns-publish-xendom: mdns-publish-xendom.o
+vnc-client: vnc-client.o vnc.o x11.o
xenscreenrc: xenscreen
./xenscreen -b > $@
diff --git a/vnc-client.c b/vnc-client.c
new file mode 100644
index 0000000..a8012cb
--- /dev/null
+++ b/vnc-client.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <signal.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include "vnc.h"
+
+/* ------------------------------------------------------------------ */
+
+
+/* ------------------------------------------------------------------ */
+
+static void usage(FILE *fp)
+{
+ fprintf(fp,
+ "This is a vnc client\n"
+ "\n"
+ "usage: vnc-client [options] hostname displayno\n"
+ "options:\n"
+ " -h print this text\n"
+ "\n"
+ "-- \n"
+ "(c) 2006 Gerd Hoffmann <kraxel@suse.de>\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+
+ gtk_init(&argc, &argv);
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "h")))
+ break;
+ switch (c) {
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ if (optind+2 > argc) {
+ usage(stderr);
+ exit(1);
+ }
+
+ if (NULL == vnc_open(argv[optind], atoi(argv[optind+1]), 1))
+ exit(1);
+
+ gtk_main();
+ fprintf(stderr,"bye...\n");
+ exit(0);
+}
diff --git a/vnc.c b/vnc.c
new file mode 100644
index 0000000..e563f64
--- /dev/null
+++ b/vnc.c
@@ -0,0 +1,410 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <signal.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include "x11.h"
+#include "vnc.h"
+
+#ifdef HAVE_VNC
+
+/* ------------------------------------------------------------------ */
+/* data tables */
+
+rfbKeySym linux_us_kbd[] = {
+ [ 9 ] = XK_Escape,
+ [ 10 ] = XK_1,
+ [ 11 ] = XK_2,
+ [ 12 ] = XK_3,
+ [ 13 ] = XK_4,
+ [ 14 ] = XK_5,
+ [ 15 ] = XK_6,
+ [ 16 ] = XK_7,
+ [ 17 ] = XK_8,
+ [ 18 ] = XK_9,
+ [ 19 ] = XK_0,
+ [ 20 ] = XK_minus,
+ [ 21 ] = XK_equal,
+ [ 22 ] = XK_BackSpace,
+ [ 23 ] = XK_Tab,
+ [ 24 ] = XK_q,
+ [ 25 ] = XK_w,
+ [ 26 ] = XK_e,
+ [ 27 ] = XK_r,
+ [ 28 ] = XK_t,
+ [ 29 ] = XK_y,
+ [ 30 ] = XK_u,
+ [ 31 ] = XK_i,
+ [ 32 ] = XK_o,
+ [ 33 ] = XK_p,
+ [ 34 ] = XK_bracketleft,
+ [ 35 ] = XK_bracketright,
+ [ 36 ] = XK_Return,
+ [ 37 ] = XK_Control_L,
+ [ 38 ] = XK_a,
+ [ 39 ] = XK_s,
+ [ 40 ] = XK_d,
+ [ 41 ] = XK_f,
+ [ 42 ] = XK_g,
+ [ 43 ] = XK_h,
+ [ 44 ] = XK_j,
+ [ 45 ] = XK_k,
+ [ 46 ] = XK_l,
+ [ 47 ] = XK_semicolon,
+ [ 48 ] = XK_apostrophe,
+ [ 49 ] = XK_grave,
+ [ 50 ] = XK_Shift_L,
+ [ 51 ] = XK_backslash,
+ [ 52 ] = XK_z,
+ [ 53 ] = XK_x,
+ [ 54 ] = XK_c,
+ [ 55 ] = XK_v,
+ [ 56 ] = XK_b,
+ [ 57 ] = XK_n,
+ [ 58 ] = XK_m,
+ [ 59 ] = XK_comma,
+ [ 60 ] = XK_period,
+ [ 61 ] = XK_slash,
+ [ 62 ] = XK_Shift_R,
+ [ 63 ] = XK_KP_Multiply,
+ [ 64 ] = XK_Alt_L,
+ [ 65 ] = XK_space,
+ [ 66 ] = XK_Caps_Lock,
+ [ 67 ] = XK_F1,
+ [ 68 ] = XK_F2,
+ [ 69 ] = XK_F3,
+ [ 70 ] = XK_F4,
+ [ 71 ] = XK_F5,
+ [ 72 ] = XK_F6,
+ [ 73 ] = XK_F7,
+ [ 74 ] = XK_F8,
+ [ 75 ] = XK_F9,
+ [ 76 ] = XK_F10,
+ [ 77 ] = XK_Num_Lock,
+ [ 78 ] = XK_Scroll_Lock,
+ [ 79 ] = XK_KP_Home,
+ [ 80 ] = XK_KP_Up,
+ [ 81 ] = XK_KP_Prior,
+ [ 82 ] = XK_KP_Subtract,
+ [ 83 ] = XK_KP_Left,
+ [ 84 ] = XK_KP_Begin,
+ [ 85 ] = XK_KP_Right,
+ [ 86 ] = XK_KP_Add,
+ [ 87 ] = XK_KP_End,
+ [ 88 ] = XK_KP_Down,
+ [ 89 ] = XK_KP_Next,
+ [ 90 ] = XK_KP_Insert,
+ [ 91 ] = XK_KP_Delete,
+ [ 93 ] = XK_Mode_switch,
+ [ 94 ] = XK_less,
+ [ 95 ] = XK_F11,
+ [ 96 ] = XK_F12,
+ [ 97 ] = XK_Home,
+ [ 98 ] = XK_Up,
+ [ 99 ] = XK_Prior,
+ [ 100 ] = XK_Left,
+ [ 102 ] = XK_Right,
+ [ 103 ] = XK_End,
+ [ 104 ] = XK_Down,
+ [ 105 ] = XK_Next,
+ [ 106 ] = XK_Insert,
+ [ 107 ] = XK_Delete,
+ [ 108 ] = XK_KP_Enter,
+ [ 109 ] = XK_Control_R,
+ [ 110 ] = XK_Pause,
+ [ 111 ] = XK_Print,
+ [ 112 ] = XK_KP_Divide,
+ [ 113 ] = XK_Alt_R,
+ [ 115 ] = XK_Super_L,
+ [ 116 ] = XK_Super_R,
+ [ 117 ] = XK_Menu,
+ [ 124 ] = XK_ISO_Level3_Shift,
+ [ 126 ] = XK_KP_Equal,
+};
+static int linux_us_kbd_size = sizeof(linux_us_kbd)/sizeof(linux_us_kbd[0]);
+
+/* ------------------------------------------------------------------ */
+/* helper functions */
+
+static void vnc_blit(char *reason, struct vnc_window *vnc, int x, int y, int w, int h)
+{
+ Window win = gdk_x11_drawable_get_xid(vnc->draw->window);
+ XGCValues values;
+
+#if 0
+ fprintf(stderr, "%s [%s]: %dx%d+%d+%d\n",
+ __FUNCTION__, reason, w, h, x, y);
+#endif
+ if (x > vnc->ximage->width)
+ return;
+ if (y > vnc->ximage->height)
+ return;
+ if (x+w > vnc->ximage->width)
+ w = vnc->ximage->width - x;
+ if (y+h > vnc->ximage->height)
+ h = vnc->ximage->height - y;
+
+ if (!vnc->gc)
+ vnc->gc = XCreateGC(vnc->dpy, win, 0, &values);
+ XPUTIMAGE(vnc->dpy, win, vnc->gc, vnc->ximage, x,y, x,y, w,h);
+}
+
+static void vnc_window_conf(struct vnc_window *vnc)
+{
+ char title[256];
+
+ if (!vnc->draw)
+ return;
+ snprintf(title, sizeof(title), "%s (%dx%d)", vnc->client->desktopName,
+ vnc->client->width, vnc->client->height);
+ gtk_window_set_title(GTK_WINDOW(vnc->win), title);
+ gtk_widget_set_size_request(vnc->draw, vnc->client->width, vnc->client->height);
+}
+
+/* ------------------------------------------------------------------ */
+/* libvncclient callbacks */
+
+static rfbBool vnc_resize(rfbClient* client)
+{
+ struct vnc_window *vnc = rfbClientGetClientData(client, vnc_open);
+
+ fprintf(stderr, "%s: %dx%d\n",
+ __FUNCTION__, client->width, client->height);
+
+ if (vnc->ximage) {
+ x11_destroy_ximage(vnc->dpy, vnc->ximage, vnc->shm);
+ vnc->ximage = NULL;
+ }
+ vnc->ximage = x11_create_ximage(vnc->dpy, client->width, client->height, &vnc->shm);
+ if (NULL == vnc->ximage) {
+ fprintf(stderr, "Oops: creating ximage failed\n");
+ goto out;
+ }
+
+ client->width = vnc->ximage->bytes_per_line / (vnc->ximage->bits_per_pixel / 8);
+ client->frameBuffer = (void*)vnc->ximage->data;
+
+ client->format.bitsPerPixel = vnc->ximage->bits_per_pixel;
+ client->format.redShift = x11_red_shift;
+ client->format.greenShift = x11_green_shift;
+ client->format.blueShift = x11_blue_shift;
+ client->format.redMax = (1 << x11_red_bits) - 1;
+ client->format.greenMax = (1 << x11_green_bits) - 1;
+ client->format.blueMax = (1 << x11_blue_bits) - 1;
+ SetFormatAndEncodings(client);
+
+ vnc_window_conf(vnc);
+
+ out:
+ return TRUE;
+}
+
+static void vnc_update(rfbClient* cl, int x, int y, int w, int h)
+{
+ struct vnc_window *vnc = rfbClientGetClientData(cl, vnc_open);
+
+ if (!GTK_WIDGET_DRAWABLE(vnc->draw))
+ return;
+ vnc_blit("update", vnc, x,y, w,h);
+}
+
+#if 0
+static void vnc_textchat(rfbClient* cl, int value, char *text)
+{
+ switch(value) {
+ case rfbTextChatOpen:
+ fprintf(stderr,"TextChat: Open\n");
+ break;
+ case rfbTextChatClose:
+ case rfbTextChatFinished:
+ fprintf(stderr,"TextChat: Close/Finished\n");
+ break;
+ default:
+ fprintf(stderr,"TextChat: \"%s\"\n", text);
+ break;
+ }
+}
+#endif
+
+/* ------------------------------------------------------------------ */
+/* glib/gtk callbacks */
+
+static gboolean vnc_data_cb(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ struct vnc_window *vnc = data;
+
+ if (!HandleRFBServerMessage(vnc->client)) {
+ /* server closed connection */
+ g_source_destroy(g_main_context_find_source_by_id
+ (g_main_context_default(), vnc->id));
+ vnc->id = 0;
+ gtk_widget_destroy(vnc->win);
+ }
+ return TRUE;
+}
+
+static void destroy_cb(GtkWidget *widget, gpointer data)
+{
+ struct vnc_window *vnc = data;
+
+ if (vnc->standalone)
+ gtk_main_quit();
+ vnc_release(vnc);
+}
+
+static gboolean expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+ struct vnc_window *vnc = data;
+
+ if (NULL == vnc->ximage)
+ return FALSE;
+ vnc_blit("expose", vnc, event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ return TRUE;
+}
+
+static gboolean button_cb(GtkWidget *widget, GdkEventButton *event,
+ gpointer data)
+{
+ struct vnc_window *vnc = data;
+
+ SendPointerEvent(vnc->client, event->x, event->y, event->state);
+ return TRUE;
+}
+
+static gboolean key_cb(GtkWidget *widget, GdkEventKey *event,
+ gpointer data)
+{
+ struct vnc_window *vnc = data;
+ rfbKeySym keysym = 0;
+ int keydown;
+
+ keydown = (8 == event->type);
+ if (event->hardware_keycode < linux_us_kbd_size)
+ keysym = linux_us_kbd[event->hardware_keycode];
+ if (keysym)
+ SendKeyEvent(vnc->client, keysym, keydown ? TRUE : FALSE);
+ else
+ fprintf(stderr, "%s: unknown keycode: %d\n",
+ __FUNCTION__, event->hardware_keycode);
+ return TRUE;
+}
+
+/* ------------------------------------------------------------------ */
+/* public API functions */
+
+struct vnc_window* vnc_open(char *hostname, int displayno, int standalone)
+{
+ char display[128];
+ char *argv[] = { "vnc-client", display, NULL };
+ int argc = sizeof(argv)/sizeof(argv[0]) -1;
+ struct vnc_window *vnc;
+ int rc;
+
+ vnc = malloc(sizeof(*vnc));
+ if (NULL == vnc)
+ goto err;
+ memset(vnc,0,sizeof(*vnc));
+ vnc->standalone = standalone;
+
+ /* x11 */
+ vnc->dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
+ if (NULL == x11_info)
+ x11_color_init(vnc->dpy);
+
+ /* rfb client */
+ snprintf(display, sizeof(display), "%s:%d", hostname, displayno);
+ fprintf(stderr, "%s: connecting to %s:%d\n", __FUNCTION__, hostname, displayno);
+ vnc->client = rfbGetClient(8,3,3);
+ if (NULL == vnc->client)
+ goto err;
+ rfbClientSetClientData(vnc->client, vnc_open, vnc);
+ vnc->client->MallocFrameBuffer = vnc_resize;
+// vnc->client->canHandleNewFBSize = TRUE;
+ vnc->client->GotFrameBufferUpdate = vnc_update;
+// vnc->client->HandleTextChat = vnc_textchat;
+ rc = rfbInitClient(vnc->client, &argc, argv);
+ if (0 == rc)
+ goto err;
+ vnc->ch = g_io_channel_unix_new(vnc->client->sock);
+ vnc->id = g_io_add_watch(vnc->ch, G_IO_IN, vnc_data_cb, vnc);
+
+ /* gtk toplevel */
+ vnc->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ g_signal_connect(G_OBJECT(vnc->win), "destroy",
+ G_CALLBACK(destroy_cb), vnc);
+
+ /* gtk drawing area */
+ vnc->draw = gtk_drawing_area_new();
+ gtk_container_add(GTK_CONTAINER(vnc->win), vnc->draw);
+ GTK_WIDGET_SET_FLAGS(vnc->draw, GTK_CAN_FOCUS);
+ gtk_widget_add_events(vnc->draw,
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_EXPOSURE_MASK);
+ gtk_widget_set_app_paintable(vnc->draw, TRUE);
+ gtk_widget_set_double_buffered(vnc->draw, FALSE);
+ g_signal_connect(G_OBJECT(vnc->draw), "expose-event",
+ G_CALLBACK(expose_cb), vnc);
+ g_signal_connect(G_OBJECT(vnc->draw), "button-press-event",
+ G_CALLBACK(button_cb), vnc);
+ g_signal_connect(G_OBJECT(vnc->draw), "button-release-event",
+ G_CALLBACK(button_cb), vnc);
+ g_signal_connect(G_OBJECT(vnc->draw), "key-press-event",
+ G_CALLBACK(key_cb), vnc);
+ g_signal_connect(G_OBJECT(vnc->draw), "key-release-event",
+ G_CALLBACK(key_cb), vnc);
+
+ /* show window */
+ vnc_window_conf(vnc);
+ gtk_widget_show_all(vnc->win);
+ return vnc;
+
+ err:
+ vnc_release(vnc);
+ return NULL;
+}
+
+void vnc_release(struct vnc_window *vnc)
+{
+ if (NULL == vnc)
+ return;
+#if 0 /* FIXME: segfaults ??? */
+ if (vnc->client)
+ rfbClientCleanup(vnc->client);
+#endif
+ if (vnc->id)
+ g_source_destroy(g_main_context_find_source_by_id
+ (g_main_context_default(), vnc->id));
+ if (vnc->ximage)
+ x11_destroy_ximage(vnc->dpy, vnc->ximage, vnc->shm);
+ if (vnc->gc)
+ XFreeGC(vnc->dpy, vnc->gc);
+ free(vnc);
+}
+
+#else
+
+struct vnc_window* vnc_open(char *hostname, int displayno, int standalone)
+{
+ fprintf(stderr, "compiled without VNC support, sorry\n");
+ return NULL;
+}
+
+void vnc_release(struct vnc_window *vnc)
+{
+ /* nothing */
+}
+
+#endif
diff --git a/vnc.h b/vnc.h
new file mode 100644
index 0000000..c8ec360
--- /dev/null
+++ b/vnc.h
@@ -0,0 +1,21 @@
+#include <X11/Xlib.h>
+#include <rfb/rfbclient.h>
+
+struct vnc_window {
+ /* vnc connection */
+ rfbClient *client;
+ GIOChannel *ch;
+ guint id;
+ /* gtk windows */
+ GtkWidget *win;
+ GtkWidget *draw;
+ XImage *ximage;
+ void *shm;
+ GC gc;
+ Display *dpy;
+ /* misc */
+ int standalone;
+};
+
+void vnc_release(struct vnc_window*);
+struct vnc_window* vnc_open(char *hostname, int displayno, int standalone);
diff --git a/x11.c b/x11.c
new file mode 100644
index 0000000..fb75c2d
--- /dev/null
+++ b/x11.c
@@ -0,0 +1,226 @@
+/*
+ * some X11 ximage / pixmaps rotines
+ *
+ * (c) 2006 Gerd Hoffmann <kraxel@suse.de>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "x11.h"
+
+/* ------------------------------------------------------------------------ */
+
+XVisualInfo *x11_info;
+int have_shmem = 0;
+
+int x11_red_bits = 0;
+int x11_red_shift = 0;
+int x11_green_bits = 0;
+int x11_green_shift = 0;
+int x11_blue_bits = 0;
+int x11_blue_shift = 0;
+
+static void
+x11_find_bits(unsigned long red_mask,
+ unsigned long green_mask,
+ unsigned long blue_mask)
+{
+ int i;
+ unsigned long mask;
+
+ for (i = 0; i < 24; i++) {
+ mask = (1 << i);
+ if (red_mask & mask)
+ x11_red_bits++;
+ else if (!x11_red_bits)
+ x11_red_shift++;
+ if (green_mask & mask)
+ x11_green_bits++;
+ else if (!x11_green_bits)
+ x11_green_shift++;
+ if (blue_mask & mask)
+ x11_blue_bits++;
+ else if (!x11_blue_bits)
+ x11_blue_shift++;
+ }
+
+#if 1
+ printf("color: bits shift\n");
+ printf("red : %04i %05i\n", x11_red_bits, x11_red_shift);
+ printf("green: %04i %05i\n", x11_green_bits, x11_green_shift);
+ printf("blue : %04i %05i\n", x11_blue_bits, x11_blue_shift);
+#endif
+}
+
+int x11_color_init(Display *dpy)
+{
+ Screen *scr;
+ XVisualInfo template;
+ int found;
+
+ scr = DefaultScreenOfDisplay(dpy);
+
+ /* Ask for visual type */
+ template.screen = XDefaultScreen(dpy);
+ template.visualid =
+ XVisualIDFromVisual(DefaultVisualOfScreen(scr));
+ x11_info = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask, &template,
+ &found);
+ if (XShmQueryExtension(dpy))
+ have_shmem = 1;
+
+ if (x11_info->class != TrueColor) {
+ fprintf(stderr, "sorry, can't handle visual\n");
+ return -1;
+ }
+ x11_find_bits(x11_info->red_mask, x11_info->green_mask, x11_info->blue_mask);
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mitshm_bang = 0;
+
+static int x11_error_dev_null(Display *dpy, XErrorEvent *event)
+{
+ mitshm_bang = 1;
+ return 0;
+}
+
+XImage* x11_create_ximage(Display *dpy, int width, int height, void **shm)
+{
+ XImage *ximage = NULL;
+ char *ximage_data;
+ XShmSegmentInfo *shminfo = NULL;
+ void *old_handler;
+ Screen *scr = DefaultScreenOfDisplay(dpy);
+
+ if (have_shmem) {
+ old_handler = XSetErrorHandler(x11_error_dev_null);
+ (*shm) = shminfo = malloc(sizeof(XShmSegmentInfo));
+ memset(shminfo, 0, sizeof(XShmSegmentInfo));
+ ximage = XShmCreateImage(dpy,
+ DefaultVisualOfScreen(scr),
+ DefaultDepthOfScreen(scr),
+ ZPixmap, NULL,
+ shminfo, width, height);
+ if (ximage) {
+ shminfo->shmid = shmget(IPC_PRIVATE,
+ ximage->bytes_per_line * ximage->height,
+ IPC_CREAT | 0777);
+ if (-1 == shminfo->shmid) {
+ fprintf(stderr,"shmget(%dMB): %s\n",
+ ximage->bytes_per_line * ximage->height / 1024 / 1024,
+ strerror(errno));
+ goto oom;
+ }
+ shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
+ if ((void *) -1 == shminfo->shmaddr) {
+ perror("shmat");
+ goto oom;
+ }
+ ximage->data = shminfo->shmaddr;
+ shminfo->readOnly = False;
+
+ XShmAttach(dpy, shminfo);
+ XSync(dpy, False);
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+ if (mitshm_bang) {
+ have_shmem = 0;
+ shmdt(shminfo->shmaddr);
+ free(shminfo);
+ shminfo = *shm = NULL;
+ XDestroyImage(ximage);
+ ximage = NULL;
+ }
+ } else {
+ have_shmem = 0;
+ free(shminfo);
+ shminfo = *shm = NULL;
+ }
+ XSetErrorHandler(old_handler);
+ }
+
+ if (ximage == NULL) {
+ (*shm) = NULL;
+ if (NULL == (ximage_data = malloc(width * height * 4))) {
+ fprintf(stderr,"Oops: out of memory\n");
+ goto oom;
+ }
+ ximage = XCreateImage(dpy,
+ DefaultVisualOfScreen(scr),
+ DefaultDepthOfScreen(scr),
+ ZPixmap, 0, ximage_data,
+ width, height,
+ 8, 0);
+ }
+ memset(ximage->data, 0, ximage->bytes_per_line * ximage->height);
+
+ return ximage;
+
+ oom:
+ if (shminfo) {
+ if (shminfo->shmid && shminfo->shmid != -1)
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+ free(shminfo);
+ }
+ if (ximage)
+ XDestroyImage(ximage);
+ return NULL;
+}
+
+void x11_destroy_ximage(Display *dpy, XImage *ximage, void *shm)
+{
+ XShmSegmentInfo *shminfo = shm;
+
+ if (shminfo) {
+ XShmDetach(dpy, shminfo);
+ XDestroyImage(ximage);
+ shmdt(shminfo->shmaddr);
+ free(shminfo);
+ } else
+ XDestroyImage(ximage);
+}
+
+Pixmap x11_create_pixmap(Display *dpy, unsigned char *byte_data,
+ int width, int height)
+{
+ Pixmap pixmap;
+ XImage *ximage;
+ XGCValues values;
+ GC gc;
+ unsigned long *long_data = (unsigned long *)byte_data;
+ int x, y;
+ void *shm;
+
+ Screen *scr = DefaultScreenOfDisplay(dpy);
+
+ pixmap = XCreatePixmap(dpy,
+ RootWindowOfScreen(scr),
+ width, height,
+ DefaultDepthOfScreen(scr));
+ gc = XCreateGC(dpy, pixmap, 0, &values);
+
+ if (NULL == (ximage = x11_create_ximage(dpy, width, height, &shm))) {
+ XFreePixmap(dpy, pixmap);
+ XFreeGC(dpy, gc);
+ return 0;
+ }
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ XPutPixel(ximage, x, y, *(long_data++));
+
+ XPUTIMAGE(dpy, pixmap, gc, ximage, 0, 0, 0, 0, width, height);
+
+ x11_destroy_ximage(dpy, ximage, shm);
+ XFreeGC(dpy, gc);
+ return pixmap;
+}
diff --git a/x11.h b/x11.h
new file mode 100644
index 0000000..8bc4f23
--- /dev/null
+++ b/x11.h
@@ -0,0 +1,27 @@
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+
+extern XVisualInfo *x11_info;
+extern int have_shmem;
+
+extern int x11_red_bits;
+extern int x11_red_shift;
+extern int x11_green_bits;
+extern int x11_green_shift;
+extern int x11_blue_bits;
+extern int x11_blue_shift;
+
+int x11_color_init(Display *dpy);
+
+XImage *x11_create_ximage(Display *dpy, int width, int height, void **shm);
+void x11_destroy_ximage(Display *dpy, XImage * ximage, void *shm);
+Pixmap x11_create_pixmap(Display *dpy, unsigned char *data,
+ int width, int height);
+
+#define XPUTIMAGE(dpy,dr,gc,xi,a,b,c,d,w,h) \
+ if (have_shmem) \
+ XShmPutImage(dpy,dr,gc,xi,a,b,c,d,w,h,True); \
+ else \
+ XPutImage(dpy,dr,gc,xi,a,b,c,d,w,h)
diff --git a/xd_view.c b/xd_view.c
index 4b510d1..dc1c1d8 100644
--- a/xd_view.c
+++ b/xd_view.c
@@ -19,6 +19,7 @@
#include "tcp.h"
#include "mdns.h"
#include "apps.h"
+#include "vnc.h"
#define array_size(x) (sizeof(x)/sizeof(*x))
@@ -134,8 +135,12 @@ static void open_vnc(gint id, char *name, char *ostype)
{
if (0 == strcmp(ostype, "hvm")) {
/* works for hvm ... */
+#ifdef HAVE_VNC
+ vnc_open("localhost", id, 0);
+#else
if (-1 == open_vnc_session("localhost", id))
gtk_message(GTK_MESSAGE_ERROR, app_error);
+#endif
} else {
gtk_message(GTK_MESSAGE_ERROR, "VNC works for hvm domains only.\n");
}