~ubuntu-branches/ubuntu/raring/remmina/raring

« back to all changes in this revision

Viewing changes to src/remminaplug_vnc.c

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2010-07-11 23:40:47 UTC
  • mfrom: (1.2.1 upstream) (8.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100711234047-id2bdu1gb59e34n4
* New upstream release.
* debian/control:
  - Bump Standards-Version to 3.9.0, no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Remmina - The GTK+ Remote Desktop Client
3
 
 * Copyright (C) 2009 - Vic Lee 
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 <gtk/gtk.h>
22
 
#include <glib/gstdio.h>
23
 
#include <glib/gi18n.h>
24
 
#include <stdlib.h>
25
 
#include <signal.h>
26
 
#include <unistd.h>
27
 
#include "config.h"
28
 
#ifdef HAVE_PTHREAD
29
 
#include <pthread.h>
30
 
#endif
31
 
#ifdef HAVE_FCNTL_H
32
 
#include <fcntl.h>
33
 
#endif
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"
41
 
 
42
 
G_DEFINE_TYPE (RemminaPlugVnc, remmina_plug_vnc, REMMINA_TYPE_PLUG)
43
 
 
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 };
52
 
 
53
 
#ifdef HAVE_PTHREAD
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}
56
 
#else
57
 
#define LOCK_BUFFER(t)
58
 
#define UNLOCK_BUFFER(t)
59
 
#endif
60
 
 
61
 
enum
62
 
{
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
69
 
};
70
 
typedef struct _RemminaPlugVncEvent
71
 
{
72
 
    gint event_type;
73
 
    union
74
 
    {
75
 
        struct
76
 
        {
77
 
            guint keyval;
78
 
            gboolean pressed;
79
 
        } key;
80
 
        struct
81
 
        {
82
 
            gint x;
83
 
            gint y;
84
 
            gint button_mask;
85
 
        } pointer;
86
 
        struct
87
 
        {
88
 
            gchar *text;
89
 
        } text;
90
 
    } event_data;
91
 
} RemminaPlugVncEvent;
92
 
 
93
 
static void
94
 
remmina_plug_vnc_event_push (RemminaPlugVnc *gp_vnc, gint event_type, gpointer p1, gpointer p2, gpointer p3)
95
 
{
96
 
    RemminaPlugVncEvent *event;
97
 
 
98
 
    event = g_new (RemminaPlugVncEvent, 1);
99
 
    event->event_type = event_type;
100
 
    switch (event_type)
101
 
    {
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);
105
 
        break;
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);
110
 
        break;
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);
114
 
        break;
115
 
    default:
116
 
        break;
117
 
    }
118
 
    g_queue_push_tail (gp_vnc->vnc_event_queue, event);
119
 
    if (write (gp_vnc->vnc_event_pipe[1], "\0", 1))
120
 
    {
121
 
        /* Ignore */
122
 
    }
123
 
}
124
 
 
125
 
static void
126
 
remmina_plug_vnc_event_free (RemminaPlugVncEvent *event)
127
 
{
128
 
    switch (event->event_type)
129
 
    {
130
 
    case REMMINA_PLUG_VNC_EVENT_CUTTEXT:
131
 
    case REMMINA_PLUG_VNC_EVENT_CHAT_SEND:
132
 
        g_free (event->event_data.text.text);
133
 
        break;
134
 
    default:
135
 
        break;
136
 
    }
137
 
    g_free (event);
138
 
}
139
 
 
140
 
static void
141
 
remmina_plug_vnc_event_free_all (RemminaPlugVnc *gp_vnc)
142
 
{
143
 
    RemminaPlugVncEvent *event;
144
 
 
145
 
    while ((event = g_queue_pop_head (gp_vnc->vnc_event_queue)) != NULL)
146
 
    {
147
 
        remmina_plug_vnc_event_free (event);
148
 
    }
149
 
}
150
 
 
151
 
static void
152
 
remmina_plug_vnc_scale_area (RemminaPlugVnc *gp_vnc, gint *x, gint *y, gint *w, gint *h)
153
 
{
154
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
155
 
    gint sx, sy, sw, sh;
156
 
 
157
 
    if (gp_vnc->rgb_buffer == NULL || gp_vnc->scale_buffer == NULL) return;
158
 
 
159
 
    if (gp_vnc->scale_width == gp->width && gp_vnc->scale_height == gp->height)
160
 
    {
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);
163
 
        return;
164
 
    }
165
 
 
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);
175
 
 
176
 
    gdk_pixbuf_scale (gp_vnc->rgb_buffer, gp_vnc->scale_buffer,
177
 
        sx, sy,
178
 
        sw, sh,
179
 
        0, 0,
180
 
        (double) gp_vnc->scale_width / (double) gp->width,
181
 
        (double) gp_vnc->scale_height / (double) gp->height,
182
 
        remmina_pref.scale_quality);
183
 
 
184
 
    *x = sx; *y = sy; *w = sw; *h = sh;
185
 
}
186
 
 
187
 
static gboolean
188
 
remmina_plug_vnc_update_scale_buffer (RemminaPlugVnc *gp_vnc, gboolean in_thread)
189
 
{
190
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
191
 
    gint width, height;
192
 
    gint x, y, w, h;
193
 
    GdkPixbuf *pixbuf;
194
 
 
195
 
    if (gp_vnc->running)
196
 
    {
197
 
        width = GTK_WIDGET (gp_vnc)->allocation.width;
198
 
        height = GTK_WIDGET (gp_vnc)->allocation.height;
199
 
        if (gp->scale)
200
 
        {
201
 
            if (width > 1 && height > 1)
202
 
            {
203
 
                LOCK_BUFFER (in_thread)
204
 
 
205
 
                if (gp_vnc->scale_buffer)
206
 
                {
207
 
                    g_object_unref (gp_vnc->scale_buffer);
208
 
                }
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);
213
 
 
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;
217
 
 
218
 
                x = 0; y = 0; w = gp->width; h = gp->height;
219
 
                remmina_plug_vnc_scale_area (gp_vnc, &x, &y, &w, &h);
220
 
 
221
 
                UNLOCK_BUFFER (in_thread)
222
 
            }
223
 
        }
224
 
        else
225
 
        {
226
 
            LOCK_BUFFER (in_thread)
227
 
 
228
 
            if (gp_vnc->scale_buffer)
229
 
            {
230
 
                g_object_unref (gp_vnc->scale_buffer);
231
 
                gp_vnc->scale_buffer = NULL;
232
 
            }
233
 
            gp_vnc->scale_width = 0;
234
 
            gp_vnc->scale_height = 0;
235
 
 
236
 
            UNLOCK_BUFFER (in_thread)
237
 
        }
238
 
        if (width > 1 && height > 1)
239
 
        {
240
 
            if (in_thread)
241
 
            {
242
 
                THREADS_ENTER
243
 
                gtk_widget_queue_draw_area (GTK_WIDGET (gp_vnc), 0, 0, width, height);
244
 
                THREADS_LEAVE
245
 
            }
246
 
            else
247
 
            {
248
 
                gtk_widget_queue_draw_area (GTK_WIDGET (gp_vnc), 0, 0, width, height);
249
 
            }
250
 
        }
251
 
    }
252
 
    gp_vnc->scale_handler = 0;
253
 
    return FALSE;
254
 
}
255
 
 
256
 
