aboutsummaryrefslogtreecommitdiffstats
path: root/vnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'vnc.c')
-rw-r--r--vnc.c232
1 files changed, 163 insertions, 69 deletions
diff --git a/vnc.c b/vnc.c
index 6c64980..2fb3eca 100644
--- a/vnc.c
+++ b/vnc.c
@@ -11,17 +11,36 @@
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
+#include <rfb/rfbclient.h>
+
#include "x11.h"
#include "vnc.h"
-#ifdef HAVE_VNC
+#ifdef HAVE_VNCCLIENT
-static int debug = 0;
+/* ------------------------------------------------------------------ */
+
+struct vnc_window {
+ /* vnc connection */
+ rfbClient *client;
+ GIOChannel *ch;
+ guint id;
+ /* gtk windows */
+ GtkWidget *win;
+ GtkWidget *draw;
+ XImage *ximage;
+ void *shm;
+ GC gc;
+ Display *dpy;
+ /* config */
+ int standalone;
+ int debug;
+};
/* ------------------------------------------------------------------ */
/* data tables */
-rfbKeySym linux_us_kbd[] = {
+rfbKeySym linux_uskbd[] = {
[ 9 ] = XK_Escape,
[ 10 ] = XK_1,
[ 11 ] = XK_2,
@@ -36,6 +55,7 @@ rfbKeySym linux_us_kbd[] = {
[ 20 ] = XK_minus,
[ 21 ] = XK_equal,
[ 22 ] = XK_BackSpace,
+
[ 23 ] = XK_Tab,
[ 24 ] = XK_q,
[ 25 ] = XK_w,
@@ -50,6 +70,7 @@ rfbKeySym linux_us_kbd[] = {
[ 34 ] = XK_bracketleft,
[ 35 ] = XK_bracketright,
[ 36 ] = XK_Return,
+
[ 37 ] = XK_Control_L,
[ 38 ] = XK_a,
[ 39 ] = XK_s,
@@ -63,6 +84,7 @@ rfbKeySym linux_us_kbd[] = {
[ 47 ] = XK_semicolon,
[ 48 ] = XK_apostrophe,
[ 49 ] = XK_grave,
+
[ 50 ] = XK_Shift_L,
[ 51 ] = XK_backslash,
[ 52 ] = XK_z,
@@ -76,10 +98,12 @@ rfbKeySym linux_us_kbd[] = {
[ 60 ] = XK_period,
[ 61 ] = XK_slash,
[ 62 ] = XK_Shift_R,
+
[ 63 ] = XK_KP_Multiply,
[ 64 ] = XK_Alt_L,
[ 65 ] = XK_space,
[ 66 ] = XK_Caps_Lock,
+
[ 67 ] = XK_F1,
[ 68 ] = XK_F2,
[ 69 ] = XK_F3,
@@ -92,6 +116,7 @@ rfbKeySym linux_us_kbd[] = {
[ 76 ] = XK_F10,
[ 77 ] = XK_Num_Lock,
[ 78 ] = XK_Scroll_Lock,
+
[ 79 ] = XK_KP_Home,
[ 80 ] = XK_KP_Up,
[ 81 ] = XK_KP_Prior,
@@ -105,8 +130,12 @@ rfbKeySym linux_us_kbd[] = {
[ 89 ] = XK_KP_Next,
[ 90 ] = XK_KP_Insert,
[ 91 ] = XK_KP_Delete,
+
[ 93 ] = XK_Mode_switch,
- [ 94 ] = XK_less,
+#if 0
+ [ 94 ] = XK_FIXME, /* Hmm, the intl kbd 105 th key ... */
+#endif
+
[ 95 ] = XK_F11,
[ 96 ] = XK_F12,
[ 97 ] = XK_Home,
@@ -119,6 +148,7 @@ rfbKeySym linux_us_kbd[] = {
[ 105 ] = XK_Next,
[ 106 ] = XK_Insert,
[ 107 ] = XK_Delete,
+
[ 108 ] = XK_KP_Enter,
[ 109 ] = XK_Control_R,
[ 110 ] = XK_Pause,
@@ -131,17 +161,18 @@ rfbKeySym linux_us_kbd[] = {
[ 124 ] = XK_ISO_Level3_Shift,
[ 126 ] = XK_KP_Equal,
};
-static int linux_us_kbd_size = sizeof(linux_us_kbd)/sizeof(linux_us_kbd[0]);
+static int linux_uskbd_size = sizeof(linux_uskbd)/sizeof(linux_uskbd[0]);
/* ------------------------------------------------------------------ */
/* helper functions */
-static void vnc_blit(char *reason, struct vnc_window *vnc, int x, int y, int w, int h)
+static void vnc_blit(struct vnc_window *vnc, char *reason,
+ int x, int y, int w, int h)
{
Window win = gdk_x11_drawable_get_xid(vnc->draw->window);
XGCValues values;
- if (debug)
+ if (vnc->debug)
fprintf(stderr, "%s [%s]: %dx%d+%d+%d\n",
__FUNCTION__, reason, w, h, x, y);
if (x > vnc->ximage->width)
@@ -164,12 +195,30 @@ static void vnc_window_conf(struct vnc_window *vnc)
if (!vnc->draw)
return;
- snprintf(title, sizeof(title), "%s (%dx%d)", vnc->client->desktopName,
+ snprintf(title, sizeof(title), "VNC: %s (%dx%d)", vnc->client->desktopName,
vnc->client->width, vnc->client->height);
gtk_window_set_title(GTK_WINDOW(vnc->win), title);
gtk_widget_set_size_request(vnc->draw, vnc->client->width, vnc->client->height);
}
+static void vnc_release(struct vnc_window *vnc)
+{
+ if (NULL == vnc)
+ return;
+#if 0 /* FIXME: segfaults ??? */
+ if (vnc->client)
+ rfbClientCleanup(vnc->client);
+#endif
+ if (vnc->id)
+ g_source_destroy(g_main_context_find_source_by_id
+ (g_main_context_default(), vnc->id));
+ if (vnc->ximage)
+ x11_destroy_ximage(vnc->dpy, vnc->ximage, vnc->shm);
+ if (vnc->gc)
+ XFreeGC(vnc->dpy, vnc->gc);
+ free(vnc);
+}
+
/* ------------------------------------------------------------------ */
/* libvncclient callbacks */
@@ -177,7 +226,7 @@ static rfbBool vnc_resize(rfbClient* client)
{
struct vnc_window *vnc = rfbClientGetClientData(client, vnc_open);
- if (debug)
+ if (vnc->debug)
fprintf(stderr, "%s: %dx%d\n",
__FUNCTION__, client->width, client->height);
@@ -215,33 +264,83 @@ static void vnc_update(rfbClient* cl, int x, int y, int w, int h)
if (!GTK_WIDGET_DRAWABLE(vnc->draw))
return;
- vnc_blit("update", vnc, x,y, w,h);
+ vnc_blit(vnc, "update", x,y, w,h);
}
-#if 0
+#ifdef HAVE_VNC_TEXT
static void vnc_textchat(rfbClient* cl, int value, char *text)
{
switch(value) {
case rfbTextChatOpen:
- fprintf(stderr,"TextChat: Open\n");
+ fprintf(stderr,"%s: Open\n", __FUNCTION__);
break;
case rfbTextChatClose:
case rfbTextChatFinished:
- fprintf(stderr,"TextChat: Close/Finished\n");
+ fprintf(stderr,"%s: Close/Finished\n", __FUNCTION__);
break;
default:
- fprintf(stderr,"TextChat: \"%s\"\n", text);
+ 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;
+ const char *passwd = "";
+ 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_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:
+ passwd = gtk_entry_get_text(GTK_ENTRY(entry));
+ if (vnc->debug)
+ fprintf(stderr,"%s: OK\n", __FUNCTION__);
+ break;
+ default:
+ if (vnc->debug)
+ fprintf(stderr,"%s: canceled\n", __FUNCTION__);
+ break;
+ }
+ gtk_widget_destroy(dialog);
+
+ return strdup(passwd);
+}
+
static void vnc_log(const char *format, ...)
{
va_list args;
- if (!debug)
- return;
+ if (1)
+ return;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
@@ -255,7 +354,7 @@ static gboolean vnc_data_cb(GIOChannel *source, GIOCondition condition,
{
struct vnc_window *vnc = data;
- if (debug)
+ if (vnc->debug)
fprintf(stderr,"%s: called\n", __FUNCTION__);
if (!HandleRFBServerMessage(vnc->client)) {
/* server closed connection */
@@ -271,7 +370,7 @@ static void destroy_cb(GtkWidget *widget, gpointer data)
{
struct vnc_window *vnc = data;
- if (debug)
+ if (vnc->debug)
fprintf(stderr,"%s: called\n", __FUNCTION__);
if (vnc->standalone)
gtk_main_quit();
@@ -284,7 +383,7 @@ static gboolean expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer dat
if (NULL == vnc->ximage)
return FALSE;
- vnc_blit("expose", vnc, event->area.x, event->area.y,
+ vnc_blit(vnc, "expose", event->area.x, event->area.y,
event->area.width, event->area.height);
return TRUE;
}
@@ -294,41 +393,50 @@ static gboolean button_cb(GtkWidget *widget, GdkEventButton *event,
{
struct vnc_window *vnc = data;
- if (debug)
+ if (vnc->debug)
fprintf(stderr,"%s: called\n", __FUNCTION__);
SendPointerEvent(vnc->client, event->x, event->y, event->state);
return TRUE;
}
-static gboolean key_cb(GtkWidget *widget, GdkEventKey *event,
- gpointer data)
+static gboolean key_cb_local(GtkWidget *widget, GdkEventKey *event,
+ gpointer data)
+{
+ struct vnc_window *vnc = data;
+ int keydown;
+
+ if (vnc->debug)
+ fprintf(stderr,"%s[%d]: called: keysym %d\n", __FUNCTION__,
+ event->type, event->keyval);
+ keydown = (8 == event->type);
+ SendKeyEvent(vnc->client, event->keyval, keydown ? TRUE : FALSE);
+ return TRUE;
+}
+
+static gboolean key_cb_uskbd(GtkWidget *widget, GdkEventKey *event,
+ gpointer data)
{
struct vnc_window *vnc = data;
rfbKeySym keysym = 0;
int keydown;
- if (debug)
- fprintf(stderr,"%s[%d]: called: sym %d, code %d\n", __FUNCTION__,
- event->type, event->keyval, event->hardware_keycode);
+ if (event->hardware_keycode < linux_uskbd_size)
+ keysym = linux_uskbd[event->hardware_keycode];
+ if (vnc->debug || 0 == keysym)
+ fprintf(stderr,"%s[%d]: called: keycode %d => keysym %d\n", __FUNCTION__,
+ event->type, event->hardware_keycode, keysym);
keydown = (8 == event->type);
- if (vnc->keysyms)
- keysym = event->keyval;
- else if (event->hardware_keycode < linux_us_kbd_size)
- keysym = linux_us_kbd[event->hardware_keycode];
if (keysym)
SendKeyEvent(vnc->client, keysym, keydown ? TRUE : FALSE);
- else if (!vnc->keysyms)
- fprintf(stderr, "%s: unknown keycode: %d\n",
- __FUNCTION__, event->hardware_keycode);
return TRUE;
}
/* ------------------------------------------------------------------ */
/* public API functions */
-struct vnc_window* vnc_open(char *hostname, int displayno,
- int standalone, int keysyms)
+GtkWidget *vnc_open(char *hostname, int displayno,
+ int standalone, int keysyms)
{
char display[128];
char *argv[] = { "vnc-client", display, NULL };
@@ -341,7 +449,6 @@ struct vnc_window* vnc_open(char *hostname, int displayno,
goto err;
memset(vnc,0,sizeof(*vnc));
vnc->standalone = standalone;
- vnc->keysyms = keysyms;
/* x11 */
vnc->dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
@@ -360,9 +467,12 @@ struct vnc_window* vnc_open(char *hostname, int displayno,
goto err;
rfbClientSetClientData(vnc->client, vnc_open, vnc);
vnc->client->MallocFrameBuffer = vnc_resize;
-// vnc->client->canHandleNewFBSize = TRUE;
vnc->client->GotFrameBufferUpdate = vnc_update;
-// vnc->client->HandleTextChat = vnc_textchat;
+ 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)
@@ -393,51 +503,35 @@ struct vnc_window* vnc_open(char *hostname, int displayno,
G_CALLBACK(button_cb), vnc);
g_signal_connect(G_OBJECT(vnc->draw), "button-release-event",
G_CALLBACK(button_cb), vnc);
- g_signal_connect(G_OBJECT(vnc->draw), "key-press-event",
- G_CALLBACK(key_cb), vnc);
- g_signal_connect(G_OBJECT(vnc->draw), "key-release-event",
- G_CALLBACK(key_cb), vnc);
+ if (keysyms) {
+ g_signal_connect(G_OBJECT(vnc->draw), "key-press-event",
+ G_CALLBACK(key_cb_local), vnc);
+ g_signal_connect(G_OBJECT(vnc->draw), "key-release-event",
+ G_CALLBACK(key_cb_local), vnc);
+ } else {
+ g_signal_connect(G_OBJECT(vnc->draw), "key-press-event",
+ G_CALLBACK(key_cb_uskbd), vnc);
+ g_signal_connect(G_OBJECT(vnc->draw), "key-release-event",
+ G_CALLBACK(key_cb_uskbd), vnc);
+ }
/* show window */
vnc_window_conf(vnc);
gtk_widget_show_all(vnc->win);
- return vnc;
+ return vnc->win;
err:
vnc_release(vnc);
return NULL;
}
-void vnc_release(struct vnc_window *vnc)
-{
- if (NULL == vnc)
- return;
-#if 0 /* FIXME: segfaults ??? */
- if (vnc->client)
- rfbClientCleanup(vnc->client);
-#endif
- if (vnc->id)
- g_source_destroy(g_main_context_find_source_by_id
- (g_main_context_default(), vnc->id));
- if (vnc->ximage)
- x11_destroy_ximage(vnc->dpy, vnc->ximage, vnc->shm);
- if (vnc->gc)
- XFreeGC(vnc->dpy, vnc->gc);
- free(vnc);
-}
-
-#else
+#else /* HAVE_VNCCLIENT */
-struct vnc_window* vnc_open(char *hostname, int displayno,
- int standalone, int keysyms)
+GtkWidget *vnc_open(char *hostname, int displayno,
+ int standalone, int keysyms)
{
fprintf(stderr, "compiled without VNC support, sorry\n");
return NULL;
}
-void vnc_release(struct vnc_window *vnc)
-{
- /* nothing */
-}
-
-#endif
+#endif /* HAVE_VNCCLIENT */