1 
2 /*
3  * Copyright (C) 2007 - Mateus Cesar Groess
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include <stdlib.h>
22 #include <gtk/gtk.h>
23 #include <gdk/gdkkeysyms.h>
24 #include <rfb/rfbclient.h>
25 
26 #ifdef LIBVNCSERVER_CONFIG_LIBVA
27 #include <gdk/gdkx.h>
28 #endif
29 
30 static rfbClient *cl;
31 static gchar *server_cut_text = NULL;
32 static gboolean framebuffer_allocated = FALSE;
33 static GtkWidget *window;
34 static GtkWidget *dialog_connecting = NULL;
35 
36 /* Redraw the screen from the backing pixmap */
expose_event(GtkWidget * widget,GdkEventExpose * event)37 static gboolean expose_event (GtkWidget      *widget,
38                               GdkEventExpose *event)
39 {
40 	static GdkImage *image = NULL;
41 
42 	if (framebuffer_allocated == FALSE) {
43 
44 		rfbClientSetClientData (cl, gtk_init, widget);
45 
46 		image = gdk_drawable_get_image (widget->window, 0, 0,
47 		                                widget->allocation.width,
48 		                                widget->allocation.height);
49 
50 		cl->frameBuffer= image->mem;
51 
52 		cl->width  = widget->allocation.width;
53 		cl->height = widget->allocation.height;
54 
55 		cl->format.bitsPerPixel = image->bits_per_pixel;
56 		cl->format.redShift     = image->visual->red_shift;
57 		cl->format.greenShift   = image->visual->green_shift;
58 		cl->format.blueShift    = image->visual->blue_shift;
59 
60 		cl->format.redMax   = (1 << image->visual->red_prec) - 1;
61 		cl->format.greenMax = (1 << image->visual->green_prec) - 1;
62 		cl->format.blueMax  = (1 << image->visual->blue_prec) - 1;
63 
64 #ifdef LIBVNCSERVER_CONFIG_LIBVA
65 		/* Allow libvncclient to use a more efficient way
66 		 * of putting the framebuffer on the screen when
67 		 * using the H.264 format.
68 		 */
69 		cl->outputWindow = GDK_WINDOW_XID(widget->window);
70 #endif
71 
72 		SetFormatAndEncodings (cl);
73 
74 		framebuffer_allocated = TRUE;
75 
76 		/* Also disable local cursor */
77 		GdkCursor* cur = gdk_cursor_new( GDK_BLANK_CURSOR );
78 		gdk_window_set_cursor (gtk_widget_get_window(GTK_WIDGET(window)), cur);
79 		gdk_cursor_unref( cur );
80 	}
81 
82 #ifndef LIBVNCSERVER_CONFIG_LIBVA
83 	gdk_draw_image (GDK_DRAWABLE (widget->window),
84 	                widget->style->fg_gc[gtk_widget_get_state(widget)],
85 	                image,
86 	                event->area.x, event->area.y,
87 	                event->area.x, event->area.y,
88 	                event->area.width, event->area.height);
89 #endif
90 
91 	return FALSE;
92 }
93 
94 struct { int gdk; int rfb; } buttonMapping[] = {
95 	{ GDK_BUTTON1_MASK, rfbButton1Mask },
96 	{ GDK_BUTTON2_MASK, rfbButton2Mask },
97 	{ GDK_BUTTON3_MASK, rfbButton3Mask },
98 	{ 0, 0 }
99 };
100 
button_event(GtkWidget * widget,GdkEventButton * event)101 static gboolean button_event (GtkWidget      *widget,
102                               GdkEventButton *event)
103 {
104 	int x, y;
105 	GdkModifierType state;
106 	int i, buttonMask;
107 
108 	gdk_window_get_pointer (event->window, &x, &y, &state);
109 
110 	for (buttonMask = 0, i = 0; buttonMapping[i].gdk; i++)
111 		if (state & buttonMapping[i].gdk)
112 			buttonMask |= buttonMapping[i].rfb;
113 	SendPointerEvent (cl, x, y, buttonMask);
114 
115 	return TRUE;
116 }
117 
motion_notify_event(GtkWidget * widget,GdkEventMotion * event)118 static gboolean motion_notify_event (GtkWidget *widget,
119                                      GdkEventMotion *event)
120 {
121 	int x, y;
122 	GdkModifierType state;
123 	int i, buttonMask;
124 
125 	if (event->is_hint)
126 		gdk_window_get_pointer (event->window, &x, &y, &state);
127 	else {
128 		x = event->x;
129 		y = event->y;
130 		state = event->state;
131 	}
132 
133 	for (buttonMask = 0, i = 0; buttonMapping[i].gdk; i++)
134 		if (state & buttonMapping[i].gdk)
135 			buttonMask |= buttonMapping[i].rfb;
136 	SendPointerEvent (cl, x, y, buttonMask);
137 
138 	return TRUE;
139 }
140 
got_cut_text(rfbClient * cl,const char * text,int textlen)141 static void got_cut_text (rfbClient *cl, const char *text, int textlen)
142 {
143 	if (server_cut_text != NULL) {
144 		g_free (server_cut_text);
145 		server_cut_text = NULL;
146 	}
147 
148 	server_cut_text = g_strdup (text);
149 }
150 
received_text_from_clipboard(GtkClipboard * clipboard,const gchar * text,gpointer data)151 void received_text_from_clipboard (GtkClipboard *clipboard,
152                                    const gchar *text,
153                                    gpointer data)
154 {
155 	if (text)
156 		SendClientCutText (cl, (char *) text, strlen (text));
157 }
158 
clipboard_local_to_remote(GtkMenuItem * menuitem,gpointer user_data)159 static void clipboard_local_to_remote (GtkMenuItem *menuitem,
160                                        gpointer     user_data)
161 {
162 	GtkClipboard *clipboard;
163 
164 	clipboard = gtk_widget_get_clipboard (GTK_WIDGET (menuitem),
165 	                                      GDK_SELECTION_CLIPBOARD);
166 	gtk_clipboard_request_text (clipboard, received_text_from_clipboard,
167 	                            NULL);
168 }
169 
clipboard_remote_to_local(GtkMenuItem * menuitem,gpointer user_data)170 static void clipboard_remote_to_local (GtkMenuItem *menuitem,
171                                        gpointer     user_data)
172 {
173 	GtkClipboard *clipboard;
174 
175 	clipboard = gtk_widget_get_clipboard (GTK_WIDGET (menuitem),
176 	                                      GDK_SELECTION_CLIPBOARD);
177 
178 	gtk_clipboard_set_text (clipboard, server_cut_text,
179 	                        strlen (server_cut_text));
180 }
181 
request_screen_refresh(GtkMenuItem * menuitem,gpointer user_data)182 static void request_screen_refresh (GtkMenuItem *menuitem,
183                                     gpointer     user_data)
184 {
185 	SendFramebufferUpdateRequest (cl, 0, 0, cl->width, cl->height, FALSE);
186 }
187 
send_f8(GtkMenuItem * menuitem,gpointer user_data)188 static void send_f8 (GtkMenuItem *menuitem,
189                      gpointer     user_data)
190 {
191 	SendKeyEvent(cl, XK_F8, TRUE);
192 	SendKeyEvent(cl, XK_F8, FALSE);
193 }
194 
send_crtl_alt_del(GtkMenuItem * menuitem,gpointer user_data)195 static void send_crtl_alt_del (GtkMenuItem *menuitem,
196                                gpointer     user_data)
197 {
198 	SendKeyEvent(cl, XK_Control_L, TRUE);
199 	SendKeyEvent(cl, XK_Alt_L, TRUE);
200 	SendKeyEvent(cl, XK_Delete, TRUE);
201 	SendKeyEvent(cl, XK_Alt_L, FALSE);
202 	SendKeyEvent(cl, XK_Control_L, FALSE);
203 	SendKeyEvent(cl, XK_Delete, FALSE);
204 }
205 
show_connect_window(int argc,char ** argv)206 static void show_connect_window(int argc, char **argv)
207 {
208 	GtkWidget *label;
209 	char buf[256];
210 
211 	dialog_connecting = gtk_dialog_new_with_buttons ("VNC Viewer",
212 	                                       NULL,
213 	                                       GTK_DIALOG_DESTROY_WITH_PARENT,
214 	                                       /*GTK_STOCK_CANCEL,
215 	                                       GTK_RESPONSE_CANCEL,*/
216 	                                       NULL);
217 
218 	/* FIXME: this works only when address[:port] is at end of arg list */
219 	char *server;
220 	if(argc==1)
221 	    server = "localhost";
222 	else
223 	   server = argv[argc-1];
224 	snprintf(buf, 255, "Connecting to %s...", server);
225 
226 	label = gtk_label_new (buf);
227 	gtk_widget_show (label);
228 
229 	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog_connecting)->vbox),
230 	                   label);
231 
232 	gtk_widget_show (dialog_connecting);
233 
234 	while (gtk_events_pending ())
235 		gtk_main_iteration ();
236 }
237 
show_popup_menu()238 static void show_popup_menu()
239 {
240 	GtkWidget *popup_menu;
241 	GtkWidget *menu_item;
242 
243 	popup_menu = gtk_menu_new ();
244 
245 	menu_item = gtk_menu_item_new_with_label ("Dismiss popup");
246 	gtk_widget_show (menu_item);
247 	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
248 
249 	menu_item = gtk_menu_item_new_with_label ("Clipboard: local -> remote");
250 	g_signal_connect (G_OBJECT (menu_item), "activate",
251 	                  G_CALLBACK (clipboard_local_to_remote), NULL);
252 	gtk_widget_show (menu_item);
253 	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
254 
255 	menu_item = gtk_menu_item_new_with_label ("Clipboard: local <- remote");
256 	g_signal_connect (G_OBJECT (menu_item), "activate",
257 	                  G_CALLBACK (clipboard_remote_to_local), NULL);
258 	gtk_widget_show (menu_item);
259 	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
260 
261 	menu_item = gtk_menu_item_new_with_label ("Request refresh");
262 	g_signal_connect (G_OBJECT (menu_item), "activate",
263 	                  G_CALLBACK (request_screen_refresh), NULL);
264 	gtk_widget_show (menu_item);
265 	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
266 
267 	menu_item = gtk_menu_item_new_with_label ("Send ctrl-alt-del");
268 	g_signal_connect (G_OBJECT (menu_item), "activate",
269 	                  G_CALLBACK (send_crtl_alt_del), NULL);
270 	gtk_widget_show (menu_item);
271 	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
272 
273 	menu_item = gtk_menu_item_new_with_label ("Send F8");
274 	g_signal_connect (G_OBJECT (menu_item), "activate",
275 	                  G_CALLBACK (send_f8), NULL);
276 	gtk_widget_show (menu_item);
277 	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
278 
279 	gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL, NULL, NULL, 0,
280 	                gtk_get_current_event_time());
281 }
282 
gdkKey2rfbKeySym(guint keyval)283 static rfbKeySym gdkKey2rfbKeySym(guint keyval)
284 {
285 	rfbKeySym k = 0;
286 	switch(keyval) {
287 	case GDK_BackSpace: k = XK_BackSpace; break;
288 	case GDK_Tab: k = XK_Tab; break;
289 	case GDK_Clear: k = XK_Clear; break;
290 	case GDK_Return: k = XK_Return; break;
291 	case GDK_Pause: k = XK_Pause; break;
292 	case GDK_Escape: k = XK_Escape; break;
293 	case GDK_space: k = XK_space; break;
294 	case GDK_Delete: k = XK_Delete; break;
295 	case GDK_KP_0: k = XK_KP_0; break;
296 	case GDK_KP_1: k = XK_KP_1; break;
297 	case GDK_KP_2: k = XK_KP_2; break;
298 	case GDK_KP_3: k = XK_KP_3; break;
299 	case GDK_KP_4: k = XK_KP_4; break;
300 	case GDK_KP_5: k = XK_KP_5; break;
301 	case GDK_KP_6: k = XK_KP_6; break;
302 	case GDK_KP_7: k = XK_KP_7; break;
303 	case GDK_KP_8: k = XK_KP_8; break;
304 	case GDK_KP_9: k = XK_KP_9; break;
305 	case GDK_KP_Decimal: k = XK_KP_Decimal; break;
306 	case GDK_KP_Divide: k = XK_KP_Divide; break;
307 	case GDK_KP_Multiply: k = XK_KP_Multiply; break;
308 	case GDK_KP_Subtract: k = XK_KP_Subtract; break;
309 	case GDK_KP_Add: k = XK_KP_Add; break;
310 	case GDK_KP_Enter: k = XK_KP_Enter; break;
311 	case GDK_KP_Equal: k = XK_KP_Equal; break;
312 	case GDK_Up: k = XK_Up; break;
313 	case GDK_Down: k = XK_Down; break;
314 	case GDK_Right: k = XK_Right; break;
315 	case GDK_Left: k = XK_Left; break;
316 	case GDK_Insert: k = XK_Insert; break;
317 	case GDK_Home: k = XK_Home; break;
318 	case GDK_End: k = XK_End; break;
319 	case GDK_Page_Up: k = XK_Page_Up; break;
320 	case GDK_Page_Down: k = XK_Page_Down; break;
321 	case GDK_F1: k = XK_F1; break;
322 	case GDK_F2: k = XK_F2; break;
323 	case GDK_F3: k = XK_F3; break;
324 	case GDK_F4: k = XK_F4; break;
325 	case GDK_F5: k = XK_F5; break;
326 	case GDK_F6: k = XK_F6; break;
327 	case GDK_F7: k = XK_F7; break;
328 	case GDK_F8: k = XK_F8; break;
329 	case GDK_F9: k = XK_F9; break;
330 	case GDK_F10: k = XK_F10; break;
331 	case GDK_F11: k = XK_F11; break;
332 	case GDK_F12: k = XK_F12; break;
333 	case GDK_F13: k = XK_F13; break;
334 	case GDK_F14: k = XK_F14; break;
335 	case GDK_F15: k = XK_F15; break;
336 	case GDK_Num_Lock: k = XK_Num_Lock; break;
337 	case GDK_Caps_Lock: k = XK_Caps_Lock; break;
338 	case GDK_Scroll_Lock: k = XK_Scroll_Lock; break;
339 	case GDK_Shift_R: k = XK_Shift_R; break;
340 	case GDK_Shift_L: k = XK_Shift_L; break;
341 	case GDK_Control_R: k = XK_Control_R; break;
342 	case GDK_Control_L: k = XK_Control_L; break;
343 	case GDK_Alt_R: k = XK_Alt_R; break;
344 	case GDK_Alt_L: k = XK_Alt_L; break;
345 	case GDK_Meta_R: k = XK_Meta_R; break;
346 	case GDK_Meta_L: k = XK_Meta_L; break;
347 #if 0
348 	/* TODO: find out keysyms */
349 	case GDK_Super_L: k = XK_LSuper; break;      /* left "windows" key */
350 	case GDK_Super_R: k = XK_RSuper; break;      /* right "windows" key */
351 	case GDK_Multi_key: k = XK_Compose; break;
352 #endif
353 	case GDK_Mode_switch: k = XK_Mode_switch; break;
354 	case GDK_Help: k = XK_Help; break;
355 	case GDK_Print: k = XK_Print; break;
356 	case GDK_Sys_Req: k = XK_Sys_Req; break;
357 	case GDK_Break: k = XK_Break; break;
358 	default: break;
359 	}
360 	if (k == 0) {
361 		if (keyval < 0x100)
362 			k = keyval;
363 		else
364 			rfbClientLog ("Unknown keysym: %d\n", keyval);
365 	}
366 
367 	return k;
368 }
369 
key_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)370 static gboolean key_event (GtkWidget *widget, GdkEventKey *event,
371                                  gpointer user_data)
372 {
373 	if ((event->type == GDK_KEY_PRESS) && (event->keyval == GDK_F8))
374 		show_popup_menu();
375 	else
376 		SendKeyEvent(cl, gdkKey2rfbKeySym (event->keyval),
377 		             (event->type == GDK_KEY_PRESS) ? TRUE : FALSE);
378 	return FALSE;
379 }
380 
quit()381 void quit ()
382 {
383 	exit (0);
384 }
385 
resize(rfbClient * client)386 static rfbBool resize (rfbClient *client) {
387 	GtkWidget *scrolled_window;
388 	GtkWidget *drawing_area=NULL;
389 	static char first=TRUE;
390 	int tmp_width, tmp_height;
391 
392 	if (first) {
393 		first=FALSE;
394 
395 		/* Create the drawing area */
396 
397 		drawing_area = gtk_drawing_area_new ();
398 		gtk_widget_set_size_request (GTK_WIDGET (drawing_area),
399 		                             client->width, client->height);
400 
401 		/* Signals used to handle backing pixmap */
402 
403 		g_signal_connect (G_OBJECT (drawing_area), "expose_event",
404 		                  G_CALLBACK (expose_event), NULL);
405 
406 		/* Event signals */
407 
408 		g_signal_connect (G_OBJECT (drawing_area),
409 		                  "motion-notify-event",
410 		                  G_CALLBACK (motion_notify_event), NULL);
411 		g_signal_connect (G_OBJECT (drawing_area),
412 		                  "button-press-event",
413 		                  G_CALLBACK (button_event), NULL);
414 		g_signal_connect (G_OBJECT (drawing_area),
415 		                  "button-release-event",
416 		                  G_CALLBACK (button_event), NULL);
417 
418 		gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
419 		                       | GDK_LEAVE_NOTIFY_MASK
420 		                       | GDK_BUTTON_PRESS_MASK
421 		                       | GDK_BUTTON_RELEASE_MASK
422 		                       | GDK_POINTER_MOTION_MASK
423 		                       | GDK_POINTER_MOTION_HINT_MASK);
424 
425 		gtk_widget_show (drawing_area);
426 
427 		scrolled_window = gtk_scrolled_window_new (NULL, NULL);
428 		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
429 		                                GTK_POLICY_AUTOMATIC,
430 		                                GTK_POLICY_AUTOMATIC);
431 		gtk_scrolled_window_add_with_viewport (
432 		                  GTK_SCROLLED_WINDOW (scrolled_window),
433 		                  drawing_area);
434 		g_signal_connect (G_OBJECT (scrolled_window),
435 		                  "key-press-event", G_CALLBACK (key_event),
436 		                  NULL);
437 		g_signal_connect (G_OBJECT (scrolled_window),
438 		                  "key-release-event", G_CALLBACK (key_event),
439 		                  NULL);
440 		gtk_widget_show (scrolled_window);
441 
442 		window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
443 		gtk_window_set_title (GTK_WINDOW (window), client->desktopName);
444 		gtk_container_add (GTK_CONTAINER (window), scrolled_window);
445 		tmp_width = (int) (
446 		            gdk_screen_get_width (gdk_screen_get_default ())
447 		            * 0.85);
448 		if (client->width > tmp_width) {
449 			tmp_height = (int) (
450 			             gdk_screen_get_height (
451 			                     gdk_screen_get_default ())
452 			             * 0.85);
453 			gtk_widget_set_size_request (window,
454 			                             tmp_width, tmp_height);
455 		} else {
456 			gtk_widget_set_size_request (window,
457 			       client->width + 2,
458 			       client->height + 2);
459 		}
460 
461 		g_signal_connect (G_OBJECT (window), "destroy",
462 		                  G_CALLBACK (quit), NULL);
463 
464 		gtk_widget_show (window);
465 	} else {
466 		gtk_widget_set_size_request (GTK_WIDGET (drawing_area),
467 		                             client->width, client->height);
468 	}
469 
470 	return TRUE;
471 }
472 
update(rfbClient * cl,int x,int y,int w,int h)473 static void update (rfbClient *cl, int x, int y, int w, int h) {
474 	if (dialog_connecting != NULL) {
475 		gtk_widget_destroy (dialog_connecting);
476 		dialog_connecting = NULL;
477 	}
478 
479 #ifndef LIBVNCSERVER_CONFIG_LIBVA
480 	GtkWidget *drawing_area = rfbClientGetClientData (cl, gtk_init);
481 
482 	if (drawing_area != NULL)
483 		gtk_widget_queue_draw_area (drawing_area, x, y, w, h);
484 #endif
485 }
486 
kbd_leds(rfbClient * cl,int value,int pad)487 static void kbd_leds (rfbClient *cl, int value, int pad) {
488         /* note: pad is for future expansion 0=unused */
489         fprintf (stderr, "Led State= 0x%02X\n", value);
490         fflush (stderr);
491 }
492 
493 /* trivial support for textchat */
text_chat(rfbClient * cl,int value,char * text)494 static void text_chat (rfbClient *cl, int value, char *text) {
495         switch (value) {
496         case rfbTextChatOpen:
497                 fprintf (stderr, "TextChat: We should open a textchat window!\n");
498                 TextChatOpen (cl);
499                 break;
500         case rfbTextChatClose:
501                 fprintf (stderr, "TextChat: We should close our window!\n");
502                 break;
503         case rfbTextChatFinished:
504                 fprintf (stderr, "TextChat: We should close our window!\n");
505                 break;
506         default:
507                 fprintf (stderr, "TextChat: Received \"%s\"\n", text);
508                 break;
509         }
510         fflush (stderr);
511 }
512 
on_entry_key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)513 static gboolean on_entry_key_press_event (GtkWidget *widget, GdkEventKey *event,
514                                           gpointer user_data)
515 {
516 	if (event->keyval == GDK_Escape)
517 		gtk_dialog_response (GTK_DIALOG(user_data), GTK_RESPONSE_REJECT);
518 	else if (event->keyval == GDK_Return)
519 		gtk_dialog_response (GTK_DIALOG(user_data), GTK_RESPONSE_ACCEPT);
520 
521 	return FALSE;
522 }
523 
GtkErrorLog(const char * format,...)524 static void GtkErrorLog (const char *format, ...)
525 {
526 	GtkWidget *dialog, *label;
527 	va_list args;
528 	char buf[256];
529 
530 	if (dialog_connecting != NULL) {
531 		gtk_widget_destroy (dialog_connecting);
532 		dialog_connecting = NULL;
533 	}
534 
535 	va_start (args, format);
536 	vsnprintf (buf, 255, format, args);
537 	va_end (args);
538 
539 	if (g_utf8_validate (buf, strlen (buf), NULL)) {
540 		label = gtk_label_new (buf);
541 	} else {
542 		const gchar *charset;
543 		gchar       *utf8;
544 
545 		(void) g_get_charset (&charset);
546 		utf8 = g_convert_with_fallback (buf, strlen (buf), "UTF-8",
547 		                                charset, NULL, NULL, NULL, NULL);
548 
549 		if (utf8) {
550 			label = gtk_label_new (utf8);
551 			g_free (utf8);
552 		} else {
553 			label = gtk_label_new (buf);
554 			g_warning ("Message Output is not in UTF-8"
555 			           "nor in locale charset.\n");
556 		}
557 	}
558 
559 	dialog = gtk_dialog_new_with_buttons ("Error",
560 	                                       NULL,
561 	                                       GTK_DIALOG_DESTROY_WITH_PARENT,
562 	                                       GTK_STOCK_OK,
563 	                                       GTK_RESPONSE_ACCEPT,
564 	                                       NULL);
565 	label = gtk_label_new (buf);
566 	gtk_widget_show (label);
567 
568 	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
569 	                   label);
570 	gtk_widget_show (dialog);
571 
572 	switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
573 	case GTK_RESPONSE_ACCEPT:
574 		break;
575 	default:
576 		break;
577 	}
578 	gtk_widget_destroy (dialog);
579 }
580 
GtkDefaultLog(const char * format,...)581 static void GtkDefaultLog (const char *format, ...)
582 {
583 	va_list args;
584 	char buf[256];
585 	time_t log_clock;
586 
587 	va_start (args, format);
588 
589 	time (&log_clock);
590 	strftime (buf, 255, "%d/%m/%Y %X ", localtime (&log_clock));
591 	fprintf (stdout, buf);
592 
593 	vfprintf (stdout, format, args);
594 	fflush (stdout);
595 
596 	va_end (args);
597 }
598 
get_password(rfbClient * client)599 static char * get_password (rfbClient *client)
600 {
601 	GtkWidget *dialog, *entry;
602 	char *password;
603 
604 	gtk_widget_destroy (dialog_connecting);
605 	dialog_connecting = NULL;
606 
607 	dialog = gtk_dialog_new_with_buttons ("Password",
608 	                                       NULL,
609 	                                       GTK_DIALOG_DESTROY_WITH_PARENT,
610 	                                       GTK_STOCK_CANCEL,
611 	                                       GTK_RESPONSE_REJECT,
612 	                                       GTK_STOCK_OK,
613 	                                       GTK_RESPONSE_ACCEPT,
614 	                                       NULL);
615 	entry = gtk_entry_new ();
616 	gtk_entry_set_visibility (GTK_ENTRY (entry),
617 	                          FALSE);
618 	g_signal_connect (GTK_OBJECT(entry), "key-press-event",
619 	                    G_CALLBACK(on_entry_key_press_event),
620 	                    GTK_OBJECT (dialog));
621 	gtk_widget_show (entry);
622 
623 	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
624 	                   entry);
625 	gtk_widget_show (dialog);
626 
627 	switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
628 	case GTK_RESPONSE_ACCEPT:
629 		password = strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
630 		break;
631 	default:
632 		password = NULL;
633 		break;
634 	}
635 	gtk_widget_destroy (dialog);
636 	return password;
637 }
638 
main(int argc,char * argv[])639 int main (int argc, char *argv[])
640 {
641 	int i;
642 	GdkImage *image;
643 
644 	rfbClientLog = GtkDefaultLog;
645 	rfbClientErr = GtkErrorLog;
646 
647 	gtk_init (&argc, &argv);
648 
649 	/* create a dummy image just to make use of its properties */
650 	image = gdk_image_new (GDK_IMAGE_FASTEST, gdk_visual_get_system(),
651 				200, 100);
652 
653 	cl = rfbGetClient (image->depth / 3, 3, image->bpp);
654 
655 	cl->format.redShift     = image->visual->red_shift;
656 	cl->format.greenShift   = image->visual->green_shift;
657 	cl->format.blueShift    = image->visual->blue_shift;
658 
659 	cl->format.redMax   = (1 << image->visual->red_prec) - 1;
660 	cl->format.greenMax = (1 << image->visual->green_prec) - 1;
661 	cl->format.blueMax  = (1 << image->visual->blue_prec) - 1;
662 
663 	g_object_unref (image);
664 
665 	cl->MallocFrameBuffer = resize;
666 	cl->canHandleNewFBSize = TRUE;
667 	cl->GotFrameBufferUpdate = update;
668 	cl->GotXCutText = got_cut_text;
669 	cl->HandleKeyboardLedState = kbd_leds;
670 	cl->HandleTextChat = text_chat;
671 	cl->GetPassword = get_password;
672 
673 	show_connect_window (argc, argv);
674 
675 	if (!rfbInitClient (cl, &argc, argv))
676 		return 1;
677 
678 	while (1) {
679 		while (gtk_events_pending ())
680 			gtk_main_iteration ();
681 		i = WaitForMessage (cl, 500);
682 		if (i < 0)
683 			return 0;
684 		if (i && framebuffer_allocated == TRUE)
685 			if (!HandleRFBServerMessage(cl))
686 				return 0;
687 	}
688 
689 	gtk_main ();
690 
691 	return 0;
692 }
693 
694