static gboolean
257
 
remmina_plug_vnc_update_scale_buffer_main (RemminaPlugVnc *gp_vnc)
258
 
{
259
 
    return remmina_plug_vnc_update_scale_buffer (gp_vnc, FALSE);
260
 
}
261
 
 
262
 
static void
263
 
remmina_plug_vnc_update_scale (RemminaPlugVnc *gp_vnc, gboolean scale)
264
 
{
265
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
266
 
    gp->scale = scale;
267
 
    if (scale)
268
 
    {
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));
272
 
    }
273
 
    else
274
 
    {
275
 
        gtk_widget_set_size_request (GTK_WIDGET (gp_vnc->drawing_area), gp->width, gp->height);
276
 
    }
277
 
}
278
 
 
279
 
#ifdef HAVE_LIBVNCCLIENT
280
 
 
281
 
typedef struct _RemminaKeyVal
282
 
{
283
 
    guint keyval;
284
 
    guint16 keycode;
285
 
} RemminaKeyVal;
286
 
 
287
 
/***************************** LibVNCClient related codes *********************************/
288
 
#include <rfb/rfbclient.h>
289
 
 
290
 
static void
291
 
remmina_plug_vnc_process_vnc_event (RemminaPlugVnc *gp_vnc)
292
 
{
293
 
    rfbClient *cl = (rfbClient*) gp_vnc->client;
294
 
    RemminaPlugVncEvent *event;
295
 
    gchar buf[100];
296
 
 
297
 
    while ((event = g_queue_pop_head (gp_vnc->vnc_event_queue)) != NULL)
298
 
    {
299
 
        if (cl)
300
 
        {
301
 
            switch (event->event_type)
302
 
            {
303
 
            case REMMINA_PLUG_VNC_EVENT_KEY:
304
 
                SendKeyEvent (cl, event->event_data.key.keyval, event->event_data.key.pressed);
305
 
                break;
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);
309
 
                break;
310
 
            case REMMINA_PLUG_VNC_EVENT_CUTTEXT:
311
 
                SendClientCutText (cl, event->event_data.text.text, strlen (event->event_data.text.text));
312
 
                break;
313
 
            case REMMINA_PLUG_VNC_EVENT_CHAT_OPEN:
314
 
                TextChatOpen (cl);
315
 
                break;
316
 
            case REMMINA_PLUG_VNC_EVENT_CHAT_SEND:
317
 
                TextChatSend (cl, event->event_data.text.text);
318
 
                break;
319
 
            case REMMINA_PLUG_VNC_EVENT_CHAT_CLOSE:
320
 
                TextChatClose (cl);
321
 
                TextChatFinish (cl);
322
 
                break;
323
 
            }
324
 
        }
325
 
        remmina_plug_vnc_event_free (event);
326
 
    }
327
 
    if (read (gp_vnc->vnc_event_pipe[0], buf, sizeof (buf)))
328
 
    {
329
 
        /* Ignore */
330
 
    }
331
 
}
332
 
 
333
 
typedef struct _RemminaPlugVncCuttextParam
334
 
{
335
 
    RemminaPlugVnc *gp_vnc;
336
 
    gchar *text;
337
 
    gint textlen;
338
 
} RemminaPlugVncCuttextParam;
339
 
 
340
 
static void
341
 
remmina_plug_vnc_update_quality (rfbClient *cl, gint quality)
342
 
{
343
 
    switch (quality)
344
 
    {
345
 
    case 9:
346
 
        cl->appData.useBGR233 = 0;
347
 
        cl->appData.encodingsString = "copyrect hextile raw";
348
 
        cl->appData.compressLevel = 0;
349
 
        cl->appData.qualityLevel = 9;
350
 
        break;
351
 
    case 2:
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;
356
 
        break;
357
 
    case 1:
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;
362
 
        break;
363
 
    case 0:
364
 
    default:
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;
369
 
        break;
370
 
    }
371
 
}
372
 
 
373
 
static void
374
 
remmina_plug_vnc_update_colordepth (rfbClient *cl, gint colordepth)
375
 
{
376
 
    cl->format.depth = colordepth;
377
 
    cl->format.bigEndian = 0;
378
 
    cl->appData.requestedDepth = colordepth;
379
 
 
380
 
    switch (colordepth)
381
 
    {
382
 
    case 24:
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;
390
 
        break;
391
 
    case 16:
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;
399
 
        break;
400
 
    case 15:
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;
408
 
        break;
409
 
    case 8:
410
 
    default:
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;
418
 
        break;
419
 
    }
420
 
}
421
 
 
422
 
static rfbBool
423
 
remmina_plug_vnc_rfb_allocfb (rfbClient *cl)
424
 
{
425
 
    RemminaPlugVnc *gp_vnc;
426
 
    RemminaPlug *gp;
427
 
    gint width, height, depth, size;
428
 
    GdkPixbuf *new_pixbuf, *old_pixbuf;
429
 
 
430
 
    gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
431
 
    gp = REMMINA_PLUG (gp_vnc);
432
 
 
433
 
    width = cl->width;
434
 
    height = cl->height;
435
 
    depth = cl->format.bitsPerPixel;
436
 
    size = width * height * (depth / 8);
437
 
 
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;
443
 
 
444
 
    LOCK_BUFFER (TRUE)
445
 
 
446
 
    gp->width = cl->width;
447
 
    gp->height = cl->height;
448
 
 
449
 
    gp_vnc->rgb_buffer = new_pixbuf;
450
 
 
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;
454
 
 
455
 
    UNLOCK_BUFFER (TRUE)
456
 
 
457
 
    if (old_pixbuf) g_object_unref (old_pixbuf);
458
 
    
459
 
    THREADS_ENTER
460
 
    remmina_plug_vnc_update_scale (gp_vnc, gp->scale);
461
 
    THREADS_LEAVE
462
 
 
463
 
    if (gp_vnc->scale_handler == 0) remmina_plug_vnc_update_scale_buffer (gp_vnc, TRUE);
464
 
 
465
 
    /* Notify window of change so that scroll border can be hidden or shown if needed */
466
 
    remmina_plug_emit_signal (gp, "desktop-resize");
467
 
 
468
 
    /* Refresh the client's updateRect - bug in xvncclient */
469
 
    cl->updateRect.w = width;
470
 
    cl->updateRect.h = height;
471
 
 
472
 
    return TRUE;
473
 
}
474
 
 
475
 
static gint
476
 
remmina_plug_vnc_bits (gint n)
477
 
{
478
 
    gint b = 0;
479
 
    while (n) { b++; n >>= 1; }
480
 
    return b;
481
 
}
482
 
 
483
 
static gboolean
484
 
remmina_plug_vnc_queue_draw_area_real (RemminaPlugVnc *gp_vnc)
485
 
{
486
 
    gint x, y, w, h;
487
 
 
488
 
    if (GTK_IS_WIDGET (gp_vnc) && gp_vnc->connected)
489
 
    {
490
 
        LOCK_BUFFER (FALSE)
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)
497
 
 
498
 
        gtk_widget_queue_draw_area (GTK_WIDGET (gp_vnc), x, y, w, h);
499
 
    }
500
 
    return FALSE;
501
 
}
502
 
 
503
 
static void
504
 
remmina_plug_vnc_queue_draw_area (RemminaPlugVnc *gp_vnc, gint x, gint y, gint w, gint h)
505
 
{
506
 
    gint nx2, ny2, ox2, oy2;
507
 
 
508
 
    LOCK_BUFFER (TRUE)
509
 
    if (gp_vnc->queuedraw_handler)
510
 
    {
511
 
        nx2 = x + w;
512
 
        ny2 = y + h;
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;
519
 
    }
520
 
    else
521
 
    {
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);
527
 
    }
528
 
    UNLOCK_BUFFER (TRUE)
529
 
}
530
 
 
531
 
static void
532
 
remmina_plug_vnc_rfb_updatefb (rfbClient* cl, int x, int y, int w, int h)
533
 
{
534
 
    RemminaPlugVnc *gp_vnc;
535
 
    RemminaPlug *gp;
536
 
    gint ix, iy, x2, y2;
537
 
    guchar *destptr, *srcptr;
538
 
    gint bytesPerPixel;
539
 
    gint rowstride;
540
 
    gint i;
541
 
    guint32 pixel;
542
 
    gint rs, gs, bs, rm, gm, bm, rb, gb, bb;
543
 
 
544
 
    gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
545
 
    gp = REMMINA_PLUG (gp_vnc);
546
 
 
547
 
    LOCK_BUFFER (TRUE)
548
 
 
549
 
    if (w >= 1 || h >= 1)
550
 
    {
551
 
        x2 = x + w;
552
 
        y2 = y + h;
553
 
        bytesPerPixel = cl->format.bitsPerPixel / 8;
554
 
        rowstride = gdk_pixbuf_get_rowstride (gp_vnc->rgb_buffer);
555
 
        switch (cl->format.bitsPerPixel)
556
 
        {
557
 
        case 32:
558
 
            /* The following codes swap red/green value */
559
 
            for (iy = y; iy < y2; iy++)
560
 
            {
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++)
564
 
                {
565
 
                    *destptr++ = *(srcptr + 2);
566
 
                    *destptr++ = *(srcptr + 1);
567
 
                    *destptr++ = *srcptr;
568
 
                    srcptr += 4;
569
 
                }
570
 
            }
571
 
            break;
572
 
        default:
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++)
583
 
            {
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++)
587
 
                {
588
 
                    pixel = 0;
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;
593
 
                }
594
 
            }
595
 
            break;
596
 
        }
597
 
    }
598
 
 
599
 
    if (gp->scale)
600
 
    {
601
 
        remmina_plug_vnc_scale_area (gp_vnc, &x, &y, &w, &h);
602
 
    }
603
 
 
604
 
    UNLOCK_BUFFER (TRUE)
605
 
 
606
 
    remmina_plug_vnc_queue_draw_area (gp_vnc, x, y, w, h);
607
 
}
608
 
 
609
 
static gboolean
610
 
remmina_plug_vnc_queue_cuttext (RemminaPlugVncCuttextParam *param)
611
 
{
612
 
    RemminaPlugVnc *gp_vnc;
613
 
    GTimeVal t;
614
 
    glong diff;
615
 
 
616
 
    gp_vnc = param->gp_vnc;
617
 
    if (GTK_IS_WIDGET (gp_vnc) && gp_vnc->connected)
618
 
    {
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;
621
 
        if (diff >= 10)
622
 
        {
623
 
            gp_vnc->clipboard_timer = t;
624
 
            gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), param->text, param->textlen);
625
 
        }
626
 
    }
627
 
    g_free (param->text);
628
 
    g_free (param);
629
 
    return FALSE;
630
 
}
631
 
 
632
 
static void
633
 
remmina_plug_vnc_rfb_cuttext (rfbClient* cl, const char *text, int textlen)
634
 
{
635
 
    RemminaPlugVncCuttextParam *param;
636
 
 
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);
643
 
}
644
 
 
645
 
static char*
646
 
remmina_plug_vnc_rfb_password (rfbClient *cl)
647
 
{
648
 
    RemminaPlugVnc *gp_vnc;
649
 
    RemminaPlug *gp;
650
 
    GtkWidget *dialog;
651
 
    gint ret;
652
 
    gchar *pwd = NULL;
653
 
 
654
 
    gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
655
 
    gp_vnc->auth_called = TRUE;
656
 
    gp = REMMINA_PLUG (gp_vnc);
657
 
 
658
 
    dialog = gp->init_dialog;
659
 
 
660
 
    if (gp_vnc->auth_first && gp->remmina_file->password && gp->remmina_file->password[0] != '\0')
661
 
    {
662
 
        pwd = g_strdup (gp->remmina_file->password);
663
 
    }
664
 
    else
665
 
    {
666
 
        THREADS_ENTER
667
 
        ret = remmina_init_dialog_authpwd (REMMINA_INIT_DIALOG (dialog), _("VNC Password"), 
668
 
            (gp->remmina_file->filename != NULL));
669
 
        THREADS_LEAVE
670
 
 
671
 
        if (ret == GTK_RESPONSE_OK)
672
 
        {
673
 
            pwd = g_strdup (REMMINA_INIT_DIALOG (dialog)->password);
674
 
        }
675
 
        else
676
 
        {
677
 
            gp_vnc->connected = FALSE;
678
 
        }
679
 
    }
680
 
    return pwd;
681
 
}
682
 
 
683
 
#ifdef LIBVNCSERVER_WITH_CLIENT_TLS
684
 
static rfbCredential*
685
 
remmina_plug_vnc_rfb_credential (rfbClient *cl, int credentialType)
686
 
{
687
 
    rfbCredential *cred;
688
 
    RemminaPlugVnc *gp_vnc;
689
 
    RemminaPlug *gp;
690
 
    GtkWidget *dialog;
691
 
    gchar *s;
692
 
    gint ret;
693
 
 
694
 
    gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
695
 
    gp_vnc->auth_called = TRUE;
696
 
    gp = REMMINA_PLUG (gp_vnc);
697
 
 
698
 
    dialog = gp->init_dialog;
699
 
 
700
 
    cred = g_new0 (rfbCredential, 1);
701
 
 
702
 
    switch (credentialType)
703
 
    {
704
 
 
705
 
    case rfbCredentialTypeUser:
706
 
 
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')
710
 
        {
711
 
            cred->userCredential.username = g_strdup (gp->remmina_file->username);
712
 
            cred->userCredential.password = g_strdup (gp->remmina_file->password);
713
 
        }
714
 
        else
715
 
        {
716
 
            THREADS_ENTER
717
 
            ret = remmina_init_dialog_authuserpwd (REMMINA_INIT_DIALOG (dialog), gp->remmina_file->username,
718
 
                (gp->remmina_file->filename != NULL));
719
 
            THREADS_LEAVE
720
 
 
721
 
            if (ret == GTK_RESPONSE_OK)
722
 
            {
723
 
                cred->userCredential.username = g_strdup (REMMINA_INIT_DIALOG (dialog)->username);
724
 
                cred->userCredential.password = g_strdup (REMMINA_INIT_DIALOG (dialog)->password);
725
 
            }
726
 
            else
727
 
            {
728
 
                g_free (cred);
729
 
                cred = NULL;
730
 
                gp_vnc->connected = FALSE;
731
 
            }
732
 
        }
733
 
        break;
734
 
 
735
 
    case rfbCredentialTypeX509:
736
 
        if (gp_vnc->auth_first &&
737
 
            gp->remmina_file->cacert && gp->remmina_file->cacert[0] != '\0')
738
 
        {
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);
747
 
        }
748
 
        else
749
 
        {
750
 
            THREADS_ENTER
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);
753
 
            THREADS_LEAVE
754
 
 
755
 
            if (ret == GTK_RESPONSE_OK)
756
 
            {
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);
765
 
            }
766
 
            else
767
 
            {
768
 
                g_free (cred);
769
 
                cred = NULL;
770
 
                gp_vnc->connected = FALSE;
771
 
            }
772
 
        }
773
 
        break;
774
 
 
775
 
    default:
776
 
        g_free (cred);
777
 
        cred = NULL;
778
 
        break;
779
 
    }
780
 
    return cred;
781
 
}
782
 
#endif
783
 
 
784
 
static void 
785
 
remmina_plug_vnc_rfb_cursor_shape (rfbClient *cl, int xhot, int yhot, int width, int height, int bytesPerPixel)
786
 
{
787
 
    RemminaPlugVnc *gp_vnc;
788
 
    guchar *pixbuf_data;
789
 
    gint iy;
790
 
    guchar *destptr, *srcptr, *srcmaskptr;
791
 
    gint i;
792
 
    gint rs, gs, bs, rm, gm, bm, rb, gb, bb;
793
 
    guint32 pixel;
794
 
    GdkDisplay *display;
795
 
    GdkPixbuf *pixbuf;
796
 
    GdkCursor *cursor;
797
 
 
798
 
    gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
799
 
    if (!GTK_WIDGET (gp_vnc)->window) return;
800
 
 
801
 
    if (width && height)
802
 
    {
803
 
        pixbuf_data = g_malloc (width * height * 4);
804
 
        
805
 
        switch (cl->format.bitsPerPixel)
806
 
        {
807
 
        case 32:
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++)
813
 
            {
814
 
                *destptr++ = *(srcptr + 2);
815
 
                *destptr++ = *(srcptr + 1);
816
 
                *destptr++ = *srcptr;
817
 
                *destptr++ = (*srcmaskptr++) ? 0xff : 0x00;
818
 
                srcptr += 4;
819
 
            }
820
 
            break;
821
 
        default:
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++)
835
 
            {
836
 
                pixel = 0;
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;
842
 
            }
843
 
            break;
844
 
        }
845
 
 
846
 
        pixbuf = gdk_pixbuf_new_from_data (pixbuf_data, GDK_COLORSPACE_RGB,
847
 
                                 TRUE, 8, width, height,
848
 
                                 width * 4, NULL, NULL);
849
 
        THREADS_ENTER
850
 
 
851
 
        display = gdk_drawable_get_display (GDK_DRAWABLE (GTK_WIDGET (gp_vnc)->window));
852
 
 
853
 
        cursor = gdk_cursor_new_from_pixbuf (display,
854
 
                                 pixbuf,
855
 
                                 xhot, yhot);
856
 
 
857
 
        gdk_window_set_cursor (GTK_WIDGET (gp_vnc)->window, cursor);
858
 
        gdk_cursor_unref (cursor);
859
 
 
860
 
        THREADS_LEAVE
861
 
 
862
 
        gdk_pixbuf_unref (pixbuf);
863
 
 
864
 
        g_free (pixbuf_data);
865
 
    }
866
 
}
867
 
 
868
 
static void
869
 
remmina_plug_vnc_rfb_bell (rfbClient *cl)
870
 
{
871
 
    RemminaPlugVnc *gp_vnc;
872
 
    GdkWindow *window;
873
 
    
874
 
    gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
875
 
    window = GTK_WIDGET (gp_vnc)->window;
876
 
 
877
 
    gdk_window_beep (window);
878
 
}
879
 
 
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.")
886
 
#endif
887
 
/* TODO: We only store the last message at this moment. */
888
 
static gchar vnc_error[MAX_ERROR_LENGTH + 1];
889
 
static void
890
 
remmina_plug_vnc_rfb_output(const char *format, ...)
891
 
{
892
 
    va_list args;
893
 
    va_start(args, format);
894
 
    gchar *f, *p;
895
 
 
896
 
    /* eliminate the last \n */
897
 
    f = g_strdup (format);
898
 
    if (f[strlen (f) - 1] == '\n') f[strlen (f) - 1] = '\0';
899
 
 
900
 
/*g_printf("%s,len=%i\n", f, strlen(f));*/
901
 
    if (g_strcmp0 (f, "VNC connection failed: %s") == 0)
902
 
    {
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));
906
 
    }
907
 
    else
908
 
    {
909
 
        g_vsnprintf (vnc_error, MAX_ERROR_LENGTH, _(f), args);
910
 
    }
911
 
/*g_print ("%s\n", vnc_error);*/
912
 
    g_free (f);
913
 
 
914
 
    va_end(args);
915
 
}
916
 
 
917
 
static void
918
 
remmina_plug_vnc_chat_send (GtkWidget *window, gchar *text, RemminaPlugVnc *gp_vnc)
919
 
{
920
 
    gchar *ptr;
921
 
 
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);
925
 
    g_free (ptr);
926
 
}
927
 
 
928
 
static void
929
 
remmina_plug_vnc_chat_window_destroy (GtkWidget *widget, RemminaPlugVnc *gp_vnc)
930
 
{
931
 
    gp_vnc->chat_window = NULL;
932
 
    remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_CHAT_CLOSE, NULL, NULL, NULL);
933
 
}
934
 
 
935
 
static gboolean
936
 
remmina_plug_vnc_close_chat (RemminaPlugVnc *gp_vnc)
937
 
{
938
 
    if (gp_vnc->chat_window)
939
 
    {
940
 
        gtk_widget_destroy (gp_vnc->chat_window);
941
 
    }
942
 
    return FALSE;
943
 
}
944
 
 
945
 
static gboolean
946
 
remmina_plug_vnc_open_chat (RemminaPlugVnc *gp_vnc)
947
 
{
948
 
    rfbClient *cl = (rfbClient*) gp_vnc->client;
949
 
 
950
 
    if (gp_vnc->chat_window)
951
 
    {
952
 
        gtk_window_present (GTK_WINDOW (gp_vnc->chat_window));
953
 
    }
954
 
    else
955
 
    {
956
 
        gp_vnc->chat_window = remmina_chat_window_new (
957
 
            GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gp_vnc))),
958
 
            cl->desktopName);
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);
964
 
    }
965
 
    remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_CHAT_OPEN, NULL, NULL, NULL);
966
 
    return FALSE;
967
 
}
968
 
 
969
 
static void
970
 
remmina_plug_vnc_rfb_chat (rfbClient* cl, int value, char *text)
971
 
