aboutsummaryrefslogtreecommitdiffstats
path: root/vnc.c
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 /vnc.c
parent75e722fc76c56c56a14546ba2dc7418fec08a558 (diff)
downloadxenwatch-397fcd38d34e02a73dc0d05e41562a82e608e203.tar.gz
add cvs viewer
Diffstat (limited to 'vnc.c')
-rw-r--r--vnc.c410
1 files changed, 410 insertions, 0 deletions
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