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