{
972
 
    RemminaPlugVnc *gp_vnc;
973
 
 
974
 
    gp_vnc = REMMINA_PLUG_VNC (rfbClientGetClientData (cl, NULL));
975
 
    switch (value)
976
 
    {
977
 
    case rfbTextChatOpen:
978
 
        IDLE_ADD ((GSourceFunc) remmina_plug_vnc_open_chat, gp_vnc);
979
 
        break;
980
 
    case rfbTextChatClose:
981
 
        /* Do nothing... but wait for the next rfbTextChatFinished signal */
982
 
        break;
983
 
    case rfbTextChatFinished:
984
 
        IDLE_ADD ((GSourceFunc) remmina_plug_vnc_close_chat, gp_vnc);
985
 
        break;
986
 
    default:
987
 
        /* value is the text length */
988
 
        THREADS_ENTER
989
 
        if (gp_vnc->chat_window)
990
 
        {
991
 
            remmina_chat_window_receive (REMMINA_CHAT_WINDOW (gp_vnc->chat_window), _("Server"), text);
992
 
            gtk_window_present (GTK_WINDOW (gp_vnc->chat_window));
993
 
        }
994
 
        THREADS_LEAVE
995
 
        break;
996
 
    }
997
 
}
998
 
 
999
 
static gboolean
1000
 
remmina_plug_vnc_incoming_connection (RemminaPlugVnc *gp_vnc, rfbClient *cl)
1001
 
{
1002
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1003
 
    fd_set fds;
1004
 
 
1005
 
    gp_vnc->listen_sock = ListenAtTcpPort (cl->listenPort);
1006
 
    if (gp_vnc->listen_sock < 0) return FALSE;
1007
 
 
1008
 
    remmina_init_dialog_set_status (REMMINA_INIT_DIALOG (gp->init_dialog),
1009
 
        _("Listening on Port %i for an Incoming VNC Connection..."), cl->listenPort);
1010
 
 
1011
 
    FD_ZERO (&fds); 
1012
 
    FD_SET (gp_vnc->listen_sock, &fds);
1013
 
    select (gp_vnc->listen_sock + 1, &fds, NULL, NULL, NULL);
1014
 
 
1015
 
    if (!FD_ISSET (gp_vnc->listen_sock, &fds))
1016
 
    {
1017
 
        close (gp_vnc->listen_sock);
1018
 
        gp_vnc->listen_sock = -1;
1019
 
        return FALSE;
1020
 
    }
1021
 
 
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))
1026
 
    {
1027
 
        return FALSE;
1028
 
    }
1029
 
 
1030
 
    return TRUE;
1031
 
}
1032
 
 
1033
 
static gboolean
1034
 
remmina_plug_vnc_main_loop (RemminaPlugVnc *gp_vnc)
1035
 
{
1036
 
    gint ret;
1037
 
    rfbClient *cl;
1038
 
    fd_set fds;
1039
 
    struct timeval timeout;
1040
 
 
1041
 
    if (!gp_vnc->connected)
1042
 
    {
1043
 
        gp_vnc->running = FALSE;
1044
 
        return FALSE;
1045
 
    }
1046
 
 
1047
 
    cl = (rfbClient*) gp_vnc->client;
1048
 
 
1049
 
    timeout.tv_sec = 10;
1050
 
    timeout.tv_usec = 0;
1051
 
    FD_ZERO (&fds);
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);
1055
 
 
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;
1059
 
 
1060
 
    if (FD_ISSET (gp_vnc->vnc_event_pipe[0], &fds))
1061
 
    {
1062
 
        remmina_plug_vnc_process_vnc_event (gp_vnc);
1063
 
    }
1064
 
    if (FD_ISSET (cl->sock, &fds))
1065
 
    {
1066
 
        ret = HandleRFBServerMessage (cl);
1067
 
        if (!ret)
1068
 
        {
1069
 
            gp_vnc->running = FALSE;
1070
 
            if (gp_vnc->connected && !REMMINA_PLUG (gp_vnc)->closed)
1071
 
            {
1072
 
                IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, gp_vnc);
1073
 
            }
1074
 
            return FALSE;
1075
 
        }
1076
 
    }
1077
 
 
1078
 
    return TRUE;
1079
 
}
1080
 
 
1081
 
static gboolean
1082
 
remmina_plug_vnc_main (RemminaPlugVnc *gp_vnc)
1083
 
{
1084
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1085
 
    rfbClient *cl = NULL;
1086
 
    gchar *host, *pos;
1087
 
    gchar *s;
1088
 
    gboolean save = FALSE;
1089
 
 
1090
 
    gp_vnc->running = TRUE;
1091
 
 
1092
 
    rfbClientLog = remmina_plug_vnc_rfb_output;
1093
 
    rfbClientErr = remmina_plug_vnc_rfb_output;
1094
 
 
1095
 
    while (gp_vnc->connected)
1096
 
    {
1097
 
        gp_vnc->auth_called = FALSE;
1098
 
 
1099
 
        host = remmina_plug_start_direct_tunnel (gp, 5900, TRUE);
1100
 
 
1101
 
        if (host == NULL)
1102
 
        {
1103
 
            gp_vnc->connected = FALSE;
1104
 
            break;
1105
 
        }
1106
 
 
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;
1113
 
#endif
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);
1120
 
 
1121
 
        if (host[0] == '\0')
1122
 
        {
1123
 
            cl->serverHost = host;
1124
 
            cl->listenSpecified = TRUE;
1125
 
            cl->listenPort = gp->remmina_file->listenport;
1126
 
 
1127
 
            remmina_plug_vnc_incoming_connection (gp_vnc, cl);
1128
 
        }
1129
 
        else
1130
 
        {
1131
 
            pos = g_strrstr (host, ":");
1132
 
            *pos++ = '\0';
1133
 
            cl->serverPort = MAX (0, atoi (pos));
1134
 
            cl->serverHost = host;
1135
 
 
1136
 
            /* Support short-form (:0, :1) */
1137
 
            if (cl->serverPort < 100) cl->serverPort += 5900;
1138
 
        }
1139
 
 
1140
 
        cl->appData.useRemoteCursor = (gp->remmina_file->showcursor ? FALSE : TRUE);
1141
 
 
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);
1145
 
 
1146
 
        if (rfbInitClient (cl, NULL, NULL)) break;
1147
 
 
1148
 
        /* If the authentication is not called, it has to be a fatel error and must quit */
1149
 
        if (!gp_vnc->auth_called)
1150
 
        {
1151
 
            gp_vnc->connected = FALSE;
1152
 
            break;
1153
 
        }
1154
 
 
1155
 
        /* vnc4server reports "already in use" after authentication. Workaround here */
1156
 
        if (strstr(vnc_error, "The server is already in use"))
1157
 
        {
1158
 
            gp_vnc->connected = FALSE;
1159
 
            gp_vnc->auth_called = FALSE;
1160
 
            break;
1161
 
        }
1162
 
 
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';
1165
 
 
1166
 
        if (!gp_vnc->connected) break;
1167
 
 
1168
 
        THREADS_ENTER
1169
 
        remmina_init_dialog_set_status_temp (REMMINA_INIT_DIALOG (gp->init_dialog),
1170
 
            _("VNC authentication failed. Trying to reconnect..."));
1171
 
        THREADS_LEAVE
1172
 
        /* It's safer to sleep a while before reconnect */
1173
 
        sleep (2);
1174
 
 
1175
 
        gp_vnc->auth_first = FALSE;
1176
 
    }
1177
 
 
1178
 
    if (!gp_vnc->connected)
1179
 
    {
1180
 
        if (cl && !gp_vnc->auth_called && !(gp->has_error))
1181
 
        {
1182
 
            g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", vnc_error);
1183
 
            gp->has_error = TRUE;
1184
 
        }
1185
 
        gp_vnc->running = FALSE;
1186
 
 
1187
 
        IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, gp_vnc);
1188
 
 
1189
 
        return FALSE;
