diff -urN gtk-vnc-0.3.7/bootstrap gtk-vnc-0.3.7.mingw/bootstrap --- gtk-vnc-0.3.7/bootstrap 1970-01-01 01:00:00.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/bootstrap 2008-10-09 12:19:03.000000000 +0100 @@ -0,0 +1,84 @@ +#!/bin/sh +# Run this after autogen.sh, to pull in all of the gnulib-related bits. +# It's important to run *after* autogen.sh, since it updates some of +# the same files autogen.sh does, yet those from gnulib are newer, +# and match the tests. So if a gnulib bug has been fixed since the +# snapshot taken for whatever gettext release you're using, yet you +# run "make check" against the wrong version, the corresponding unit +# test in gl-tests/ may well fail. + +usage() { + echo >&2 "\ +Usage: $0 [OPTION]... +Bootstrap this package from the checked-out sources. + +Options: + --gnulib-srcdir=DIRNAME Specify the local directory where gnulib + sources reside. Use this if you already + have gnulib sources on your machine, and + do not want to waste your bandwidth downloading + them again. + +If the file bootstrap.conf exists in the current working directory, its +contents are read as shell variables to configure the bootstrap. + +Running without arguments will suffice in most cases. +" +} + +for option +do + case $option in + --help) + usage + exit;; + --gnulib-srcdir=*) + GNULIB_SRCDIR=`expr "$option" : '--gnulib-srcdir=\(.*\)'`;; + *) + echo >&2 "$0: $option: unknown option" + exit 1;; + esac +done + +cleanup_gnulib() { + st=$? + rm -fr .gnulib + exit $st +} + +case ${GNULIB_SRCDIR--} in +-) + if [ ! -d .gnulib ]; then + echo "$0: getting gnulib files..." + + trap cleanup_gnulib 1 2 13 15 + + git clone --depth 1 git://git.sv.gnu.org/gnulib .gnulib || + cleanup_gnulib + + trap - 1 2 13 15 + fi + GNULIB_SRCDIR=.gnulib +esac + +gnulib_tool=$GNULIB_SRCDIR/gnulib-tool +<$gnulib_tool || exit + +modules=' +getaddrinfo +vc-list-files +' + +# Tell gnulib to: +# require LGPLv2+ +# put *.m4 files in new gnulib/m4/ dir +# put *.[ch] files in new gnulib/lib/ dir. + +$gnulib_tool \ + --lgpl=2 \ + --with-tests \ + --m4-base=gnulib/m4 \ + --source-base=gnulib/lib \ + --tests-base=gnulib/tests \ + --import $modules + diff -urN gtk-vnc-0.3.7/configure.ac gtk-vnc-0.3.7.mingw/configure.ac --- gtk-vnc-0.3.7/configure.ac 2008-09-05 13:32:15.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/configure.ac 2008-10-09 12:19:03.000000000 +0100 @@ -23,15 +23,29 @@ AC_CONFIG_HEADERS([config.h:config.hin]) - AC_CANONICAL_TARGET AM_INIT_AUTOMAKE(gtk-vnc, 0.3.7) + +dnl gl_INIT uses m4_foreach_w, yet that is not defined in autoconf-2.59. +dnl In order to accommodate developers with such old tools, here's a +dnl replacement definition. +m4_ifndef([m4_foreach_w], + [m4_define([m4_foreach_w], + [m4_foreach([$1], m4_split(m4_normalize([$2]), [ ]), [$3])])]) + +gl_EARLY +gl_INIT + AC_PROG_CC_STDC AM_PROG_CC_C_O +AC_LIBTOOL_WIN32_DLL + AC_PROG_LIBTOOL +AC_CHECK_HEADERS([pwd.h winsock2.h]) + AC_ARG_WITH(python, [ --with-python build python bindings], [case "${withval}" in @@ -234,6 +248,8 @@ AC_CONFIG_FILES( Makefile + gnulib/lib/Makefile + gnulib/tests/Makefile src/Makefile examples/Makefile plugin/Makefile diff -urN gtk-vnc-0.3.7/Makefile.am gtk-vnc-0.3.7.mingw/Makefile.am --- gtk-vnc-0.3.7/Makefile.am 2008-09-05 13:32:15.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/Makefile.am 2008-10-09 12:19:01.000000000 +0100 @@ -1,5 +1,9 @@ -SUBDIRS = src examples plugin +SUBDIRS = gnulib/lib src examples plugin gnulib/tests + +ACLOCAL_AMFLAGS = -I gnulib/m4 + + pkgconfig_DATA = @PACKAGE@-1.0.pc pkgconfigdir = $(libdir)/pkgconfig diff -urN gtk-vnc-0.3.7/src/continuation.c gtk-vnc-0.3.7.mingw/src/continuation.c --- gtk-vnc-0.3.7/src/continuation.c 2008-09-05 13:32:16.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/continuation.c 2008-10-09 12:19:03.000000000 +0100 @@ -8,6 +8,8 @@ * GTK VNC Widget */ +#include + #include "continuation.h" /* diff -urN gtk-vnc-0.3.7/src/coroutine_gthread.c gtk-vnc-0.3.7.mingw/src/coroutine_gthread.c --- gtk-vnc-0.3.7/src/coroutine_gthread.c 2008-09-05 13:32:16.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/coroutine_gthread.c 2008-10-09 12:19:03.000000000 +0100 @@ -8,6 +8,8 @@ * GTK VNC Widget */ +#include + #include "coroutine.h" #include #include @@ -17,13 +19,24 @@ static struct coroutine *current; static struct coroutine leader; +#if 0 +#define CO_DEBUG(OP) fprintf(stderr, "%s %p %s %d\n", OP, g_thread_self(), __FUNCTION__, __LINE__) +#else +#define CO_DEBUG(OP) +#endif + static void coroutine_system_init(void) { - if (!g_thread_supported()) + if (!g_thread_supported()) { + CO_DEBUG("INIT"); g_thread_init(NULL); + } + run_cond = g_cond_new(); run_lock = g_mutex_new(); + CO_DEBUG("LOCK"); + g_mutex_lock(run_lock); /* The thread that creates the first coroutine is the system coroutine * so let's fill out a structure for it */ @@ -42,17 +55,22 @@ static gpointer coroutine_thread(gpointer opaque) { struct coroutine *co = opaque; - + CO_DEBUG("LOCK"); g_mutex_lock(run_lock); - while (!co->runnable) + while (!co->runnable) { + CO_DEBUG("WAIT"); g_cond_wait(run_cond, run_lock); + } + CO_DEBUG("RUNNABLE"); current = co; co->data = co->entry(co->data); co->exited = 1; co->caller->runnable = TRUE; + CO_DEBUG("BROADCAST"); g_cond_broadcast(run_cond); + CO_DEBUG("UNLOCK"); g_mutex_unlock(run_lock); return NULL; @@ -62,7 +80,8 @@ { if (run_cond == NULL) coroutine_system_init(); - + + CO_DEBUG("NEW"); co->thread = g_thread_create_full(coroutine_thread, co, co->stack_size, FALSE, TRUE, G_THREAD_PRIORITY_NORMAL, @@ -88,15 +107,19 @@ to->runnable = TRUE; to->data = arg; to->caller = from; + CO_DEBUG("BROADCAST"); g_cond_broadcast(run_cond); + CO_DEBUG("UNLOCK"); g_mutex_unlock(run_lock); - + CO_DEBUG("LOCK"); g_mutex_lock(run_lock); - while (!from->runnable) + while (!from->runnable) { + CO_DEBUG("WAIT"); g_cond_wait(run_cond, run_lock); - + } current = from; + CO_DEBUG("SWAPPED"); return from->data; } @@ -111,6 +134,7 @@ fprintf(stderr, "Co-routine is re-entering itself\n"); abort(); } + CO_DEBUG("SWAP"); return coroutine_swap(coroutine_self(), to, arg); } @@ -121,6 +145,8 @@ fprintf(stderr, "Co-routine is yielding to no one\n"); abort(); } + + CO_DEBUG("SWAP"); coroutine_self()->caller = NULL; return coroutine_swap(coroutine_self(), to, arg); } diff -urN gtk-vnc-0.3.7/src/coroutine_ucontext.c gtk-vnc-0.3.7.mingw/src/coroutine_ucontext.c --- gtk-vnc-0.3.7/src/coroutine_ucontext.c 2008-09-05 13:32:16.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/coroutine_ucontext.c 2008-10-09 12:19:03.000000000 +0100 @@ -8,6 +8,8 @@ * GTK VNC Widget */ +#include + #include #include #include diff -urN gtk-vnc-0.3.7/src/gvnc.c gtk-vnc-0.3.7.mingw/src/gvnc.c --- gtk-vnc-0.3.7/src/gvnc.c 2008-09-05 13:32:16.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/gvnc.c 2008-10-09 12:19:03.000000000 +0100 @@ -8,13 +8,10 @@ * GTK VNC Widget */ -#include "gvnc.h" +#include -#include -#include -#include +#include "gvnc.h" -#include #include #include #include @@ -40,6 +37,15 @@ #include #include "vnc_keycodes.h" +#include "socketcompat.h" +#include "getaddrinfo.h" + +/* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it + even if its emulated getaddrinfo() for us . */ +#ifndef AI_ADDRCONFIG +# define AI_ADDRCONFIG 0 +#endif + struct wait_queue { @@ -185,7 +191,6 @@ g_io_add_watch(channel, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, g_io_wait_helper, coroutine_self()); ret = coroutine_yield(NULL); - return *ret; } @@ -321,10 +326,8 @@ /* inflate as much as possible */ err = inflate(gvnc->strm, Z_SYNC_FLUSH); - if (err != Z_OK) { - errno = EIO; - return -1; - } + if (err != Z_OK) + return -EIO; gvnc->uncompressed_length = (uint8_t *)gvnc->strm->next_out - gvnc->uncompressed_buffer; gvnc->compressed_length -= (uint8_t *)gvnc->strm->next_in - gvnc->compressed_buffer; @@ -344,7 +347,7 @@ size_t offset = 0; if (gvnc->has_error) return -EINVAL; - + while (offset < len) { size_t tmp; @@ -352,10 +355,10 @@ * so we must by-pass it */ if (gvnc_use_compression(gvnc)) { int ret = gvnc_zread(gvnc, data + offset, len); - if (ret == -1) { + if (ret < 0) { GVNC_DEBUG("Closing the connection: gvnc_read() - gvnc_zread() failed\n"); gvnc->has_error = TRUE; - return -errno; + return ret; } offset += ret; continue; @@ -366,17 +369,19 @@ ret = gnutls_read(gvnc->tls_session, gvnc->read_buffer, 4096); if (ret < 0) { if (ret == GNUTLS_E_AGAIN) - errno = EAGAIN; + ret = -EAGAIN; else - errno = EIO; - ret = -1; + ret = -EIO; } - } else - ret = read(fd, gvnc->read_buffer, 4096); + } else { + ret = recv(fd, gvnc->read_buffer, 4096, 0); + if (ret < 0) + ret = socket_errno() * -1; + } - if (ret == -1) { - switch (errno) { - case EAGAIN: + if (ret < 0) { + switch (ret * -1) { + case EWOULDBLOCK: if (gvnc->wait_interruptable) { if (!g_io_wait_interruptable(&gvnc->wait, gvnc->channel, G_IO_IN)) @@ -386,9 +391,9 @@ case EINTR: continue; default: - GVNC_DEBUG("Closing the connection: gvnc_read() - ret=-1\n"); + GVNC_DEBUG("Closing the connection: gvnc_read() - ret=%d\n", ret); gvnc->has_error = TRUE; - return -errno; + return ret; } } if (ret == 0) { @@ -425,23 +430,25 @@ gvnc->write_offset-offset); if (ret < 0) { if (ret == GNUTLS_E_AGAIN) - errno = EAGAIN; + ret = -EAGAIN; else - errno = EIO; - ret = -1; + ret = -EIO; } - } else - ret = write(fd, - gvnc->write_buffer+offset, - gvnc->write_offset-offset); - if (ret == -1) { - switch (errno) { - case EAGAIN: + } else { + ret = send(fd, + gvnc->write_buffer+offset, + gvnc->write_offset-offset, 0); + if (ret < 0) + ret = socket_errno() * -1; + } + if (ret < 0) { + switch (ret * -1) { + case EWOULDBLOCK: g_io_wait(gvnc->channel, G_IO_OUT); case EINTR: continue; default: - GVNC_DEBUG("Closing the connection: gvnc_flush\n"); + GVNC_DEBUG("Closing the connection: gvnc_flush %d\n", ret); gvnc->has_error = TRUE; return; } @@ -488,7 +495,7 @@ retry: ret = write(fd, data, len); if (ret < 0) { - if (errno == EINTR) + if (socket_errno() == EINTR) goto retry; return -1; } @@ -506,7 +513,7 @@ retry: ret = read(fd, data, len); if (ret < 0) { - if (errno == EINTR) + if (socket_errno() == EINTR) goto retry; return -1; } @@ -2802,12 +2809,12 @@ if (gvnc_has_error(gvnc)) return FALSE; - if (!gvnc->fmt.true_color_flag && gvnc->ops.get_preferred_pixel_format) + if (!gvnc->fmt.true_color_flag && gvnc->ops.get_preferred_pixel_format) { if (gvnc->ops.get_preferred_pixel_format(gvnc->ops_data, &gvnc->fmt)) gvnc_set_pixel_format(gvnc, &gvnc->fmt); else goto fail; - + } memset(&gvnc->strm, 0, sizeof(gvnc->strm)); /* FIXME what level? */ for (i = 0; i < 5; i++) @@ -2822,15 +2829,16 @@ return !gvnc_has_error(gvnc); } -gboolean gvnc_open_fd(struct gvnc *gvnc, int fd) +static gboolean gvnc_set_nonblock(int fd) { - int flags; - if (gvnc_is_open(gvnc)) { - GVNC_DEBUG ("Error: already connected?\n"); +#ifdef __MINGW32__ + unsigned long flags = 1; + if (ioctlsocket(fd, FIONBIO, &flags) < 0) { + GVNC_DEBUG ("Failed to set nonblocking flag\n"); return FALSE; } - - GVNC_DEBUG("Connecting to FD %d\n", fd); +#else + int flags; if ((flags = fcntl(fd, F_GETFL)) < 0) { GVNC_DEBUG ("Failed to fcntl()\n"); return FALSE; @@ -2840,6 +2848,21 @@ GVNC_DEBUG ("Failed to fcntl()\n"); return FALSE; } +#endif + return TRUE; +} + +gboolean gvnc_open_fd(struct gvnc *gvnc, int fd) +{ + if (gvnc_is_open(gvnc)) { + GVNC_DEBUG ("Error: already connected?\n"); + return FALSE; + } + + GVNC_DEBUG("Connecting to FD %d\n", fd); + + if (!gvnc_set_nonblock(fd)) + return FALSE; if (!(gvnc->channel = g_io_channel_unix_new(fd))) { GVNC_DEBUG ("Failed to g_io_channel_unix_new()\n"); @@ -2873,7 +2896,7 @@ runp = ai; while (runp != NULL) { - int flags, fd; + int fd; GIOChannel *chan; if ((fd = socket(runp->ai_family, runp->ai_socktype, @@ -2883,17 +2906,8 @@ } GVNC_DEBUG("Trying socket %d\n", fd); - if ((flags = fcntl(fd, F_GETFL)) < 0) { - close(fd); - GVNC_DEBUG ("Failed to fcntl()\n"); - break; - } - flags |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, flags) < 0) { - close(fd); - GVNC_DEBUG ("Failed to fcntl()\n"); - break; - } + if (!gvnc_set_nonblock(fd)) + break; if (!(chan = g_io_channel_unix_new(fd))) { close(fd); @@ -2904,21 +2918,22 @@ reconnect: /* FIXME: Better handle EINPROGRESS/EISCONN return values, as explained in connect(2) man page */ - if ( (connect(fd, runp->ai_addr, runp->ai_addrlen) == 0) || errno == EISCONN) { + if ((connect(fd, runp->ai_addr, runp->ai_addrlen) == 0) || + socket_errno() == EISCONN) { gvnc->channel = chan; gvnc->fd = fd; freeaddrinfo(ai); return !gvnc_has_error(gvnc); } - - if (errno == EINPROGRESS) { + if (socket_errno() == EINPROGRESS || + socket_errno() == EWOULDBLOCK) { g_io_wait(chan, G_IO_OUT|G_IO_ERR|G_IO_HUP); goto reconnect; - } else if (errno != ECONNREFUSED && - errno != EHOSTUNREACH) { + } else if (socket_errno() != ECONNREFUSED && + socket_errno() != EHOSTUNREACH) { g_io_channel_unref(chan); close(fd); - GVNC_DEBUG ("Failed with errno = %d\n", errno); + GVNC_DEBUG ("Failed with errno = %d\n", socket_errno()); break; } close(fd); diff -urN gtk-vnc-0.3.7/src/Makefile.am gtk-vnc-0.3.7.mingw/src/Makefile.am --- gtk-vnc-0.3.7/src/Makefile.am 2008-09-05 13:32:15.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/Makefile.am 2008-10-09 12:19:03.000000000 +0100 @@ -4,13 +4,15 @@ lib_LTLIBRARIES = libgtk-vnc-1.0.la libgtk_vnc_1_0_la_LIBADD = @GTK_LIBS@ @GTKGLEXT_LIBS@ @GNUTLS_LIBS@ \ - @GTHREAD_LIBS@ + @GTHREAD_LIBS@ \ + ../gnulib/lib/libgnu.la libgtk_vnc_1_0_la_CFLAGS = @GTK_CFLAGS@ @GTKGLEXT_CFLAGS@ @GNUTLS_CFLAGS@ \ @GTHREAD_CFLAGS@ @WARNING_CFLAGS@ \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ - -DG_LOG_DOMAIN=\"gtk-vnc\" + -DG_LOG_DOMAIN=\"gtk-vnc\" \ + -I$(top_srcdir)gnulib/lib -I../gnulib/lib libgtk_vnc_1_0_la_LDFLAGS = -Wl, @LD_VERSION_SCRIPT_SUPPORT@ \ - -version-info 0:1:0 + -version-info 0:1:0 -no-undefined gtk_vnc_includedir = $(includedir)/gtk-vnc-1.0/ gtk_vnc_include_HEADERS = vncdisplay.h @@ -22,7 +24,7 @@ vncdisplay.h vncdisplay.c \ vncmarshal.h vncmarshal.c \ x_keymap.h x_keymap.c vnc_keycodes.h \ - utils.h + utils.h socketcompat.h if WITH_UCONTEXT libgtk_vnc_1_0_la_SOURCES += continuation.h continuation.c coroutine_ucontext.c diff -urN gtk-vnc-0.3.7/src/socketcompat.h gtk-vnc-0.3.7.mingw/src/socketcompat.h --- gtk-vnc-0.3.7/src/socketcompat.h 1970-01-01 01:00:00.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/socketcompat.h 2008-10-09 12:19:03.000000000 +0100 @@ -0,0 +1,64 @@ +/* + * socketcompat.h: Socket compatibility for Windows, making it slightly + * less painful to use. + * + * Use this header under the following circumstances: + * (a) Instead of including any of: , , + * , , , AND + * (b) The file will be part of what is built on Windows (basically + * just remote client stuff). + * + * You need to use socket_errno() instead of errno to get socket + * errors. + * + * Copyright (C) 2008 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Richard W.M. Jones + */ + +#ifndef __SOCKETCOMPAT_H__ +#define __SOCKETCOMPAT_H__ + +#include + +#include + +#ifndef HAVE_WINSOCK2_H /* Unix & Cygwin. */ + +#include +#include +#include +#include +#include + +static inline int +socket_errno (void) +{ + return errno; +} + +#else /* MinGW & Win32 */ + +#include + +/* Socket functions in Windows don't set errno. Instead of using errno + * to test for socket errors, call this function to get the errno. + */ +static inline int +socket_errno (void) +{ + return WSAGetLastError (); +} + +/* Compatibility. */ +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ECONNREFUSED WSAECONNREFUSED +#define EINPROGRESS WSAEINPROGRESS +#define EHOSTUNREACH WSAEHOSTUNREACH +#define EISCONN WSAEISCONN + +#endif /* HAVE_WINSOCK2_H */ + +#endif /* __WINSOCKWRAPPER_H__ */ diff -urN gtk-vnc-0.3.7/src/vncdisplay.c gtk-vnc-0.3.7.mingw/src/vncdisplay.c --- gtk-vnc-0.3.7/src/vncdisplay.c 2008-10-09 12:16:42.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/vncdisplay.c 2008-10-09 12:19:03.000000000 +0100 @@ -8,6 +8,8 @@ * GTK VNC Widget */ +#include + #include "vncdisplay.h" #include "coroutine.h" #include "gvnc.h" @@ -24,7 +26,9 @@ #include #include #include +#ifdef HAVE_PWD_H #include +#endif #if WITH_GTKGLEXT #include @@ -2191,33 +2195,44 @@ static int vnc_display_set_x509_credential(VncDisplay *obj, const char *name) { - char sysdir[PATH_MAX], userdir[PATH_MAX]; - struct passwd *pw; char file[PATH_MAX]; + char sysdir[PATH_MAX]; +#ifndef __MINGW32__ + char userdir[PATH_MAX]; + struct passwd *pw; char *dirs[] = { sysdir, userdir }; +#else + char *dirs[] = { sysdir }; +#endif strncpy(sysdir, SYSCONFDIR "/pki", PATH_MAX-1); sysdir[PATH_MAX-1] = '\0'; +#ifndef __MINGW32__ if (!(pw = getpwuid(getuid()))) return TRUE; snprintf(userdir, PATH_MAX-1, "%s/.pki", pw->pw_dir); userdir[PATH_MAX-1] = '\0'; +#endif - if (vnc_display_best_path(file, PATH_MAX, "CA", "cacert.pem", dirs, 2) < 0) + if (vnc_display_best_path(file, PATH_MAX, "CA", "cacert.pem", + dirs, sizeof(dirs)/sizeof(dirs[0])) < 0) return TRUE; gvnc_set_credential_x509_cacert(obj->priv->gvnc, file); /* Don't mind failures of CRL */ - if (vnc_display_best_path(file, PATH_MAX, "CA", "cacrl.pem", dirs, 2) == 0) + if (vnc_display_best_path(file, PATH_MAX, "CA", "cacrl.pem", + dirs, sizeof(dirs)/sizeof(dirs[0])) == 0) gvnc_set_credential_x509_cacert(obj->priv->gvnc, file); /* Set client key & cert if we have them. Server will reject auth * if it decides it requires them*/ - if (vnc_display_best_path(file, PATH_MAX, name, "private/clientkey.pem", dirs, 2) == 0) + if (vnc_display_best_path(file, PATH_MAX, name, "private/clientkey.pem", + dirs, sizeof(dirs)/sizeof(dirs[0])) == 0) gvnc_set_credential_x509_key(obj->priv->gvnc, file); - if (vnc_display_best_path(file, PATH_MAX, name, "clientcert.pem", dirs, 2) == 0) + if (vnc_display_best_path(file, PATH_MAX, name, "clientcert.pem", + dirs, sizeof(dirs)/sizeof(dirs[0])) == 0) gvnc_set_credential_x509_cert(obj->priv->gvnc, file); return FALSE; diff -urN gtk-vnc-0.3.7/src/vncdisplay.c.orig gtk-vnc-0.3.7.mingw/src/vncdisplay.c.orig --- gtk-vnc-0.3.7/src/vncdisplay.c.orig 2008-09-05 13:32:16.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/src/vncdisplay.c.orig 1970-01-01 01:00:00.000000000 +0100 @@ -1,2491 +0,0 @@ -/* - * Copyright (C) 2006 Anthony Liguori - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2 or - * later as published by the Free Software Foundation. - * - * GTK VNC Widget - */ - -#include "vncdisplay.h" -#include "coroutine.h" -#include "gvnc.h" -#include "utils.h" -#include "vncmarshal.h" -#include "config.h" -#include "x_keymap.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if WITH_GTKGLEXT -#include -#include -#endif - -#define VNC_DISPLAY_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE((obj), VNC_TYPE_DISPLAY, VncDisplayPrivate)) - -struct _VncDisplayPrivate -{ - int fd; - char *host; - char *port; - GdkGC *gc; - GdkImage *image; - GdkCursor *null_cursor; - GdkCursor *remote_cursor; - -#if WITH_GTKGLEXT - int gl_enabled; - GdkGLConfig *gl_config; - GdkGLDrawable *gl_drawable; - GdkGLContext *gl_context; - uint8_t *gl_tex_data; - int gl_texture_width; - int gl_texture_height; - int gl_width; - int gl_height; - GLuint gl_tex; -#endif - - struct gvnc_framebuffer fb; - struct coroutine coroutine; - struct gvnc *gvnc; - - guint open_id; - - gboolean in_pointer_grab; - gboolean in_keyboard_grab; - - guint down_keyval[16]; - guint down_scancode[16]; - - int button_mask; - int last_x; - int last_y; - - gboolean absolute; - - gboolean grab_pointer; - gboolean grab_keyboard; - gboolean local_pointer; - gboolean read_only; - gboolean allow_lossy; - gboolean allow_scaling; - gboolean shared_flag; - gboolean force_size; - - GSList *preferable_auths; -}; - -/* Delayed signal emission. - * - * We want signals to be delivered in the system coroutine. This helps avoid - * confusing applications. This is particularly important when using - * GThread based coroutines since GTK gets very upset if a signal handler is - * run in a different thread from the main loop if that signal handler isn't - * written to use explicit locking. - */ -struct signal_data -{ - VncDisplay *obj; - struct coroutine *caller; - - int signum; - GValueArray *cred_list; - int width; - int height; - const char *msg; - unsigned int auth_type; - GString *str; -}; - -G_DEFINE_TYPE(VncDisplay, vnc_display, GTK_TYPE_DRAWING_AREA) - -/* Properties */ -enum -{ - PROP_0, - PROP_POINTER_LOCAL, - PROP_POINTER_GRAB, - PROP_KEYBOARD_GRAB, - PROP_READ_ONLY, - PROP_WIDTH, - PROP_HEIGHT, - PROP_NAME, - PROP_LOSSY_ENCODING, - PROP_SCALING, - PROP_SHARED_FLAG, - PROP_FORCE_SIZE -}; - -/* Signals */ -typedef enum -{ - VNC_POINTER_GRAB, - VNC_POINTER_UNGRAB, - VNC_KEYBOARD_GRAB, - VNC_KEYBOARD_UNGRAB, - - VNC_CONNECTED, - VNC_INITIALIZED, - VNC_DISCONNECTED, - VNC_AUTH_CREDENTIAL, - - VNC_DESKTOP_RESIZE, - - VNC_AUTH_FAILURE, - VNC_AUTH_UNSUPPORTED, - - VNC_SERVER_CUT_TEXT, - VNC_BELL, - - LAST_SIGNAL -} vnc_display_signals; - -static guint signals[LAST_SIGNAL] = { 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, 0,}; -static GParamSpec *signalCredParam; -gboolean debug_enabled = FALSE; - -static const GOptionEntry gtk_vnc_args[] = -{ - { "gtk-vnc-debug", 0, 0, G_OPTION_ARG_NONE, &debug_enabled, "Enables debug output", 0 }, - { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, 0 } -}; - - -static void -vnc_display_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - VncDisplay *vnc = VNC_DISPLAY (object); - - switch (prop_id) - { - case PROP_POINTER_LOCAL: - g_value_set_boolean (value, vnc->priv->local_pointer); - break; - case PROP_POINTER_GRAB: - g_value_set_boolean (value, vnc->priv->grab_pointer); - break; - case PROP_KEYBOARD_GRAB: - g_value_set_boolean (value, vnc->priv->grab_keyboard); - break; - case PROP_READ_ONLY: - g_value_set_boolean (value, vnc->priv->read_only); - break; - case PROP_WIDTH: - g_value_set_int (value, vnc_display_get_width (vnc)); - break; - case PROP_HEIGHT: - g_value_set_int (value, vnc_display_get_height (vnc)); - break; - case PROP_NAME: - g_value_set_string (value, vnc_display_get_name (vnc)); - break; - case PROP_LOSSY_ENCODING: - g_value_set_boolean (value, vnc->priv->allow_lossy); - break; - case PROP_SCALING: - g_value_set_boolean (value, vnc->priv->allow_scaling); - break; - case PROP_SHARED_FLAG: - g_value_set_boolean (value, vnc->priv->shared_flag); - break; - case PROP_FORCE_SIZE: - g_value_set_boolean (value, vnc->priv->force_size); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -vnc_display_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - VncDisplay *vnc = VNC_DISPLAY (object); - - switch (prop_id) - { - case PROP_POINTER_LOCAL: - vnc_display_set_pointer_local (vnc, g_value_get_boolean (value)); - break; - case PROP_POINTER_GRAB: - vnc_display_set_pointer_grab (vnc, g_value_get_boolean (value)); - break; - case PROP_KEYBOARD_GRAB: - vnc_display_set_keyboard_grab (vnc, g_value_get_boolean (value)); - break; - case PROP_READ_ONLY: - vnc_display_set_read_only (vnc, g_value_get_boolean (value)); - break; - case PROP_LOSSY_ENCODING: - vnc_display_set_lossy_encoding (vnc, g_value_get_boolean (value)); - break; - case PROP_SCALING: - vnc_display_set_scaling (vnc, g_value_get_boolean (value)); - break; - case PROP_SHARED_FLAG: - vnc_display_set_shared_flag (vnc, g_value_get_boolean (value)); - break; - case PROP_FORCE_SIZE: - vnc_display_set_force_size (vnc, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -GtkWidget *vnc_display_new(void) -{ - return GTK_WIDGET(g_object_new(VNC_TYPE_DISPLAY, NULL)); -} - -static GdkCursor *create_null_cursor(void) -{ - GdkBitmap *image; - gchar data[4] = {0}; - GdkColor fg = { 0, 0, 0, 0 }; - GdkCursor *cursor; - - image = gdk_bitmap_create_from_data(NULL, data, 1, 1); - - cursor = gdk_cursor_new_from_pixmap(GDK_PIXMAP(image), - GDK_PIXMAP(image), - &fg, &fg, 0, 0); - gdk_bitmap_unref(image); - - return cursor; -} - -static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose) -{ - VncDisplay *obj = VNC_DISPLAY(widget); - VncDisplayPrivate *priv = obj->priv; - int x, y, w, h; - GdkRectangle drawn; - GdkRegion *clear, *copy; - - GVNC_DEBUG("Expose %dx%d @ %d,%d\n", - expose->area.x, - expose->area.y, - expose->area.width, - expose->area.height); - - if (priv->image == NULL) { -#if WITH_GTKGLEXT - if (priv->gl_tex_data == NULL) -#endif - { - GdkGC *gc = gdk_gc_new(widget->window); - gdk_draw_rectangle(widget->window, gc, TRUE, - expose->area.x, expose->area.y, - expose->area.width, - expose->area.height); - g_object_unref(gc); - return TRUE; - } - } - -#if WITH_GTKGLEXT - if (priv->gl_enabled) { - float rx, ry; - int wx = 0, wy = 0; - int ww = priv->gl_width, wh = priv->gl_height; - double scale_x, scale_y; - - scale_x = (double)priv->gl_width / priv->fb.width; - scale_y = (double)priv->gl_height / priv->fb.height; - - x = expose->area.x / scale_x; - y = expose->area.y / scale_y; - w = expose->area.width / scale_x; - h = expose->area.height / scale_y; - - y -= 5; - h += 10; - if (y < 0) - y = 0; - - x -= 5; - w += 10; - if (x < 0) - x = 0; - - x = MIN(x, priv->fb.width); - y = MIN(y, priv->fb.height); - w = MIN(x + w, priv->fb.width); - h = MIN(y + h, priv->fb.height); - w -= x; - h -= y; - - gdk_gl_drawable_gl_begin(priv->gl_drawable, priv->gl_context); - glBindTexture(GL_TEXTURE_2D, priv->gl_tex); - glPixelStorei(GL_UNPACK_ROW_LENGTH, priv->fb.width); - glTexSubImage2D(GL_TEXTURE_2D, 0, - x, y, w, h, - GL_BGRA_EXT, - GL_UNSIGNED_BYTE, - priv->gl_tex_data + - y * 4 * priv->fb.width + - x * 4); - rx = (float)priv->fb.width / priv->gl_texture_width; - ry = (float)priv->fb.height / priv->gl_texture_height; - - glEnable(GL_TEXTURE_2D); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - glBegin(GL_QUADS); - glTexCoord2f(0,ry); glVertex3f(wx, wy, 0); - glTexCoord2f(0,0); glVertex3f(wx, wy+wh, 0); - glTexCoord2f(rx,0); glVertex3f(wx+ww, wy+wh, 0); - glTexCoord2f(rx,ry); glVertex3f(wx+ww, wy, 0); - glEnd(); - glDisable(GL_TEXTURE_2D); - glFlush(); - gdk_gl_drawable_gl_end(priv->gl_drawable); - } else -#endif - { - int mx = 0, my = 0; - int ww, wh; - - gdk_drawable_get_size(widget->window, &ww, &wh); - if (ww > priv->fb.width) - mx = (ww - priv->fb.width) / 2; - if (wh > priv->fb.height) - my = (wh - priv->fb.height) / 2; - - x = MIN(expose->area.x - mx, priv->fb.width); - y = MIN(expose->area.y - my, priv->fb.height); - w = MIN(expose->area.x + expose->area.width - mx, priv->fb.width); - h = MIN(expose->area.y + expose->area.height - my, priv->fb.height); - x = MAX(0, x); - y = MAX(0, y); - w = MAX(0, w); - h = MAX(0, h); - - w -= x; - h -= y; - - drawn.x = x + mx; - drawn.y = y + my; - drawn.width = w; - drawn.height = h; - - clear = gdk_region_rectangle(&expose->area); - copy = gdk_region_rectangle(&drawn); - gdk_region_subtract(clear, copy); - - gdk_gc_set_clip_region(priv->gc, copy); - gdk_draw_image(widget->window, priv->gc, priv->image, - x, y, x + mx, y + my, w, h); - - gdk_gc_set_clip_region(priv->gc, clear); - gdk_draw_rectangle(widget->window, priv->gc, TRUE, expose->area.x, expose->area.y, - expose->area.width, expose->area.height); - - gdk_region_destroy(clear); - gdk_region_destroy(copy); - } - - return TRUE; -} - -static void do_keyboard_grab(VncDisplay *obj, gboolean quiet) -{ - VncDisplayPrivate *priv = obj->priv; - - gdk_keyboard_grab(GTK_WIDGET(obj)->window, - FALSE, - GDK_CURRENT_TIME); - priv->in_keyboard_grab = TRUE; - if (!quiet) - g_signal_emit(obj, signals[VNC_KEYBOARD_GRAB], 0); -} - - -static void do_keyboard_ungrab(VncDisplay *obj, gboolean quiet) -{ - VncDisplayPrivate *priv = obj->priv; - - gdk_keyboard_ungrab(GDK_CURRENT_TIME); - priv->in_keyboard_grab = FALSE; - if (!quiet) - g_signal_emit(obj, signals[VNC_KEYBOARD_UNGRAB], 0); -} - -static void do_pointer_hide(VncDisplay *obj) -{ - VncDisplayPrivate *priv = obj->priv; - gdk_window_set_cursor(GTK_WIDGET(obj)->window, - priv->remote_cursor ? priv->remote_cursor : priv->null_cursor); -} - -static void do_pointer_show(VncDisplay *obj) -{ - VncDisplayPrivate *priv = obj->priv; - gdk_window_set_cursor(GTK_WIDGET(obj)->window, - priv->remote_cursor); -} - -static void do_pointer_grab(VncDisplay *obj, gboolean quiet) -{ - VncDisplayPrivate *priv = obj->priv; - - /* If we're not already grabbing keyboard, grab it now */ - if (!priv->grab_keyboard) - do_keyboard_grab(obj, quiet); - - gdk_pointer_grab(GTK_WIDGET(obj)->window, - TRUE, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_SCROLL_MASK, - GTK_WIDGET(obj)->window, - priv->remote_cursor ? priv->remote_cursor : priv->null_cursor, - GDK_CURRENT_TIME); - priv->in_pointer_grab = TRUE; - if (!quiet) - g_signal_emit(obj, signals[VNC_POINTER_GRAB], 0); -} - -static void do_pointer_ungrab(VncDisplay *obj, gboolean quiet) -{ - VncDisplayPrivate *priv = obj->priv; - - /* If we grabbed keyboard upon pointer grab, then ungrab it now */ - if (!priv->grab_keyboard) - do_keyboard_ungrab(obj, quiet); - - gdk_pointer_ungrab(GDK_CURRENT_TIME); - priv->in_pointer_grab = FALSE; - - if (priv->absolute) - do_pointer_hide(obj); - - if (!quiet) - g_signal_emit(obj, signals[VNC_POINTER_UNGRAB], 0); -} - -void vnc_display_force_grab(VncDisplay *obj, gboolean enable) -{ - if (enable) - do_pointer_grab(obj, FALSE); - else - do_pointer_ungrab(obj, FALSE); -} - -static gboolean button_event(GtkWidget *widget, GdkEventButton *button) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - int n; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return FALSE; - - if (priv->read_only) - return FALSE; - - gtk_widget_grab_focus (widget); - - if (priv->grab_pointer && !priv->absolute && !priv->in_pointer_grab && - button->button == 1 && button->type == GDK_BUTTON_PRESS) - do_pointer_grab(VNC_DISPLAY(widget), FALSE); - - n = 1 << (button->button - 1); - if (button->type == GDK_BUTTON_PRESS) - priv->button_mask |= n; - else if (button->type == GDK_BUTTON_RELEASE) - priv->button_mask &= ~n; - - if (priv->absolute) { - gvnc_pointer_event(priv->gvnc, priv->button_mask, - priv->last_x, priv->last_y); - } else { - gvnc_pointer_event(priv->gvnc, priv->button_mask, - 0x7FFF, 0x7FFF); - } - - return TRUE; -} - -static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *scroll) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - int mask; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return FALSE; - - if (priv->read_only) - return FALSE; - - if (scroll->direction == GDK_SCROLL_UP) - mask = (1 << 3); - else if (scroll->direction == GDK_SCROLL_DOWN) - mask = (1 << 4); - else if (scroll->direction == GDK_SCROLL_LEFT) - mask = (1 << 5); - else if (scroll->direction == GDK_SCROLL_RIGHT) - mask = (1 << 6); - else - return FALSE; - - if (priv->absolute) { - gvnc_pointer_event(priv->gvnc, priv->button_mask | mask, - priv->last_x, priv->last_y); - gvnc_pointer_event(priv->gvnc, priv->button_mask, - priv->last_x, priv->last_y); - } else { - gvnc_pointer_event(priv->gvnc, priv->button_mask | mask, - 0x7FFF, 0x7FFF); - gvnc_pointer_event(priv->gvnc, priv->button_mask, - 0x7FFF, 0x7FFF); - } - - return TRUE; -} - -static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - int dx, dy; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return FALSE; - - if (!priv->absolute && !priv->in_pointer_grab) - return FALSE; - - if (priv->read_only) - return FALSE; - -#if WITH_GTKGLEXT - if (priv->gl_enabled) { - motion->x *= priv->fb.width; - motion->x /= priv->gl_width; - motion->y *= priv->fb.height; - motion->y /= priv->gl_height; - } else -#endif - { - int ww, wh; - int mw = 0, mh = 0; - - gdk_drawable_get_size(widget->window, &ww, &wh); - if (ww > priv->fb.width) - mw = (ww - priv->fb.width) / 2; - if (wh > priv->fb.height) - mh = (wh - priv->fb.height) / 2; - - motion->x -= mw; - motion->y -= mh; - - if (motion->x < 0 || motion->x >= priv->fb.width || - motion->y < 0 || motion->y >= priv->fb.height) - return FALSE; - } - - if (!priv->absolute && priv->in_pointer_grab) { - GdkDrawable *drawable = GDK_DRAWABLE(widget->window); - GdkDisplay *display = gdk_drawable_get_display(drawable); - GdkScreen *screen = gdk_drawable_get_screen(drawable); - int x = (int)motion->x_root; - int y = (int)motion->y_root; - - if (x == 0) x += 200; - if (y == 0) y += 200; - if (x == (gdk_screen_get_width(screen) - 1)) x -= 200; - if (y == (gdk_screen_get_height(screen) - 1)) y -= 200; - - if (x != (int)motion->x_root || y != (int)motion->y_root) { - gdk_display_warp_pointer(display, screen, x, y); - priv->last_x = -1; - priv->last_y = -1; - return FALSE; - } - } - - if (priv->last_x != -1) { - if (priv->absolute) { - dx = (int)motion->x; - dy = (int)motion->y; - } else { - dx = (int)motion->x + 0x7FFF - priv->last_x; - dy = (int)motion->y + 0x7FFF - priv->last_y; - } - - gvnc_pointer_event(priv->gvnc, priv->button_mask, dx, dy); - } - - priv->last_x = (int)motion->x; - priv->last_y = (int)motion->y; - - return TRUE; -} - -static gboolean key_event(GtkWidget *widget, GdkEventKey *key) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - guint keyval; - gint group, level; - GdkModifierType consumed; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return FALSE; - - if (priv->read_only) - return FALSE; - - /* - * Key handling in VNC is screwy. The event.keyval from GTK is - * interpreted relative to modifier state. This really messes - * up with VNC which has no concept of modifiers - it just sees - * key up & down events - the remote end interprets modifiers - * itself. So if we interpret at the client end you can end up - * with 'Alt' key press generating Alt_L, and key release generating - * ISO_Prev_Group. This really really confuses the VNC server - * with 'Alt' getting stuck on. - * - * So we have to redo GTK's keycode -> keyval translation - * using only the SHIFT modifier which the RFB explicitly - * requires to be interpreted at client end. - * - * Arggggh. - */ - gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(), - key->hardware_keycode, - key->state & (GDK_SHIFT_MASK | GDK_LOCK_MASK), - key->group, - &keyval, - &group, - &level, - &consumed); - - keyval = x_keymap_get_keyval_from_keycode(key->hardware_keycode, keyval); - - /* - * More VNC suckiness with key state & modifiers in particular - * - * Because VNC has no concept of modifiers, we have to track what keys are - * pressed and when the widget looses focus send fake key up events for all - * keys current held down. This is because upon gaining focus any keys held - * down are no longer likely to be down. This would thus result in keys - * being 'stuck on' in the remote server. eg upon Alt-Tab to switch window - * focus you'd never see key up for the Alt or Tab keys without this :-( - * - * This is mostly a problem with modifier keys, but its best to just track - * all key presses regardless. There's a limit to how many keys a user can - * press at once due to a max of 10 fingers (normally :-), so down_key_vals - * is only storing upto 16 for now. Should be plenty... - * - * Arggggh. - */ - if (key->type == GDK_KEY_PRESS) { - int i; - for (i = 0 ; i < (int)(sizeof(priv->down_keyval)/sizeof(priv->down_keyval[0])) ; i++) { - if (priv->down_scancode[i] == 0) { - priv->down_keyval[i] = keyval; - priv->down_scancode[i] = key->hardware_keycode; - /* Send the actual key event we're dealing with */ - gvnc_key_event(priv->gvnc, 1, keyval, key->hardware_keycode); - break; - } else if (priv->down_scancode[i] == key->hardware_keycode) { - /* Got an press when we're already pressed ! Why ... ? - * - * Well, GTK merges sequential press+release pairs of the same - * key so instead of press+release,press+release,press+release - * we only get press+press+press+press+press+release. This - * really annoys some VNC servers, so we have to un-merge - * them into a sensible stream of press+release pairs - */ - /* Fake an up event for the previous down event */ - gvnc_key_event(priv->gvnc, 0, keyval, key->hardware_keycode); - /* Now send our actual ldown event */ - gvnc_key_event(priv->gvnc, 1, keyval, key->hardware_keycode); - break; - } - } - } else { - int i; - for (i = 0 ; i < (int)(sizeof(priv->down_keyval)/sizeof(priv->down_keyval[0])) ; i++) { - /* We were pressed, and now we're released, so... */ - if (priv->down_scancode[i] == key->hardware_keycode) { - priv->down_keyval[i] = 0; - priv->down_scancode[i] = 0; - /* ..send the key release event we're dealing with */ - gvnc_key_event(priv->gvnc, 0, keyval, key->hardware_keycode); - break; - } - } - } - - if ((!priv->grab_keyboard || !priv->absolute) && - key->type == GDK_KEY_PRESS && - ((keyval == GDK_Control_L && (key->state & GDK_MOD1_MASK)) || - (keyval == GDK_Alt_L && (key->state & GDK_CONTROL_MASK)))) { - if (priv->in_pointer_grab) - do_pointer_ungrab(VNC_DISPLAY(widget), FALSE); - else - do_pointer_grab(VNC_DISPLAY(widget), FALSE); - } - - return TRUE; -} - -static gboolean enter_event(GtkWidget *widget, GdkEventCrossing *crossing) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return FALSE; - - if (crossing->mode != GDK_CROSSING_NORMAL) - return FALSE; - - if (priv->grab_keyboard) - do_keyboard_grab(VNC_DISPLAY(widget), FALSE); - - return TRUE; -} - -static gboolean leave_event(GtkWidget *widget, GdkEventCrossing *crossing) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return FALSE; - - if (crossing->mode != GDK_CROSSING_NORMAL) - return FALSE; - - if (priv->grab_keyboard) - do_keyboard_ungrab(VNC_DISPLAY(widget), FALSE); - - if (priv->grab_pointer) - do_pointer_ungrab(VNC_DISPLAY(widget), FALSE); - - return TRUE; -} - - -static gboolean focus_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UNUSED) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - int i; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return FALSE; - - for (i = 0 ; i < (int)(sizeof(priv->down_keyval)/sizeof(priv->down_keyval[0])) ; i++) { - /* We are currently pressed so... */ - if (priv->down_scancode[i] != 0) { - /* ..send the fake key release event to match */ - gvnc_key_event(priv->gvnc, 0, - priv->down_keyval[i], priv->down_scancode[i]); - priv->down_keyval[i] = 0; - priv->down_scancode[i] = 0; - } - } - - return TRUE; -} - -#if WITH_GTKGLEXT -static void realize_event(GtkWidget *widget) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; - - GTK_WIDGET_CLASS (vnc_display_parent_class)->realize(widget); - - if (priv->gl_config == NULL) - return; - - priv->gl_drawable = gtk_widget_get_gl_drawable(widget); - priv->gl_context = gtk_widget_get_gl_context(widget); -} -#endif - -static gboolean on_update(void *opaque, int x, int y, int w, int h) -{ - GtkWidget *widget = GTK_WIDGET(opaque); - VncDisplay *obj = VNC_DISPLAY(widget); - VncDisplayPrivate *priv = obj->priv; - -#if WITH_GTKGLEXT - if (priv->gl_enabled) { - double scale_x, scale_y; - - scale_x = (double)priv->gl_width / priv->fb.width; - scale_y = (double)priv->gl_height / priv->fb.height; - - x *= scale_x; - y *= scale_y; - w *= scale_x; - h *= scale_y; - } else -#endif - { - int ww, wh; - int mw = 0, mh = 0; - - gdk_drawable_get_size(widget->window, &ww, &wh); - if (ww > priv->fb.width) - mw = (ww - priv->fb.width) / 2; - if (wh > priv->fb.height) - mh = (wh - priv->fb.height) / 2; - - x += mw; - y += mh; - } - - gtk_widget_queue_draw_area(widget, x, y, w, h); - - return TRUE; -} - -static void setup_gdk_image(VncDisplay *obj, gint width, gint height) -{ - VncDisplayPrivate *priv = obj->priv; - GdkVisual *visual; - - visual = gdk_drawable_get_visual(GTK_WIDGET(obj)->window); - - priv->image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height); - GVNC_DEBUG("Visual mask: %3d %3d %3d\n shift: %3d %3d %3d\n", - visual->red_mask, - visual->green_mask, - visual->blue_mask, - visual->red_shift, - visual->green_shift, - visual->blue_shift); - - priv->fb.red_mask = visual->red_mask >> visual->red_shift; - priv->fb.green_mask = visual->green_mask >> visual->green_shift; - priv->fb.blue_mask = visual->blue_mask >> visual->blue_shift; - priv->fb.red_shift = visual->red_shift; - priv->fb.green_shift = visual->green_shift; - priv->fb.blue_shift = visual->blue_shift; - priv->fb.depth = priv->image->depth; - priv->fb.bpp = priv->image->bpp; - priv->fb.width = priv->image->width; - priv->fb.height = priv->image->height; - priv->fb.linesize = priv->image->bpl; - priv->fb.data = (uint8_t *)priv->image->mem; - priv->fb.byte_order = priv->image->byte_order == GDK_LSB_FIRST ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; - - if (priv->force_size) - gtk_widget_set_size_request(GTK_WIDGET(obj), width, height); -} - -#if WITH_GTKGLEXT -static int pow_of_2(int value) -{ - int i; - for (i = 0; value >= (1 << i); i++); - return (1 << i); -} - -static void setup_gl_image(VncDisplay *obj, gint width, gint height) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(obj)->priv; - void *dummy; - - priv->gl_texture_width = pow_of_2(width); - priv->gl_texture_height = pow_of_2(height); - - gdk_gl_drawable_gl_begin(priv->gl_drawable, priv->gl_context); - - glGenTextures(1, &priv->gl_tex); - glBindTexture(GL_TEXTURE_2D, priv->gl_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - dummy = g_malloc(priv->gl_texture_width*priv->gl_texture_height*4); - memset(dummy, 0, priv->gl_texture_width*priv->gl_texture_height*4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - priv->gl_texture_width, priv->gl_texture_height, 0, - GL_RGB, GL_UNSIGNED_BYTE, - dummy); - g_free(dummy); - - gdk_gl_drawable_gl_end(priv->gl_drawable); - - priv->gl_tex_data = g_malloc(width * height * 4); - - priv->fb.red_mask = 0xFF; - priv->fb.green_mask = 0xFF; - priv->fb.blue_mask = 0xFF; - priv->fb.red_shift = 16; - priv->fb.green_shift = 8; - priv->fb.blue_shift = 0; - priv->fb.depth = 32; - priv->fb.bpp = 4; - priv->fb.width = width; - priv->fb.height = height; - priv->fb.linesize = priv->fb.width * priv->fb.bpp; - priv->fb.data = (uint8_t *)priv->gl_tex_data; -} -#endif - -static gboolean emit_signal_auth_cred(gpointer opaque) -{ - struct signal_data *s = opaque; - - switch (s->signum) { - case VNC_AUTH_CREDENTIAL: - g_signal_emit(G_OBJECT(s->obj), - signals[VNC_AUTH_CREDENTIAL], - 0, - s->cred_list); - break; - case VNC_DESKTOP_RESIZE: - g_signal_emit(G_OBJECT(s->obj), - signals[VNC_DESKTOP_RESIZE], - 0, - s->width, s->height); - break; - case VNC_AUTH_FAILURE: - g_signal_emit(G_OBJECT(s->obj), - signals[VNC_AUTH_FAILURE], - 0, - s->msg); - break; - case VNC_AUTH_UNSUPPORTED: - g_signal_emit(G_OBJECT(s->obj), - signals[VNC_AUTH_UNSUPPORTED], - 0, - s->auth_type); - break; - case VNC_SERVER_CUT_TEXT: - g_signal_emit(G_OBJECT(s->obj), - signals[VNC_SERVER_CUT_TEXT], - 0, - s->str->str); - break; - case VNC_BELL: - case VNC_CONNECTED: - case VNC_INITIALIZED: - case VNC_DISCONNECTED: - g_signal_emit(G_OBJECT(s->obj), - signals[s->signum], - 0); - break; - } - - coroutine_yieldto(s->caller, NULL); - - return FALSE; -} - -/* This function should be used to emit signals from gvnc callbacks */ -static void emit_signal_delayed(VncDisplay *obj, int signum, - struct signal_data *data) -{ - data->obj = obj; - data->caller = coroutine_self(); - data->signum = signum; - g_idle_add(emit_signal_auth_cred, data); - coroutine_yield(NULL); -} - -static gboolean do_resize(void *opaque, int width, int height, gboolean quiet) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - VncDisplayPrivate *priv = obj->priv; - struct signal_data s; - - if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc)) - return TRUE; - - if (priv->image) { - g_object_unref(priv->image); - priv->image = NULL; - } - -#if WITH_GTKGLEXT - if (priv->gl_tex_data) { - gdk_gl_drawable_gl_begin(priv->gl_drawable, - priv->gl_context); - glDeleteTextures(1, &priv->gl_tex); - gdk_gl_drawable_gl_end(priv->gl_drawable); - g_free(priv->gl_tex_data); - priv->gl_tex_data = NULL; - } -#endif - - if (priv->gc == NULL) { - priv->null_cursor = create_null_cursor(); - if (priv->local_pointer) - do_pointer_show(obj); - else if (priv->in_pointer_grab || priv->absolute) - do_pointer_hide(obj); - priv->gc = gdk_gc_new(GTK_WIDGET(obj)->window); - } - -#if WITH_GTKGLEXT - if (priv->gl_enabled) - setup_gl_image(obj, width, height); - else -#endif - setup_gdk_image(obj, width, height); - - gvnc_set_local(priv->gvnc, &priv->fb); - - if (!quiet) { - s.width = width; - s.height = height; - emit_signal_delayed(obj, VNC_DESKTOP_RESIZE, &s); - } - - return TRUE; -} - -static gboolean on_resize(void *opaque, int width, int height) -{ - return do_resize(opaque, width, height, FALSE); -} - -static gboolean on_pixel_format(void *opaque, - struct gvnc_pixel_format *fmt G_GNUC_UNUSED) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - VncDisplayPrivate *priv = obj->priv; - - return do_resize(opaque, priv->fb.width, priv->fb.height, TRUE); -} - -static gboolean on_get_preferred_pixel_format(void *opaque, - struct gvnc_pixel_format *fmt) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - GdkVisual *v = gdk_drawable_get_visual(GTK_WIDGET(obj)->window); - - GVNC_DEBUG("Setting pixel format to true color\n"); - - fmt->true_color_flag = 1; - fmt->depth = v->depth; - fmt->bits_per_pixel = v->depth > 16 ? 32 : v->depth; - fmt->red_max = v->red_mask >> v->red_shift; - fmt->green_max = v->green_mask >> v->green_shift; - fmt->blue_max = v->blue_mask >> v->blue_shift; - fmt->red_shift = v->red_shift; - fmt->green_shift = v->green_shift; - fmt->blue_shift = v->blue_shift; - fmt->byte_order = v->byte_order == GDK_LSB_FIRST ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; - - return TRUE; -} - -#if WITH_GTKGLEXT -static void build_gl_image_from_gdk(uint32_t *data, GdkImage *image) -{ - GdkVisual *visual; - int i, j; - uint8_t *row; - - visual = image->visual; - row = image->mem; - for (j = 0; j < image->height; j++) { - uint8_t *src = row; - for (i = 0; i < image->width; i++) { - uint32_t pixel = 0; - switch (image->bpp) { - case 1: - pixel = *(uint8_t *)src; - break; - case 2: - pixel = *(uint16_t *)src; - break; - case 4: - pixel = *(uint32_t *)src; - break; - } - *data = ((pixel & visual->red_mask) >> visual->red_shift) << (24 - visual->red_prec) | - ((pixel & visual->green_mask) >> visual->green_shift) << (16 - visual->green_prec) | - ((pixel & visual->blue_mask) >> visual->blue_shift) << (8 - visual->blue_prec); - src += image->bpp; - data++; - } - row += image->bpl; - - } -} - -static void build_gdk_image_from_gl(GdkImage *image, uint32_t *data) -{ - GdkVisual *visual; - int i, j; - uint8_t *row; - - visual = image->visual; - row = image->mem; - for (j = 0; j < image->height; j++) { - uint8_t *dst = row; - for (i = 0; i < image->width; i++) { - uint32_t pixel; - - pixel = (((*data >> (24 - visual->red_prec)) << visual->red_shift) & visual->red_mask) | - (((*data >> (16 - visual->green_prec)) << visual->green_shift) & visual->green_mask) | - (((*data >> (8 - visual->blue_prec)) << visual->blue_shift) & visual->blue_mask); - - switch (image->bpp) { - case 1: - *(uint8_t *)dst = pixel; - break; - case 2: - *(uint16_t *)dst = pixel; - break; - case 4: - *(uint32_t *)dst = pixel; - break; - } - dst += image->bpp; - data++; - } - row += image->bpl; - } -} - -static void scale_display(VncDisplay *obj, gint width, gint height) -{ - VncDisplayPrivate *priv = VNC_DISPLAY(obj)->priv; - - if (priv->gl_drawable == NULL) - return; - - if (priv->gl_enabled == 0) { - GdkImage *image; - - priv->gl_enabled = 1; - - image = priv->image; - priv->image = NULL; - - do_resize(obj, priv->fb.width, priv->fb.height, TRUE); - build_gl_image_from_gdk((uint32_t *)priv->fb.data, image); - - g_object_unref(image); - } - - priv->gl_width = width; - priv->gl_height = height; - - gdk_gl_drawable_gl_begin(priv->gl_drawable, priv->gl_context); - glClearColor (0.0, 0.0, 0.0, 0.0); - glShadeModel(GL_FLAT); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glViewport(0, 0, priv->gl_width, priv->gl_height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, priv->gl_width, 0.0, priv->gl_height, -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gdk_gl_drawable_gl_end(priv->gl_drawable); -} - -static void rescale_display(VncDisplay *obj, gint width, gint height) -{ - VncDisplayPrivate *priv = obj->priv; - - if (priv->allow_scaling && - (priv->fb.width != width || - priv->fb.height != height)) - scale_display(obj, width, height); - else if (priv->gl_enabled) { - void *data; - priv->gl_enabled = 0; - - data = priv->gl_tex_data; - priv->gl_tex_data = NULL; - - do_resize(GTK_WIDGET(obj), priv->fb.width, priv->fb.height, TRUE); - - build_gdk_image_from_gl(priv->image, (uint32_t *)data); - gdk_gl_drawable_gl_begin(priv->gl_drawable, - priv->gl_context); - glDeleteTextures(1, &priv->gl_tex); - gdk_gl_drawable_gl_end(priv->gl_drawable); - g_free(data); - } -} - -static gboolean configure_event(GtkWidget *widget, GdkEventConfigure *configure) -{ - VncDisplay *obj = VNC_DISPLAY(widget); - VncDisplayPrivate *priv = obj->priv; - - if (priv->fb.data == NULL) - return FALSE; - - rescale_display(VNC_DISPLAY(widget), - configure->width, configure->height); - - return FALSE; -} -#endif - -static gboolean on_pointer_type_change(void *opaque, int absolute) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - VncDisplayPrivate *priv = obj->priv; - - if (absolute && priv->in_pointer_grab && !priv->grab_pointer) - do_pointer_ungrab(obj, FALSE); - - priv->absolute = absolute; - - if (!priv->in_pointer_grab && !priv->absolute) - do_pointer_show(obj); - - return TRUE; -} - -static gboolean on_auth_cred(void *opaque) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - GValueArray *cred_list; - GValue username, password, clientname; - struct signal_data s; - - memset(&username, 0, sizeof(username)); - memset(&password, 0, sizeof(password)); - memset(&clientname, 0, sizeof(clientname)); - - cred_list = g_value_array_new(0); - if (gvnc_wants_credential_username(obj->priv->gvnc)) { - g_value_init(&username, G_PARAM_SPEC_VALUE_TYPE(signalCredParam)); - g_value_set_enum(&username, VNC_DISPLAY_CREDENTIAL_USERNAME); - cred_list = g_value_array_append(cred_list, &username); - } - if (gvnc_wants_credential_password(obj->priv->gvnc)) { - g_value_init(&password, G_PARAM_SPEC_VALUE_TYPE(signalCredParam)); - g_value_set_enum(&password, VNC_DISPLAY_CREDENTIAL_PASSWORD); - cred_list = g_value_array_append(cred_list, &password); - } - if (gvnc_wants_credential_x509(obj->priv->gvnc)) { - g_value_init(&clientname, G_PARAM_SPEC_VALUE_TYPE(signalCredParam)); - g_value_set_enum(&clientname, VNC_DISPLAY_CREDENTIAL_CLIENTNAME); - cred_list = g_value_array_append(cred_list, &clientname); - } - - s.cred_list = cred_list; - emit_signal_delayed(obj, VNC_AUTH_CREDENTIAL, &s); - - g_value_array_free(cred_list); - - return TRUE; -} - -static gboolean on_auth_type(void *opaque, unsigned int ntype, unsigned int *types) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - VncDisplayPrivate *priv = obj->priv; - GSList *l; - guint i; - - if (!ntype) - return TRUE; - - for (l = priv->preferable_auths; l; l=l->next) { - gvnc_auth pref = GPOINTER_TO_UINT (l->data); - - for (i=0; igvnc, types[i]); - return TRUE; - } - } - } - - gvnc_set_auth_type(priv->gvnc, types[0]); - return TRUE; -} - -static gboolean on_auth_subtype(void *opaque, unsigned int ntype, unsigned int *types) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - VncDisplayPrivate *priv = obj->priv; - - GSList *l; - guint i; - - if (!ntype) - return TRUE; - - for (l = priv->preferable_auths; l; l=l->next) { - gvnc_auth pref = GPOINTER_TO_UINT (l->data); - - for (i=0; igvnc, types[i]); - return TRUE; - } - } - } - - gvnc_set_auth_subtype(priv->gvnc, types[0]); - return TRUE; -} - -static gboolean on_auth_failure(void *opaque, const char *msg) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - struct signal_data s; - - s.msg = msg; - emit_signal_delayed(obj, VNC_AUTH_FAILURE, &s); - - return TRUE; -} - -static gboolean on_auth_unsupported(void *opaque, unsigned int auth_type) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - struct signal_data s; - - s.auth_type = auth_type; - emit_signal_delayed(obj, VNC_AUTH_UNSUPPORTED, &s); - - return TRUE; -} - -static gboolean on_server_cut_text(void *opaque, const void* text, size_t len) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - GString *str = g_string_new_len ((const gchar *)text, len); - struct signal_data s; - - s.str = str; - emit_signal_delayed(obj, VNC_SERVER_CUT_TEXT, &s); - - g_string_free (str, TRUE); - return TRUE; -} - -static gboolean on_bell(void *opaque) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - struct signal_data s; - - emit_signal_delayed(obj, VNC_BELL, &s); - - return TRUE; -} - -static gboolean on_local_cursor(void *opaque, int x, int y, int width, int height, uint8_t *image) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - VncDisplayPrivate *priv = obj->priv; - - if (priv->remote_cursor) { - gdk_cursor_unref(priv->remote_cursor); - priv->remote_cursor = NULL; - } - - if (width && height) { - GdkDisplay *display = gdk_drawable_get_display(GDK_DRAWABLE(GTK_WIDGET(obj)->window)); - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(image, GDK_COLORSPACE_RGB, - TRUE, 8, width, height, - width * 4, NULL, NULL); - priv->remote_cursor = gdk_cursor_new_from_pixbuf(display, - pixbuf, - x, y); - gdk_pixbuf_unref(pixbuf); - } - - if (priv->in_pointer_grab) { - do_pointer_ungrab(obj, TRUE); - do_pointer_grab(obj, TRUE); - } else if (priv->absolute) { - do_pointer_hide(obj); - } - - return TRUE; -} - -static gboolean check_pixbuf_support(const char *name) -{ - GSList *list, *i; - - list = gdk_pixbuf_get_formats(); - - for (i = list; i; i = i->next) { - GdkPixbufFormat *fmt = i->data; - if (!strcmp(gdk_pixbuf_format_get_name(fmt), name)) - break; - } - - g_slist_free(list); - - return !!(i); -} - -static gboolean on_render_jpeg(void *opaque G_GNUC_UNUSED, - rgb24_render_func *render, void *render_opaque, - int x, int y, int w, int h, - uint8_t *data, int size) -{ - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - GdkPixbuf *p; - uint8_t *pixels; - - if (!gdk_pixbuf_loader_write(loader, data, size, NULL)) - return FALSE; - - gdk_pixbuf_loader_close(loader, NULL); - - p = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader)); - g_object_unref(loader); - - pixels = gdk_pixbuf_get_pixels(p); - - render(render_opaque, x, y, w, h, - gdk_pixbuf_get_pixels(p), - gdk_pixbuf_get_rowstride(p)); - - gdk_pixbuf_unref(p); - - return TRUE; -} - -static const struct gvnc_ops vnc_display_ops = { - .auth_cred = on_auth_cred, - .auth_type = on_auth_type, - .auth_subtype = on_auth_subtype, - .auth_failure = on_auth_failure, - .update = on_update, - .resize = on_resize, - .pixel_format = on_pixel_format, - .pointer_type_change = on_pointer_type_change, - .local_cursor = on_local_cursor, - .auth_unsupported = on_auth_unsupported, - .server_cut_text = on_server_cut_text, - .bell = on_bell, - .render_jpeg = on_render_jpeg, - .get_preferred_pixel_format = on_get_preferred_pixel_format -}; - -/* we use an idle function to allow the coroutine to exit before we actually - * unref the object since the coroutine's state is part of the object */ -static gboolean delayed_unref_object(gpointer data) -{ - VncDisplay *obj = VNC_DISPLAY(data); - - g_assert(obj->priv->coroutine.exited == TRUE); - - if (obj->priv->image) { - g_object_unref(obj->priv->image); - obj->priv->image = NULL; - } - -#if WITH_GTKGLEXT - if (obj->priv->gl_tex_data) - g_free(obj->priv->gl_tex_data); - obj->priv->gl_tex_data = NULL; - obj->priv->gl_enabled = 0; -#endif - - g_object_unref(G_OBJECT(data)); - return FALSE; -} - -static void *vnc_coroutine(void *opaque) -{ - VncDisplay *obj = VNC_DISPLAY(opaque); - VncDisplayPrivate *priv = obj->priv; - - /* this order is extremely important! */ - int32_t encodings[] = { GVNC_ENCODING_TIGHT_JPEG5, - GVNC_ENCODING_TIGHT, - GVNC_ENCODING_EXT_KEY_EVENT, - GVNC_ENCODING_DESKTOP_RESIZE, - GVNC_ENCODING_WMVi, - GVNC_ENCODING_RICH_CURSOR, - GVNC_ENCODING_XCURSOR, - GVNC_ENCODING_POINTER_CHANGE, - GVNC_ENCODING_ZRLE, - GVNC_ENCODING_HEXTILE, - GVNC_ENCODING_RRE, - GVNC_ENCODING_COPY_RECT, - GVNC_ENCODING_RAW }; - int32_t *encodingsp; - int n_encodings; - int ret; - struct signal_data s; - - if (priv->gvnc == NULL || gvnc_is_open(priv->gvnc)) { - g_idle_add(delayed_unref_object, obj); - return NULL; - } - - GVNC_DEBUG("Started background coroutine\n"); - x_keymap_set_keymap_entries(); - - if (priv->fd != -1) { - if (!gvnc_open_fd(priv->gvnc, priv->fd)) - goto cleanup; - } else { - if (!gvnc_open_host(priv->gvnc, priv->host, priv->port)) - goto cleanup; - } - - emit_signal_delayed(obj, VNC_CONNECTED, &s); - - GVNC_DEBUG("Protocol initialization\n"); - if (!gvnc_initialize(priv->gvnc, priv->shared_flag)) - goto cleanup; - - emit_signal_delayed(obj, VNC_INITIALIZED, &s); - - encodingsp = encodings; - n_encodings = G_N_ELEMENTS(encodings); - - if (check_pixbuf_support("jpeg")) { - if (!priv->allow_lossy) { - encodingsp++; - n_encodings--; - } - } else { - encodingsp += 2; - n_encodings -= 2; - } - - if (!gvnc_set_encodings(priv->gvnc, n_encodings, encodingsp)) - goto cleanup; - - if (!gvnc_framebuffer_update_request(priv->gvnc, 0, 0, 0, priv->fb.width, priv->fb.height)) - goto cleanup; - - GVNC_DEBUG("Running main loop\n"); - while ((ret = gvnc_server_message(priv->gvnc))) { - if (!gvnc_framebuffer_update_request(priv->gvnc, 1, 0, 0, - priv->fb.width, priv->fb.height)) - goto cleanup; - } - - cleanup: - GVNC_DEBUG("Doing final VNC cleanup\n"); - gvnc_close(priv->gvnc); - emit_signal_delayed(obj, VNC_DISCONNECTED, &s); - g_idle_add(delayed_unref_object, obj); - x_keymap_free_keymap_entries(); - /* Co-routine exits now - the VncDisplay object may no longer exist, - so don't do anything else now unless you like SEGVs */ - return NULL; -} - -static gboolean do_vnc_display_open(gpointer data) -{ - VncDisplay *obj = VNC_DISPLAY(data); - struct coroutine *co; - - if (obj->priv->gvnc == NULL || gvnc_is_open(obj->priv->gvnc)) { - g_object_unref(G_OBJECT(obj)); - return FALSE; - } - - obj->priv->open_id = 0; - - co = &obj->priv->coroutine; - - co->stack_size = 16 << 20; - co->entry = vnc_coroutine; - co->release = NULL; - - coroutine_init(co); - coroutine_yieldto(co, obj); - - return FALSE; -} - -gboolean vnc_display_open_fd(VncDisplay *obj, int fd) -{ - if (obj->priv->gvnc == NULL || gvnc_is_open(obj->priv->gvnc)) - return FALSE; - - obj->priv->fd = fd; - obj->priv->host = NULL; - obj->priv->port = NULL; - - g_object_ref(G_OBJECT(obj)); /* Unref'd when co-routine exits */ - obj->priv->open_id = g_idle_add(do_vnc_display_open, obj); - - return TRUE; -} - -gboolean vnc_display_open_host(VncDisplay *obj, const char *host, const char *port) -{ - if (obj->priv->gvnc == NULL || gvnc_is_open(obj->priv->gvnc)) - return FALSE; - - obj->priv->host = g_strdup(host); - if (!obj->priv->host) { - return FALSE; - } - obj->priv->port = g_strdup(port); - if (!obj->priv->port) { - g_free(obj->priv->host); - obj->priv->host = NULL; - return FALSE; - } - - g_object_ref(G_OBJECT(obj)); /* Unref'd when co-routine exits */ - obj->priv->open_id = g_idle_add(do_vnc_display_open, obj); - return TRUE; -} - -gboolean vnc_display_is_open(VncDisplay *obj) -{ - if (obj->priv->gvnc == NULL) - return FALSE; - return gvnc_is_open(obj->priv->gvnc); -} - -void vnc_display_close(VncDisplay *obj) -{ - VncDisplayPrivate *priv = obj->priv; - GtkWidget *widget = GTK_WIDGET(obj); - - if (priv->open_id) { - g_source_remove(priv->open_id); - obj->priv->open_id = 0; - } - - if (priv->gvnc == NULL) - return; - - if (gvnc_is_open(priv->gvnc)) { - GVNC_DEBUG("Requesting graceful shutdown of connection\n"); - gvnc_shutdown(priv->gvnc); - } - -#if WITH_GTKGLEXT - if (priv->gl_tex_data) { - gdk_gl_drawable_gl_begin(priv->gl_drawable, - priv->gl_context); - glDeleteTextures(1, &priv->gl_tex); - gdk_gl_drawable_gl_end(priv->gl_drawable); - } -#endif - - if (widget->window) { - gint width, height; - - gdk_drawable_get_size(widget->window, &width, &height); - gtk_widget_queue_draw_area(widget, 0, 0, width, height); - } -} - - -void vnc_display_send_keys(VncDisplay *obj, const guint *keyvals, int nkeyvals) -{ - vnc_display_send_keys_ex(obj, keyvals, - nkeyvals, VNC_DISPLAY_KEY_EVENT_CLICK); -} - -static guint get_keycode_from_keyval(guint keyval) -{ - guint keycode = 0; - GdkKeymapKey *keys = NULL; - gint n_keys = 0; - - if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), - keyval, &keys, &n_keys)) { - /* FIXME what about levels? */ - keycode = keys[0].keycode; - g_free(keys); - } - - return keycode; -} - -void vnc_display_send_keys_ex(VncDisplay *obj, const guint *keyvals, - int nkeyvals, VncDisplayKeyEvent kind) -{ - int i; - - if (obj->priv->gvnc == NULL || !gvnc_is_open(obj->priv->gvnc)) - return; - - if (kind & VNC_DISPLAY_KEY_EVENT_PRESS) { - for (i = 0 ; i < nkeyvals ; i++) - gvnc_key_event(obj->priv->gvnc, 1, keyvals[i], - get_keycode_from_keyval(keyvals[i])); - } - - if (kind & VNC_DISPLAY_KEY_EVENT_RELEASE) { - for (i = (nkeyvals-1) ; i >= 0 ; i--) - gvnc_key_event(obj->priv->gvnc, 0, keyvals[i], - get_keycode_from_keyval(keyvals[i])); - } -} - -void vnc_display_send_pointer(VncDisplay *obj, gint x, gint y, int button_mask) -{ - VncDisplayPrivate *priv = obj->priv; - - if (priv->gvnc == NULL || !gvnc_is_open(obj->priv->gvnc)) - return; - - if (priv->absolute) { - priv->button_mask = button_mask; - priv->last_x = x; - priv->last_y = y; - gvnc_pointer_event(priv->gvnc, priv->button_mask, x, y); - } -} - -static void vnc_display_destroy (GtkObject *obj) -{ - VncDisplay *display = VNC_DISPLAY (obj); - GVNC_DEBUG("Requesting that VNC close\n"); - vnc_display_close(display); - GTK_OBJECT_CLASS (vnc_display_parent_class)->destroy (obj); -} - - -static void vnc_display_finalize (GObject *obj) -{ - VncDisplay *display = VNC_DISPLAY (obj); - VncDisplayPrivate *priv = display->priv; - - GVNC_DEBUG("Releasing VNC widget\n"); - if (gvnc_is_open(priv->gvnc)) { - g_warning("VNC widget finalized before the connection finished shutting down\n"); - } - gvnc_free(priv->gvnc); - display->priv->gvnc = NULL; - -#if WITH_GTKGLEXT - if (priv->gl_enabled) { - gdk_gl_drawable_gl_begin(priv->gl_drawable, - priv->gl_context); - glDeleteTextures(1, &priv->gl_tex); - gdk_gl_drawable_gl_end(priv->gl_drawable); - if (priv->gl_tex_data) { - g_free(priv->gl_tex_data); - priv->gl_tex_data = NULL; - } - } - - if (priv->gl_config) { - g_object_unref(G_OBJECT(priv->gl_config)); - priv->gl_config = NULL; - } -#endif - - if (priv->image) { - g_object_unref(priv->image); - priv->image = NULL; - } - - g_slist_free (priv->preferable_auths); - - G_OBJECT_CLASS (vnc_display_parent_class)->finalize (obj); -} - -static void vnc_display_class_init(VncDisplayClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass); - GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass); - - gtkwidget_class->expose_event = expose_event; - gtkwidget_class->motion_notify_event = motion_event; - gtkwidget_class->button_press_event = button_event; - gtkwidget_class->button_release_event = button_event; - gtkwidget_class->scroll_event = scroll_event; - gtkwidget_class->key_press_event = key_event; - gtkwidget_class->key_release_event = key_event; - gtkwidget_class->enter_notify_event = enter_event; - gtkwidget_class->leave_notify_event = leave_event; - gtkwidget_class->focus_out_event = focus_event; -#if WITH_GTKGLEXT - gtkwidget_class->realize = realize_event; - gtkwidget_class->configure_event = configure_event; -#endif - - - object_class->finalize = vnc_display_finalize; - object_class->get_property = vnc_display_get_property; - object_class->set_property = vnc_display_set_property; - - gtkobject_class->destroy = vnc_display_destroy; - - g_object_class_install_property (object_class, - PROP_POINTER_LOCAL, - g_param_spec_boolean ( "local-pointer", - "Local Pointer", - "Whether we should use the local pointer", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_POINTER_GRAB, - g_param_spec_boolean ( "grab-pointer", - "Grab Pointer", - "Whether we should grab the pointer", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_KEYBOARD_GRAB, - g_param_spec_boolean ( "grab-keyboard", - "Grab Keyboard", - "Whether we should grab the keyboard", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_READ_ONLY, - g_param_spec_boolean ( "read-only", - "Read Only", - "Whether this connection is read-only mode", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_WIDTH, - g_param_spec_int ( "width", - "Width", - "The width of the remote screen", - 0, - G_MAXINT, - 0, - G_PARAM_READABLE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_HEIGHT, - g_param_spec_int ( "height", - "Height", - "The height of the remote screen", - 0, - G_MAXINT, - 0, - G_PARAM_READABLE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_NAME, - g_param_spec_string ( "name", - "Name", - "The screen name of the remote connection", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_LOSSY_ENCODING, - g_param_spec_boolean ( "lossy-encoding", - "Lossy Encoding", - "Whether we should use a lossy encoding", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_SCALING, - g_param_spec_boolean ( "scaling", - "Scaling", - "Whether we should use scaling", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_SHARED_FLAG, - g_param_spec_boolean ( "shared-flag", - "Shared Flag", - "Whether we should leave other clients connected to the server", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - g_object_class_install_property (object_class, - PROP_FORCE_SIZE, - g_param_spec_boolean ( "force-size", - "Force widget size", - "Whether we should define the widget size", - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - - signalCredParam = g_param_spec_enum("credential", - "credential", - "credential", - vnc_display_credential_get_type(), - 0, - G_PARAM_READABLE); - - signals[VNC_CONNECTED] = - g_signal_new ("vnc-connected", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (VncDisplayClass, vnc_connected), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[VNC_INITIALIZED] = - g_signal_new ("vnc-initialized", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (VncDisplayClass, vnc_initialized), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[VNC_DISCONNECTED] = - g_signal_new ("vnc-disconnected", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (VncDisplayClass, vnc_disconnected), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[VNC_AUTH_CREDENTIAL] = - g_signal_new ("vnc-auth-credential", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (VncDisplayClass, vnc_auth_credential), - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, - 1, - G_TYPE_VALUE_ARRAY); - - - signals[VNC_POINTER_GRAB] = - g_signal_new("vnc-pointer-grab", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[VNC_POINTER_UNGRAB] = - g_signal_new("vnc-pointer-ungrab", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[VNC_KEYBOARD_GRAB] = - g_signal_new("vnc-keyboard-grab", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[VNC_KEYBOARD_UNGRAB] = - g_signal_new("vnc-keyboard-ungrab", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - - signals[VNC_DESKTOP_RESIZE] = - g_signal_new("vnc-desktop-resize", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_user_marshal_VOID__INT_INT, - G_TYPE_NONE, - 2, - G_TYPE_INT, G_TYPE_INT); - - signals[VNC_AUTH_FAILURE] = - g_signal_new("vnc-auth-failure", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - signals[VNC_AUTH_UNSUPPORTED] = - g_signal_new("vnc-auth-unsupported", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, - 1, - G_TYPE_UINT); - - signals[VNC_SERVER_CUT_TEXT] = - g_signal_new("vnc-server-cut-text", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - signals[VNC_BELL] = - g_signal_new("vnc-bell", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private(klass, sizeof(VncDisplayPrivate)); -} - -static void vnc_display_init(VncDisplay *display) -{ - GtkObject *obj = GTK_OBJECT(display); - GtkWidget *widget = GTK_WIDGET(display); - VncDisplayPrivate *priv; - - GTK_WIDGET_SET_FLAGS(obj, GTK_CAN_FOCUS); - - gtk_widget_add_events(widget, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_SCROLL_MASK | - GDK_KEY_PRESS_MASK); - gtk_widget_set_double_buffered(widget, FALSE); - - priv = display->priv = VNC_DISPLAY_GET_PRIVATE(display); - memset(priv, 0, sizeof(VncDisplayPrivate)); - priv->last_x = -1; - priv->last_y = -1; - priv->absolute = 1; - priv->fd = -1; - priv->read_only = FALSE; - priv->allow_lossy = FALSE; - priv->allow_scaling = FALSE; - priv->grab_pointer = FALSE; - priv->grab_keyboard = FALSE; - priv->local_pointer = FALSE; - priv->shared_flag = FALSE; - priv->force_size = TRUE; - - priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VENCRYPT)); - priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_TLS)); - priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VNC)); - priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_NONE)); - -#if WITH_GTKGLEXT - if (gtk_gl_init_check(NULL, NULL)) { - priv->gl_config = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | - GDK_GL_MODE_DEPTH); - if (!gtk_widget_set_gl_capability(widget, - priv->gl_config, - NULL, - TRUE, - GDK_GL_RGBA_TYPE)) { - g_warning("Could not enable OpenGL"); - g_object_unref(G_OBJECT(priv->gl_config)); - priv->gl_config = NULL; - } - } else - priv->gl_config = NULL; -#endif - - priv->gvnc = gvnc_new(&vnc_display_ops, obj); -} - -static int vnc_display_best_path(char *buf, - int buflen, - const char *basedir, - const char *basefile, - char **dirs, - unsigned int ndirs) -{ - unsigned int i; - for (i = 0 ; i < ndirs ; i++) { - struct stat sb; - snprintf(buf, buflen-1, "%s/%s/%s", dirs[i], basedir, basefile); - buf[buflen-1] = '\0'; - if (stat(buf, &sb) == 0) - return 0; - } - return -1; -} - -static int vnc_display_set_x509_credential(VncDisplay *obj, const char *name) -{ - char sysdir[PATH_MAX], userdir[PATH_MAX]; - struct passwd *pw; - char file[PATH_MAX]; - char *dirs[] = { sysdir, userdir }; - - strncpy(sysdir, SYSCONFDIR "/pki", PATH_MAX-1); - sysdir[PATH_MAX-1] = '\0'; - - if (!(pw = getpwuid(getuid()))) - return TRUE; - - snprintf(userdir, PATH_MAX-1, "%s/.pki", pw->pw_dir); - userdir[PATH_MAX-1] = '\0'; - - if (vnc_display_best_path(file, PATH_MAX, "CA", "cacert.pem", dirs, 2) < 0) - return TRUE; - gvnc_set_credential_x509_cacert(obj->priv->gvnc, file); - - /* Don't mind failures of CRL */ - if (vnc_display_best_path(file, PATH_MAX, "CA", "cacrl.pem", dirs, 2) == 0) - gvnc_set_credential_x509_cacert(obj->priv->gvnc, file); - - /* Set client key & cert if we have them. Server will reject auth - * if it decides it requires them*/ - if (vnc_display_best_path(file, PATH_MAX, name, "private/clientkey.pem", dirs, 2) == 0) - gvnc_set_credential_x509_key(obj->priv->gvnc, file); - if (vnc_display_best_path(file, PATH_MAX, name, "clientcert.pem", dirs, 2) == 0) - gvnc_set_credential_x509_cert(obj->priv->gvnc, file); - - return FALSE; -} - -gboolean vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data) -{ - switch (type) { - case VNC_DISPLAY_CREDENTIAL_PASSWORD: - if (gvnc_set_credential_password(obj->priv->gvnc, data)) - return FALSE; - return TRUE; - - case VNC_DISPLAY_CREDENTIAL_USERNAME: - if (gvnc_set_credential_username(obj->priv->gvnc, data)) - return FALSE; - return TRUE; - - case VNC_DISPLAY_CREDENTIAL_CLIENTNAME: - return vnc_display_set_x509_credential(obj, data); - } - - return FALSE; -} - -void vnc_display_set_pointer_local(VncDisplay *obj, gboolean enable) -{ - if (obj->priv->gc) { - if (enable) - do_pointer_show(obj); - else if (obj->priv->in_pointer_grab || obj->priv->absolute) - do_pointer_hide(obj); - } - obj->priv->local_pointer = enable; -} - -void vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable) -{ - VncDisplayPrivate *priv = obj->priv; - - priv->grab_pointer = enable; - if (!enable && priv->absolute && priv->in_pointer_grab) - do_pointer_ungrab(obj, FALSE); -} - -void vnc_display_set_keyboard_grab(VncDisplay *obj, gboolean enable) -{ - VncDisplayPrivate *priv = obj->priv; - - priv->grab_keyboard = enable; - if (!enable && priv->in_keyboard_grab && !priv->in_pointer_grab) - do_keyboard_ungrab(obj, FALSE); -} - -void vnc_display_set_read_only(VncDisplay *obj, gboolean enable) -{ - obj->priv->read_only = enable; -} - -GType vnc_display_credential_get_type(void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - { VNC_DISPLAY_CREDENTIAL_PASSWORD, "VNC_DISPLAY_CREDENTIAL_PASSWORD", "password" }, - { VNC_DISPLAY_CREDENTIAL_USERNAME, "VNC_DISPLAY_CREDENTIAL_USERNAME", "username" }, - { VNC_DISPLAY_CREDENTIAL_CLIENTNAME, "VNC_DISPLAY_CREDENTIAL_CLIENTNAME", "clientname" }, - { 0, NULL, NULL } - }; - etype = g_enum_register_static ("VncDisplayCredentialType", values ); - } - - return etype; -} - -GType vnc_display_key_event_get_type(void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - { VNC_DISPLAY_KEY_EVENT_PRESS, "VNC_DISPLAY_KEY_EVENT_PRESS", "press" }, - { VNC_DISPLAY_KEY_EVENT_RELEASE, "VNC_DISPLAY_KEY_EVENT_RELEASE", "release" }, - { VNC_DISPLAY_KEY_EVENT_CLICK, "VNC_DISPLAY_KEY_EVENT_CLICK", "click" }, - { 0, NULL, NULL } - }; - etype = g_enum_register_static ("VncDisplayKeyEvents", values ); - } - - return etype; -} - -GdkPixbuf *vnc_display_get_pixbuf(VncDisplay *obj) -{ - VncDisplayPrivate *priv = obj->priv; - GdkPixbuf *pixbuf; - - if (!priv->gvnc || - !gvnc_is_initialized(priv->gvnc)) - return NULL; - - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, - priv->image->width, priv->image->height); - - if (!gdk_pixbuf_get_from_image(pixbuf, - priv->image, - gdk_colormap_get_system(), - 0, 0, 0, 0, - priv->image->width, - priv->image->height)) - return NULL; - - return pixbuf; -} - - -int vnc_display_get_width(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), -1); - - return gvnc_get_width (obj->priv->gvnc); -} - -int vnc_display_get_height(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), -1); - - return gvnc_get_height (obj->priv->gvnc); -} - -const char * vnc_display_get_name(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), NULL); - - return gvnc_get_name (obj->priv->gvnc); -} - -void vnc_display_client_cut_text(VncDisplay *obj, const gchar *text) -{ - g_return_if_fail (VNC_IS_DISPLAY (obj)); - - gvnc_client_cut_text(obj->priv->gvnc, text, strlen (text)); -} - -void vnc_display_set_lossy_encoding(VncDisplay *obj, gboolean enable) -{ - g_return_if_fail (VNC_IS_DISPLAY (obj)); - obj->priv->allow_lossy = enable; -} - -void vnc_display_set_shared_flag(VncDisplay *obj, gboolean shared) -{ - g_return_if_fail (VNC_IS_DISPLAY (obj)); - obj->priv->shared_flag = shared; -} - -#if WITH_GTKGLEXT -gboolean vnc_display_set_scaling(VncDisplay *obj, gboolean enable) -{ - GtkWidget *widget = GTK_WIDGET(obj); - gint width, height; - - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - if (obj->priv->gl_config == NULL) - return FALSE; - - obj->priv->allow_scaling = enable; - if (gvnc_is_open(obj->priv->gvnc) && widget->window) { - gdk_drawable_get_size(widget->window, &width, &height); - rescale_display(obj, width, height); - gtk_widget_queue_draw_area(widget, 0, 0, width, height); - } - - return TRUE; -} -#else -gboolean vnc_display_set_scaling(VncDisplay *obj G_GNUC_UNUSED, - gboolean enable G_GNUC_UNUSED) -{ - return FALSE; -} -#endif - -void vnc_display_set_force_size(VncDisplay *obj, gboolean enabled) -{ - g_return_if_fail (VNC_IS_DISPLAY (obj)); - obj->priv->force_size = enabled; -} - -gboolean vnc_display_get_force_size(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->force_size; -} - -gboolean vnc_display_get_scaling(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->allow_scaling; -} - -gboolean vnc_display_get_lossy_encoding(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->allow_lossy; -} - -gboolean vnc_display_get_shared_flag(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->shared_flag; -} - -gboolean vnc_display_get_pointer_local(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->local_pointer; -} - -gboolean vnc_display_get_pointer_grab(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->grab_pointer; -} - -gboolean vnc_display_get_keyboard_grab(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->grab_keyboard; -} - -gboolean vnc_display_get_read_only(VncDisplay *obj) -{ - g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE); - - return obj->priv->read_only; -} - -gboolean vnc_display_is_pointer_absolute(VncDisplay *obj) -{ - return obj->priv->absolute; -} - -GOptionGroup * -vnc_display_get_option_group (void) -{ - GOptionGroup *group; - - group = g_option_group_new ("gtk-vnc", "GTK-VNC Options", "Show GTK-VNC Options", NULL, NULL); - - g_option_group_add_entries (group, gtk_vnc_args); - - return group; -} - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff -urN gtk-vnc-0.3.7/vc-list-files gtk-vnc-0.3.7.mingw/vc-list-files --- gtk-vnc-0.3.7/vc-list-files 1970-01-01 01:00:00.000000000 +0100 +++ gtk-vnc-0.3.7.mingw/vc-list-files 2008-10-09 12:19:03.000000000 +0100 @@ -0,0 +1,107 @@ +#!/bin/sh +# List version-controlled file names. + +# Print a version string. +scriptversion=2008-07-11.19 + +# Copyright (C) 2006-2008 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# List the specified version-controlled files. +# With no argument, list them all. With a single DIRECTORY argument, +# list the version-controlled files in that directory. + +# If there's an argument, it must be a single, "."-relative directory name. +# cvsu is part of the cvsutils package: http://www.red-bean.com/cvsutils/ + +postprocess= +case $1 in + --help) cat <. +EOF + exit ;; + + --version) + year=`echo "$scriptversion" | sed 's/[^0-9].*//'` + cat < +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +EOF + exit ;; + + -C) + test "$2" = . || postprocess="| sed 's|^|$2/|'" + cd "$2" || exit 1 + shift; shift ;; +esac + +dir= +case $# in + 0) ;; + 1) dir=$1 ;; + *) echo "$0: too many arguments" 1>&2 + echo "Usage: $0 [-C srcdir] [DIR]" 1>&2; exit 1;; +esac + +test "x$dir" = x && dir=. + +if test -d .git; then + eval exec git ls-files '"$dir"' $postprocess +elif test -d .hg; then + eval exec hg locate '"$dir/*"' $postprocess +elif test -d .bzr; then + test "$postprocess" = '' && postprocess="| sed 's|^\./||'" + eval exec bzr ls --versioned '"$dir"' $postprocess +elif test -d CVS; then + test "$postprocess" = '' && postprocess="| sed 's|^\./||'" + if test -x build-aux/cvsu; then + eval build-aux/cvsu --find --types=AFGM '"$dir"' $postprocess + elif (cvsu --help) >/dev/null 2>&1; then + eval cvsu --find --types=AFGM '"$dir"' $postprocess + else + eval awk -F/ \''{ \ + if (!$1 && $3 !~ /^-/) { \ + f=FILENAME; \ + if (f ~ /CVS\/Entries$/) \ + f = substr(f, 0, length(f)-11); \ + print f $2; \ + }}'\'' \ + `find "$dir" -name Entries -print` /dev/null' $postprocess + fi +else + echo "$0: Failed to determine type of version control used in `pwd`" 1>&2 + exit 1 +fi + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: