|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 - Mateus Cesar Groess
|
|
|
|
*
|
|
|
|
* 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 2 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
#include <rfb/rfbclient.h>
|
|
|
|
|
|
|
|
#ifdef LIBVNCSERVER_CONFIG_LIBVA
|
|
|
|
#include <gdk/gdkx.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static rfbClient *cl;
|
|
|
|
static gchar *server_cut_text = NULL;
|
|
|
|
static gboolean framebuffer_allocated = FALSE;
|
|
|
|
static GtkWidget *window;
|
|
|
|
static GtkWidget *dialog_connecting = NULL;
|
|
|
|
|
|
|
|
/* Redraw the screen from the backing pixmap */
|
|
|
|
static gboolean expose_event (GtkWidget *widget,
|
|
|
|
GdkEventExpose *event)
|
|
|
|
{
|
|
|
|
static GdkImage *image = NULL;
|
|
|
|
|
|
|
|
if (framebuffer_allocated == FALSE) {
|
|
|
|
|
|
|
|
rfbClientSetClientData (cl, gtk_init, widget);
|
|
|
|
|
|
|
|
image = gdk_drawable_get_image (widget->window, 0, 0,
|
|
|
|
widget->allocation.width,
|
|
|
|
widget->allocation.height);
|
|
|
|
|
|
|
|
cl->frameBuffer= image->mem;
|
|
|
|
|
|
|
|
cl->width = widget->allocation.width;
|
|
|
|
cl->height = widget->allocation.height;
|
|
|
|
|
|
|
|
cl->format.bitsPerPixel = image->bits_per_pixel;
|
|
|
|
cl->format.redShift = image->visual->red_shift;
|
|
|
|
cl->format.greenShift = image->visual->green_shift;
|
|
|
|
cl->format.blueShift = image->visual->blue_shift;
|
|
|
|
|
|
|
|
cl->format.redMax = (1 << image->visual->red_prec) - 1;
|
|
|
|
cl->format.greenMax = (1 << image->visual->green_prec) - 1;
|
|
|
|
cl->format.blueMax = (1 << image->visual->blue_prec) - 1;
|
|
|
|
|
|
|
|
#ifdef LIBVNCSERVER_CONFIG_LIBVA
|
|
|
|
/* Allow libvncclient to use a more efficient way
|
|
|
|
* of putting the framebuffer on the screen when
|
|
|
|
* using the H.264 format.
|
|
|
|
*/
|
|
|
|
cl->outputWindow = GDK_WINDOW_XID(widget->window);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SetFormatAndEncodings (cl);
|
|
|
|
|
|
|
|
framebuffer_allocated = TRUE;
|
|
|
|
|
|
|
|
/* Also disable local cursor */
|
|
|
|
GdkCursor* cur = gdk_cursor_new( GDK_BLANK_CURSOR );
|
|
|
|
gdk_window_set_cursor (gtk_widget_get_window(GTK_WIDGET(window)), cur);
|
|
|
|
gdk_cursor_unref( cur );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef LIBVNCSERVER_CONFIG_LIBVA
|
|
|
|
gdk_draw_image (GDK_DRAWABLE (widget->window),
|
|
|
|
widget->style->fg_gc[gtk_widget_get_state(widget)],
|
|
|
|
image,
|
|
|
|
event->area.x, event->area.y,
|
|
|
|
event->area.x, event->area.y,
|
|
|
|
event->area.width, event->area.height);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct { int gdk; int rfb; } buttonMapping[] = {
|
|
|
|
{ GDK_BUTTON1_MASK, rfbButton1Mask },
|
|
|
|
{ GDK_BUTTON2_MASK, rfbButton2Mask },
|
|
|
|
{ GDK_BUTTON3_MASK, rfbButton3Mask },
|
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean button_event (GtkWidget *widget,
|
|
|
|
GdkEventButton *event)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
GdkModifierType state;
|
|
|
|
int i, buttonMask;
|
|
|
|
|
|
|
|
gdk_window_get_pointer (event->window, &x, &y, &state);
|
|
|
|
|
|
|
|
for (buttonMask = 0, i = 0; buttonMapping[i].gdk; i++)
|
|
|
|
if (state & buttonMapping[i].gdk)
|
|
|
|
buttonMask |= buttonMapping[i].rfb;
|
|
|
|
SendPointerEvent (cl, x, y, buttonMask);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean motion_notify_event (GtkWidget *widget,
|
|
|
|
GdkEventMotion *event)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
GdkModifierType state;
|
|
|
|
int i, buttonMask;
|
|
|
|
|
|
|
|
if (event->is_hint)
|
|
|
|
gdk_window_get_pointer (event->window, &x, &y, &state);
|
|
|
|
else {
|
|
|
|
x = event->x;
|
|
|
|
y = event->y;
|
|
|
|
state = event->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (buttonMask = 0, i = 0; buttonMapping[i].gdk; i++)
|
|
|
|
if (state & buttonMapping[i].gdk)
|
|
|
|
buttonMask |= buttonMapping[i].rfb;
|
|
|
|
SendPointerEvent (cl, x, y, buttonMask);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void got_cut_text (rfbClient *cl, const char *text, int textlen)
|
|
|
|
{
|
|
|
|
if (server_cut_text != NULL) {
|
|
|
|
g_free (server_cut_text);
|
|
|
|
server_cut_text = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
server_cut_text = g_strdup (text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void received_text_from_clipboard (GtkClipboard *clipboard,
|
|
|
|
const gchar *text,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
if (text)
|
|
|
|
SendClientCutText (cl, (char *) text, strlen (text));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void clipboard_local_to_remote (GtkMenuItem *menuitem,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkClipboard *clipboard;
|
|
|
|
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (menuitem),
|
|
|
|
GDK_SELECTION_CLIPBOARD);
|
|
|
|
gtk_clipboard_request_text (clipboard, received_text_from_clipboard,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void clipboard_remote_to_local (GtkMenuItem *menuitem,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkClipboard *clipboard;
|
|
|
|
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (menuitem),
|
|
|
|
GDK_SELECTION_CLIPBOARD);
|
|
|
|
|
|
|
|
gtk_clipboard_set_text (clipboard, server_cut_text,
|
|
|
|
strlen (server_cut_text));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void request_screen_refresh (GtkMenuItem *menuitem,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
SendFramebufferUpdateRequest (cl, 0, 0, cl->width, cl->height, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_f8 (GtkMenuItem *menuitem,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
SendKeyEvent(cl, XK_F8, TRUE);
|
|
|
|
SendKeyEvent(cl, XK_F8, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_crtl_alt_del (GtkMenuItem *menuitem,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
SendKeyEvent(cl, XK_Control_L, TRUE);
|
|
|
|
SendKeyEvent(cl, XK_Alt_L, TRUE);
|
|
|
|
SendKeyEvent(cl, XK_Delete, TRUE);
|
|
|
|
SendKeyEvent(cl, XK_Alt_L, FALSE);
|
|
|
|
SendKeyEvent(cl, XK_Control_L, FALSE);
|
|
|
|
SendKeyEvent(cl, XK_Delete, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_connect_window(int argc, char **argv)
|
|
|
|
{
|
|
|
|
GtkWidget *label;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
dialog_connecting = gtk_dialog_new_with_buttons ("VNC Viewer",
|
|
|
|
NULL,
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
/*GTK_STOCK_CANCEL,
|
|
|
|
GTK_RESPONSE_CANCEL,*/
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* FIXME: this works only when address[:port] is at end of arg list */
|
|
|
|
char *server;
|
|
|
|
if(argc==1)
|
|
|
|
server = "localhost";
|
|
|
|
else
|
|
|
|
server = argv[argc-1];
|
|
|
|
snprintf(buf, 255, "Connecting to %s...", server);
|
|
|
|
|
|
|
|
label = gtk_label_new (buf);
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog_connecting)->vbox),
|
|
|
|
label);
|
|
|
|
|
|
|
|
gtk_widget_show (dialog_connecting);
|
|
|
|
|
|
|
|
while (gtk_events_pending ())
|
|
|
|
gtk_main_iteration ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_popup_menu()
|
|
|
|
{
|
|
|
|
GtkWidget *popup_menu;
|
|
|
|
GtkWidget *menu_item;
|
|
|
|
|
|
|
|
popup_menu = gtk_menu_new ();
|
|
|
|
|
|
|
|
menu_item = gtk_menu_item_new_with_label ("Dismiss popup");
|
|
|
|
gtk_widget_show (menu_item);
|
|
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
|
|
|
|
|
|
|
menu_item = gtk_menu_item_new_with_label ("Clipboard: local -> remote");
|
|
|
|
g_signal_connect (G_OBJECT (menu_item), "activate",
|
|
|
|
G_CALLBACK (clipboard_local_to_remote), NULL);
|
|
|
|
gtk_widget_show (menu_item);
|
|
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
|
|
|
|
|
|
|
menu_item = gtk_menu_item_new_with_label ("Clipboard: local <- remote");
|
|
|
|
g_signal_connect (G_OBJECT (menu_item), "activate",
|
|
|
|
G_CALLBACK (clipboard_remote_to_local), NULL);
|
|
|
|
gtk_widget_show (menu_item);
|
|
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
|
|
|
|
|
|
|
menu_item = gtk_menu_item_new_with_label ("Request refresh");
|
|
|
|
g_signal_connect (G_OBJECT (menu_item), "activate",
|
|
|
|
G_CALLBACK (request_screen_refresh), NULL);
|
|
|
|
gtk_widget_show (menu_item);
|
|
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
|
|
|
|
|
|
|
menu_item = gtk_menu_item_new_with_label ("Send ctrl-alt-del");
|
|
|
|
g_signal_connect (G_OBJECT (menu_item), "activate",
|
|
|
|
G_CALLBACK (send_crtl_alt_del), NULL);
|
|
|
|
gtk_widget_show (menu_item);
|
|
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
|
|
|
|
|
|
|
menu_item = gtk_menu_item_new_with_label ("Send F8");
|
|
|
|
g_signal_connect (G_OBJECT (menu_item), "activate",
|
|
|
|
G_CALLBACK (send_f8), NULL);
|
|
|
|
gtk_widget_show (menu_item);
|
|
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
|
|
|
|
|
|
|
gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL, NULL, NULL, 0,
|
|
|
|
gtk_get_current_event_time());
|
|
|
|
}
|
|
|
|
|
|
|
|
static rfbKeySym gdkKey2rfbKeySym(guint keyval)
|
|
|
|
{
|
|
|
|
rfbKeySym k = 0;
|
|
|
|
switch(keyval) {
|
|
|
|
case GDK_BackSpace: k = XK_BackSpace; break;
|
|
|
|
case GDK_Tab: k = XK_Tab; break;
|
|
|
|
case GDK_Clear: k = XK_Clear; break;
|
|
|
|
case GDK_Return: k = XK_Return; break;
|
|
|
|
case GDK_Pause: k = XK_Pause; break;
|
|
|
|
case GDK_Escape: k = XK_Escape; break;
|
|
|
|
case GDK_space: k = XK_space; break;
|
|
|
|
case GDK_Delete: k = XK_Delete; break;
|
|
|
|
case GDK_KP_0: k = XK_KP_0; break;
|
|
|
|
case GDK_KP_1: k = XK_KP_1; break;
|
|
|
|
case GDK_KP_2: k = XK_KP_2; break;
|
|
|
|
case GDK_KP_3: k = XK_KP_3; break;
|
|
|
|
case GDK_KP_4: k = XK_KP_4; break;
|
|
|
|
case GDK_KP_5: k = XK_KP_5; break;
|
|
|
|
case GDK_KP_6: k = XK_KP_6; break;
|
|
|
|
case GDK_KP_7: k = XK_KP_7; break;
|
|
|
|
case GDK_KP_8: k = XK_KP_8; break;
|
|
|
|
case GDK_KP_9: k = XK_KP_9; break;
|
|
|
|
case GDK_KP_Decimal: k = XK_KP_Decimal; break;
|
|
|
|
case GDK_KP_Divide: k = XK_KP_Divide; break;
|
|
|
|
case GDK_KP_Multiply: k = XK_KP_Multiply; break;
|
|
|
|
case GDK_KP_Subtract: k = XK_KP_Subtract; break;
|
|
|
|
case GDK_KP_Add: k = XK_KP_Add; break;
|
|
|
|
case GDK_KP_Enter: k = XK_KP_Enter; break;
|
|
|
|
case GDK_KP_Equal: k = XK_KP_Equal; break;
|
|
|
|
case GDK_Up: k = XK_Up; break;
|
|
|
|
case GDK_Down: k = XK_Down; break;
|
|
|
|
case GDK_Right: k = XK_Right; break;
|
|
|
|
case GDK_Left: k = XK_Left; break;
|
|
|
|
case GDK_Insert: k = XK_Insert; break;
|
|
|
|
case GDK_Home: k = XK_Home; break;
|
|
|
|
case GDK_End: k = XK_End; break;
|
|
|
|
case GDK_Page_Up: k = XK_Page_Up; break;
|
|
|
|
case GDK_Page_Down: k = XK_Page_Down; break;
|
|
|
|
case GDK_F1: k = XK_F1; break;
|
|
|
|
case GDK_F2: k = XK_F2; break;
|
|
|
|
case GDK_F3: k = XK_F3; break;
|
|
|
|
case GDK_F4: k = XK_F4; break;
|
|
|
|
case GDK_F5: k = XK_F5; break;
|
|
|
|
case GDK_F6: k = XK_F6; break;
|
|
|
|
case GDK_F7: k = XK_F7; break;
|
|
|
|
case GDK_F8: k = XK_F8; break;
|
|
|
|
case GDK_F9: k = XK_F9; break;
|
|
|
|
case GDK_F10: k = XK_F10; break;
|
|
|
|
case GDK_F11: k = XK_F11; break;
|
|
|
|
case GDK_F12: k = XK_F12; break;
|
|
|
|
case GDK_F13: k = XK_F13; break;
|
|
|
|
case GDK_F14: k = XK_F14; break;
|
|
|
|
case GDK_F15: k = XK_F15; break;
|
|
|
|
case GDK_Num_Lock: k = XK_Num_Lock; break;
|
|
|
|
case GDK_Caps_Lock: k = XK_Caps_Lock; break;
|
|
|
|
case GDK_Scroll_Lock: k = XK_Scroll_Lock; break;
|
|
|
|
case GDK_Shift_R: k = XK_Shift_R; break;
|
|
|
|
case GDK_Shift_L: k = XK_Shift_L; break;
|
|
|
|
case GDK_Control_R: k = XK_Control_R; break;
|
|
|
|
case GDK_Control_L: k = XK_Control_L; break;
|
|
|
|
case GDK_Alt_R: k = XK_Alt_R; break;
|
|
|
|
case GDK_Alt_L: k = XK_Alt_L; break;
|
|
|
|
case GDK_Meta_R: k = XK_Meta_R; break;
|
|
|
|
case GDK_Meta_L: k = XK_Meta_L; break;
|
|
|
|
#if 0
|
|
|
|
/* TODO: find out keysyms */
|
|
|
|
case GDK_Super_L: k = XK_LSuper; break; /* left "windows" key */
|
|
|
|
case GDK_Super_R: k = XK_RSuper; break; /* right "windows" key */
|
|
|
|
case GDK_Multi_key: k = XK_Compose; break;
|
|
|
|
#endif
|
|
|
|
case GDK_Mode_switch: k = XK_Mode_switch; break;
|
|
|
|
case GDK_Help: k = XK_Help; break;
|
|
|
|
case GDK_Print: k = XK_Print; break;
|
|
|
|
case GDK_Sys_Req: k = XK_Sys_Req; break;
|
|
|
|
case GDK_Break: k = XK_Break; break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
if (k == 0) {
|
|
|
|
if (keyval < 0x100)
|
|
|
|
k = keyval;
|
|
|
|
else
|
|
|
|
rfbClientLog ("Unknown keysym: %d\n", keyval);
|
|
|
|
}
|
|
|
|
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean key_event (GtkWidget *widget, GdkEventKey *event,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
if ((event->type == GDK_KEY_PRESS) && (event->keyval == GDK_F8))
|
|
|
|
show_popup_menu();
|
|
|
|
else
|
|
|
|
SendKeyEvent(cl, gdkKey2rfbKeySym (event->keyval),
|
|
|
|
(event->type == GDK_KEY_PRESS) ? TRUE : FALSE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void quit ()
|
|
|
|
{
|
|
|
|
exit (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static rfbBool resize (rfbClient *client) {
|
|
|
|
GtkWidget *scrolled_window;
|
|
|
|
GtkWidget *drawing_area=NULL;
|
|
|
|
static char first=TRUE;
|
|
|
|
int tmp_width, tmp_height;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
first=FALSE;
|
|
|
|
|
|
|
|
/* Create the drawing area */
|
|
|
|
|
|
|
|
drawing_area = gtk_drawing_area_new ();
|
|
|
|
gtk_widget_set_size_request (GTK_WIDGET (drawing_area),
|
|
|
|
client->width, client->height);
|
|
|
|
|
|
|
|
/* Signals used to handle backing pixmap */
|
|
|
|
|
|
|
|
g_signal_connect (G_OBJECT (drawing_area), "expose_event",
|
|
|
|
G_CALLBACK (expose_event), NULL);
|
|
|
|
|
|
|
|
/* Event signals */
|
|
|
|
|
|
|
|
g_signal_connect (G_OBJECT (drawing_area),
|
|
|
|
"motion-notify-event",
|
|
|
|
G_CALLBACK (motion_notify_event), NULL);
|
|
|
|
g_signal_connect (G_OBJECT (drawing_area),
|
|
|
|
"button-press-event",
|
|
|
|
G_CALLBACK (button_event), NULL);
|
|
|
|
g_signal_connect (G_OBJECT (drawing_area),
|
|
|
|
"button-release-event",
|
|
|
|
G_CALLBACK (button_event), NULL);
|
|
|
|
|
|
|
|
gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
|
|
|
|
| GDK_LEAVE_NOTIFY_MASK
|
|
|
|
| GDK_BUTTON_PRESS_MASK
|
|
|
|
| GDK_BUTTON_RELEASE_MASK
|
|
|
|
| GDK_POINTER_MOTION_MASK
|
|
|
|
| GDK_POINTER_MOTION_HINT_MASK);
|
|
|
|
|
|
|
|
gtk_widget_show (drawing_area);
|
|
|
|
|
|
|
|
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
|
|
|
GTK_POLICY_AUTOMATIC,
|
|
|
|
GTK_POLICY_AUTOMATIC);
|
|
|
|
gtk_scrolled_window_add_with_viewport (
|
|
|
|
GTK_SCROLLED_WINDOW (scrolled_window),
|
|
|
|
drawing_area);
|
|
|
|
g_signal_connect (G_OBJECT (scrolled_window),
|
|
|
|
"key-press-event", G_CALLBACK (key_event),
|
|
|
|
NULL);
|
|
|
|
g_signal_connect (G_OBJECT (scrolled_window),
|
|
|
|
"key-release-event", G_CALLBACK (key_event),
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (scrolled_window);
|
|
|
|
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (window), client->desktopName);
|
|
|
|
gtk_container_add (GTK_CONTAINER (window), scrolled_window);
|
|
|
|
tmp_width = (int) (
|
|
|
|
gdk_screen_get_width (gdk_screen_get_default ())
|
|
|
|
* 0.85);
|
|
|
|
if (client->width > tmp_width) {
|
|
|
|
tmp_height = (int) (
|
|
|
|
gdk_screen_get_height (
|
|
|
|
gdk_screen_get_default ())
|
|
|
|
* 0.85);
|
|
|
|
gtk_widget_set_size_request (window,
|
|
|
|
tmp_width, tmp_height);
|
|
|
|
} else {
|
|
|
|
gtk_widget_set_size_request (window,
|
|
|
|
client->width + 2,
|
|
|
|
client->height + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_connect (G_OBJECT (window), "destroy",
|
|
|
|
G_CALLBACK (quit), NULL);
|
|
|
|
|
|
|
|
gtk_widget_show (window);
|
|
|
|
} else {
|
|
|
|
gtk_widget_set_size_request (GTK_WIDGET (drawing_area),
|
|
|
|
client->width, client->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update (rfbClient *cl, int x, int y, int w, int h) {
|
|
|
|
if (dialog_connecting != NULL) {
|
|
|
|
gtk_widget_destroy (dialog_connecting);
|
|
|
|
dialog_connecting = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef LIBVNCSERVER_CONFIG_LIBVA
|
|
|
|
GtkWidget *drawing_area = rfbClientGetClientData (cl, gtk_init);
|
|
|
|
|
|
|
|
if (drawing_area != NULL)
|
|
|
|
gtk_widget_queue_draw_area (drawing_area, x, y, w, h);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kbd_leds (rfbClient *cl, int value, int pad) {
|
|
|
|
/* note: pad is for future expansion 0=unused */
|
|
|
|
fprintf (stderr, "Led State= 0x%02X\n", value);
|
|
|
|
fflush (stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* trivial support for textchat */
|
|
|
|
static void text_chat (rfbClient *cl, int value, char *text) {
|
|
|
|
switch (value) {
|
|
|
|
case rfbTextChatOpen:
|
|
|
|
fprintf (stderr, "TextChat: We should open a textchat window!\n");
|
|
|
|
TextChatOpen (cl);
|
|
|
|
break;
|
|
|
|
case rfbTextChatClose:
|
|
|
|
fprintf (stderr, "TextChat: We should close our window!\n");
|
|
|
|
break;
|
|
|
|
case rfbTextChatFinished:
|
|
|
|
fprintf (stderr, "TextChat: We should close our window!\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf (stderr, "TextChat: Received \"%s\"\n", text);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fflush (stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean on_entry_key_press_event (GtkWidget *widget, GdkEventKey *event,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
if (event->keyval == GDK_Escape)
|
|
|
|
gtk_dialog_response (GTK_DIALOG(user_data), GTK_RESPONSE_REJECT);
|
|
|
|
else if (event->keyval == GDK_Return)
|
|
|
|
gtk_dialog_response (GTK_DIALOG(user_data), GTK_RESPONSE_ACCEPT);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GtkErrorLog (const char *format, ...)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog, *label;
|
|
|
|
va_list args;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
if (dialog_connecting != NULL) {
|
|
|
|
gtk_widget_destroy (dialog_connecting);
|
|
|
|
dialog_connecting = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
vsnprintf (buf, 255, format, args);
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
if (g_utf8_validate (buf, strlen (buf), NULL)) {
|
|
|
|
label = gtk_label_new (buf);
|
|
|
|
} else {
|
|
|
|
const gchar *charset;
|
|
|
|
gchar *utf8;
|
|
|
|
|
|
|
|
(void) g_get_charset (&charset);
|
|
|
|
utf8 = g_convert_with_fallback (buf, strlen (buf), "UTF-8",
|
|
|
|
charset, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (utf8) {
|
|
|
|
label = gtk_label_new (utf8);
|
|
|
|
g_free (utf8);
|
|
|
|
} else {
|
|
|
|
label = gtk_label_new (buf);
|
|
|
|
g_warning ("Message Output is not in UTF-8"
|
|
|
|
"nor in locale charset.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dialog = gtk_dialog_new_with_buttons ("Error",
|
|
|
|
NULL,
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_OK,
|
|
|
|
GTK_RESPONSE_ACCEPT,
|
|
|
|
NULL);
|
|
|
|
label = gtk_label_new (buf);
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
|
|
|
|
label);
|
|
|
|
gtk_widget_show (dialog);
|
|
|
|
|
|
|
|
switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
|
|
|
|
case GTK_RESPONSE_ACCEPT:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GtkDefaultLog (const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char buf[256];
|
|
|
|
time_t log_clock;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
|
|
|
|
time (&log_clock);
|
|
|
|
strftime (buf, 255, "%d/%m/%Y %X ", localtime (&log_clock));
|
|
|
|
fprintf (stdout, buf);
|
|
|
|
|
|
|
|
vfprintf (stdout, format, args);
|
|
|
|
fflush (stdout);
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char * get_password (rfbClient *client)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog, *entry;
|
|
|
|
char *password;
|
|
|
|
|
|
|
|
gtk_widget_destroy (dialog_connecting);
|
|
|
|
dialog_connecting = NULL;
|
|
|
|
|
|
|
|
dialog = gtk_dialog_new_with_buttons ("Password",
|
|
|
|
NULL,
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_CANCEL,
|
|
|
|
GTK_RESPONSE_REJECT,
|
|
|
|
GTK_STOCK_OK,
|
|
|
|
GTK_RESPONSE_ACCEPT,
|
|
|
|
NULL);
|
|
|
|
entry = gtk_entry_new ();
|
|
|
|
gtk_entry_set_visibility (GTK_ENTRY (entry),
|
|
|
|
FALSE);
|
|
|
|
g_signal_connect (GTK_OBJECT(entry), "key-press-event",
|
|
|
|
G_CALLBACK(on_entry_key_press_event),
|
|
|
|
GTK_OBJECT (dialog));
|
|
|
|
gtk_widget_show (entry);
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
|
|
|
|
entry);
|
|
|
|
gtk_widget_show (dialog);
|
|
|
|
|
|
|
|
switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
|
|
|
|
case GTK_RESPONSE_ACCEPT:
|
|
|
|
password = strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
password = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
return password;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
GdkImage *image;
|
|
|
|
|
|
|
|
rfbClientLog = GtkDefaultLog;
|
|
|
|
rfbClientErr = GtkErrorLog;
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
/* create a dummy image just to make use of its properties */
|
|
|
|
image = gdk_image_new (GDK_IMAGE_FASTEST, gdk_visual_get_system(),
|
|
|
|
200, 100);
|
|
|
|
|
|
|
|
cl = rfbGetClient (image->depth / 3, 3, image->bpp);
|
|
|
|
|
|
|
|
cl->format.redShift = image->visual->red_shift;
|
|
|
|
cl->format.greenShift = image->visual->green_shift;
|
|
|
|
cl->format.blueShift = image->visual->blue_shift;
|
|
|
|
|
|
|
|
cl->format.redMax = (1 << image->visual->red_prec) - 1;
|
|
|
|
cl->format.greenMax = (1 << image->visual->green_prec) - 1;
|
|
|
|
cl->format.blueMax = (1 << image->visual->blue_prec) - 1;
|
|
|
|
|
|
|
|
g_object_unref (image);
|
|
|
|
|
|
|
|
cl->MallocFrameBuffer = resize;
|
|
|
|
cl->canHandleNewFBSize = TRUE;
|
|
|
|
cl->GotFrameBufferUpdate = update;
|
|
|
|
cl->GotXCutText = got_cut_text;
|
|
|
|
cl->HandleKeyboardLedState = kbd_leds;
|
|
|
|
cl->HandleTextChat = text_chat;
|
|
|
|
cl->GetPassword = get_password;
|
|
|
|
|
|
|
|
show_connect_window (argc, argv);
|
|
|
|
|
|
|
|
if (!rfbInitClient (cl, &argc, argv))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
while (gtk_events_pending ())
|
|
|
|
gtk_main_iteration ();
|
|
|
|
i = WaitForMessage (cl, 500);
|
|
|
|
if (i < 0)
|
|
|
|
return 0;
|
|
|
|
if (i && framebuffer_allocated == TRUE)
|
|
|
|
if (!HandleRFBServerMessage(cl))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|