1190
 
    }
1191
 
 
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;
1194
 
    if (s && s[0])
1195
 
    {
1196
 
        if (gp->remmina_file->username) g_free (gp->remmina_file->username);
1197
 
        gp->remmina_file->username = g_strdup (s);
1198
 
        save = TRUE;
1199
 
    }
1200
 
    s = REMMINA_INIT_DIALOG (gp->init_dialog)->cacert;
1201
 
    if (s && s[0])
1202
 
    {
1203
 
        if (gp->remmina_file->cacert) g_free (gp->remmina_file->cacert);
1204
 
        gp->remmina_file->cacert = g_strdup (s);
1205
 
        save = TRUE;
1206
 
    }
1207
 
    s = REMMINA_INIT_DIALOG (gp->init_dialog)->cacrl;
1208
 
    if (s && s[0])
1209
 
    {
1210
 
        if (gp->remmina_file->cacrl) g_free (gp->remmina_file->cacrl);
1211
 
        gp->remmina_file->cacrl = g_strdup (s);
1212
 
        save = TRUE;
1213
 
    }
1214
 
    s = REMMINA_INIT_DIALOG (gp->init_dialog)->clientcert;
1215
 
    if (s && s[0])
1216
 
    {
1217
 
        if (gp->remmina_file->clientcert) g_free (gp->remmina_file->clientcert);
1218
 
        gp->remmina_file->clientcert = g_strdup (s);
1219
 
        save = TRUE;
1220
 
    }
1221
 
    s = REMMINA_INIT_DIALOG (gp->init_dialog)->clientkey;
1222
 
    if (s && s[0])
1223
 
    {
1224
 
        if (gp->remmina_file->clientkey) g_free (gp->remmina_file->clientkey);
1225
 
        gp->remmina_file->clientkey = g_strdup (s);
1226
 
        save = TRUE;
1227
 
    }
1228
 
    if (REMMINA_INIT_DIALOG (gp->init_dialog)->save_password)
1229
 
    {
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);
1233
 
        save = TRUE;
1234
 
    }
1235
 
    if (save)
1236
 
    {
1237
 
        remmina_file_save (gp->remmina_file);
1238
 
    }
1239
 
 
1240
 
    gp_vnc->client = cl;
1241
 
 
1242
 
    remmina_plug_emit_signal (gp, "connect");
1243
 
 
1244
 
    if (gp->remmina_file->disableserverinput)
1245
 
    {
1246
 
        PermitServerInput(cl, 1);
1247
 
    }
1248
 
 
1249
 
    if (gp_vnc->thread)
1250
 
    {
1251
 
        while (remmina_plug_vnc_main_loop (gp_vnc)) { }
1252
 
        gp_vnc->running = FALSE;
1253
 
    }
1254
 
    else
1255
 
    {
1256
 
        IDLE_ADD ((GSourceFunc) remmina_plug_vnc_main_loop, gp_vnc);
1257
 
    }
1258
 
 
1259
 
    return FALSE;
1260
 
}
1261
 
 
1262
 
#ifdef HAVE_PTHREAD
1263
 
static gpointer
1264
 
remmina_plug_vnc_main_thread (gpointer data)
1265
 
{
1266
 
    pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
1267
 
 
1268
 
    CANCEL_ASYNC
1269
 
    remmina_plug_vnc_main (REMMINA_PLUG_VNC (data));
1270
 
    return NULL;
1271
 
}
1272
 
#endif
1273
 
 
1274
 
static gboolean
1275
 
remmina_plug_vnc_on_motion (GtkWidget *widget, GdkEventMotion *event, RemminaPlugVnc *gp_vnc)
1276
 
{
1277
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1278
 
    gint x, y;
1279
 
 
1280
 
    if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1281
 
    if (gp->remmina_file->viewonly) return FALSE;
1282
 
 
1283
 
    if (gp->scale)
1284
 
    {
1285
 
        x = event->x * gp->width / gp_vnc->scale_width;
1286
 
        y = event->y * gp->height / gp_vnc->scale_height;
1287
 
    }
1288
 
    else
1289
 
    {
1290
 
        x = event->x;
1291
 
        y = event->y;
1292
 
    }
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));
1295
 
    return TRUE;
1296
 
}
1297
 
 
1298
 
static gboolean
1299
 
remmina_plug_vnc_on_button (GtkWidget *widget, GdkEventButton *event, RemminaPlugVnc *gp_vnc)
1300
 
{
1301
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1302
 
    gint x, y;
1303
 
    gint mask;
1304
 
 
1305
 
    if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1306
 
    if (gp->remmina_file->viewonly) return FALSE;
1307
 
 
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;
1312
 
 
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)));
1317
 
    if (gp->scale)
1318
 
    {
1319
 
        x = event->x * gp->width / gp_vnc->scale_width;
1320
 
        y = event->y * gp->height / gp_vnc->scale_height;
1321
 
    }
1322
 
    else
1323
 
    {
1324
 
        x = event->x;
1325
 
        y = event->y;
1326
 
    }
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));
1329
 
    return TRUE;
1330
 
}
1331
 
 
1332
 
static gboolean
1333
 
remmina_plug_vnc_on_scroll (GtkWidget *widget, GdkEventScroll *event, RemminaPlugVnc *gp_vnc)
1334
 
{
1335
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1336
 
    gint x, y;
1337
 
    gint mask;
1338
 
 
1339
 
    if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1340
 
    if (gp->remmina_file->viewonly) return FALSE;
1341
 
 
1342
 
    switch (event->direction)
1343
 
    {
1344
 
    case GDK_SCROLL_UP:
1345
 
        mask = (1 << 3);
1346
 
        break;
1347
 
    case GDK_SCROLL_DOWN:
1348
 
        mask = (1 << 4);
1349
 
        break;
1350
 
    case GDK_SCROLL_LEFT:
1351
 
        mask = (1 << 5);
1352
 
        break;
1353
 
    case GDK_SCROLL_RIGHT:
1354
 
        mask = (1 << 6);
1355
 
        break;
1356
 
    default:
1357
 
        return FALSE;
1358
 
    }
1359
 
 
1360
 
    if (gp->scale)
1361
 
    {
1362
 
        x = event->x * gp->width / gp_vnc->scale_width;
1363
 
        y = event->y * gp->height / gp_vnc->scale_height;
1364
 
    }
1365
 
    else
1366
 
    {
1367
 
        x = event->x;
1368
 
        y = event->y;
1369
 
    }
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));
1374
 
 
1375
 
    return TRUE;
1376
 
}
1377
 
 
1378
 
static void
1379
 
remmina_plug_vnc_release_key (RemminaPlugVnc *gp_vnc, guint16 keycode)
1380
 
{
1381
 
    RemminaKeyVal *k;
1382
 
    gint i;
1383
 
 
1384
 
    if (keycode == 0)
1385
 
    {
1386
 
        /* Send all release key events for previously pressed keys */
1387
 
        for (i = 0; i < gp_vnc->pressed_keys->len; i++)
1388
 
        {
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);
1391
 
            g_free (k);
1392
 
        }
1393
 
        g_ptr_array_set_size (gp_vnc->pressed_keys, 0);
1394
 
    }
1395
 
    else
