2
* Remmina - The GTK+ Remote Desktop Client
3
* Copyright (C) 2009 - Vic Lee
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.
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.
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.
22
#include <glib/gstdio.h>
23
#include <glib/gi18n.h>
34
#include "remminapublic.h"
35
#include "remminapref.h"
36
#include "remminafile.h"
37
#include "remminainitdialog.h"
38
#include "remminachatwindow.h"
39
#include "remminaplug.h"
40
#include "remminaplug_vnc.h"
42
G_DEFINE_TYPE (RemminaPlugVnc, remmina_plug_vnc, REMMINA_TYPE_PLUG)
44
#define dot_cursor_width 5
45
#define dot_cursor_height 5
46
#define dot_cursor_x_hot 2
47
#define dot_cursor_y_hot 2
48
static const gchar dot_cursor_bits[] = {
49
0x00, 0x0e, 0x0e, 0x0e, 0x00 };
50
static const gchar dot_cursor_mask_bits[] = {
51
0x0e, 0x1f, 0x1f, 0x1f, 0x0e };
54
#define LOCK_BUFFER(t) if(t){CANCEL_DEFER}pthread_mutex_lock(&gp_vnc->buffer_mutex);
55
#define UNLOCK_BUFFER(t) pthread_mutex_unlock(&gp_vnc->buffer_mutex);if(t){CANCEL_ASYNC}
57
#define LOCK_BUFFER(t)
58
#define UNLOCK_BUFFER(t)
63
REMMINA_PLUG_VNC_EVENT_KEY,
64
REMMINA_PLUG_VNC_EVENT_POINTER,
65
REMMINA_PLUG_VNC_EVENT_CUTTEXT,
66
REMMINA_PLUG_VNC_EVENT_CHAT_OPEN,
67
REMMINA_PLUG_VNC_EVENT_CHAT_SEND,
68
REMMINA_PLUG_VNC_EVENT_CHAT_CLOSE
70
typedef struct _RemminaPlugVncEvent
91
} RemminaPlugVncEvent;
94
remmina_plug_vnc_event_push (RemminaPlugVnc *gp_vnc, gint event_type, gpointer p1, gpointer p2, gpointer p3)
96
RemminaPlugVncEvent *event;
98
event = g_new (RemminaPlugVncEvent, 1);
99
event->event_type = event_type;
102
case REMMINA_PLUG_VNC_EVENT_KEY:
103
event->event_data.key.keyval = GPOINTER_TO_UINT (p1);
104
event->event_data.key.pressed = GPOINTER_TO_INT (p2);
106
case REMMINA_PLUG_VNC_EVENT_POINTER:
107
event->event_data.pointer.x = GPOINTER_TO_INT (p1);
108
event->event_data.pointer.y = GPOINTER_TO_INT (p2);
109
event->event_data.pointer.button_mask = GPOINTER_TO_INT (p3);
111
case REMMINA_PLUG_VNC_EVENT_CUTTEXT:
112
case REMMINA_PLUG_VNC_EVENT_CHAT_SEND:
113
event->event_data.text.text = g_strdup ((char*) p1);
118
g_queue_push_tail (gp_vnc->vnc_event_queue, event);
119
if (write (gp_vnc->vnc_event_pipe[1], "\0", 1))
126
remmina_plug_vnc_event_free (RemminaPlugVncEvent *event)
128
switch (event->event_type)
130
case REMMINA_PLUG_VNC_EVENT_CUTTEXT:
131
case REMMINA_PLUG_VNC_EVENT_CHAT_SEND:
132
g_free (event->event_data.text.text);
141
remmina_plug_vnc_event_free_all (RemminaPlugVnc *gp_vnc)
143
RemminaPlugVncEvent *event;
145
while ((event = g_queue_pop_head (gp_vnc->vnc_event_queue)) != NULL)
147
remmina_plug_vnc_event_free (event);
152
remmina_plug_vnc_scale_area (RemminaPlugVnc *gp_vnc, gint *x, gint *y, gint *w, gint *h)
154
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
157
if (gp_vnc->rgb_buffer == NULL || gp_vnc->scale_buffer == NULL) return;
159
if (gp_vnc->scale_width == gp->width && gp_vnc->scale_height == gp->height)
161
/* Same size, just copy the pixels */
162
gdk_pixbuf_copy_area (gp_vnc->rgb_buffer, *x, *y, *w, *h, gp_vnc->scale_buffer, *x, *y);
166
/* We have to extend the scaled region 2 scaled pixels, to avoid gaps */
167
sx = MIN (MAX (0, (*x) * gp_vnc->scale_width / gp->width
168
- gp_vnc->scale_width / gp->width - 2), gp_vnc->scale_width - 1);
169
sy = MIN (MAX (0, (*y) * gp_vnc->scale_height / gp->height
170
- gp_vnc->scale_height / gp->height - 2), gp_vnc->scale_height - 1);
171
sw = MIN (gp_vnc->scale_width - sx, (*w) * gp_vnc->scale_width / gp->width
172
+ gp_vnc->scale_width / gp->width + 4);
173
sh = MIN (gp_vnc->scale_height - sy, (*h) * gp_vnc->scale_height / gp->height
174
+ gp_vnc->scale_height / gp->height + 4);
176
gdk_pixbuf_scale (gp_vnc->rgb_buffer, gp_vnc->scale_buffer,
180
(double) gp_vnc->scale_width / (double) gp->width,
181
(double) gp_vnc->scale_height / (double) gp->height,
182
remmina_pref.scale_quality);
184
*x = sx; *y = sy; *w = sw; *h = sh;
188
remmina_plug_vnc_update_scale_buffer (RemminaPlugVnc *gp_vnc, gboolean in_thread)
190
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
197
width = GTK_WIDGET (gp_vnc)->allocation.width;
198
height = GTK_WIDGET (gp_vnc)->allocation.height;
201
if (width > 1 && height > 1)
203
LOCK_BUFFER (in_thread)
205
if (gp_vnc->scale_buffer)
207
g_object_unref (gp_vnc->scale_buffer);
209
gp_vnc->scale_width = (gp->remmina_file->hscale > 0 ?
210
MAX (1, gp->width * gp->remmina_file->hscale / 100) : width);
211
gp_vnc->scale_height = (gp->remmina_file->vscale > 0 ?
212
MAX (1, gp->height * gp->remmina_file->vscale / 100) : height);
214
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
215
gp_vnc->scale_width, gp_vnc->scale_height);
216
gp_vnc->scale_buffer = pixbuf;
218
x = 0; y = 0; w = gp->width; h = gp->height;
219
remmina_plug_vnc_scale_area (gp_vnc, &x, &y, &w, &h);
221
UNLOCK_BUFFER (in_thread)
226
LOCK_BUFFER (in_thread)
228
if (gp_vnc->scale_buffer)
230
g_object_unref (gp_vnc->scale_buffer);
231
gp_vnc->scale_buffer = NULL;
233
gp_vnc->scale_width = 0;
234
gp_vnc->scale_height = 0;
236
UNLOCK_BUFFER (in_thread)
238
if (width > 1 && height > 1)
243
gtk_widget_queue_draw_area (GTK_WIDGET (gp_vnc), 0, 0, width, height);
248
gtk_widget_queue_draw_area (GTK_WIDGET (gp_vnc), 0, 0, width, height);
252
gp_vnc->scale_handler = 0;
257
remmina_plug_vnc_update_scale_buffer_main (RemminaPlugVnc *gp_vnc)
259
return remmina_plug_vnc_update_scale_buffer (gp_vnc, FALSE);
263
remmina_plug_vnc_update_scale (RemminaPlugVnc *gp_vnc, gboolean scale)
265
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
269
gtk_widget_set_size_request (GTK_WIDGET (gp_vnc->drawing_area),
270
(gp->remmina_file->hscale > 0 ? gp->width * gp->remmina_file->hscale / 100 : -1),
271
(gp->remmina_file->vscale > 0 ? gp->height * gp->remmina_file->vscale / 100 : -1));
275
gtk_widget_set_size_request (GTK_WIDGET (gp_vnc->drawing_area), gp->width, gp->height);
279
#ifdef HAVE_LIBVNCCLIENT
281
typedef struct _RemminaKeyVal
287
/***************************** LibVNCClient related codes *********************************/
288
#include <rfb/rfbclient.h>
291
remmina_plug_vnc_process_vnc_event (RemminaPlugVnc *gp_vnc)
293
rfbClient *cl = (rfbClient*) gp_vnc->client;
294
RemminaPlugVncEvent *event;
297
while ((event = g_queue_pop_head (gp_vnc->vnc_event_queue)) != NULL)
301
switch (event->event_type)
303
case REMMINA_PLUG_VNC_EVENT_KEY:
304
SendKeyEvent (cl, event->event_data.key.keyval, event->event_data.key.pressed);
306
case REMMINA_PLUG_VNC_EVENT_POINTER:
307
SendPointerEvent (cl, event->event_data.pointer.x, event->event_data.pointer.y,
308
event->event_data.pointer.button_mask);
310
case REMMINA_PLUG_VNC_EVENT_CUTTEXT:
311
SendClientCutText (cl, event->event_data.text.text, strlen (event->event_data.text.text));
313
case REMMINA_PLUG_VNC_EVENT_CHAT_OPEN:
316
case REMMINA_PLUG_VNC_EVENT_CHAT_SEND:
317
TextChatSend (cl, event->event_data.text.text);
319
case REMMINA_PLUG_VNC_EVENT_CHAT_CLOSE:
325
remmina_plug_vnc_event_free (event);
327
if (read (gp_vnc->vnc_event_pipe[0], buf, sizeof (buf)))
333
typedef struct _RemminaPlugVncCuttextParam
335
RemminaPlugVnc *gp_vnc;
338
} RemminaPlugVncCuttextParam;
341
remmina_plug_vnc_update_quality (rfbClient *cl, gint quality)
346
cl->appData.useBGR233 = 0;
347
cl->appData.encodingsString = "copyrect hextile raw";
348
cl->appData.compressLevel = 0;
349
cl->appData.qualityLevel = 9;
352
cl->appData.useBGR233 = 0;
353
cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
354
cl->appData.compressLevel = 3;
355
cl->appData.qualityLevel = 7;
358
cl->appData.useBGR233 = 0;
359
cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
360
cl->appData.compressLevel = 5;
361
cl->appData.qualityLevel = 5;
365
cl->appData.useBGR233 = 1;
366
cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
367
cl->appData.compressLevel = 9;
368
cl->appData.qualityLevel = 0;
374
remmina_plug_vnc_update_colordepth (rfbClient *cl, gint colordepth)
376
cl->format.depth = colordepth;
377
cl->format.bigEndian = 0;
378
cl->appData.requestedDepth = colordepth;
383
cl->format.bitsPerPixel = 32;
384
cl->format.redMax = 0xff;
385
cl->format.greenMax = 0xff;
386
cl->format.blueMax = 0xff;
387
cl->format.redShift = 16;
388
cl->format.greenShift = 8;
389
cl->format.blueShift = 0;
392
cl->format.bitsPerPixel = 16;
393
cl->format.redMax = 0x1f;
394
cl->format.greenMax = 0x3f;
395
cl->format.blueMax = 0x1f;
396
cl->format.redShift = 11;
397
cl->format.greenShift = 5;
398
cl->format.blueShift = 0;
401
cl->format.bitsPerPixel = 16;
402
cl->format.redMax = 0x1f;
403
cl->format.greenMax = 0x1f;
404
cl->format.blueMax = 0x1f;
405
cl->format.redShift = 10;
406
cl->format.greenShift = 5;
407
cl->format.blueShift = 0;
411
cl->format.bitsPerPixel = 8;
412
cl->format.redMax = 7;
413
cl->format.greenMax = 7;
414
cl->format.blueMax = 3;
415
cl->format.redShift = 0;
416
cl->format.greenShift = 3;
417
cl->format.blueShift = 6;
423
remmina_plug_vnc_rfb_allocfb (rfbClient *cl)
425
RemminaPlugVnc *gp_vnc;
427
gint width, height, depth, size;
428
GdkPixbuf *new_pixbuf, *old_pixbuf;
430
gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
431
gp = REMMINA_PLUG (gp_vnc);
435
depth = cl->format.bitsPerPixel;
436
size = width * height * (depth / 8);
438
/* Putting gdk_pixbuf_new inside a gdk_thread_enter/leave pair could cause dead-lock! */
439
new_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
440
if (new_pixbuf == NULL) return FALSE;
441
gdk_pixbuf_fill (new_pixbuf, 0);
442
old_pixbuf = gp_vnc->rgb_buffer;
446
gp->width = cl->width;
447
gp->height = cl->height;
449
gp_vnc->rgb_buffer = new_pixbuf;
451
if (gp_vnc->vnc_buffer) g_free (gp_vnc->vnc_buffer);
452
gp_vnc->vnc_buffer = (guchar*) g_malloc (size);
453
cl->frameBuffer = gp_vnc->vnc_buffer;
457
if (old_pixbuf) g_object_unref (old_pixbuf);
460
remmina_plug_vnc_update_scale (gp_vnc, gp->scale);
463
if (gp_vnc->scale_handler == 0) remmina_plug_vnc_update_scale_buffer (gp_vnc, TRUE);
465
/* Notify window of change so that scroll border can be hidden or shown if needed */
466
remmina_plug_emit_signal (gp, "desktop-resize");
468
/* Refresh the client's updateRect - bug in xvncclient */
469
cl->updateRect.w = width;
470
cl->updateRect.h = height;
476
remmina_plug_vnc_bits (gint n)
479
while (n) { b++; n >>= 1; }
484
remmina_plug_vnc_queue_draw_area_real (RemminaPlugVnc *gp_vnc)
488
if (GTK_IS_WIDGET (gp_vnc) && gp_vnc->connected)
491
x = gp_vnc->queuedraw_x;
492
y = gp_vnc->queuedraw_y;
493
w = gp_vnc->queuedraw_w;
494
h = gp_vnc->queuedraw_h;
495
gp_vnc->queuedraw_handler = 0;
496
UNLOCK_BUFFER (FALSE)
498
gtk_widget_queue_draw_area (GTK_WIDGET (gp_vnc), x, y, w, h);
504
remmina_plug_vnc_queue_draw_area (RemminaPlugVnc *gp_vnc, gint x, gint y, gint w, gint h)
506
gint nx2, ny2, ox2, oy2;
509
if (gp_vnc->queuedraw_handler)
513
ox2 = gp_vnc->queuedraw_x + gp_vnc->queuedraw_w;
514
oy2 = gp_vnc->queuedraw_y + gp_vnc->queuedraw_h;
515
gp_vnc->queuedraw_x = MIN (gp_vnc->queuedraw_x, x);
516
gp_vnc->queuedraw_y = MIN (gp_vnc->queuedraw_y, y);
517
gp_vnc->queuedraw_w = MAX (ox2, nx2) - gp_vnc->queuedraw_x;
518
gp_vnc->queuedraw_h = MAX (oy2, ny2) - gp_vnc->queuedraw_y;
522
gp_vnc->queuedraw_x = x;
523
gp_vnc->queuedraw_y = y;
524
gp_vnc->queuedraw_w = w;
525
gp_vnc->queuedraw_h = h;
526
gp_vnc->queuedraw_handler = IDLE_ADD ((GSourceFunc) remmina_plug_vnc_queue_draw_area_real, gp_vnc);
532
remmina_plug_vnc_rfb_updatefb (rfbClient* cl, int x, int y, int w, int h)
534
RemminaPlugVnc *gp_vnc;
537
guchar *destptr, *srcptr;
542
gint rs, gs, bs, rm, gm, bm, rb, gb, bb;
544
gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
545
gp = REMMINA_PLUG (gp_vnc);
549
if (w >= 1 || h >= 1)
553
bytesPerPixel = cl->format.bitsPerPixel / 8;
554
rowstride = gdk_pixbuf_get_rowstride (gp_vnc->rgb_buffer);
555
switch (cl->format.bitsPerPixel)
558
/* The following codes swap red/green value */
559
for (iy = y; iy < y2; iy++)
561
destptr = gdk_pixbuf_get_pixels (gp_vnc->rgb_buffer) + iy * rowstride + x * 3;
562
srcptr = gp_vnc->vnc_buffer + ((iy * gp->width + x) * bytesPerPixel);
563
for (ix = x; ix < x2; ix++)
565
*destptr++ = *(srcptr + 2);
566
*destptr++ = *(srcptr + 1);
567
*destptr++ = *srcptr;
573
rm = cl->format.redMax;
574
gm = cl->format.greenMax;
575
bm = cl->format.blueMax;
576
rb = 8 - remmina_plug_vnc_bits (rm);
577
gb = 8 - remmina_plug_vnc_bits (gm);
578
bb = 8 - remmina_plug_vnc_bits (bm);
579
rs = cl->format.redShift;
580
gs = cl->format.greenShift;
581
bs = cl->format.blueShift;
582
for (iy = y; iy < y2; iy++)
584
destptr = gdk_pixbuf_get_pixels (gp_vnc->rgb_buffer) + iy * rowstride + x * 3;
585
srcptr = gp_vnc->vnc_buffer + ((iy * gp->width + x) * bytesPerPixel);
586
for (ix = x; ix < x2; ix++)
589
for (i = 0; i < bytesPerPixel; i++) pixel += (*srcptr++) << (8 * i);
590
*destptr++ = ((pixel >> rs) & rm) << rb;
591
*destptr++ = ((pixel >> gs) & gm) << gb;
592
*destptr++ = ((pixel >> bs) & bm) << bb;
601
remmina_plug_vnc_scale_area (gp_vnc, &x, &y, &w, &h);
606
remmina_plug_vnc_queue_draw_area (gp_vnc, x, y, w, h);
610
remmina_plug_vnc_queue_cuttext (RemminaPlugVncCuttextParam *param)
612
RemminaPlugVnc *gp_vnc;
616
gp_vnc = param->gp_vnc;
617
if (GTK_IS_WIDGET (gp_vnc) && gp_vnc->connected)
619
g_get_current_time (&t);
620
diff = (t.tv_sec - gp_vnc->clipboard_timer.tv_sec) * 10 + (t.tv_usec - gp_vnc->clipboard_timer.tv_usec) / 100000;
623
gp_vnc->clipboard_timer = t;
624
gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), param->text, param->textlen);
627
g_free (param->text);
633
remmina_plug_vnc_rfb_cuttext (rfbClient* cl, const char *text, int textlen)
635
RemminaPlugVncCuttextParam *param;
637
param = g_new (RemminaPlugVncCuttextParam, 1);
638
param->gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
639
param->text = g_malloc (textlen);
640
memcpy (param->text, text, textlen);
641
param->textlen = textlen;
642
IDLE_ADD ((GSourceFunc) remmina_plug_vnc_queue_cuttext, param);
646
remmina_plug_vnc_rfb_password (rfbClient *cl)
648
RemminaPlugVnc *gp_vnc;
654
gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
655
gp_vnc->auth_called = TRUE;
656
gp = REMMINA_PLUG (gp_vnc);
658
dialog = gp->init_dialog;
660
if (gp_vnc->auth_first && gp->remmina_file->password && gp->remmina_file->password[0] != '\0')
662
pwd = g_strdup (gp->remmina_file->password);
667
ret = remmina_init_dialog_authpwd (REMMINA_INIT_DIALOG (dialog), _("VNC Password"),
668
(gp->remmina_file->filename != NULL));
671
if (ret == GTK_RESPONSE_OK)
673
pwd = g_strdup (REMMINA_INIT_DIALOG (dialog)->password);
677
gp_vnc->connected = FALSE;
683
#ifdef LIBVNCSERVER_WITH_CLIENT_TLS
684
static rfbCredential*
685
remmina_plug_vnc_rfb_credential (rfbClient *cl, int credentialType)
688
RemminaPlugVnc *gp_vnc;
694
gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
695
gp_vnc->auth_called = TRUE;
696
gp = REMMINA_PLUG (gp_vnc);
698
dialog = gp->init_dialog;
700
cred = g_new0 (rfbCredential, 1);
702
switch (credentialType)
705
case rfbCredentialTypeUser:
707
if (gp_vnc->auth_first &&
708
gp->remmina_file->username && gp->remmina_file->username[0] != '\0' &&
709
gp->remmina_file->password && gp->remmina_file->password[0] != '\0')
711
cred->userCredential.username = g_strdup (gp->remmina_file->username);
712
cred->userCredential.password = g_strdup (gp->remmina_file->password);
717
ret = remmina_init_dialog_authuserpwd (REMMINA_INIT_DIALOG (dialog), gp->remmina_file->username,
718
(gp->remmina_file->filename != NULL));
721
if (ret == GTK_RESPONSE_OK)
723
cred->userCredential.username = g_strdup (REMMINA_INIT_DIALOG (dialog)->username);
724
cred->userCredential.password = g_strdup (REMMINA_INIT_DIALOG (dialog)->password);
730
gp_vnc->connected = FALSE;
735
case rfbCredentialTypeX509:
736
if (gp_vnc->auth_first &&
737
gp->remmina_file->cacert && gp->remmina_file->cacert[0] != '\0')
739
s = gp->remmina_file->cacert;
740
cred->x509Credential.x509CACertFile = (s && s[0] ? g_strdup (s) : NULL);
741
s = gp->remmina_file->cacrl;
742
cred->x509Credential.x509CACrlFile = (s && s[0] ? g_strdup (s) : NULL);
743
s = gp->remmina_file->clientcert;
744
cred->x509Credential.x509ClientCertFile = (s && s[0] ? g_strdup (s) : NULL);
745
s = gp->remmina_file->clientkey;
746
cred->x509Credential.x509ClientKeyFile = (s && s[0] ? g_strdup (s) : NULL);
751
ret = remmina_init_dialog_authx509 (REMMINA_INIT_DIALOG (dialog), gp->remmina_file->cacert,
752
gp->remmina_file->cacrl, gp->remmina_file->clientcert, gp->remmina_file->clientkey);
755
if (ret == GTK_RESPONSE_OK)
757
s = REMMINA_INIT_DIALOG (dialog)->cacert;
758
cred->x509Credential.x509CACertFile = (s && s[0] ? g_strdup (s) : NULL);
759
s = REMMINA_INIT_DIALOG (dialog)->cacrl;
760
cred->x509Credential.x509CACrlFile = (s && s[0] ? g_strdup (s) : NULL);
761
s = REMMINA_INIT_DIALOG (dialog)->clientcert;
762
cred->x509Credential.x509ClientCertFile = (s && s[0] ? g_strdup (s) : NULL);
763
s = REMMINA_INIT_DIALOG (dialog)->clientkey;
764
cred->x509Credential.x509ClientKeyFile = (s && s[0] ? g_strdup (s) : NULL);
770
gp_vnc->connected = FALSE;
785
remmina_plug_vnc_rfb_cursor_shape (rfbClient *cl, int xhot, int yhot, int width, int height, int bytesPerPixel)
787
RemminaPlugVnc *gp_vnc;
790
guchar *destptr, *srcptr, *srcmaskptr;
792
gint rs, gs, bs, rm, gm, bm, rb, gb, bb;
798
gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
799
if (!GTK_WIDGET (gp_vnc)->window) return;
803
pixbuf_data = g_malloc (width * height * 4);
805
switch (cl->format.bitsPerPixel)
808
/* The following codes fill in the Alpha channel of the cursor and swap red/blue value */
809
destptr = pixbuf_data;
810
srcptr = cl->rcSource;
811
srcmaskptr = cl->rcMask;
812
for (iy = 0; iy < width * height; iy++)
814
*destptr++ = *(srcptr + 2);
815
*destptr++ = *(srcptr + 1);
816
*destptr++ = *srcptr;
817
*destptr++ = (*srcmaskptr++) ? 0xff : 0x00;
822
rm = cl->format.redMax;
823
gm = cl->format.greenMax;
824
bm = cl->format.blueMax;
825
rb = 8 - remmina_plug_vnc_bits (rm);
826
gb = 8 - remmina_plug_vnc_bits (gm);
827
bb = 8 - remmina_plug_vnc_bits (bm);
828
rs = cl->format.redShift;
829
gs = cl->format.greenShift;
830
bs = cl->format.blueShift;
831
destptr = pixbuf_data;
832
srcptr = cl->rcSource;
833
srcmaskptr = cl->rcMask;
834
for (iy = 0; iy < width * height; iy++)
837
for (i = 0; i < bytesPerPixel; i++) pixel += (*srcptr++) << (8 * i);
838
*destptr++ = ((pixel >> rs) & rm) << rb;
839
*destptr++ = ((pixel >> gs) & gm) << gb;
840
*destptr++ = ((pixel >> bs) & bm) << bb;
841
*destptr++ = (*srcmaskptr++) ? 0xff : 0x00;
846
pixbuf = gdk_pixbuf_new_from_data (pixbuf_data, GDK_COLORSPACE_RGB,
847
TRUE, 8, width, height,
848
width * 4, NULL, NULL);
851
display = gdk_drawable_get_display (GDK_DRAWABLE (GTK_WIDGET (gp_vnc)->window));
853
cursor = gdk_cursor_new_from_pixbuf (display,
857
gdk_window_set_cursor (GTK_WIDGET (gp_vnc)->window, cursor);
858
gdk_cursor_unref (cursor);
862
gdk_pixbuf_unref (pixbuf);
864
g_free (pixbuf_data);
869
remmina_plug_vnc_rfb_bell (rfbClient *cl)
871
RemminaPlugVnc *gp_vnc;
874
gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
875
window = GTK_WIDGET (gp_vnc)->window;
877
gdk_window_beep (window);
880
/* Translate known VNC messages. It's for intltool only, not for gcc */
881
#ifdef __DO_NOT_COMPILE_ME__
882
N_("Unable to connect to VNC server")
883
N_("Couldn't convert '%s' to host address")
884
N_("VNC connection failed: %s")
885
N_("Your connection has been rejected.")
887
/* TODO: We only store the last message at this moment. */
888
static gchar vnc_error[MAX_ERROR_LENGTH + 1];
890
remmina_plug_vnc_rfb_output(const char *format, ...)
893
va_start(args, format);
896
/* eliminate the last \n */
897
f = g_strdup (format);
898
if (f[strlen (f) - 1] == '\n') f[strlen (f) - 1] = '\0';
900
/*g_printf("%s,len=%i\n", f, strlen(f));*/
901
if (g_strcmp0 (f, "VNC connection failed: %s") == 0)
903
p = va_arg (args, gchar*);
904
/*g_printf("(param)%s,len=%i\n", p, strlen(p));*/
905
g_snprintf (vnc_error, MAX_ERROR_LENGTH, _(f), _(p));
909
g_vsnprintf (vnc_error, MAX_ERROR_LENGTH, _(f), args);
911
/*g_print ("%s\n", vnc_error);*/
918
remmina_plug_vnc_chat_send (GtkWidget *window, gchar *text, RemminaPlugVnc *gp_vnc)
922
/* Need to add a line-feed for UltraVNC */
923
ptr = g_strdup_printf ("%s\n", text);
924
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_CHAT_SEND, ptr, NULL, NULL);
929
remmina_plug_vnc_chat_window_destroy (GtkWidget *widget, RemminaPlugVnc *gp_vnc)
931
gp_vnc->chat_window = NULL;
932
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_CHAT_CLOSE, NULL, NULL, NULL);
936
remmina_plug_vnc_close_chat (RemminaPlugVnc *gp_vnc)
938
if (gp_vnc->chat_window)
940
gtk_widget_destroy (gp_vnc->chat_window);
946
remmina_plug_vnc_open_chat (RemminaPlugVnc *gp_vnc)
948
rfbClient *cl = (rfbClient*) gp_vnc->client;
950
if (gp_vnc->chat_window)
952
gtk_window_present (GTK_WINDOW (gp_vnc->chat_window));
956
gp_vnc->chat_window = remmina_chat_window_new (
957
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gp_vnc))),
959
g_signal_connect (G_OBJECT (gp_vnc->chat_window), "destroy",
960
G_CALLBACK (remmina_plug_vnc_chat_window_destroy), gp_vnc);
961
g_signal_connect (G_OBJECT (gp_vnc->chat_window), "send",
962
G_CALLBACK (remmina_plug_vnc_chat_send), gp_vnc);
963
gtk_widget_show (gp_vnc->chat_window);
965
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_CHAT_OPEN, NULL, NULL, NULL);
970
remmina_plug_vnc_rfb_chat (rfbClient* cl, int value, char *text)
972
RemminaPlugVnc *gp_vnc;
974
gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
977
case rfbTextChatOpen:
978
IDLE_ADD ((GSourceFunc) remmina_plug_vnc_open_chat, gp_vnc);
980
case rfbTextChatClose:
981
/* Do nothing... but wait for the next rfbTextChatFinished signal */
983
case rfbTextChatFinished:
984
IDLE_ADD ((GSourceFunc) remmina_plug_vnc_close_chat, gp_vnc);
987
/* value is the text length */
989
if (gp_vnc->chat_window)
991
remmina_chat_window_receive (REMMINA_CHAT_WINDOW (gp_vnc->chat_window), _("Server"), text);
992
gtk_window_present (GTK_WINDOW (gp_vnc->chat_window));
1000
remmina_plug_vnc_incoming_connection (RemminaPlugVnc *gp_vnc, rfbClient *cl)
1002
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1005
gp_vnc->listen_sock = ListenAtTcpPort (cl->listenPort);
1006
if (gp_vnc->listen_sock < 0) return FALSE;
1008
remmina_init_dialog_set_status (REMMINA_INIT_DIALOG (gp->init_dialog),
1009
_("Listening on Port %i for an Incoming VNC Connection..."), cl->listenPort);
1012
FD_SET (gp_vnc->listen_sock, &fds);
1013
select (gp_vnc->listen_sock + 1, &fds, NULL, NULL, NULL);
1015
if (!FD_ISSET (gp_vnc->listen_sock, &fds))
1017
close (gp_vnc->listen_sock);
1018
gp_vnc->listen_sock = -1;
1022
cl->sock = AcceptTcpConnection (gp_vnc->listen_sock);
1023
close (gp_vnc->listen_sock);
1024
gp_vnc->listen_sock = -1;
1025
if (cl->sock < 0 || !SetNonBlocking (cl->sock))
1034
remmina_plug_vnc_main_loop (RemminaPlugVnc *gp_vnc)
1039
struct timeval timeout;
1041
if (!gp_vnc->connected)
1043
gp_vnc->running = FALSE;
1047
cl = (rfbClient*) gp_vnc->client;
1049
timeout.tv_sec = 10;
1050
timeout.tv_usec = 0;
1052
FD_SET (cl->sock, &fds);
1053
FD_SET (gp_vnc->vnc_event_pipe[0], &fds);
1054
ret = select (MAX (cl->sock, gp_vnc->vnc_event_pipe[0]) + 1, &fds, NULL, NULL, &timeout);
1056
/* Sometimes it returns <0 when opening a modal dialog in other window. Absolutely weird */
1057
/* So we continue looping anyway */
1058
if (ret <= 0) return TRUE;
1060
if (FD_ISSET (gp_vnc->vnc_event_pipe[0], &fds))
1062
remmina_plug_vnc_process_vnc_event (gp_vnc);
1064
if (FD_ISSET (cl->sock, &fds))
1066
ret = HandleRFBServerMessage (cl);
1069
gp_vnc->running = FALSE;
1070
if (gp_vnc->connected && !REMMINA_PLUG (gp_vnc)->closed)
1072
IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, gp_vnc);
1082
remmina_plug_vnc_main (RemminaPlugVnc *gp_vnc)
1084
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1085
rfbClient *cl = NULL;
1088
gboolean save = FALSE;
1090
gp_vnc->running = TRUE;
1092
rfbClientLog = remmina_plug_vnc_rfb_output;
1093
rfbClientErr = remmina_plug_vnc_rfb_output;
1095
while (gp_vnc->connected)
1097
gp_vnc->auth_called = FALSE;
1099
host = remmina_plug_start_direct_tunnel (gp, 5900, TRUE);
1103
gp_vnc->connected = FALSE;
1107
cl = rfbGetClient(8, 3, 4);
1108
cl->MallocFrameBuffer = remmina_plug_vnc_rfb_allocfb;
1109
cl->canHandleNewFBSize = TRUE;
1110
cl->GetPassword = remmina_plug_vnc_rfb_password;
1111
#ifdef LIBVNCSERVER_WITH_CLIENT_TLS
1112
cl->GetCredential = remmina_plug_vnc_rfb_credential;
1114
cl->GotFrameBufferUpdate = remmina_plug_vnc_rfb_updatefb;
1115
cl->GotXCutText = remmina_plug_vnc_rfb_cuttext;
1116
cl->GotCursorShape = remmina_plug_vnc_rfb_cursor_shape;
1117
cl->Bell = remmina_plug_vnc_rfb_bell;
1118
cl->HandleTextChat = remmina_plug_vnc_rfb_chat;
1119
rfbClientSetClientData (cl, NULL, gp_vnc);
1121
if (host[0] == '\0')
1123
cl->serverHost = host;
1124
cl->listenSpecified = TRUE;
1125
cl->listenPort = gp->remmina_file->listenport;
1127
remmina_plug_vnc_incoming_connection (gp_vnc, cl);
1131
pos = g_strrstr (host, ":");
1133
cl->serverPort = MAX (0, atoi (pos));
1134
cl->serverHost = host;
1136
/* Support short-form (:0, :1) */
1137
if (cl->serverPort < 100) cl->serverPort += 5900;
1140
cl->appData.useRemoteCursor = (gp->remmina_file->showcursor ? FALSE : TRUE);
1142
remmina_plug_vnc_update_quality (cl, gp->remmina_file->quality);
1143
remmina_plug_vnc_update_colordepth (cl, gp->remmina_file->colordepth);
1144
SetFormatAndEncodings (cl);
1146
if (rfbInitClient (cl, NULL, NULL)) break;
1148
/* If the authentication is not called, it has to be a fatel error and must quit */
1149
if (!gp_vnc->auth_called)
1151
gp_vnc->connected = FALSE;
1155
/* vnc4server reports "already in use" after authentication. Workaround here */
1156
if (strstr(vnc_error, "The server is already in use"))
1158
gp_vnc->connected = FALSE;
1159
gp_vnc->auth_called = FALSE;
1163
/* Otherwise, it's a password error. Try to clear saved password if any */
1164
if (gp->remmina_file->password) gp->remmina_file->password[0] = '\0';
1166
if (!gp_vnc->connected) break;
1169
remmina_init_dialog_set_status_temp (REMMINA_INIT_DIALOG (gp->init_dialog),
1170
_("VNC authentication failed. Trying to reconnect..."));
1172
/* It's safer to sleep a while before reconnect */
1175
gp_vnc->auth_first = FALSE;
1178
if (!gp_vnc->connected)
1180
if (cl && !gp_vnc->auth_called && !(gp->has_error))
1182
g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", vnc_error);
1183
gp->has_error = TRUE;
1185
gp_vnc->running = FALSE;
1187
IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, gp_vnc);
1192
/* Save user name and certificates if any; save the password if it's requested to do so */
1193
s = REMMINA_INIT_DIALOG (gp->init_dialog)->username;
1196
if (gp->remmina_file->username) g_free (gp->remmina_file->username);
1197
gp->remmina_file->username = g_strdup (s);
1200
s = REMMINA_INIT_DIALOG (gp->init_dialog)->cacert;
1203
if (gp->remmina_file->cacert) g_free (gp->remmina_file->cacert);
1204
gp->remmina_file->cacert = g_strdup (s);
1207
s = REMMINA_INIT_DIALOG (gp->init_dialog)->cacrl;
1210
if (gp->remmina_file->cacrl) g_free (gp->remmina_file->cacrl);
1211
gp->remmina_file->cacrl = g_strdup (s);
1214
s = REMMINA_INIT_DIALOG (gp->init_dialog)->clientcert;
1217
if (gp->remmina_file->clientcert) g_free (gp->remmina_file->clientcert);
1218
gp->remmina_file->clientcert = g_strdup (s);
1221
s = REMMINA_INIT_DIALOG (gp->init_dialog)->clientkey;
1224
if (gp->remmina_file->clientkey) g_free (gp->remmina_file->clientkey);
1225
gp->remmina_file->clientkey = g_strdup (s);
1228
if (REMMINA_INIT_DIALOG (gp->init_dialog)->save_password)
1230
if (gp->remmina_file->password) g_free (gp->remmina_file->password);
1231
gp->remmina_file->password =
1232
g_strdup (REMMINA_INIT_DIALOG (gp->init_dialog)->password);
1237
remmina_file_save (gp->remmina_file);
1240
gp_vnc->client = cl;
1242
remmina_plug_emit_signal (gp, "connect");
1244
if (gp->remmina_file->disableserverinput)
1246
PermitServerInput(cl, 1);
1251
while (remmina_plug_vnc_main_loop (gp_vnc)) { }
1252
gp_vnc->running = FALSE;
1256
IDLE_ADD ((GSourceFunc) remmina_plug_vnc_main_loop, gp_vnc);
1264
remmina_plug_vnc_main_thread (gpointer data)
1266
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
1269
remmina_plug_vnc_main (REMMINA_PLUG_VNC (data));
1275
remmina_plug_vnc_on_motion (GtkWidget *widget, GdkEventMotion *event, RemminaPlugVnc *gp_vnc)
1277
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1280
if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1281
if (gp->remmina_file->viewonly) return FALSE;
1285
x = event->x * gp->width / gp_vnc->scale_width;
1286
y = event->y * gp->height / gp_vnc->scale_height;
1293
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_POINTER,
1294
GINT_TO_POINTER (x), GINT_TO_POINTER (y), GINT_TO_POINTER (gp_vnc->button_mask));
1299
remmina_plug_vnc_on_button (GtkWidget *widget, GdkEventButton *event, RemminaPlugVnc *gp_vnc)
1301
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1305
if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1306
if (gp->remmina_file->viewonly) return FALSE;
1308
/* We only accept 3 buttons */
1309
if (event->button < 1 || event->button > 3) return FALSE;
1310
/* We bypass 2button-press and 3button-press events */
1311
if (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) return TRUE;
1313
mask = (1 << (event->button - 1));
1314
gp_vnc->button_mask = (event->type == GDK_BUTTON_PRESS ?
1315
(gp_vnc->button_mask | mask) :
1316
(gp_vnc->button_mask & (0xff - mask)));
1319
x = event->x * gp->width / gp_vnc->scale_width;
1320
y = event->y * gp->height / gp_vnc->scale_height;
1327
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_POINTER,
1328
GINT_TO_POINTER (x), GINT_TO_POINTER (y), GINT_TO_POINTER (gp_vnc->button_mask));
1333
remmina_plug_vnc_on_scroll (GtkWidget *widget, GdkEventScroll *event, RemminaPlugVnc *gp_vnc)
1335
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1339
if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1340
if (gp->remmina_file->viewonly) return FALSE;
1342
switch (event->direction)
1347
case GDK_SCROLL_DOWN:
1350
case GDK_SCROLL_LEFT:
1353
case GDK_SCROLL_RIGHT:
1362
x = event->x * gp->width / gp_vnc->scale_width;
1363
y = event->y * gp->height / gp_vnc->scale_height;
1370
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_POINTER,
1371
GINT_TO_POINTER (x), GINT_TO_POINTER (y), GINT_TO_POINTER (mask | gp_vnc->button_mask));
1372
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_POINTER,
1373
GINT_TO_POINTER (x), GINT_TO_POINTER (y), GINT_TO_POINTER (gp_vnc->button_mask));
1379
remmina_plug_vnc_release_key (RemminaPlugVnc *gp_vnc, guint16 keycode)
1386
/* Send all release key events for previously pressed keys */
1387
for (i = 0; i < gp_vnc->pressed_keys->len; i++)
1389
k = g_ptr_array_index (gp_vnc->pressed_keys, i);
1390
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_KEY, GUINT_TO_POINTER (k->keyval), GINT_TO_POINTER (FALSE), NULL);
1393
g_ptr_array_set_size (gp_vnc->pressed_keys, 0);
1397
/* Unregister the keycode only */
1398
for (i = 0; i < gp_vnc->pressed_keys->len; i++)
1400
k = g_ptr_array_index (gp_vnc->pressed_keys, i);
1401
if (k->keycode == keycode)
1404
g_ptr_array_remove_index_fast (gp_vnc->pressed_keys, i);
1412
remmina_plug_vnc_on_key (GtkWidget *widget, GdkEventKey *event, RemminaPlugVnc *gp_vnc)
1414
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1418
if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1419
if (gp->remmina_file->viewonly) return FALSE;
1421
keyval = remmina_pref_keymap_keyval (gp->remmina_file->gkeymap, event->keyval);
1423
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_KEY, GUINT_TO_POINTER (keyval),
1424
GINT_TO_POINTER (event->type == GDK_KEY_PRESS ? TRUE : FALSE), NULL);
1426
/* Register/unregister the pressed key */
1427
if (event->type == GDK_KEY_PRESS)
1429
k = g_new (RemminaKeyVal, 1);
1431
k->keycode = event->hardware_keycode;
1432
g_ptr_array_add (gp_vnc->pressed_keys, k);
1436
remmina_plug_vnc_release_key (gp_vnc, event->hardware_keycode);
1442
remmina_plug_vnc_on_cuttext_request (GtkClipboard *clipboard, const gchar *text, RemminaPlugVnc *gp_vnc)
1449
/* A timer (1 second) to avoid clipboard "loopback": text cut out from VNC won't paste back into VNC */
1450
g_get_current_time (&t);
1451
diff = (t.tv_sec - gp_vnc->clipboard_timer.tv_sec) * 10 + (t.tv_usec - gp_vnc->clipboard_timer.tv_usec) / 100000;
1452
if (diff < 10) return;
1454
gp_vnc->clipboard_timer = t;
1455
remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_CUTTEXT, (gpointer) text, NULL, NULL);
1460
remmina_plug_vnc_on_cuttext (GtkClipboard *clipboard, GdkEvent *event, RemminaPlugVnc *gp_vnc)
1462
if (!gp_vnc->connected || !gp_vnc->client) return;
1463
if (REMMINA_PLUG (gp_vnc)->remmina_file->viewonly) return;
1465
gtk_clipboard_request_text (clipboard, (GtkClipboardTextReceivedFunc) remmina_plug_vnc_on_cuttext_request, gp_vnc);
1469
remmina_plug_vnc_on_realize (RemminaPlugVnc *gp_vnc, gpointer data)
1471
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1473
GdkPixmap *source, *mask;
1476
if (gp->remmina_file->showcursor)
1478
/* Hide local cursor (show a small dot instead) */
1479
gdk_color_parse ("black", &fg);
1480
gdk_color_parse ("white", &bg);
1481
source = gdk_bitmap_create_from_data (NULL, dot_cursor_bits, dot_cursor_width, dot_cursor_height);
1482
mask = gdk_bitmap_create_from_data (NULL, dot_cursor_mask_bits, dot_cursor_width, dot_cursor_height);
1483
cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, dot_cursor_x_hot, dot_cursor_y_hot);
1484
gdk_pixmap_unref (source);
1485
gdk_pixmap_unref (mask);
1486
gdk_window_set_cursor (GTK_WIDGET (gp)->window, cursor);
1487
gdk_cursor_unref (cursor);
1491
/******************************************************************************************/
1494
remmina_plug_vnc_open_connection (RemminaPlug *gp)
1496
RemminaPlugVnc *gp_vnc = REMMINA_PLUG_VNC (gp);
1498
gp_vnc->connected = TRUE;
1500
g_signal_connect (G_OBJECT (gp_vnc), "realize",
1501
G_CALLBACK (remmina_plug_vnc_on_realize), NULL);
1502
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "motion-notify-event",
1503
G_CALLBACK (remmina_plug_vnc_on_motion), gp_vnc);
1504
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "button-press-event",
1505
G_CALLBACK (remmina_plug_vnc_on_button), gp_vnc);
1506
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "button-release-event",
1507
G_CALLBACK (remmina_plug_vnc_on_button), gp_vnc);
1508
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "scroll-event",
1509
G_CALLBACK (remmina_plug_vnc_on_scroll), gp_vnc);
1510
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "key-press-event",
1511
G_CALLBACK (remmina_plug_vnc_on_key), gp_vnc);
1512
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "key-release-event",
1513
G_CALLBACK (remmina_plug_vnc_on_key), gp_vnc);
1515
gp_vnc->clipboard_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)),
1516
"owner-change", G_CALLBACK (remmina_plug_vnc_on_cuttext), gp_vnc);
1519
if (pthread_create (&gp_vnc->thread, NULL, remmina_plug_vnc_main_thread, gp_vnc))
1521
/* I don't think this will ever happen... */
1522
g_print ("Failed to initialize pthread. Falling back to non-thread mode...\n");
1523
g_timeout_add (0, (GSourceFunc) remmina_plug_vnc_main, gp);
1527
g_timeout_add (0, (GSourceFunc) remmina_plug_vnc_main, gp);
1534
remmina_plug_vnc_close_connection_timeout (RemminaPlugVnc *gp_vnc)
1536
/* wait until the running attribute is set to false by the VNC thread */
1537
if (gp_vnc->running) return TRUE;
1539
/* unregister the clipboard monitor */
1540
if (gp_vnc->clipboard_handler)
1542
g_signal_handler_disconnect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)),
1543
gp_vnc->clipboard_handler);
1544
gp_vnc->clipboard_handler = 0;
1547
if (gp_vnc->queuedraw_handler)
1549
g_source_remove (gp_vnc->queuedraw_handler);
1550
gp_vnc->queuedraw_handler = 0;
1552
if (gp_vnc->scale_handler)
1554
g_source_remove (gp_vnc->scale_handler);
1555
gp_vnc->scale_handler = 0;
1557
if (gp_vnc->chat_window)
1559
gtk_widget_destroy (gp_vnc->chat_window);
1560
gp_vnc->chat_window = NULL;
1562
if (gp_vnc->listen_sock >= 0)
1564
close (gp_vnc->listen_sock);
1568
rfbClientCleanup((rfbClient*) gp_vnc->client);
1569
gp_vnc->client = NULL;
1571
if (gp_vnc->rgb_buffer)
1573
g_object_unref (gp_vnc->rgb_buffer);
1574
gp_vnc->rgb_buffer = NULL;
1576
if (gp_vnc->vnc_buffer)
1578
g_free (gp_vnc->vnc_buffer);
1579
gp_vnc->vnc_buffer = NULL;
1581
if (gp_vnc->scale_buffer)
1583
g_object_unref (gp_vnc->scale_buffer);
1584
gp_vnc->scale_buffer = NULL;
1586
g_ptr_array_free (gp_vnc->pressed_keys, TRUE);
1587
remmina_plug_vnc_event_free_all (gp_vnc);
1588
g_queue_free (gp_vnc->vnc_event_queue);
1589
close (gp_vnc->vnc_event_pipe[0]);
1590
close (gp_vnc->vnc_event_pipe[1]);
1593
pthread_mutex_destroy (&gp_vnc->buffer_mutex);
1596
remmina_plug_emit_signal (REMMINA_PLUG (gp_vnc), "disconnect");
1602
remmina_plug_vnc_close_connection (RemminaPlug *gp)
1604
RemminaPlugVnc *gp_vnc = REMMINA_PLUG_VNC (gp);
1606
gp_vnc->connected = FALSE;
1611
pthread_cancel (gp_vnc->thread);
1612
if (gp_vnc->thread) pthread_join (gp_vnc->thread, NULL);
1613
gp_vnc->running = FALSE;
1614
remmina_plug_vnc_close_connection_timeout (gp_vnc);
1618
g_timeout_add (200, (GSourceFunc) remmina_plug_vnc_close_connection_timeout, gp);
1621
g_timeout_add (200, (GSourceFunc) remmina_plug_vnc_close_connection_timeout, gp);
1628
remmina_plug_vnc_query_feature (RemminaPlug *gp, RemminaPlugFeature feature)
1632
case REMMINA_PLUG_FEATURE_PREF:
1633
case REMMINA_PLUG_FEATURE_PREF_QUALITY:
1634
case REMMINA_PLUG_FEATURE_PREF_VIEWONLY:
1635
case REMMINA_PLUG_FEATURE_UNFOCUS:
1636
case REMMINA_PLUG_FEATURE_SCALE:
1637
return GINT_TO_POINTER (1);
1638
case REMMINA_PLUG_FEATURE_PREF_DISABLESERVERINPUT:
1639
return (SupportsClient2Server ((rfbClient*) (REMMINA_PLUG_VNC (gp)->client), rfbSetServerInput) ?
1640
GINT_TO_POINTER (1) : NULL);
1641
case REMMINA_PLUG_FEATURE_TOOL_CHAT:
1642
return (SupportsClient2Server ((rfbClient*) (REMMINA_PLUG_VNC (gp)->client), rfbTextChat) ?
1643
GINT_TO_POINTER (1) : NULL);
1650
remmina_plug_vnc_call_feature (RemminaPlug *gp, RemminaPlugFeature feature, const gpointer data)
1652
RemminaPlugVnc *gp_vnc = REMMINA_PLUG_VNC (gp);
1655
case REMMINA_PLUG_FEATURE_PREF_QUALITY:
1656
remmina_plug_vnc_update_quality ((rfbClient*) (gp_vnc->client), GPOINTER_TO_INT (data));
1657
SetFormatAndEncodings ((rfbClient*) (gp_vnc->client));
1659
case REMMINA_PLUG_FEATURE_PREF_VIEWONLY:
1660
gp->remmina_file->viewonly = (data != NULL);
1662
case REMMINA_PLUG_FEATURE_PREF_DISABLESERVERINPUT:
1663
PermitServerInput ((rfbClient*) (gp_vnc->client), (data ? 1 : 0));
1664
gp->remmina_file->disableserverinput = (data ? TRUE : FALSE);
1666
case REMMINA_PLUG_FEATURE_UNFOCUS:
1667
remmina_plug_vnc_release_key (gp_vnc, 0);
1669
case REMMINA_PLUG_FEATURE_SCALE:
1670
remmina_plug_vnc_update_scale (gp_vnc, (data != NULL));
1672
case REMMINA_PLUG_FEATURE_TOOL_CHAT:
1673
remmina_plug_vnc_open_chat (gp_vnc);
1680
#else /* HAVE_LIBVNCCLIENT */
1683
remmina_plug_vnc_open_connection (RemminaPlug *gp)
1686
/* This should never happen because if no VNC support users are not able to select VNC in preference dialog */
1687
dialog = gtk_message_dialog_new (NULL,
1688
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1689
"VNC not supported");
1690
gtk_dialog_run (GTK_DIALOG (dialog));
1691
gtk_widget_destroy (dialog);
1696
remmina_plug_vnc_close_connection (RemminaPlug *gp)
1702
remmina_plug_vnc_query_feature (RemminaPlug *gp, RemminaPlugFeature feature)
1708
remmina_plug_vnc_call_feature (RemminaPlug *gp, RemminaPlugFeature feature, const gpointer data)
1712
#endif /* HAVE_LIBVNCCLIENT */
1715
remmina_plug_vnc_on_expose (GtkWidget *widget, GdkEventExpose *event, RemminaPlugVnc *gp_vnc)
1717
RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1719
gint width, height, x, y, rowstride;
1723
/* widget == gp_vnc->drawing_area */
1724
buffer = (gp->scale ? gp_vnc->scale_buffer : gp_vnc->rgb_buffer);
1727
UNLOCK_BUFFER (FALSE)
1731
width = (gp->scale ? gp_vnc->scale_width : gp->width);
1732
height = (gp->scale ? gp_vnc->scale_height : gp->height);
1733
if (event->area.x >= width || event->area.y >= height)
1735
UNLOCK_BUFFER (FALSE)
1740
rowstride = gdk_pixbuf_get_rowstride (buffer);
1742
/* this is a little tricky. It "moves" the rgb_buffer pointer to (x,y) as top-left corner,
1743
and keeps the same rowstride. This is an effective way to "clip" the rgb_buffer for gdk. */
1744
gdk_draw_rgb_image (widget->window, widget->style->white_gc,
1746
MIN (width - x, event->area.width), MIN (height - y, event->area.height),
1748
gdk_pixbuf_get_pixels (buffer) + y * rowstride + x * 3,
1751
UNLOCK_BUFFER (FALSE)
1756
remmina_plug_vnc_on_configure (GtkWidget *widget, GdkEventConfigure *event, RemminaPlugVnc *gp_vnc)
1758
/* We do a delayed reallocating to improve performance */
1759
if (gp_vnc->scale_handler) g_source_remove (gp_vnc->scale_handler);
1760
gp_vnc->scale_handler = g_timeout_add (1000, (GSourceFunc) remmina_plug_vnc_update_scale_buffer_main, gp_vnc);
1765
remmina_plug_vnc_class_init (RemminaPlugVncClass *klass)
1767
klass->parent_class.open_connection = remmina_plug_vnc_open_connection;
1768
klass->parent_class.close_connection = remmina_plug_vnc_close_connection;
1769
klass->parent_class.query_feature = remmina_plug_vnc_query_feature;
1770
klass->parent_class.call_feature = remmina_plug_vnc_call_feature;
1774
remmina_plug_vnc_destroy (GtkWidget *widget, gpointer data)
1779
remmina_plug_vnc_init (RemminaPlugVnc *gp_vnc)
1783
gp_vnc->drawing_area = gtk_drawing_area_new ();
1784
gtk_widget_show (gp_vnc->drawing_area);
1785
gtk_container_add (GTK_CONTAINER (gp_vnc), gp_vnc->drawing_area);
1787
gtk_widget_add_events (gp_vnc->drawing_area, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK
1788
| GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
1789
GTK_WIDGET_SET_FLAGS (gp_vnc->drawing_area, GTK_CAN_FOCUS);
1791
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "expose_event",
1792
G_CALLBACK (remmina_plug_vnc_on_expose), gp_vnc);
1793
g_signal_connect (G_OBJECT (gp_vnc->drawing_area), "configure_event",
1794
G_CALLBACK (remmina_plug_vnc_on_configure), gp_vnc);
1795
g_signal_connect (G_OBJECT (gp_vnc), "destroy", G_CALLBACK (remmina_plug_vnc_destroy), NULL);
1797
gp_vnc->connected = FALSE;
1798
gp_vnc->running = FALSE;
1799
gp_vnc->auth_called = FALSE;
1800
gp_vnc->auth_first = TRUE;
1801
gp_vnc->rgb_buffer = NULL;
1802
gp_vnc->vnc_buffer = NULL;
1803
gp_vnc->scale_buffer = NULL;
1804
gp_vnc->scale_width = 0;
1805
gp_vnc->scale_height = 0;
1806
gp_vnc->scale_handler = 0;
1807
gp_vnc->queuedraw_x = 0;
1808
gp_vnc->queuedraw_y = 0;
1809
gp_vnc->queuedraw_w = 0;
1810
gp_vnc->queuedraw_h = 0;
1811
gp_vnc->queuedraw_handler = 0;
1812
gp_vnc->clipboard_handler = 0;
1813
g_get_current_time (&gp_vnc->clipboard_timer);
1814
gp_vnc->client = NULL;
1815
gp_vnc->listen_sock = -1;
1816
gp_vnc->button_mask = 0;
1817
gp_vnc->pressed_keys = g_ptr_array_new ();
1818
gp_vnc->chat_window = NULL;
1820
gp_vnc->vnc_event_queue = g_queue_new ();
1821
if (pipe (gp_vnc->vnc_event_pipe))
1823
g_print ("Error creating pipes.\n");
1824
gp_vnc->vnc_event_pipe[0] = 0;
1825
gp_vnc->vnc_event_pipe[1] = 0;
1827
flags = fcntl (gp_vnc->vnc_event_pipe[0], F_GETFL, 0);
1828
fcntl (gp_vnc->vnc_event_pipe[0], F_SETFL, flags | O_NONBLOCK);
1830
pthread_mutex_init (&gp_vnc->buffer_mutex, NULL);
1835
remmina_plug_vnc_new (gboolean scale)
1837
RemminaPlugVnc *gp_vnc;
1839
gp_vnc = REMMINA_PLUG_VNC (g_object_new (REMMINA_TYPE_PLUG_VNC, NULL));
1840
REMMINA_PLUG (gp_vnc)->scale = scale;
1842
return GTK_WIDGET (gp_vnc);