aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkraxel <kraxel>2007-08-17 16:00:51 +0000
committerkraxel <kraxel>2007-08-17 16:00:51 +0000
commitbc328e784fdbe3afebbb28253b4f2ad2c1c15eb8 (patch)
treebf9fa5e7cf1b6b7d8d9ff7ff73a72dd47dfddcfa
parenteccfb31d8a10d756f33454a5eca97083d246c6ad (diff)
downloadxenwatch-bc328e784fdbe3afebbb28253b4f2ad2c1c15eb8.tar.gz
switch to gtk-vnc widget
-rw-r--r--GNUmakefile15
-rw-r--r--VERSION2
-rw-r--r--vnc-old.c1379
-rw-r--r--vnc.c1095
4 files changed, 1486 insertions, 1005 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 857a7d8..d8a083f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -9,13 +9,13 @@ CFLAGS += -DVERSION='"$(VERSION)"' -DLIB='"$(LIB)"'
TARGETS := xenlog xenscreen
BUILD_GTK := xenwatch xenstore mdns-browser
BUILD_AVAHI := mdns-publish-xendom mdns-publish-vnc
-BUILD_VNCCLIENT := vnc-client
+BUILD_GTK_VNC := vnc-client
NEEDS_XENSTORE := xenlog xenscreen xenwatch xenstore mdns-publish-xendom mdns-publish-vnc
NEEDS_LIBVIRT := xenscreen
NEEDS_GTK := xenwatch xenstore mdns-browser vnc-client
NEEDS_AVAHI := mdns-browser mdns-publish-xendom mdns-publish-vnc
-NEEDS_VNCCLIENT := xenwatch mdns-browser vnc-client
+NEEDS_GTK_VNC := xenwatch mdns-browser vnc-client
# default target
all: build
@@ -31,9 +31,8 @@ LIB := $(LIB)
HAVE_GTK := $(call ac_pkg_config,gtk+-x11-2.0)
HAVE_AVAHI := $(call ac_pkg_config,avahi-glib)
HAVE_LIBVIRT := $(call ac_pkg_config,libvirt)
+HAVE_GTK_VNC := $(call ac_pkg_config,gtk-vnc-1.0)
HAVE_XENSTORE := $(call ac_lib,xs_daemon_open,xenstore)
-HAVE_VNCCLIENT := $(call ac_lib,rfbGetClient,vncclient,-lz -ljpeg)
-HAVE_VNC_TEXT := $(call ac_lib,TextChatSend,vncclient,-lz -ljpeg)
endef
@@ -42,9 +41,9 @@ 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_VNCCLIENT)
- $(NEEDS_VNCCLIENT) : LDLIBS += -lvncclient -lz -ljpeg -lGL
+ ifeq ($(HAVE_GTK_VNC),yes)
+ TARGETS += $(BUILD_GTK_VNC)
+ $(NEEDS_GTK_VNC) : pkglst += gtk-vnc-1.0
endif
endif
@@ -62,7 +61,7 @@ ifeq ($(HAVE_LIBVIRT),yes)
endif
# compile flags
-CFLAGS += $(call ac_inc_cflags,XENSTORE LIBVIRT AVAHI VNCCLIENT VNC_TEXT)
+CFLAGS += $(call ac_inc_cflags,XENSTORE LIBVIRT AVAHI GTK_VNC)
CFLAGS += $(shell test "$(pkglst)" != "" && pkg-config --cflags $(pkglst))
LDLIBS += $(shell test "$(pkglst)" != "" && pkg-config --libs $(pkglst))
diff --git a/VERSION b/VERSION
index 3b04cfb..be58634 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2
+0.3
diff --git a/vnc-old.c b/vnc-old.c
new file mode 100644
index 0000000..3fc3d65
--- /dev/null
+++ b/vnc-old.c
@@ -0,0 +1,1379 @@
+#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 <X11/X.h>
+#include <X11/Xlib.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include "x11.h"
+#include "vnc.h"
+
+#ifdef HAVE_VNCCLIENT
+
+#include <rfb/rfbclient.h>
+
+static int debug_libvnc;
+
+/* ------------------------------------------------------------------ */
+
+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 *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;
+
+ /* config */
+ int fullscreen;
+ int viewonly;
+ int standalone;
+ int showpointer;
+ int gl_allways;
+ int gl_fullscreen;
+ int uskbd;
+ 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)
+{
+ 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);
+ } else {
+ snprintf(textline, sizeof(textline), "connecting to %s ...",
+ vnc->display);
+ gtk_window_set_title(GTK_WINDOW(vnc->win), textline);
+ }
+
+ if (vnc->input_grabbed) {
+ gtk_label_set_text(GTK_LABEL(vnc->line),
+ "Press Ctrl-Alt to release input grab.");
+ } else if (vnc->client) {
+ snprintf(textline, sizeof(textline), "VNC: \"%s\" at %s",
+ vnc->client->desktopName ?: "", vnc->display);
+ gtk_label_set_text(GTK_LABEL(vnc->line), textline);
+ }
+
+ 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);
+}
+
+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
+
+static char *vnc_passwd(rfbClient* cl)
+{
+ struct vnc_window *vnc = rfbClientGetClientData(cl, vnc_open);
+ GtkWidget *dialog, *label, *entry;
+ char *passwd = NULL;
+ const char *txt;
+ char message[256];
+
+ if (vnc->debug)
+ fprintf(stderr,"%s: called\n", __FUNCTION__);
+
+ /* Create the widgets */
+ dialog = gtk_dialog_new_with_buttons("Password needed",
+ vnc->win ? GTK_WINDOW(vnc->win) : NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT,
+ NULL);
+
+ snprintf(message, sizeof(message),
+ "Please enter vnc screen password for \"%s\".",
+ vnc->client->desktopName ? : "unknown");
+ label = gtk_label_new(message);
+ entry = gtk_entry_new();
+ gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+ gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+ gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 10);
+
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), entry);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
+
+ /* show and wait for response */
+ gtk_widget_show_all(dialog);
+ switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
+ case GTK_RESPONSE_ACCEPT:
+ txt = gtk_entry_get_text(GTK_ENTRY(entry));
+ passwd = strdup(txt);
+ if (vnc->debug)
+ fprintf(stderr,"%s: OK: \"%s\"\n", __FUNCTION__, passwd);
+ break;
+ default:
+ if (vnc->debug)
+ fprintf(stderr,"%s: canceled\n", __FUNCTION__);
+ passwd = strdup("");
+ break;
+ }
+ gtk_widget_destroy(dialog);
+
+ 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);
+}
+
+/* ------------------------------------------------------------------ */
+/* 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);
+ }
+ dpy_flush(vnc, __FUNCTION__);
+ return TRUE;
+}
+
+static void destroy_cb(GtkWidget *widget, gpointer data)
+{
+ struct vnc_window *vnc = data;
+
+ if (vnc->debug)
+ fprintf(stderr,"%s: called\n", __FUNCTION__);
+ if (vnc->standalone)
+ gtk_main_quit();
+ vnc_release(vnc);
+}
+
+static gboolean expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer 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;
+}
+
+static gboolean configure_cb(GtkWidget *widget, GdkEventConfigure *event,
+ gpointer 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;
+}
+
+static gboolean window_state_cb(GtkWidget *widget, GdkEventWindowState *event,
+ gpointer 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;
+}
+
+static void send_mouse(struct vnc_window *vnc, int x, int y,
+ int x11state, int x11press, int x11release)
+{
+ 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;
+
+ 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);
+}
+
+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;
+}
+
+static gboolean motion_cb(GtkWidget *widget, GdkEventMotion *event,
+ 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);
+}
+
+static gboolean key_cb(GtkWidget *widget, GdkEventKey *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);
+
+ if (vnc->uskbd)
+ key_uskbd(vnc, event);
+ else
+ key_local(vnc, event);
+ return TRUE;
+}
+
+static void menu_btn(GtkWidget *widget, gpointer data)
+{
+ struct vnc_window *vnc = data;
+
+ gtk_menu_popup(GTK_MENU(vnc->popup), NULL, NULL, NULL, NULL,
+ 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)
+{
+ struct vnc_window *vnc = user_data;
+
+ vnc->fullscreen = gtk_toggle_action_get_active(action);
+ if (vnc->fullscreen)
+ gtk_window_fullscreen(GTK_WINDOW(vnc->win));
+ else
+ 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 (vnc->draw->window)
+ gdk_window_set_cursor(vnc->draw->window,
+ vnc->showpointer ? vnc->on : vnc->off);
+}
+
+static void menu_cb_view_only(GtkToggleAction *action, gpointer user_data)
+{
+ struct vnc_window *vnc = 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";
+ static char *copyright = "(c) 2005-2007 Gerd Hoffmann";
+ static char *authors[] = { "Gerd Hoffmann <kraxel@redhat.com>", NULL };
+ struct vnc_window *vnc = user_data;
+
+ gtk_show_about_dialog(GTK_WINDOW(vnc->win),
+ "authors", authors,
+ "comments", comments,
+ "copyright", copyright,
+ "logo-icon-name", GTK_STOCK_ABOUT,
+ "version", VERSION,
+ NULL);
+}
+
+static void menu_cb_quit(GtkMenuItem *item, void *user_data)
+{
+ struct vnc_window *vnc = user_data;
+
+ gtk_widget_destroy(vnc->win);
+}
+
+/* ------------------------------------------------------------------ */
+
+static const GtkActionEntry entries[] = {
+ {
+ /* popup menu */
+ .name = "ConfMenu",
+ .label = "Config",
+ },{
+ /* menu items */
+ .name = "About",
+ .stock_id = GTK_STOCK_ABOUT,
+ .label = "_About ...",
+ .callback = G_CALLBACK(menu_cb_about),
+ },{
+ .name = "Close",
+ .stock_id = GTK_STOCK_QUIT,
+ .label = "_Close",
+// .accelerator = "<control>Q",
+ .tooltip = "Quit the job",
+ .callback = G_CALLBACK(menu_cb_quit),
+ }
+};
+
+static const GtkToggleActionEntry tentries[] = {
+ {
+ .name = "FullScreen",
+ .label = "_Fullscreen",
+ .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),
+ },{
+ .name = "ViewOnly",
+ .label = "_View only",
+ .callback = G_CALLBACK(menu_cb_view_only),
+ }
+};
+
+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>"
+"</ui>";
+
+/* ------------------------------------------------------------------ */
+/* public API functions */
+
+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)
+ goto err;
+ 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;
+
+ /* 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;
+
+ /* popup menu */
+ vnc->ui = gtk_ui_manager_new();
+ vnc->ag = gtk_action_group_new("MenuActions");
+ 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);
+
+ err = NULL;
+ if (!gtk_ui_manager_add_ui_from_string(vnc->ui, ui_xml, -1, &err)) {
+ g_message("building menus failed: %s", err->message);
+ g_error_free(err);
+ exit(1);
+ }
+ vnc->popup = gtk_ui_manager_get_widget(vnc->ui, "/ConfMenu");
+ gtk_menu_set_title(GTK_MENU(vnc->popup), "Config");
+
+ /* 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");
+ g_signal_connect(G_OBJECT(vnc->mbutton), "clicked",
+ G_CALLBACK(menu_btn), vnc);
+ GTK_WIDGET_UNSET_FLAGS(vnc->mbutton, GTK_CAN_FOCUS);
+
+ /* packing */
+ 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_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
+
+ frame = gtk_frame_new(NULL);
+ gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0);
+ gtk_container_add(GTK_CONTAINER(frame), vnc->line);
+ gtk_misc_set_alignment(GTK_MISC(vnc->line), 0, 0.5);
+ gtk_misc_set_padding(GTK_MISC(vnc->line), 3, 1);
+
+ frame = gtk_frame_new(NULL);
+ gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
+ gtk_container_add(GTK_CONTAINER(frame), vnc->res);
+ gtk_misc_set_padding(GTK_MISC(vnc->res), 3, 1);
+
+ gtk_box_pack_start(GTK_BOX(hbox), vnc->mbutton, FALSE, TRUE, 0);
+
+ /* show window */
+ gtk_widget_show_all(vnc->win);
+ vnc_window_conf(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;
+
+ return vnc->win;
+
+ err:
+ vnc_release(vnc);
+ return NULL;
+}
+
+#else /* HAVE_VNCCLIENT */
+
+GtkWidget *vnc_open(char *hostname, int tcpport, unsigned long flags,
+ int debug_level)
+{
+ fprintf(stderr, "compiled without VNC support, sorry\n");
+ return NULL;
+}
+
+#endif /* HAVE_VNCCLIENT */
diff --git a/vnc.c b/vnc.c
index 3fc3d65..60da94e 100644
--- a/vnc.c
+++ b/vnc.c
@@ -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)