1396
 
    {
1397
 
        /* Unregister the keycode only */
1398
 
        for (i = 0; i < gp_vnc->pressed_keys->len; i++)
1399
 
        {
1400
 
            k = g_ptr_array_index (gp_vnc->pressed_keys, i);
1401
 
            if (k->keycode == keycode)
1402
 
            {
1403
 
                g_free (k);
1404
 
                g_ptr_array_remove_index_fast (gp_vnc->pressed_keys, i);
1405
 
                break;
1406
 
            }
1407
 
        }
1408
 
    }
1409
 
}
1410
 
 
1411
 
static gboolean
1412
 
remmina_plug_vnc_on_key (GtkWidget *widget, GdkEventKey *event, RemminaPlugVnc *gp_vnc)
1413
 
{
1414
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1415
 
    RemminaKeyVal *k;
1416
 
    guint keyval;
1417
 
 
1418
 
    if (!gp_vnc->connected || !gp_vnc->client) return FALSE;
1419
 
    if (gp->remmina_file->viewonly) return FALSE;
1420
 
 
1421
 
    keyval = remmina_pref_keymap_keyval (gp->remmina_file->gkeymap, event->keyval);
1422
 
 
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);
1425
 
 
1426
 
    /* Register/unregister the pressed key */
1427
 
    if (event->type == GDK_KEY_PRESS)
1428
 
    {
1429
 
        k = g_new (RemminaKeyVal, 1);
1430
 
        k->keyval = keyval;
1431
 
        k->keycode = event->hardware_keycode;
1432
 
        g_ptr_array_add (gp_vnc->pressed_keys, k);
1433
 
    }
1434
 
    else
1435
 
    {
1436
 
        remmina_plug_vnc_release_key (gp_vnc, event->hardware_keycode);
1437
 
    }
1438
 
    return TRUE;
1439
 
}
1440
 
 
1441
 
static void
1442
 
remmina_plug_vnc_on_cuttext_request (GtkClipboard *clipboard, const gchar *text, RemminaPlugVnc *gp_vnc)
1443
 
{
1444
 
    GTimeVal t;
1445
 
    glong diff;
1446
 
 
1447
 
    if (text)
1448
 
    {
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;
1453
 
 
1454
 
        gp_vnc->clipboard_timer = t;
1455
 
        remmina_plug_vnc_event_push (gp_vnc, REMMINA_PLUG_VNC_EVENT_CUTTEXT, (gpointer) text, NULL, NULL);
1456
 
    }
1457
 
}
1458
 
 
1459
 
static void
1460
 
remmina_plug_vnc_on_cuttext (GtkClipboard *clipboard, GdkEvent *event, RemminaPlugVnc *gp_vnc)
1461
 
{
1462
 
    if (!gp_vnc->connected || !gp_vnc->client) return;
1463
 
    if (REMMINA_PLUG (gp_vnc)->remmina_file->viewonly) return;
1464
 
 
1465
 
    gtk_clipboard_request_text (clipboard, (GtkClipboardTextReceivedFunc) remmina_plug_vnc_on_cuttext_request, gp_vnc);
1466
 
}
1467
 
 
1468
 
static void
1469
 
remmina_plug_vnc_on_realize (RemminaPlugVnc *gp_vnc, gpointer data)
1470
 
{
1471
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1472
 
    GdkCursor *cursor;
1473
 
    GdkPixmap *source, *mask;
1474
 
    GdkColor fg, bg;
1475
 
 
1476
 
    if (gp->remmina_file->showcursor)
1477
 
    {
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);
1488
 
    }
1489
 
}
1490
 
 
1491
 
/******************************************************************************************/
1492
 
 
1493
 
static gboolean
1494
 
remmina_plug_vnc_open_connection (RemminaPlug *gp)
1495
 
{
1496
 
    RemminaPlugVnc *gp_vnc = REMMINA_PLUG_VNC (gp);
1497
 
 
1498
 
    gp_vnc->connected = TRUE;
1499
 
 
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);
1514
 
 
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);
1517
 
 
1518
 
#ifdef HAVE_PTHREAD
1519
 
    if (pthread_create (&gp_vnc->thread, NULL, remmina_plug_vnc_main_thread, gp_vnc))
1520
 
    {
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);
1524
 
        gp_vnc->thread = 0;
1525
 
    }
1526
 
#else
1527
 
    g_timeout_add (0, (GSourceFunc) remmina_plug_vnc_main, gp);
1528
 
#endif
1529
 
 
1530
 
    return TRUE;
1531
 
}
1532
 
 
1533
 
static gboolean
1534
 
remmina_plug_vnc_close_connection_timeout (RemminaPlugVnc *gp_vnc)
1535
 
{
1536
 
    /* wait until the running attribute is set to false by the VNC thread */
1537
 
    if (gp_vnc->running) return TRUE;
1538
 
 
1539
 
    /* unregister the clipboard monitor */
1540
 
    if (gp_vnc->clipboard_handler)
1541
 
    {
1542
 
        g_signal_handler_disconnect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)),
1543
 
            gp_vnc->clipboard_handler);
1544
 
        gp_vnc->clipboard_handler = 0;
1545
 
    }
1546
 
 
1547
 
    if (gp_vnc->queuedraw_handler)
1548
 
    {
1549
 
        g_source_remove (gp_vnc->queuedraw_handler);
1550
 
        gp_vnc->queuedraw_handler = 0;
1551
 
    }
1552
 
    if (gp_vnc->scale_handler)
1553
 
    {
1554
 
        g_source_remove (gp_vnc->scale_handler);
1555
 
        gp_vnc->scale_handler = 0;
1556
 
    }
1557
 
    if (gp_vnc->chat_window)
1558
 
    {
1559
 
        gtk_widget_destroy (gp_vnc->chat_window);
1560
 
        gp_vnc->chat_window = NULL;
1561
 
    }
1562
 
    if (gp_vnc->listen_sock >= 0)
1563
 
    {
1564
 
        close (gp_vnc->listen_sock);
1565
 
    }
1566
 
    if (gp_vnc->client)
1567
 
    {
1568
 
        rfbClientCleanup((rfbClient*) gp_vnc->client);
1569
 
        gp_vnc->client = NULL;
1570
 
    }
1571
 
    if (gp_vnc->rgb_buffer)
1572
 
    {
1573
 
        g_object_unref (gp_vnc->rgb_buffer);
1574
 
        gp_vnc->rgb_buffer = NULL;
1575
 
    }
1576
 
    if (gp_vnc->vnc_buffer)
1577
 
    {
1578
 
        g_free (gp_vnc->vnc_buffer);
1579
 
        gp_vnc->vnc_buffer = NULL;
1580
 
    }
1581
 
    if (gp_vnc->scale_buffer)
1582
 
    {
1583
 
        g_object_unref (gp_vnc->scale_buffer);
1584
 
        gp_vnc->scale_buffer = NULL;
1585
 
    }
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]);
1591
 
    
1592
 
#ifdef HAVE_PTHREAD
1593
 
    pthread_mutex_destroy (&gp_vnc->buffer_mutex);
1594
 
#endif
1595
 
 
1596
 
    remmina_plug_emit_signal (REMMINA_PLUG (gp_vnc), "disconnect");
1597
 
 
1598
 
    return FALSE;
1599
 
}
1600
 
 
1601
 
static gboolean
1602
 
remmina_plug_vnc_close_connection (RemminaPlug *gp)
1603
 
