diff options
author | kraxel <kraxel> | 2006-10-25 14:47:11 +0000 |
---|---|---|
committer | kraxel <kraxel> | 2006-10-25 14:47:11 +0000 |
commit | 397fcd38d34e02a73dc0d05e41562a82e608e203 (patch) | |
tree | 051bfb9d033634e8d6832cfb754a1be6a777c2e6 /vnc.c | |
parent | 75e722fc76c56c56a14546ba2dc7418fec08a558 (diff) | |
download | xenwatch-397fcd38d34e02a73dc0d05e41562a82e608e203.tar.gz |
add cvs viewer
Diffstat (limited to 'vnc.c')
-rw-r--r-- | vnc.c | 410 |
1 files changed, 410 insertions, 0 deletions
@@ -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 |