diff options
Diffstat (limited to 'vnc.c')
-rw-r--r-- | vnc.c | 1095 |
1 files changed, 99 insertions, 996 deletions
@@ -20,519 +20,48 @@ #include "x11.h" #include "vnc.h" -#ifdef HAVE_VNCCLIENT +#ifdef HAVE_GTK_VNC -#include <rfb/rfbclient.h> - -static int debug_libvnc; +#include <vncdisplay.h> /* ------------------------------------------------------------------ */ -struct pos { - int x; - int y; -}; - -struct rect { - int w; - int h; -}; - struct vnc_window { - /* vnc connection */ - char display[128]; - rfbClient *client; - GIOChannel *ch; - guint id, connected; - /* gtk */ GtkAccelGroup *ac; GtkActionGroup *ag; GtkUIManager *ui; GtkWidget *win; - GtkWidget *draw; + GtkWidget *vnc; GtkWidget *line, *res, *mbutton, *popup; - GdkCursor *on,*off; - int filter_installed; - int input_grabbed; - /* x11 */ - XImage *ximage; - void *shm; - GC gc; - Display *dpy; - unsigned char keydown[32]; - - /* opengl */ - int have_gl; - GLuint tex; - int tex_max; - unsigned char *tex_data; - unsigned int dirty_y1, dirty_y2; - - /* window / vnc display config */ - struct rect window; - struct pos vncoff; - struct rect vncdpy; - struct rect texture; - int updates, redraw; + /* connection */ + char display[100]; + char hostname[80]; + char tcpport[16]; + + /* state */ + int input_grabbed; + int connected; /* config */ int fullscreen; - int viewonly; int standalone; int showpointer; - int gl_allways; - int gl_fullscreen; - int uskbd; + int viewonly; int debug; }; /* ------------------------------------------------------------------ */ -/* data tables */ - -rfbKeySym linux_uskbd[][2] = { -#include "linux-uskbd.h" -}; -static int linux_uskbd_size = sizeof(linux_uskbd)/sizeof(linux_uskbd[0]); - -/* ------------------------------------------------------------------ */ -/* prototypes */ - -static GdkFilterReturn event_filter(GdkXEvent *gdkxevent, GdkEvent *gtkevent, - gpointer data); -static void vnc_window_conf(struct vnc_window *vnc); -static void vnc_window_texts(struct vnc_window *vnc); - -/* ------------------------------------------------------------------ */ -/* opengl bits */ - -static int gl_error; -static int gl_attrib[] = { GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - None }; - -static int -catch_gl_error(Display * dpy, XErrorEvent * event) -{ - fprintf(stderr,"WARNING: Your OpenGL setup is broken.\n"); - gl_error++; - return 0; -} - -static int gl_init(struct vnc_window *vnc) -{ - Window win = gdk_x11_drawable_get_xid(vnc->draw->window); - Screen *scr = DefaultScreenOfDisplay(vnc->dpy); - void *old_handler; - XVisualInfo *visinfo; - GLXContext ctx; - - if (vnc->debug) - fprintf(stderr, "gl: init [window=0x%lx]\n", win); - if (!win) - return -1; - visinfo = glXChooseVisual(vnc->dpy, XScreenNumberOfScreen(scr), - gl_attrib); - if (!visinfo) { - if (vnc->debug) - fprintf(stderr,"gl: can't get visual (rgb,db)\n"); - return -1; - } - ctx = glXCreateContext(vnc->dpy, visinfo, NULL, True); - if (!ctx) { - if (vnc->debug) - fprintf(stderr,"gl: can't create context\n"); - return -1; - } - - /* there is no point in using OpenGL for image scaling if it - * isn't hardware accelerated ... */ - if (vnc->debug) - fprintf(stderr, "gl: DRI=%s\n", - glXIsDirect(vnc->dpy, ctx) ? "Yes" : "No"); - if (!glXIsDirect(vnc->dpy, ctx)) - return -1; - - old_handler = XSetErrorHandler(catch_gl_error); - glXMakeCurrent(vnc->dpy, win, ctx); - XSync(vnc->dpy, False); - XSetErrorHandler(old_handler); - if (gl_error) - return -1; - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &vnc->tex_max); - if (vnc->debug) - fprintf(stderr, "gl: texture max size: %d\n", vnc->tex_max); - return 0; -} - -static void gl_resize_window(struct vnc_window *vnc) -{ - if (!vnc->tex) - return; - - glClearColor (0.0, 0.0, 0.0, 0.0); - glShadeModel(GL_FLAT); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glViewport(0, 0, vnc->window.w, vnc->window.h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, vnc->window.w, 0.0, vnc->window.h, -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - vnc->redraw++; -} - -static void gl_blit(struct vnc_window *vnc, int y1, int y2) -{ - Window win = gdk_x11_drawable_get_xid(vnc->draw->window); - float x,y; - unsigned int ww = vnc->window.w, wh = vnc->window.h; - int wx = 0, wy = 0; - - if (!vnc->tex) - return; - - if (y1 > vnc->vncdpy.h) - y1 = vnc->vncdpy.h; - if (y2 > vnc->vncdpy.h) - y2 = vnc->vncdpy.h; - - glBindTexture(GL_TEXTURE_2D, vnc->tex); - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0,y1, vnc->vncdpy.w, y2 - y1, - GL_BGRA_EXT /* GL_RGB */, - GL_UNSIGNED_BYTE, - vnc->tex_data + y1 * 4 * vnc->vncdpy.w); - x = (float)vnc->vncdpy.w / vnc->texture.w; - y = (float)vnc->vncdpy.h / vnc->texture.h; - - glEnable(GL_TEXTURE_2D); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - glBegin(GL_QUADS); - glTexCoord2f(0,y); glVertex3f(wx, wy, 0); - glTexCoord2f(0,0); glVertex3f(wx, wy+wh, 0); - glTexCoord2f(x,0); glVertex3f(wx+ww, wy+wh, 0); - glTexCoord2f(x,y); glVertex3f(wx+ww, wy, 0); - glEnd(); - glXSwapBuffers(vnc->dpy, win); - glDisable(GL_TEXTURE_2D); -} - -static void gl_update_vnc(struct vnc_window *vnc, - int x, int y, int w, int h) -{ - if (vnc->dirty_y1 > y) - vnc->dirty_y1 = y; - if (vnc->dirty_y2 < y+h) - vnc->dirty_y2 = y+h; - vnc->updates++; -} - -static void gl_update_win(struct vnc_window *vnc, - int x, int y, int w, int h) -{ - vnc->dirty_y1 = 0; - vnc->dirty_y2 = vnc->vncdpy.h; - vnc->updates++; -} - -static void gl_flush(struct vnc_window *vnc) -{ - if (vnc->redraw) { - vnc->dirty_y1 = 0; - vnc->dirty_y2 = vnc->vncdpy.h; - } - gl_blit(vnc, vnc->dirty_y1, vnc->dirty_y2); - - vnc->dirty_y1 = 99999; - vnc->dirty_y2 = 0; - vnc->updates = 0; - vnc->redraw = 0; -} - -/* ------------------------------------------------------------------ */ -/* x11 draw bits */ - -static void x11_update_win(struct vnc_window *vnc, - int x, int y, int w, int h) -{ - Window win = gdk_x11_drawable_get_xid(vnc->draw->window); - - if (!vnc->gc) { - XGCValues values; - XColor color, dummy; - Colormap cmap; - - cmap = gdk_x11_colormap_get_xcolormap(gtk_widget_get_colormap(vnc->win)); - XAllocNamedColor(vnc->dpy, cmap, "#404040", &color, &dummy); - values.function = GXcopy; - values.foreground = color.pixel; - vnc->gc = XCreateGC(vnc->dpy, win, - GCForeground|GCFunction, - &values); - } - - if (x < vnc->vncoff.x) - vnc->redraw++; - if (y < vnc->vncoff.y) - vnc->redraw++; - if (x+w > vnc->vncoff.x + vnc->vncdpy.w) - vnc->redraw++; - if (y+h > vnc->vncoff.y + vnc->vncdpy.h) - vnc->redraw++; - - if (vnc->redraw) { - XFillRectangle(vnc->dpy, win, vnc->gc, - 0,0, vnc->window.w, vnc->window.h); - XPUTIMAGE(vnc->dpy, win, vnc->gc, vnc->ximage, 0,0, - vnc->vncoff.x, vnc->vncoff.y, - vnc->vncdpy.w, vnc->vncdpy.h); - vnc->redraw = 0; - } else { - XPUTIMAGE(vnc->dpy, win, vnc->gc, vnc->ximage, - x-vnc->vncoff.x, y-vnc->vncoff.y, - x,y, w,h); - } -} - -static void x11_update_vnc(struct vnc_window *vnc, - int x, int y, int w, int h) -{ - x11_update_win(vnc, x + vnc->vncoff.x, y + vnc->vncoff.y, w, h); -} - -static void x11_resize_window(struct vnc_window *vnc) -{ - vnc->vncoff.x = (vnc->window.w - vnc->vncdpy.w) / 2; - vnc->vncoff.y = (vnc->window.h - vnc->vncdpy.h) / 2; -} - -static void x11_flush(struct vnc_window *vnc) -{ - if (vnc->redraw) - x11_update_win(vnc, 0, 0, vnc->vncdpy.w, vnc->vncdpy.w); - vnc->updates = 0; - vnc->redraw = 0; -} - -/* ------------------------------------------------------------------ */ -/* x11/gl wrappers */ - -/* vnc display coordinates */ -static void dpy_update_vnc(struct vnc_window *vnc, - int x, int y, int w, int h) -{ - if (vnc->debug) - fprintf(stderr, "%s: mode%s%s, %dx%d+%d+%d\n", __FUNCTION__, - vnc->tex ? " GL" : "", - vnc->ximage ? " X11" : "", - w, h, x, y); - if (vnc->ximage) - x11_update_vnc(vnc, x, y, w, h); - if (vnc->tex) - gl_update_vnc(vnc, x, y, w, h); -} - -/* app window coordinates */ -static void dpy_update_win(struct vnc_window *vnc, - int x, int y, int w, int h) -{ - if (vnc->debug) - fprintf(stderr, "%s: mode%s%s, %dx%d+%d+%d\n", __FUNCTION__, - vnc->tex ? " GL" : "", - vnc->ximage ? " X11" : "", - w, h, x, y); - if (vnc->ximage) - x11_update_win(vnc, x, y, w, h); - if (vnc->tex) - gl_update_win(vnc, x, y, w, h); -} - -static void dpy_redraw(struct vnc_window *vnc) -{ - vnc->redraw++; -} - -static void dpy_flush(struct vnc_window *vnc, const char *caller) -{ - if (vnc->debug) - fprintf(stderr, "%s: from %s, mode%s%s, updates %d, redraw %d\n", - __FUNCTION__, caller, - vnc->tex ? " GL" : "", - vnc->ximage ? " X11" : "", - vnc->updates, vnc->redraw); - if (!vnc->updates && !vnc->redraw) - return; - - if (vnc->ximage) - x11_flush(vnc); - if (vnc->tex) - gl_flush(vnc); -} - -static int dpy_gl_check(struct vnc_window *vnc) -{ - int using_gl = 0; - - if (vnc->have_gl && vnc->vncdpy.w < vnc->tex_max && vnc->vncdpy.h < vnc->tex_max) { - if (vnc->gl_allways) - using_gl = 1; - if (vnc->gl_fullscreen && vnc->fullscreen) - using_gl = 1; - } - return using_gl; -} - -static void dpy_setup(struct vnc_window *vnc, int width, int height, int using_gl) -{ - /* cleanup */ - if (vnc->ximage) { - x11_destroy_ximage(vnc->dpy, vnc->ximage, vnc->shm); - vnc->ximage = NULL; - } - if (vnc->tex) { - /* FIXME: release texture */ - vnc->tex = 0; - vnc->vncdpy.w = 0; - vnc->vncdpy.h = 0; - free(vnc->tex_data); - vnc->tex_data = NULL; - } - - vnc->vncdpy.w = width; - vnc->vncdpy.h = height; - - if (!using_gl) { - /* init X11 */ - vnc->ximage = x11_create_ximage(vnc->dpy, vnc->vncdpy.w, vnc->vncdpy.h, &vnc->shm); - if (NULL == vnc->ximage) { - fprintf(stderr, "Oops: creating ximage failed\n"); - return; - } - - vnc->client->width = - vnc->ximage->bytes_per_line / (vnc->ximage->bits_per_pixel / 8); - vnc->client->frameBuffer = (void*)vnc->ximage->data; - - vnc->client->format.bitsPerPixel = vnc->ximage->bits_per_pixel; - vnc->client->format.redShift = x11_red_shift; - vnc->client->format.greenShift = x11_green_shift; - vnc->client->format.blueShift = x11_blue_shift; - vnc->client->format.redMax = (1 << x11_red_bits) - 1; - vnc->client->format.greenMax = (1 << x11_green_bits) - 1; - vnc->client->format.blueMax = (1 << x11_blue_bits) - 1; - } else { - /* init OpenGL */ - void *dummy; - int i; - - /* figure texture size (power of two) */ - for (i = 0; vnc->vncdpy.w >= (1 << i); i++) - ; - vnc->texture.w = (1 << i); - for (i = 0; vnc->vncdpy.h >= (1 << i); i++) - ; - vnc->texture.h = (1 << i); - if (vnc->debug) - fprintf(stderr,"%s: client %dx%d, tex %dx%d\n", __FUNCTION__, - vnc->vncdpy.w, vnc->vncdpy.h, vnc->texture.w, vnc->texture.h); - - /* create texture */ - glGenTextures(1, &vnc->tex); - glBindTexture(GL_TEXTURE_2D, vnc->tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - dummy = malloc(vnc->texture.w * vnc->texture.h * 4); - memset(dummy, 128, vnc->texture.w * vnc->texture.h * 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - vnc->texture.w, vnc->texture.h, 0, - GL_RGB, GL_UNSIGNED_BYTE, - dummy); - free(dummy); - - /* image buffer */ - vnc->tex_data = malloc(vnc->vncdpy.w * vnc->vncdpy.h * 4); - vnc->client->frameBuffer = vnc->tex_data; - - vnc->client->format.bitsPerPixel = 32; - vnc->client->format.redShift = 16; - vnc->client->format.greenShift = 8; - vnc->client->format.blueShift = 0; - vnc->client->format.redMax = 255; - vnc->client->format.greenMax = 255; - vnc->client->format.blueMax = 255; - } - - if (vnc->debug) - fprintf(stderr, "%s: SetFormatAndEncodings: %s\n", __FUNCTION__, - using_gl ? "GL" : "X11" ); - SetFormatAndEncodings(vnc->client); - SendFramebufferUpdateRequest(vnc->client, 0, 0, - vnc->vncdpy.w, vnc->vncdpy.h, False); - vnc_window_conf(vnc); -} - -static void dpy_resize_window(struct vnc_window *vnc) -{ - int using_gl; - - vnc->vncoff.x = 0; - vnc->vncoff.y = 0; - using_gl = dpy_gl_check(vnc); - if ((vnc->tex && !using_gl) || - (vnc->ximage && using_gl)) { - /* switching display mode */ - dpy_setup(vnc, vnc->client->width, vnc->client->height, using_gl); - } else { - if (vnc->ximage) - x11_resize_window(vnc); - if (vnc->tex) - gl_resize_window(vnc); - dpy_redraw(vnc); - } - vnc_window_texts(vnc); -} - -/* ------------------------------------------------------------------ */ /* helper functions */ -static void XAddInput(Display *dpy, Window win, long mask) -{ - XWindowAttributes attr; - - XGetWindowAttributes(dpy, win, &attr); - XSelectInput(dpy, win, attr.your_event_mask | mask); -} - -static GdkCursor* empty_cursor(void) -{ - static char bits[32]; - GdkCursor *cursor; - GdkPixmap *pixmap; - GdkColor fg = { 0, 0, 0, 0 }; - GdkColor bg = { 0, 0, 0, 0 }; - - pixmap = gdk_bitmap_create_from_data(NULL, bits, 16, 16); - cursor = gdk_cursor_new_from_pixmap(pixmap, pixmap, &fg, &bg, 0, 0); - gdk_pixmap_unref(pixmap); - return cursor; -} - static void vnc_window_texts(struct vnc_window *vnc) { + const char *name = vnc_display_get_name(VNC_DISPLAY(vnc->vnc)); char textline[256]; - int pos; - if (vnc->client && vnc->client->desktopName && - strlen(vnc->client->desktopName)) { - gtk_window_set_title(GTK_WINDOW(vnc->win), vnc->client->desktopName); + if (vnc->connected) { + gtk_window_set_title(GTK_WINDOW(vnc->win), name); } else { snprintf(textline, sizeof(textline), "connecting to %s ...", vnc->display); @@ -542,151 +71,28 @@ static void vnc_window_texts(struct vnc_window *vnc) if (vnc->input_grabbed) { gtk_label_set_text(GTK_LABEL(vnc->line), "Press Ctrl-Alt to release input grab."); - } else if (vnc->client) { + } else if (vnc->connected) { snprintf(textline, sizeof(textline), "VNC: \"%s\" at %s", - vnc->client->desktopName ?: "", vnc->display); + name ?: "", vnc->display); gtk_label_set_text(GTK_LABEL(vnc->line), textline); + } else { + gtk_label_set_text(GTK_LABEL(vnc->line), "VNC: disconnected"); } - if (vnc->client) { - pos = 0; - pos += snprintf(textline+pos, sizeof(textline)-pos, "%dx%d", - vnc->vncdpy.w, vnc->vncdpy.h); - if (vnc->vncdpy.w != vnc->window.w || - vnc->vncdpy.h != vnc->window.h) - pos += snprintf(textline+pos, sizeof(textline)-pos, " @ %dx%d", - vnc->window.w, vnc->window.h); - pos += snprintf(textline+pos, sizeof(textline)-pos, " (%s)", - vnc->ximage ? "X11" : "GL"); - gtk_label_set_text(GTK_LABEL(vnc->res), textline); - } -} - -static void vnc_window_conf(struct vnc_window *vnc) -{ - if (!vnc->draw) - return; - if (vnc->client) - gtk_widget_set_size_request(vnc->draw, vnc->vncdpy.w, vnc->vncdpy.h); - if (vnc->draw->window) { - gdk_window_set_cursor(vnc->draw->window, - vnc->showpointer ? vnc->on : vnc->off); - /* FIXME */ - XAddInput(vnc->dpy, gdk_x11_drawable_get_xid(vnc->draw->window), - KeymapStateMask); - } - dpy_resize_window(vnc); + snprintf(textline, sizeof(textline), "%dx%d", + vnc_display_get_width(VNC_DISPLAY(vnc->vnc)), + vnc_display_get_height(VNC_DISPLAY(vnc->vnc))); + gtk_label_set_text(GTK_LABEL(vnc->res), textline); } static void vnc_release(struct vnc_window *vnc) { - int sock = -1; - if (NULL == vnc) return; - if (vnc->connected && vnc->client) { - /* - * library bugs? - * - calling rfbClientCleanup() unconnected segfaults - * - rfbClientCleanup() doesn't close the socket - */ - sock = vnc->client->sock; - rfbClientCleanup(vnc->client); - vnc->client = NULL; - } - if (vnc->filter_installed) - gdk_window_remove_filter(vnc->draw->window, event_filter, vnc); - 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); - if (-1 != sock) - close(sock); free(vnc); } -static void grab_input(struct vnc_window *vnc, guint32 time) -{ - if (vnc->viewonly) - return; - if (vnc->input_grabbed) - return; - gdk_pointer_grab(vnc->draw->window, - FALSE, - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK, - vnc->draw->window, - NULL, - time); - gdk_keyboard_grab(vnc->draw->window, - FALSE, - time); - vnc->input_grabbed = 1; - vnc_window_texts(vnc); -} - -static void ungrab_input(struct vnc_window *vnc, guint32 time) -{ - if (!vnc->input_grabbed) - return; - gdk_pointer_ungrab(time); - gdk_keyboard_ungrab(time); - vnc->input_grabbed = 0; - vnc_window_texts(vnc); -} - -/* ------------------------------------------------------------------ */ -/* libvncclient callbacks */ - -static rfbBool vnc_resize(rfbClient* client) -{ - struct vnc_window *vnc = rfbClientGetClientData(client, vnc_open); - - if (vnc->debug) - fprintf(stderr, "%s: %dx%d\n", - __FUNCTION__, client->width, client->height); - if (vnc->vncdpy.w == client->width && - vnc->vncdpy.h == client->height) { - if (vnc->debug) - fprintf(stderr, "%s: no size change, early exit\n", __FUNCTION__); - return TRUE; - } - - dpy_setup(vnc, client->width, client->height, dpy_gl_check(vnc)); - 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; - dpy_update_vnc(vnc, x,y, w,h); -} - -#ifdef HAVE_VNC_TEXT -static void vnc_textchat(rfbClient* cl, int value, char *text) -{ - switch(value) { - case rfbTextChatOpen: - fprintf(stderr,"%s: Open\n", __FUNCTION__); - break; - case rfbTextChatClose: - case rfbTextChatFinished: - fprintf(stderr,"%s: Close/Finished\n", __FUNCTION__); - break; - default: - fprintf(stderr,"%s: \"%s\"\n", __FUNCTION__, text); - break; - } -} -#endif - +#if 0 static char *vnc_passwd(rfbClient* cl) { struct vnc_window *vnc = rfbClientGetClientData(cl, vnc_open); @@ -740,238 +146,94 @@ static char *vnc_passwd(rfbClient* cl) return passwd; } - -static void vnc_log(const char *format, ...) -{ - va_list args; - - if (!debug_libvnc) - return; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} +#endif /* ------------------------------------------------------------------ */ -/* glib/gtk callbacks */ +/* vnc widget callbacks */ -static gboolean vnc_data_cb(GIOChannel *source, GIOCondition condition, - gpointer data) +static void vnc_connected(GtkWidget *vncdisplay, void *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); - } - dpy_flush(vnc, __FUNCTION__); - return TRUE; + if (vnc->debug) + fprintf(stderr, "%s\n", __FUNCTION__); } -static void destroy_cb(GtkWidget *widget, gpointer data) +static void vnc_initialized(GtkWidget *vncdisplay, void *data) { struct vnc_window *vnc = data; if (vnc->debug) - fprintf(stderr,"%s: called\n", __FUNCTION__); - if (vnc->standalone) - gtk_main_quit(); - vnc_release(vnc); + fprintf(stderr, "%s\n", __FUNCTION__); + vnc->connected = 1; + vnc_window_texts(vnc); } -static gboolean expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data) +static void vnc_disconnected(GtkWidget *vncdisplay, void *data) { struct vnc_window *vnc = data; - dpy_update_win(vnc, event->area.x, event->area.y, - event->area.width, event->area.height); - if (0 == event->count) - dpy_flush(vnc, __FUNCTION__); - return TRUE; + if (vnc->debug) + fprintf(stderr, "%s\n", __FUNCTION__); + vnc->connected = 0; + vnc_window_texts(vnc); } -static gboolean configure_cb(GtkWidget *widget, GdkEventConfigure *event, - gpointer data) +static void vnc_grab(GtkWidget *vncdisplay, void *data) { struct vnc_window *vnc = data; if (vnc->debug) - fprintf(stderr,"%s: %dx%d\n", __FUNCTION__, - event->width, event->height); - vnc->window.w = event->width; - vnc->window.h = event->height; - dpy_resize_window(vnc); - dpy_flush(vnc, __FUNCTION__); - return TRUE; + fprintf(stderr, "%s\n", __FUNCTION__); + vnc->input_grabbed = 1; + vnc_window_texts(vnc); } -static gboolean window_state_cb(GtkWidget *widget, GdkEventWindowState *event, - gpointer data) +static void vnc_ungrab(GtkWidget *vncdisplay, void *data) { struct vnc_window *vnc = data; - GtkWidget *item; - if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) { - vnc->fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; - if (vnc->debug) - fprintf(stderr, "%s: fullscreen %s\n", __FUNCTION__, - vnc->fullscreen ? "on" : "off"); - item = gtk_ui_manager_get_widget(vnc->ui, "/ConfMenu/FullScreen"); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), vnc->fullscreen); - } - return TRUE; + if (vnc->debug) + fprintf(stderr, "%s\n", __FUNCTION__); + vnc->input_grabbed = 0; + vnc_window_texts(vnc); } -static void send_mouse(struct vnc_window *vnc, int x, int y, - int x11state, int x11press, int x11release) +static void vnc_credential(GtkWidget *vncdisplay, void *data) { - static const struct { - int rfbmask; - int x11mask; - int x11nr; - } buttons[] = { - { - .rfbmask = rfbButton1Mask, - .x11mask = Button1Mask, - .x11nr = Button1, - },{ - .rfbmask = rfbButton2Mask, - .x11mask = Button2Mask, - .x11nr = Button2, - },{ - .rfbmask = rfbButton3Mask, - .x11mask = Button3Mask, - .x11nr = Button3, - },{ - .rfbmask = rfbButton4Mask, - .x11mask = Button4Mask, - .x11nr = Button4, - },{ - .rfbmask = rfbButton5Mask, - .x11mask = Button5Mask, - .x11nr = Button5, - } - }; - int i, rfbstate = 0; - - if (vnc->viewonly) - return; - - for (i = 0; i < sizeof(buttons)/sizeof(buttons[0]); i++) { - if (x11state & buttons[i].x11mask) - rfbstate |= buttons[i].rfbmask; - if (x11press == buttons[i].x11nr) - rfbstate |= buttons[i].rfbmask; - if (x11release == buttons[i].x11nr) - rfbstate &= ~buttons[i].rfbmask; - } - - /* fixup mouse coordinates */ - x -= vnc->vncoff.x; - y -= vnc->vncoff.y; - if (vnc->tex) { - x = x * vnc->window.w / vnc->vncdpy.w; - y = y * vnc->window.h / vnc->vncdpy.h; - } - if (x < 0) - x = 0; - if (y < 0) - y = 0; - if (x >= vnc->vncdpy.w) - x = vnc->vncdpy.w -1; - if (y >= vnc->vncdpy.h) - y = vnc->vncdpy.h -1; +// struct vnc_window *vnc = data; - if (vnc->debug) - fprintf(stderr,"%s: +%d+%d x11state 0x%x rfbstate 0x%x\n", - __FUNCTION__, x, y, x11state, rfbstate); - SendPointerEvent(vnc->client, x, y, rfbstate); + fprintf(stderr, "%s: not implemented yet\n", __FUNCTION__); } -static gboolean button_cb(GtkWidget *widget, GdkEventButton *event, - gpointer data) -{ - struct vnc_window *vnc = data; - switch (event->type) { - case GDK_BUTTON_PRESS: - send_mouse(vnc, event->x, event->y, event->state, event->button, 0); - grab_input(vnc, event->time); - break; - case GDK_BUTTON_RELEASE: - send_mouse(vnc, event->x, event->y, event->state, 0, event->button); - break; - default: - /* keep gcc happy */ - break; - } - return TRUE; -} +/* ------------------------------------------------------------------ */ +/* glib/gtk callbacks */ -static gboolean motion_cb(GtkWidget *widget, GdkEventMotion *event, - gpointer data) +static void destroy_cb(GtkWidget *widget, gpointer data) { struct vnc_window *vnc = data; - send_mouse(vnc, event->x, event->y, event->state, 0, 0); - return TRUE; -} - -static void key_local(struct vnc_window *vnc, GdkEventKey *event) -{ - int keydown; if (vnc->debug) - fprintf(stderr,"%s[%d]: called: keysym %d\n", __FUNCTION__, - event->type, event->keyval); - keydown = (8 == event->type); - if (!vnc->viewonly) - SendKeyEvent(vnc->client, event->keyval, keydown ? TRUE : FALSE); -} - -static void key_uskbd(struct vnc_window *vnc, GdkEventKey *event) -{ - rfbKeySym keysym = 0; - int shift,keydown; - - keydown = (8 == event->type); - if (event->hardware_keycode < 256) { - int by = event->hardware_keycode / 8; - int bi = event->hardware_keycode % 8; - if (keydown) - vnc->keydown[by] |= (1 << bi); - else - vnc->keydown[by] &= ~(1 << bi); - } - - shift = (event->state & GDK_SHIFT_MASK) ? 1 : 0; - if (event->hardware_keycode < linux_uskbd_size) { - keysym = linux_uskbd[event->hardware_keycode][shift]; - if (0 == keysym) - keysym = linux_uskbd[event->hardware_keycode][0]; - } - - if (vnc->debug || 0 == keysym) - fprintf(stderr,"%s[%d]: called: keycode %d => keysym %d\n", __FUNCTION__, - event->type, event->hardware_keycode, keysym); - if (keysym && !vnc->viewonly) - SendKeyEvent(vnc->client, keysym, keydown ? TRUE : FALSE); + fprintf(stderr,"%s: called\n", __FUNCTION__); + if (vnc->standalone) + gtk_main_quit(); + vnc_release(vnc); } -static gboolean key_cb(GtkWidget *widget, GdkEventKey *event, - gpointer data) +static gboolean window_state_cb(GtkWidget *widget, GdkEventWindowState *event, + gpointer data) { struct vnc_window *vnc = data; - int mask = GDK_CONTROL_MASK | GDK_MOD1_MASK; - - if (mask == (event->state & mask)) - ungrab_input(vnc, event->time); + GtkWidget *item; - if (vnc->uskbd) - key_uskbd(vnc, event); - else - key_local(vnc, event); + if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) { + vnc->fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; + if (vnc->debug) + fprintf(stderr, "%s: fullscreen %s\n", __FUNCTION__, + vnc->fullscreen ? "on" : "off"); + item = gtk_ui_manager_get_widget(vnc->ui, "/ConfMenu/FullScreen"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), vnc->fullscreen); + } return TRUE; } @@ -983,46 +245,6 @@ static void menu_btn(GtkWidget *widget, gpointer data) 0, gtk_get_current_event_time()); } -static GdkFilterReturn event_filter(GdkXEvent *gdkxevent, GdkEvent *gtkevent, - gpointer data) -{ - struct vnc_window *vnc = data; - XEvent *xevent = gdkxevent; - int by, bi, keydown, keycode; - rfbKeySym keysym = 0; - - switch (xevent->type) { - case KeymapNotify: - if (!vnc->uskbd) - return GDK_FILTER_REMOVE; - if (!GTK_WIDGET_HAS_FOCUS(vnc->draw)) - return GDK_FILTER_REMOVE; - for (by = 0; by < 32; by++) { - if (vnc->keydown[by] == xevent->xkeymap.key_vector[by]) - continue; - for (bi = 0; bi < 8; bi++) { - if ((vnc->keydown[by] & (1 << bi)) == - (xevent->xkeymap.key_vector[by] & (1 << bi))) - continue; - keydown = xevent->xkeymap.key_vector[by] & (1 << bi); - keycode = by * 8 + bi; - keysym = linux_uskbd[keycode][0]; - if (!keysym) - continue; - if (vnc->debug) - fprintf(stderr,"%s: KeymapNotify: %-7s %3d\n", __FUNCTION__, - keydown ? "press" : "release", keycode); - if (!vnc->viewonly) - SendKeyEvent(vnc->client, keysym, keydown ? TRUE : FALSE); - } - } - memcpy(vnc->keydown, xevent->xkeymap.key_vector, 32); - return GDK_FILTER_REMOVE; - default: - return GDK_FILTER_CONTINUE; - } -} - /* ------------------------------------------------------------------ */ static void menu_cb_full_screen(GtkToggleAction *action, gpointer user_data) @@ -1036,21 +258,16 @@ static void menu_cb_full_screen(GtkToggleAction *action, gpointer user_data) gtk_window_unfullscreen(GTK_WINDOW(vnc->win)); } -static void menu_cb_us_keyboard(GtkToggleAction *action, gpointer user_data) -{ - struct vnc_window *vnc = user_data; - - vnc->uskbd = gtk_toggle_action_get_active(action); -} - static void menu_cb_show_pointer(GtkToggleAction *action, gpointer user_data) { struct vnc_window *vnc = user_data; vnc->showpointer = gtk_toggle_action_get_active(action); +#if 0 if (vnc->draw->window) gdk_window_set_cursor(vnc->draw->window, vnc->showpointer ? vnc->on : vnc->off); +#endif } static void menu_cb_view_only(GtkToggleAction *action, gpointer user_data) @@ -1060,29 +277,6 @@ static void menu_cb_view_only(GtkToggleAction *action, gpointer user_data) vnc->viewonly = gtk_toggle_action_get_active(action); } -static void menu_cb_gl(GtkRadioAction *action, GtkRadioAction *current, - gpointer user_data) -{ - struct vnc_window *vnc = user_data; - int value = gtk_radio_action_get_current_value(action); - - switch (value) { - case 1: /* OFF */ - vnc->gl_fullscreen = 0; - vnc->gl_allways = 0; - break; - case 2: /* fullscreen ON */ - vnc->gl_fullscreen = 1; - vnc->gl_allways = 0; - break; - case 3: /* allways ON */ - vnc->gl_fullscreen = 1; - vnc->gl_allways = 1; - break; - } - dpy_resize_window(vnc); -} - static void menu_cb_about(GtkMenuItem *item, void *user_data) { static char *comments = "simple vnc client"; @@ -1136,10 +330,6 @@ static const GtkToggleActionEntry tentries[] = { .accelerator = "F11", .callback = G_CALLBACK(menu_cb_full_screen), },{ - .name = "USKbd", - .label = "US _Keyboard", - .callback = G_CALLBACK(menu_cb_us_keyboard), - },{ .name = "ShowPointer", .label = "Show _Pointer", .callback = G_CALLBACK(menu_cb_show_pointer), @@ -1150,34 +340,13 @@ static const GtkToggleActionEntry tentries[] = { } }; -static const GtkRadioActionEntry rentries[] = { - { - .name = "GL_OFF", - .label = "_Disable OpenGL scaling", - .value = 1, - },{ - .name = "GL_FSonly", - .label = "OpenGL scaling for fullscreen", - .value = 2, - },{ - .name = "GL_ON", - .label = "Allways scale using _OpenGL", - .value = 3, - } -}; - static char ui_xml[] = "<ui>" " <popup action='ConfMenu'>" " <menuitem action='FullScreen'/>" -" <menuitem action='USKbd'/>" " <menuitem action='ShowPointer'/>" " <menuitem action='ViewOnly'/>" " <separator/>" -" <menuitem action='GL_OFF'/>" -" <menuitem action='GL_FSonly'/>" -" <menuitem action='GL_ON'/>" -" <separator/>" " <menuitem action='About'/>" " <menuitem action='Close'/>" " </popup>" @@ -1190,12 +359,8 @@ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, int debug_level) { GtkWidget *vbox, *hbox, *frame, *item; - GtkAction *action; GError *err; - char *argv[] = { "vnc-client", NULL, NULL }; - int argc = sizeof(argv)/sizeof(argv[0]) -1; struct vnc_window *vnc; - int rc; vnc = malloc(sizeof(*vnc)); if (NULL == vnc) @@ -1203,61 +368,38 @@ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, memset(vnc,0,sizeof(*vnc)); vnc->standalone = (flags & VNC_FLAG_STANDALONE); vnc->showpointer = (flags & VNC_FLAG_SHOW_MOUSE); - vnc->uskbd = (flags & VNC_FLAG_US_KBD); vnc->viewonly = (flags & VNC_FLAG_VIEW_ONLY); - vnc->gl_allways = (flags & VNC_FLAG_GL_ALLWAYS); - vnc->gl_fullscreen = (flags & VNC_FLAG_GL_FULLSCR); vnc->debug = debug_level; - debug_libvnc = debug_level; - snprintf(vnc->display, sizeof(vnc->display), - "%s:%d", hostname, tcpport - 5900); - vnc->dirty_y1 = 99999; - vnc->dirty_y2 = 0; - - /* x11 */ - vnc->dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default()); - if (NULL == x11_info) - if (0 != x11_color_init(vnc->dpy)) - goto err; + snprintf(vnc->display, sizeof(vnc->display), "%s:%d", + hostname, tcpport - 5900); + snprintf(vnc->hostname, sizeof(vnc->hostname),"%s", hostname); + snprintf(vnc->tcpport, sizeof(vnc->tcpport),"%d", tcpport); /* gtk toplevel */ vnc->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(vnc->win), "destroy", G_CALLBACK(destroy_cb), vnc); - vnc->on = gdk_cursor_new(GDK_LEFT_PTR); - vnc->off = empty_cursor(); - - /* gtk drawing area */ - vnc->draw = gtk_drawing_area_new(); - GTK_WIDGET_SET_FLAGS(vnc->draw, GTK_CAN_FOCUS); - gtk_widget_add_events(vnc->draw, - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_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), "motion-notify-event", - G_CALLBACK(motion_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); - g_signal_connect(G_OBJECT(vnc->draw), "configure-event", - G_CALLBACK(configure_cb), vnc); g_signal_connect(G_OBJECT(vnc->win), "window-state-event", G_CALLBACK(window_state_cb), vnc); - gdk_window_add_filter(NULL, event_filter, vnc); - vnc->filter_installed = 1; + + /* vnc display widget */ + vnc->vnc = vnc_display_new(); + gtk_signal_connect(GTK_OBJECT(vnc->vnc), "vnc-connected", + GTK_SIGNAL_FUNC(vnc_connected), vnc); + gtk_signal_connect(GTK_OBJECT(vnc->vnc), "vnc-initialized", + GTK_SIGNAL_FUNC(vnc_initialized), vnc); + gtk_signal_connect(GTK_OBJECT(vnc->vnc), "vnc-disconnected", + GTK_SIGNAL_FUNC(vnc_disconnected), vnc); + gtk_signal_connect(GTK_OBJECT(vnc->vnc), "vnc-pointer-grab", + GTK_SIGNAL_FUNC(vnc_grab), vnc); + gtk_signal_connect(GTK_OBJECT(vnc->vnc), "vnc-pointer-ungrab", + GTK_SIGNAL_FUNC(vnc_ungrab), vnc); + gtk_signal_connect(GTK_OBJECT(vnc->vnc), "vnc-auth-credential", + GTK_SIGNAL_FUNC(vnc_credential), NULL); + vnc_display_set_pointer_grab(VNC_DISPLAY(vnc->vnc), TRUE); +// vnc_display_set_keyboard_grab(VNC_DISPLAY(vnc->vnc), TRUE); +// vnc_display_set_pointer_local(VNC_DISPLAY(vnc->vnc), TRUE); /* popup menu */ vnc->ui = gtk_ui_manager_new(); @@ -1265,9 +407,6 @@ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, gtk_action_group_add_actions(vnc->ag, entries, G_N_ELEMENTS(entries), vnc); gtk_action_group_add_toggle_actions(vnc->ag, tentries, G_N_ELEMENTS(tentries), vnc); - gtk_action_group_add_radio_actions(vnc->ag, rentries, - G_N_ELEMENTS(rentries), - 0, G_CALLBACK(menu_cb_gl), vnc); gtk_ui_manager_insert_action_group(vnc->ui, vnc->ag, 0); vnc->ac = gtk_ui_manager_get_accel_group(vnc->ui); gtk_window_add_accel_group(GTK_WINDOW(vnc->win), vnc->ac); @@ -1279,28 +418,18 @@ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, exit(1); } vnc->popup = gtk_ui_manager_get_widget(vnc->ui, "/ConfMenu"); - gtk_menu_set_title(GTK_MENU(vnc->popup), "Config"); + gtk_menu_set_title(GTK_MENU(vnc->popup), "Menu"); /* popup menu: initial state */ - item = gtk_ui_manager_get_widget(vnc->ui, "/ConfMenu/USKbd"); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), vnc->uskbd); item = gtk_ui_manager_get_widget(vnc->ui, "/ConfMenu/ShowPointer"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), vnc->showpointer); item = gtk_ui_manager_get_widget(vnc->ui, "/ConfMenu/ViewOnly"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), vnc->viewonly); - - action = gtk_ui_manager_get_action(vnc->ui, "/ConfMenu/GL_ON"); - if (vnc->gl_allways) - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), 3); - else if (vnc->gl_fullscreen) - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), 2); - else - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), 1); /* labels for the status line */ vnc->line = gtk_label_new("status line"); vnc->res = gtk_label_new("vnc screen resolution"); - vnc->mbutton = gtk_button_new_with_label("config"); + vnc->mbutton = gtk_button_new_with_label("menu"); g_signal_connect(G_OBJECT(vnc->mbutton), "clicked", G_CALLBACK(menu_btn), vnc); GTK_WIDGET_UNSET_FLAGS(vnc->mbutton, GTK_CAN_FOCUS); @@ -1309,7 +438,7 @@ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, vbox = gtk_vbox_new(FALSE, 0); hbox = gtk_hbox_new(FALSE, 1); gtk_container_add(GTK_CONTAINER(vnc->win), vbox); - gtk_box_pack_start(GTK_BOX(vbox), vnc->draw, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), vnc->vnc, TRUE, TRUE, 0); gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); frame = gtk_frame_new(NULL); @@ -1327,38 +456,12 @@ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, /* show window */ gtk_widget_show_all(vnc->win); - vnc_window_conf(vnc); + vnc_window_texts(vnc); if (flags & VNC_FLAG_FULLSCREEN) gtk_window_fullscreen(GTK_WINDOW(vnc->win)); - /* opengl */ - if (0 == gl_init(vnc)) - vnc->have_gl = 1; - - /* rfb client */ - argv[1] = vnc->display; - fprintf(stderr, "%s: connecting to %s\n", __FUNCTION__, vnc->display); - if (8 == x11_red_bits) - vnc->client = rfbGetClient(8,3,4); - else - vnc->client = rfbGetClient(5,3,2); - if (NULL == vnc->client) - goto err; - rfbClientSetClientData(vnc->client, vnc_open, vnc); - vnc->client->MallocFrameBuffer = vnc_resize; - vnc->client->GotFrameBufferUpdate = vnc_update; - vnc->client->GetPassword = vnc_passwd; -#ifdef HAVE_VNC_TEXT - vnc->client->canHandleNewFBSize = TRUE; /* was added before textchat */ - vnc->client->HandleTextChat = vnc_textchat; -#endif - rfbClientLog = vnc_log; - 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); - vnc->connected = 1; + /* connect */ + vnc_display_open_host(VNC_DISPLAY(vnc->vnc), vnc->hostname, vnc->tcpport); return vnc->win; @@ -1367,7 +470,7 @@ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, return NULL; } -#else /* HAVE_VNCCLIENT */ +#else /* HAVE_GTK_VNC */ GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags, int debug_level) |