{
1604
 
    RemminaPlugVnc *gp_vnc = REMMINA_PLUG_VNC (gp);
1605
 
 
1606
 
    gp_vnc->connected = FALSE;
1607
 
 
1608
 
#ifdef HAVE_PTHREAD
1609
 
    if (gp_vnc->thread)
1610
 
    {
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);
1615
 
    }
1616
 
    else
1617
 
    {
1618
 
        g_timeout_add (200, (GSourceFunc) remmina_plug_vnc_close_connection_timeout, gp);
1619
 
    }
1620
 
#else
1621
 
    g_timeout_add (200, (GSourceFunc) remmina_plug_vnc_close_connection_timeout, gp);
1622
 
#endif
1623
 
 
1624
 
    return FALSE;
1625
 
}
1626
 
 
1627
 
static gpointer
1628
 
remmina_plug_vnc_query_feature (RemminaPlug *gp, RemminaPlugFeature feature)
1629
 
{
1630
 
    switch (feature)
1631
 
    {
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);
1644
 
        default:
1645
 
            return NULL;
1646
 
    }
1647
 
}
1648
 
 
1649
 
static void
1650
 
remmina_plug_vnc_call_feature (RemminaPlug *gp, RemminaPlugFeature feature, const gpointer data)
1651
 
{
1652
 
    RemminaPlugVnc *gp_vnc = REMMINA_PLUG_VNC (gp);
1653
 
    switch (feature)
1654
 
    {
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));
1658
 
            break;
1659
 
        case REMMINA_PLUG_FEATURE_PREF_VIEWONLY:
1660
 
            gp->remmina_file->viewonly = (data != NULL);
1661
 
            break;
1662
 
        case REMMINA_PLUG_FEATURE_PREF_DISABLESERVERINPUT:
1663
 
            PermitServerInput ((rfbClient*) (gp_vnc->client), (data ? 1 : 0));
1664
 
            gp->remmina_file->disableserverinput = (data ? TRUE : FALSE);
1665
 
            break;
1666
 
        case REMMINA_PLUG_FEATURE_UNFOCUS:
1667
 
            remmina_plug_vnc_release_key (gp_vnc, 0);
1668
 
            break;
1669
 
        case REMMINA_PLUG_FEATURE_SCALE:
1670
 
            remmina_plug_vnc_update_scale (gp_vnc, (data != NULL));
1671
 
            break;
1672
 
        case REMMINA_PLUG_FEATURE_TOOL_CHAT:
1673
 
            remmina_plug_vnc_open_chat (gp_vnc);
1674
 
            break;
1675
 
        default:
1676
 
            break;
1677
 
    }
1678
 
}
1679
 
 
1680
 
#else /* HAVE_LIBVNCCLIENT */
1681
 
 
1682
 
static gboolean
1683
 
remmina_plug_vnc_open_connection (RemminaPlug *gp)
1684
 
{
1685
 
    GtkWidget *dialog;
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);
1692
 
    return FALSE;
1693
 
}
1694
 
 
1695
 
static gboolean
1696
 
remmina_plug_vnc_close_connection (RemminaPlug *gp)
1697
 
{
1698
 
    return FALSE;
1699
 
}
1700
 
 
1701
 
static gpointer
1702
 
remmina_plug_vnc_query_feature (RemminaPlug *gp, RemminaPlugFeature feature)
1703
 
{
1704
 
    return NULL;
1705
 
}
1706
 
 
1707
 
static void
1708
 
remmina_plug_vnc_call_feature (RemminaPlug *gp, RemminaPlugFeature feature, const gpointer data)
1709
 
{
1710
 
}
1711
 
 
1712
 
#endif /* HAVE_LIBVNCCLIENT */
1713
 
 
1714
 
static gboolean
1715
 
remmina_plug_vnc_on_expose (GtkWidget *widget, GdkEventExpose *event, RemminaPlugVnc *gp_vnc)
1716
 
{
1717
 
    RemminaPlug *gp = REMMINA_PLUG (gp_vnc);
1718
 
    GdkPixbuf *buffer;
1719
 
    gint width, height, x, y, rowstride;
1720
 
 
1721
 
    LOCK_BUFFER (FALSE)
1722
 
 
1723
 
    /* widget == gp_vnc->drawing_area */
1724
 
    buffer = (gp->scale ? gp_vnc->scale_buffer : gp_vnc->rgb_buffer);
1725
 
    if (!buffer)
1726
 
    {
1727
 
        UNLOCK_BUFFER (FALSE)
1728
 
        return FALSE;
1729
 
    }
1730
 
 
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)
1734
 
    {
1735
 
        UNLOCK_BUFFER (FALSE)
1736
 
        return FALSE;
1737
 
    }
1738
 
    x = event->area.x;
1739
 
    y = event->area.y;
1740
 
    rowstride = gdk_pixbuf_get_rowstride (buffer);
1741
 
 
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,
1745
 
        x, y,
1746
 
        MIN (width - x, event->area.width), MIN (height - y, event->area.height),
1747
 
        GDK_RGB_DITHER_MAX,
1748
 
        gdk_pixbuf_get_pixels (buffer) + y * rowstride + x * 3,
1749
 
        rowstride);
1750
 
 
1751
 
    UNLOCK_BUFFER (FALSE)
1752
 
    return TRUE;
1753
 
}
1754
 
 
1755
 
static gboolean
1756
 
remmina_plug_vnc_on_configure (GtkWidget *widget, GdkEventConfigure *event, RemminaPlugVnc *gp_vnc)
1757
 
{
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);
1761
 
    return FALSE;
1762
 
}
1763
 
 
1764
 
static void
1765
 
remmina_plug_vnc_class_init (RemminaPlugVncClass *klass)
1766
 
{
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;
1771
 
}
1772
 
 
1773
 
static void
1774
 
remmina_plug_vnc_destroy (GtkWidget *widget, gpointer data)
1775
 
{
1776
 
}
1777
 
 
1778
 
static void
1779
 
remmina_plug_vnc_init (RemminaPlugVnc *gp_vnc)
1780
 
{
1781
 
    gint flags;
1782
 
 
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);
1786
 
 
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);
1790
 
 
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);
1796
 
 
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;
1819
 
    gp_vnc->thread = 0;
1820
 
    gp_vnc->vnc_event_queue = g_queue_new ();
1821
 
    if (pipe (gp_vnc->vnc_event_pipe))
1822
 
    {
1823
 
        g_print ("Error creating pipes.\n");
1824
 
        gp_vnc->vnc_event_pipe[0] = 0;
1825
 
        gp_vnc->vnc_event_pipe[1] = 0;
1826
 
    }
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);
1829
 
#ifdef HAVE_PTHREAD
1830
 
    pthread_mutex_init (&gp_vnc->buffer_mutex, NULL);
1831
 
#endif
1832
 
}
1833
 
 
1834
 
GtkWidget*
1835
 
remmina_plug_vnc_new (gboolean scale)
1836
 
{
1837
 
    RemminaPlugVnc *gp_vnc;
1838
 
 
1839
 
    gp_vnc = REMMINA_PLUG_VNC (g_object_new (REMMINA_TYPE_PLUG_VNC, NULL));
1840
 
    REMMINA_PLUG (gp_vnc)->scale = scale;
1841
 
 
1842
 
    return GTK_WIDGET (gp_vnc);
1843
 
}
1844