~ubuntu-branches/ubuntu/saucy/remmina/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/scroll_smooth.patch/remmina-plugins/rdp/rdp_event.c

  • Committer: Package Import Robot
  • Author(s): Jean-Louis Dupond
  • Date: 2012-04-22 23:10:05 UTC
  • Revision ID: package-import@ubuntu.com-20120422231005-7wz1utk5ez0bevub
Tags: 1.0.0-1ubuntu6
debian/patches/scroll_smooth.patch: fix scrolling with GDK_SCROLL_SMOOTH
(LP: #952964).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Remmina - The GTK+ Remote Desktop Client
 
3
 * Copyright (C) 2010 Jay Sorg
 
4
 * Copyright (C) 2010-2011 Vic Lee
 
5
 * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place, Suite 330, 
 
20
 * Boston, MA 02111-1307, USA.
 
21
 */
 
22
 
 
23
/* X11 drawings were ported from xfreerdp */
 
24
 
 
25
#include "rdp_plugin.h"
 
26
#include "rdp_event.h"
 
27
#include "rdp_gdi.h"
 
28
#include <gdk/gdkkeysyms.h>
 
29
#include <cairo/cairo-xlib.h>
 
30
#include <freerdp/kbd/kbd.h>
 
31
 
 
32
static void remmina_rdp_event_event_push(RemminaProtocolWidget* gp, const RemminaPluginRdpEvent* e)
 
33
{
 
34
        rfContext* rfi;
 
35
        RemminaPluginRdpEvent* event;
 
36
 
 
37
        rfi = GET_DATA(gp);
 
38
 
 
39
        if (rfi->event_queue)
 
40
        {
 
41
                event = g_memdup(e, sizeof(RemminaPluginRdpEvent));
 
42
                g_async_queue_push(rfi->event_queue, event);
 
43
 
 
44
                if (write(rfi->event_pipe[1], "\0", 1))
 
45
                {
 
46
                }
 
47
        }
 
48
}
 
49
 
 
50
static void remmina_rdp_event_release_key(RemminaProtocolWidget* gp, gint scancode)
 
51
{
 
52
        gint i, k;
 
53
        rfContext* rfi;
 
54
        RemminaPluginRdpEvent rdp_event = { 0 };
 
55
 
 
56
        rfi = GET_DATA(gp);
 
57
        rdp_event.type = REMMINA_RDP_EVENT_TYPE_SCANCODE;
 
58
 
 
59
        if (scancode == 0)
 
60
        {
 
61
                /* Send all release key events for previously pressed keys */
 
62
                rdp_event.key_event.up = True;
 
63
 
 
64
                for (i = 0; i < rfi->pressed_keys->len; i++)
 
65
                {
 
66
                        rdp_event.key_event.key_code = g_array_index(rfi->pressed_keys, gint, i);
 
67
                        remmina_rdp_event_event_push(gp, &rdp_event);
 
68
                }
 
69
 
 
70
                g_array_set_size(rfi->pressed_keys, 0);
 
71
        }
 
72
        else
 
73
        {
 
74
                /* Unregister the keycode only */
 
75
                for (i = 0; i < rfi->pressed_keys->len; i++)
 
76
                {
 
77
                        k = g_array_index(rfi->pressed_keys, gint, i);
 
78
 
 
79
                        if (k == scancode)
 
80
                        {
 
81
                                g_array_remove_index_fast(rfi->pressed_keys, i);
 
82
                                break;
 
83
                        }
 
84
                }
 
85
        }
 
86
}
 
87
 
 
88
static void remmina_rdp_event_scale_area(RemminaProtocolWidget* gp, gint* x, gint* y, gint* w, gint* h)
 
89
{
 
90
        gint width, height;
 
91
        gint sx, sy, sw, sh;
 
92
        rfContext* rfi;
 
93
 
 
94
        rfi = GET_DATA(gp);
 
95
 
 
96
        if (!rfi->rgb_surface)
 
97
                return;
 
98
 
 
99
        width = remmina_plugin_service->protocol_plugin_get_width(gp);
 
100
        height = remmina_plugin_service->protocol_plugin_get_height(gp);
 
101
 
 
102
        if ((width == 0) || (height == 0))
 
103
                return;
 
104
 
 
105
        if ((rfi->scale_width == width) && (rfi->scale_height == height))
 
106
        {
 
107
                /* Same size, just copy the pixels */
 
108
                *x = MIN(MAX(0, *x), width - 1);
 
109
                *y = MIN(MAX(0, *y), height - 1);
 
110
                *w = MIN(width - *x, *w);
 
111
                *h = MIN(height - *y, *h);
 
112
                return;
 
113
        }
 
114
 
 
115
        /* We have to extend the scaled region one scaled pixel, to avoid gaps */
 
116
 
 
117
        sx = MIN(MAX(0, (*x) * rfi->scale_width / width
 
118
                - rfi->scale_width / width - 2), rfi->scale_width - 1);
 
119
 
 
120
        sy = MIN(MAX(0, (*y) * rfi->scale_height / height
 
121
                - rfi->scale_height / height - 2), rfi->scale_height - 1);
 
122
 
 
123
        sw = MIN(rfi->scale_width - sx, (*w) * rfi->scale_width / width
 
124
                + rfi->scale_width / width + 4);
 
125
 
 
126
        sh = MIN(rfi->scale_height - sy, (*h) * rfi->scale_height / height
 
127
                + rfi->scale_height / height + 4);
 
128
 
 
129
        *x = sx;
 
130
        *y = sy;
 
131
        *w = sw;
 
132
        *h = sh;
 
133
}
 
134
 
 
135
void remmina_rdp_event_update_region(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui)
 
136
{
 
137
        rfContext* rfi;
 
138
        gint x, y, w, h;
 
139
 
 
140
        x = ui->region.x;
 
141
        y = ui->region.y;
 
142
        w = ui->region.width;
 
143
        h = ui->region.height;
 
144
 
 
145
        rfi = GET_DATA(gp);
 
146
 
 
147
        if (rfi->sw_gdi)
 
148
        {
 
149
                XPutImage(rfi->display, rfi->primary, rfi->gc, rfi->image, x, y, x, y, w, h);
 
150
                XCopyArea(rfi->display, rfi->primary, rfi->rgb_surface, rfi->gc, x, y, w, h, x, y);
 
151
        }
 
152
 
 
153
        if (remmina_plugin_service->protocol_plugin_get_scale(gp))
 
154
                remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
 
155
 
 
156
        gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
 
157
}
 
158
 
 
159
void remmina_rdp_event_update_rect(RemminaProtocolWidget* gp, gint x, gint y, gint w, gint h)
 
160
{
 
161
        rfContext* rfi;
 
162
 
 
163
        rfi = GET_DATA(gp);
 
164
 
 
165
        if (rfi->sw_gdi)
 
166
        {
 
167
                XPutImage(rfi->display, rfi->primary, rfi->gc, rfi->image, x, y, x, y, w, h);
 
168
                XCopyArea(rfi->display, rfi->primary, rfi->rgb_surface, rfi->gc, x, y, w, h, x, y);
 
169
        }
 
170
 
 
171
        if (remmina_plugin_service->protocol_plugin_get_scale(gp))
 
172
                remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
 
173
 
 
174
        gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
 
175
}
 
176
 
 
177
static gboolean remmina_rdp_event_update_scale_factor(RemminaProtocolWidget* gp)
 
178
{
 
179
        GtkAllocation a;
 
180
        gboolean scale;
 
181
        gint width, height;
 
182
        gint hscale, vscale;
 
183
        gint gpwidth, gpheight;
 
184
        RemminaFile* remminafile;
 
185
        rfContext* rfi;
 
186
 
 
187
        rfi = GET_DATA(gp);
 
188
        remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
 
189
 
 
190
        gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
 
191
        width = a.width;
 
192
        height = a.height;
 
193
        scale = remmina_plugin_service->protocol_plugin_get_scale(gp);
 
194
 
 
195
        if (scale)
 
196
        {
 
197
                if ((width > 1) && (height > 1))
 
198
                {
 
199
                        gpwidth = remmina_plugin_service->protocol_plugin_get_width(gp);
 
200
                        gpheight = remmina_plugin_service->protocol_plugin_get_height(gp);
 
201
                        hscale = remmina_plugin_service->file_get_int(remminafile, "hscale", 0);
 
202
                        vscale = remmina_plugin_service->file_get_int(remminafile, "vscale", 0);
 
203
 
 
204
                        rfi->scale_width = (hscale > 0 ?
 
205
                                MAX(1, gpwidth * hscale / 100) : width);
 
206
                        rfi->scale_height = (vscale > 0 ?
 
207
                                MAX(1, gpheight * vscale / 100) : height);
 
208
 
 
209
                        rfi->scale_x = (gdouble) rfi->scale_width / (gdouble) gpwidth;
 
210
                        rfi->scale_y = (gdouble) rfi->scale_height / (gdouble) gpheight;
 
211
                }
 
212
        }
 
213
        else
 
214
        {
 
215
                rfi->scale_width = 0;
 
216
                rfi->scale_height = 0;
 
217
                rfi->scale_x = 0;
 
218
                rfi->scale_y = 0;
 
219
        }
 
220
 
 
221
        if ((width > 1) && (height > 1))
 
222
                gtk_widget_queue_draw_area(GTK_WIDGET(gp), 0, 0, width, height);
 
223
 
 
224
        rfi->scale_handler = 0;
 
225
 
 
226
        return FALSE;
 
227
}
 
228
 
 
229
#if GTK_VERSION == 2
 
230
static gboolean remmina_rdp_event_on_expose(GtkWidget *widget, GdkEventExpose *event, RemminaProtocolWidget *gp)
 
231
#else
 
232
static gboolean remmina_rdp_event_on_draw(GtkWidget* widget, cairo_t* context, RemminaProtocolWidget* gp)
 
233
#endif
 
234
{
 
235
        gboolean scale;
 
236
        rfContext* rfi;
 
237
#if GTK_VERSION == 2
 
238
        gint x, y;
 
239
        cairo_t *context;
 
240
#endif
 
241
 
 
242
        rfi = GET_DATA(gp);
 
243
 
 
244
        if (!rfi->rgb_cairo_surface)
 
245
                return FALSE;
 
246
 
 
247
        scale = remmina_plugin_service->protocol_plugin_get_scale(gp);
 
248
 
 
249
#if GTK_VERSION == 2
 
250
        x = event->area.x;
 
251
        y = event->area.y;
 
252
 
 
253
        context = gdk_cairo_create(gtk_widget_get_window (rfi->drawing_area));
 
254
        cairo_rectangle(context, x, y, event->area.width, event->area.height);
 
255
#else
 
256
        cairo_rectangle(context, 0, 0, gtk_widget_get_allocated_width(widget),
 
257
                gtk_widget_get_allocated_height(widget));
 
258
#endif
 
259
 
 
260
        if (scale)
 
261
                cairo_scale(context, rfi->scale_x, rfi->scale_y);
 
262
 
 
263
        cairo_set_source_surface(context, rfi->rgb_cairo_surface, 0, 0);
 
264
        cairo_fill(context);
 
265
 
 
266
#if GTK_VERSION == 2
 
267
        cairo_destroy(context);
 
268
#endif
 
269
 
 
270
        return TRUE;
 
271
}
 
272
 
 
273
static gboolean remmina_rdp_event_on_configure(GtkWidget* widget, GdkEventConfigure* event, RemminaProtocolWidget* gp)
 
274
{
 
275
        rfContext* rfi;
 
276
 
 
277
        rfi = GET_DATA(gp);
 
278
 
 
279
        /* We do a delayed reallocating to improve performance */
 
280
 
 
281
        if (rfi->scale_handler)
 
282
                g_source_remove(rfi->scale_handler);
 
283
 
 
284
        rfi->scale_handler = g_timeout_add(1000, (GSourceFunc) remmina_rdp_event_update_scale_factor, gp);
 
285
 
 
286
        return FALSE;
 
287
}
 
288
 
 
289
static void remmina_rdp_event_translate_pos(RemminaProtocolWidget* gp, int ix, int iy, uint16* ox, uint16* oy)
 
290
{
 
291
        rfContext* rfi;
 
292
 
 
293
        rfi = GET_DATA(gp);
 
294
 
 
295
        if ((rfi->scale) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1))
 
296
        {
 
297
                *ox = (uint16) (ix * remmina_plugin_service->protocol_plugin_get_width(gp) / rfi->scale_width);
 
298
                *oy = (uint16) (iy * remmina_plugin_service->protocol_plugin_get_height(gp) / rfi->scale_height);
 
299
        }
 
300
        else
 
301
        {
 
302
                *ox = (uint16) ix;
 
303
                *oy = (uint16) iy;
 
304
        }
 
305
}
 
306
 
 
307
static gboolean remmina_rdp_event_on_motion(GtkWidget* widget, GdkEventMotion* event, RemminaProtocolWidget* gp)
 
308
{
 
309
        RemminaPluginRdpEvent rdp_event = { 0 };
 
310
 
 
311
        rdp_event.type = REMMINA_RDP_EVENT_TYPE_MOUSE;
 
312
        rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
 
313
 
 
314
        remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
 
315
        remmina_rdp_event_event_push(gp, &rdp_event);
 
316
 
 
317
        return TRUE;
 
318
}
 
319
 
 
320
static gboolean remmina_rdp_event_on_button(GtkWidget* widget, GdkEventButton* event, RemminaProtocolWidget* gp)
 
321
{
 
322
        gint flag;
 
323
        RemminaPluginRdpEvent rdp_event = { 0 };
 
324
 
 
325
        /* We only accept 3 buttons */
 
326
        if ((event->button < 1) || (event->button > 3))
 
327
                return FALSE;
 
328
 
 
329
        /* We bypass 2button-press and 3button-press events */
 
330
        if ((event->type != GDK_BUTTON_PRESS) && (event->type != GDK_BUTTON_RELEASE))
 
331
                return TRUE;
 
332
 
 
333
        rdp_event.type = REMMINA_RDP_EVENT_TYPE_MOUSE;
 
334
        remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
 
335
 
 
336
        flag = 0;
 
337
 
 
338
        if (event->type == GDK_BUTTON_PRESS)
 
339
                flag = PTR_FLAGS_DOWN;
 
340
 
 
341
        switch (event->button)
 
342
        {
 
343
                case 1:
 
344
                        flag |= PTR_FLAGS_BUTTON1;
 
345
                        break;
 
346
                case 2:
 
347
                        flag |= PTR_FLAGS_BUTTON3;
 
348
                        break;
 
349
                case 3:
 
350
                        flag |= PTR_FLAGS_BUTTON2;
 
351
                        break;
 
352
        }
 
353
 
 
354
        if (flag != 0)
 
355
        {
 
356
                rdp_event.mouse_event.flags = flag;
 
357
                remmina_rdp_event_event_push(gp, &rdp_event);
 
358
        }
 
359
 
 
360
        return TRUE;
 
361
}
 
362
 
 
363
static gboolean remmina_rdp_event_on_scroll(GtkWidget* widget, GdkEventScroll* event, RemminaProtocolWidget* gp)
 
364
{
 
365
        gint flag;
 
366
        RemminaPluginRdpEvent rdp_event = { 0 };
 
367
 
 
368
        flag = 0;
 
369
        rdp_event.type = REMMINA_RDP_EVENT_TYPE_MOUSE;
 
370
 
 
371
        switch (event->direction)
 
372
        {
 
373
                case GDK_SCROLL_UP:
 
374
                        flag = PTR_FLAGS_WHEEL | 0x0078;
 
375
                        break;
 
376
 
 
377
                case GDK_SCROLL_DOWN:
 
378
                        flag = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088;
 
379
                        break;
 
380
 
 
381
                default:
 
382
                        return FALSE;
 
383
        }
 
384
 
 
385
        rdp_event.mouse_event.flags = flag;
 
386
        remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
 
387
        remmina_rdp_event_event_push(gp, &rdp_event);
 
388
 
 
389
        return TRUE;
 
390
}
 
391
 
 
392
static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, RemminaProtocolWidget* gp)
 
393
{
 
394
        Display* display;
 
395
        KeyCode cooked_keycode;
 
396
        rfContext* rfi;
 
397
        RemminaPluginRdpEvent rdp_event;
 
398
 
 
399
        rfi = GET_DATA(gp);
 
400
        rdp_event.type = REMMINA_RDP_EVENT_TYPE_SCANCODE;
 
401
        rdp_event.key_event.up = (event->type == GDK_KEY_PRESS ? False : True);
 
402
        rdp_event.key_event.extended = False;
 
403
 
 
404
        switch (event->keyval)
 
405
        {
 
406
                case GDK_KEY_Pause:
 
407
                        rdp_event.key_event.key_code = 0x1D;
 
408
                        rdp_event.key_event.up = False;
 
409
                        remmina_rdp_event_event_push(gp, &rdp_event);
 
410
                        rdp_event.key_event.key_code = 0x45;
 
411
                        rdp_event.key_event.up = False;
 
412
                        remmina_rdp_event_event_push(gp, &rdp_event);
 
413
                        rdp_event.key_event.key_code = 0x1D;
 
414
                        rdp_event.key_event.up = True;
 
415
                        remmina_rdp_event_event_push(gp, &rdp_event);
 
416
                        rdp_event.key_event.key_code = 0x45;
 
417
                        rdp_event.key_event.up = True;
 
418
                        remmina_rdp_event_event_push(gp, &rdp_event);
 
419
                        break;
 
420
 
 
421
                default:
 
422
                        if (!rfi->use_client_keymap)
 
423
                        {
 
424
                                rdp_event.key_event.key_code = freerdp_kbd_get_scancode_by_keycode(event->hardware_keycode, &rdp_event.key_event.extended);
 
425
                                remmina_plugin_service->log_printf("[RDP]keyval=%04X keycode=%i scancode=%i extended=%i\n",
 
426
                                                event->keyval, event->hardware_keycode, rdp_event.key_event.key_code, &rdp_event.key_event.extended);
 
427
                        }
 
428
                        else
 
429
                        {
 
430
                                display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default());
 
431
                                cooked_keycode = XKeysymToKeycode(display, XKeycodeToKeysym(display, event->hardware_keycode, 0));
 
432
                                rdp_event.key_event.key_code = freerdp_kbd_get_scancode_by_keycode(cooked_keycode, &rdp_event.key_event.extended);
 
433
                                remmina_plugin_service->log_printf("[RDP]keyval=%04X raw_keycode=%i cooked_keycode=%i scancode=%i extended=%i\n",
 
434
                                                event->keyval, event->hardware_keycode, cooked_keycode, rdp_event.key_event.key_code, &rdp_event.key_event.extended);
 
435
                        }
 
436
 
 
437
                        if (rdp_event.key_event.key_code)
 
438
                                remmina_rdp_event_event_push(gp, &rdp_event);
 
439
 
 
440
                        break;
 
441
        }
 
442
 
 
443
        /* Register/unregister the pressed key */
 
444
        if (rdp_event.key_event.key_code)
 
445
        {
 
446
                if (event->type == GDK_KEY_PRESS)
 
447
                        g_array_append_val(rfi->pressed_keys, rdp_event.key_event.key_code);
 
448
                else
 
449
                        remmina_rdp_event_release_key(gp, rdp_event.key_event.key_code);
 
450
        }
 
451
 
 
452
        return TRUE;
 
453
}
 
454
 
 
455
void remmina_rdp_event_init(RemminaProtocolWidget* gp)
 
456
{
 
457
        gint n;
 
458
        gint i;
 
459
        gchar* s;
 
460
        gint flags;
 
461
        XPixmapFormatValues* pf;
 
462
        XPixmapFormatValues* pfs;
 
463
        rfContext* rfi;
 
464
 
 
465
        rfi = GET_DATA(gp);
 
466
        rfi->drawing_area = gtk_drawing_area_new();
 
467
        gtk_widget_show(rfi->drawing_area);
 
468
        gtk_container_add(GTK_CONTAINER(gp), rfi->drawing_area);
 
469
 
 
470
        gtk_widget_add_events(rfi->drawing_area, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK
 
471
                | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
 
472
        gtk_widget_set_can_focus(rfi->drawing_area, TRUE);
 
473
 
 
474
        remmina_plugin_service->protocol_plugin_register_hostkey(gp, rfi->drawing_area);
 
475
 
 
476
        s = remmina_plugin_service->pref_get_value("rdp_use_client_keymap");
 
477
        rfi->use_client_keymap = (s && s[0] == '1' ? TRUE : FALSE);
 
478
        g_free(s);
 
479
 
 
480
#if GTK_VERSION == 3
 
481
        g_signal_connect(G_OBJECT(rfi->drawing_area), "draw",
 
482
                G_CALLBACK(remmina_rdp_event_on_draw), gp);
 
483
#elif GTK_VERSION == 2
 
484
        g_signal_connect(G_OBJECT(rfi->drawing_area), "expose-event",
 
485
                G_CALLBACK(remmina_rdp_event_on_expose), gp);
 
486
#endif
 
487
        g_signal_connect(G_OBJECT(rfi->drawing_area), "configure-event",
 
488
                G_CALLBACK(remmina_rdp_event_on_configure), gp);
 
489
        g_signal_connect(G_OBJECT(rfi->drawing_area), "motion-notify-event",
 
490
                G_CALLBACK(remmina_rdp_event_on_motion), gp);
 
491
        g_signal_connect(G_OBJECT(rfi->drawing_area), "button-press-event",
 
492
                G_CALLBACK(remmina_rdp_event_on_button), gp);
 
493
        g_signal_connect(G_OBJECT(rfi->drawing_area), "button-release-event",
 
494
                G_CALLBACK(remmina_rdp_event_on_button), gp);
 
495
        g_signal_connect(G_OBJECT(rfi->drawing_area), "scroll-event",
 
496
                G_CALLBACK(remmina_rdp_event_on_scroll), gp);
 
497
        g_signal_connect(G_OBJECT(rfi->drawing_area), "key-press-event",
 
498
                G_CALLBACK(remmina_rdp_event_on_key), gp);
 
499
        g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event",
 
500
                G_CALLBACK(remmina_rdp_event_on_key), gp);
 
501
 
 
502
        rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof (gint));
 
503
        rfi->event_queue = g_async_queue_new_full(g_free);
 
504
        rfi->ui_queue = g_async_queue_new();
 
505
 
 
506
        if (pipe(rfi->event_pipe))
 
507
        {
 
508
                g_print("Error creating pipes.\n");
 
509
                rfi->event_pipe[0] = -1;
 
510
                rfi->event_pipe[1] = -1;
 
511
        }
 
512
        else
 
513
        {
 
514
                flags = fcntl(rfi->event_pipe[0], F_GETFL, 0);
 
515
                fcntl(rfi->event_pipe[0], F_SETFL, flags | O_NONBLOCK);
 
516
        }
 
517
 
 
518
        rfi->object_table = g_hash_table_new_full(NULL, NULL, NULL, g_free);
 
519
 
 
520
        rfi->display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
 
521
        rfi->depth = DefaultDepth(rfi->display, DefaultScreen(rfi->display));
 
522
        rfi->visual = GDK_VISUAL_XVISUAL(gdk_visual_get_best_with_depth(rfi->depth));
 
523
        pfs = XListPixmapFormats(rfi->display, &n);
 
524
 
 
525
        if (pfs)
 
526
        {
 
527
                for (i = 0; i < n; i++)
 
528
                {
 
529
                        pf = pfs + i;
 
530
 
 
531
                        if (pf->depth == rfi->depth)
 
532
                        {
 
533
                                rfi->scanline_pad = pf->scanline_pad;
 
534
                                rfi->bpp = pf->bits_per_pixel;
 
535
                                break;
 
536
                        }
 
537
                }
 
538
 
 
539
                XFree(pfs);
 
540
        }
 
541
}
 
542
 
 
543
void remmina_rdp_event_uninit(RemminaProtocolWidget* gp)
 
544
{
 
545
        rfContext* rfi;
 
546
        RemminaPluginRdpUiObject* ui;
 
547
 
 
548
        rfi = GET_DATA(gp);
 
549
 
 
550
        if (rfi->scale_handler)
 
551
        {
 
552
                g_source_remove(rfi->scale_handler);
 
553
                rfi->scale_handler = 0;
 
554
        }
 
555
        if (rfi->ui_handler)
 
556
        {
 
557
                g_source_remove(rfi->ui_handler);
 
558
                rfi->ui_handler = 0;
 
559
        }
 
560
        while ((ui =(RemminaPluginRdpUiObject*) g_async_queue_try_pop(rfi->ui_queue)) != NULL)
 
561
        {
 
562
                rf_object_free(gp, ui);
 
563
        }
 
564
 
 
565
        if (rfi->gc)
 
566
        {
 
567
                XFreeGC(rfi->display, rfi->gc);
 
568
                rfi->gc = 0;
 
569
        }
 
570
        if (rfi->gc_default)
 
571
        {
 
572
                XFreeGC(rfi->display, rfi->gc_default);
 
573
                rfi->gc_default = 0;
 
574
        }
 
575
        if (rfi->rgb_cairo_surface)
 
576
        {
 
577
                cairo_surface_destroy(rfi->rgb_cairo_surface);
 
578
                rfi->rgb_cairo_surface = NULL;
 
579
        }
 
580
        if (rfi->rgb_surface)
 
581
        {
 
582
                XFreePixmap(rfi->display, rfi->rgb_surface);
 
583
                rfi->rgb_surface = 0;
 
584
        }
 
585
        if (rfi->gc_mono)
 
586
        {
 
587
                XFreeGC(rfi->display, rfi->gc_mono);
 
588
                rfi->gc_mono = 0;
 
589
        }
 
590
        if (rfi->bitmap_mono)
 
591
        {
 
592
                XFreePixmap(rfi->display, rfi->bitmap_mono);
 
593
                rfi->bitmap_mono = 0;
 
594
        }
 
595
 
 
596
        g_hash_table_destroy(rfi->object_table);
 
597
 
 
598
        g_array_free(rfi->pressed_keys, TRUE);
 
599
        g_async_queue_unref(rfi->event_queue);
 
600
        rfi->event_queue = NULL;
 
601
        g_async_queue_unref(rfi->ui_queue);
 
602
        rfi->ui_queue = NULL;
 
603
        close(rfi->event_pipe[0]);
 
604
        close(rfi->event_pipe[1]);
 
605
}
 
606
 
 
607
void remmina_rdp_event_update_scale(RemminaProtocolWidget* gp)
 
608
{
 
609
        gint width, height;
 
610
        gint hscale, vscale;
 
611
        RemminaFile* remminafile;
 
612
        rfContext* rfi;
 
613
 
 
614
        rfi = GET_DATA(gp);
 
615
        remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
 
616
 
 
617
        width = remmina_plugin_service->protocol_plugin_get_width(gp);
 
618
        height = remmina_plugin_service->protocol_plugin_get_height(gp);
 
619
        hscale = remmina_plugin_service->file_get_int(remminafile, "hscale", 0);
 
620
        vscale = remmina_plugin_service->file_get_int(remminafile, "vscale", 0);
 
621
 
 
622
        if (rfi->scale)
 
623
        {
 
624
                gtk_widget_set_size_request(rfi->drawing_area,
 
625
                        (hscale > 0 ? width * hscale / 100 : -1),
 
626
                        (vscale > 0 ? height * vscale / 100 : -1));
 
627
        }
 
628
        else
 
629
        {
 
630
                gtk_widget_set_size_request(rfi->drawing_area, width, height);
 
631
        }
 
632
 
 
633
        remmina_plugin_service->protocol_plugin_emit_signal(gp, "update-align");
 
634
}
 
635
 
 
636
static uint8 remmina_rdp_event_rop2_map[] =
 
637
{
 
638
        GXclear,                /* 0 */
 
639
        GXnor,                  /* DPon */
 
640
        GXandInverted,          /* DPna */
 
641
        GXcopyInverted,         /* Pn */
 
642
        GXandReverse,           /* PDna */
 
643
        GXinvert,               /* Dn */
 
644
        GXxor,                  /* DPx */
 
645
        GXnand,                 /* DPan */
 
646
        GXand,                  /* DPa */
 
647
        GXequiv,                /* DPxn */
 
648
        GXnoop,                 /* D */
 
649
        GXorInverted,           /* DPno */
 
650
        GXcopy,                 /* P */
 
651
        GXorReverse,            /* PDno */
 
652
        GXor,                   /* DPo */
 
653
        GXset                   /* 1 */
 
654
};
 
655
 
 
656
static void remmina_rdp_event_set_rop2(rfContext* rfi, gint rop2)
 
657
{
 
658
        if ((rop2 < 0x01) || (rop2 > 0x10))
 
659
        {
 
660
                remmina_plugin_service->log_printf("[RDP]unknown rop2 0x%x", rop2);
 
661
        }
 
662
        else
 
663
        {
 
664
                XSetFunction(rfi->display, rfi->gc, remmina_rdp_event_rop2_map[rop2 - 1]);
 
665
        }
 
666
}
 
667
 
 
668
static void remmina_rdp_event_set_rop3(rfContext* rfi, gint rop3)
 
669
{
 
670
        switch (rop3)
 
671
        {
 
672
                case 0x00: /* 0 - 0 */
 
673
                        XSetFunction(rfi->display, rfi->gc, GXclear);
 
674
                        break;
 
675
                case 0x05: /* ~(P | D) - DPon */
 
676
                        XSetFunction(rfi->display, rfi->gc, GXnor);
 
677
                        break;
 
678
                case 0x0a: /* ~P & D - DPna */
 
679
                        XSetFunction(rfi->display, rfi->gc, GXandInverted);
 
680
                        break;
 
681
                case 0x0f: /* ~P - Pn */
 
682
                        XSetFunction(rfi->display, rfi->gc, GXcopyInverted);
 
683
                        break;
 
684
                case 0x11: /* ~(S | D) - DSon */
 
685
                        XSetFunction(rfi->display, rfi->gc, GXnor);
 
686
                        break;
 
687
                case 0x22: /* ~S & D - DSna */
 
688
                        XSetFunction(rfi->display, rfi->gc, GXandInverted);
 
689
                        break;
 
690
                case 0x33: /* ~S - Sn */
 
691
                        XSetFunction(rfi->display, rfi->gc, GXcopyInverted);
 
692
                        break;
 
693
                case 0x44: /* S & ~D - SDna */
 
694
                        XSetFunction(rfi->display, rfi->gc, GXandReverse);
 
695
                        break;
 
696
                case 0x50: /* P & ~D - PDna */
 
697
                        XSetFunction(rfi->display, rfi->gc, GXandReverse);
 
698
                        break;
 
699
                case 0x55: /* ~D - Dn */
 
700
                        XSetFunction(rfi->display, rfi->gc, GXinvert);
 
701
                        break;
 
702
                case 0x5a: /* D ^ P - DPx */
 
703
                        XSetFunction(rfi->display, rfi->gc, GXxor);
 
704
                        break;
 
705
                case 0x5f: /* ~(P & D) - DPan */
 
706
                        XSetFunction(rfi->display, rfi->gc, GXnand);
 
707
                        break;
 
708
                case 0x66: /* D ^ S - DSx */
 
709
                        XSetFunction(rfi->display, rfi->gc, GXxor);
 
710
                        break;
 
711
                case 0x77: /* ~(S & D) - DSan */
 
712
                        XSetFunction(rfi->display, rfi->gc, GXnand);
 
713
                        break;
 
714
                case 0x88: /* D & S - DSa */
 
715
                        XSetFunction(rfi->display, rfi->gc, GXand);
 
716
                        break;
 
717
                case 0x99: /* ~(S ^ D) - DSxn */
 
718
                        XSetFunction(rfi->display, rfi->gc, GXequiv);
 
719
                        break;
 
720
                case 0xa0: /* P & D - DPa */
 
721
                        XSetFunction(rfi->display, rfi->gc, GXand);
 
722
                        break;
 
723
                case 0xa5: /* ~(P ^ D) - PDxn */
 
724
                        XSetFunction(rfi->display, rfi->gc, GXequiv);
 
725
                        break;
 
726
                case 0xaa: /* D - D */
 
727
                        XSetFunction(rfi->display, rfi->gc, GXnoop);
 
728
                        break;
 
729
                case 0xaf: /* ~P | D - DPno */
 
730
                        XSetFunction(rfi->display, rfi->gc, GXorInverted);
 
731
                        break;
 
732
                case 0xbb: /* ~S | D - DSno */
 
733
                        XSetFunction(rfi->display, rfi->gc, GXorInverted);
 
734
                        break;
 
735
                case 0xcc: /* S - S */
 
736
                        XSetFunction(rfi->display, rfi->gc, GXcopy);
 
737
                        break;
 
738
                case 0xdd: /* S | ~D - SDno */
 
739
                        XSetFunction(rfi->display, rfi->gc, GXorReverse);
 
740
                        break;
 
741
                case 0xee: /* D | S - DSo */
 
742
                        XSetFunction(rfi->display, rfi->gc, GXor);
 
743
                        break;
 
744
                case 0xf0: /* P - P */
 
745
                        XSetFunction(rfi->display, rfi->gc, GXcopy);
 
746
                        break;
 
747
                case 0xf5: /* P | ~D - PDno */
 
748
                        XSetFunction(rfi->display, rfi->gc, GXorReverse);
 
749
                        break;
 
750
                case 0xfa: /* P | D - DPo */
 
751
                        XSetFunction(rfi->display, rfi->gc, GXor);
 
752
                        break;
 
753
                case 0xff: /* 1 - 1 */
 
754
                        XSetFunction(rfi->display, rfi->gc, GXset);
 
755
                        break;
 
756
                default:
 
757
                        remmina_plugin_service->log_printf("[RDP]unknown rop3 0x%x", rop3);
 
758
                        break;
 
759
        }
 
760
}
 
761
 
 
762
static void remmina_rdp_event_insert_drawable(rfContext* rfi, guint object_id, Drawable obj)
 
763
{
 
764
        Drawable* p;
 
765
 
 
766
        p = g_new(Drawable, 1);
 
767
        *p = obj;
 
768
        g_hash_table_insert(rfi->object_table, GINT_TO_POINTER(object_id), p);
 
769
}
 
770
 
 
771
static Drawable remmina_rdp_event_get_drawable(rfContext* rfi, guint object_id)
 
772
{
 
773
        Drawable* p;
 
774
 
 
775
        p = (Drawable*) g_hash_table_lookup(rfi->object_table, GINT_TO_POINTER(object_id));
 
776
 
 
777
        if (!p)
 
778
                return 0;
 
779
 
 
780
        return *p;
 
781
}
 
782
 
 
783
static void remmina_rdp_event_connected(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui)
 
784
{
 
785
        rfContext* rfi;
 
786
 
 
787
        rfi = GET_DATA(gp);
 
788
 
 
789
        gtk_widget_realize(rfi->drawing_area);
 
790
 
 
791
        rfi->drawable = GDK_WINDOW_XID(gtk_widget_get_window(rfi->drawing_area));
 
792
 
 
793
        rfi->rgb_surface = XCreatePixmap(rfi->display, rfi->drawable,
 
794
                rfi->settings->width, rfi->settings->height, rfi->depth);
 
795
 
 
796
        rfi->rgb_cairo_surface = cairo_xlib_surface_create(rfi->display,
 
797
                        rfi->rgb_surface, rfi->visual, rfi->width, rfi->height);
 
798
 
 
799
        rfi->drw_surface = rfi->rgb_surface;
 
800
 
 
801
        remmina_rdp_event_update_scale(gp);
 
802
}
 
803
 
 
804
static void remmina_rdp_event_rfx(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui)
 
805
{
 
806
        XImage* image;
 
807
        gint i, tx, ty;
 
808
        RFX_MESSAGE* message;
 
809
        rfContext* rfi;
 
810
 
 
811
        rfi = GET_DATA(gp);
 
812
        message = ui->rfx.message;
 
813
 
 
814
        XSetFunction(rfi->display, rfi->gc, GXcopy);
 
815
        XSetFillStyle(rfi->display, rfi->gc, FillSolid);
 
816
 
 
817
        XSetClipRectangles(rfi->display, rfi->gc, ui->rfx.left, ui->rfx.top,
 
818
                (XRectangle*) message->rects, message->num_rects, YXBanded);
 
819
 
 
820
        /* Draw the tiles to primary surface, each is 64x64. */
 
821
        for (i = 0; i < message->num_tiles; i++)
 
822
        {
 
823
                image = XCreateImage(rfi->display, rfi->visual, 24, ZPixmap, 0,
 
824
                        (char*) message->tiles[i]->data, 64, 64, 32, 0);
 
825
 
 
826
                tx = message->tiles[i]->x + ui->rfx.left;
 
827
                ty = message->tiles[i]->y + ui->rfx.top;
 
828
 
 
829
                XPutImage(rfi->display, rfi->rgb_surface, rfi->gc, image, 0, 0, tx, ty, 64, 64);
 
830
                XFree(image);
 
831
 
 
832
                remmina_rdp_event_update_rect(gp, tx, ty, message->rects[i].width, message->rects[i].height);
 
833
        }
 
834
 
 
835
        XSetClipMask(rfi->display, rfi->gc, None);
 
836
}
 
837
 
 
838
static void remmina_rdp_event_nocodec(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui)
 
839
{
 
840
        XImage* image;
 
841
        rfContext* rfi;
 
842
 
 
843
        rfi = GET_DATA(gp);
 
844
 
 
845
        XSetFunction(rfi->display, rfi->gc, GXcopy);
 
846
        XSetFillStyle(rfi->display, rfi->gc, FillSolid);
 
847
 
 
848
        image = XCreateImage(rfi->display, rfi->visual, 24, ZPixmap, 0,
 
849
                (char*) ui->nocodec.bitmap, ui->nocodec.width, ui->nocodec.height, 32, 0);
 
850
 
 
851
        XPutImage(rfi->display, rfi->rgb_surface, rfi->gc, image, 0, 0,
 
852
                ui->nocodec.left, ui->nocodec.top,
 
853
                ui->nocodec.width, ui->nocodec.height);
 
854
 
 
855
        remmina_rdp_event_update_rect(gp,
 
856
                ui->nocodec.left, ui->nocodec.top,
 
857
                ui->nocodec.width, ui->nocodec.height);
 
858
 
 
859
        XSetClipMask(rfi->display, rfi->gc, None);
 
860
}
 
861
 
 
862
gboolean remmina_rdp_event_queue_ui(RemminaProtocolWidget* gp)
 
863
{
 
864
        rfContext* rfi;
 
865
        RemminaPluginRdpUiObject* ui;
 
866
 
 
867
        rfi = GET_DATA(gp);
 
868
 
 
869
        ui = (RemminaPluginRdpUiObject*) g_async_queue_try_pop(rfi->ui_queue);
 
870
 
 
871
        if (ui)
 
872
        {
 
873
                switch (ui->type)
 
874
                {
 
875
                        case REMMINA_RDP_UI_UPDATE_REGION:
 
876
                                remmina_rdp_event_update_region(gp, ui);
 
877
                                break;
 
878
 
 
879
                        case REMMINA_RDP_UI_CONNECTED:
 
880
                                remmina_rdp_event_connected(gp, ui);
 
881
                                break;
 
882
 
 
883
                        case REMMINA_RDP_UI_RFX:
 
884
                                remmina_rdp_event_rfx(gp, ui);
 
885
                                break;
 
886
 
 
887
                        case REMMINA_RDP_UI_NOCODEC:
 
888
                                remmina_rdp_event_nocodec(gp, ui);
 
889
                                break;
 
890
 
 
891
                        default:
 
892
                                break;
 
893
                }
 
894
                rf_object_free(gp, ui);
 
895
 
 
896
                return TRUE;
 
897
        }
 
898
        else
 
899
        {
 
900
                LOCK_BUFFER(FALSE)
 
901
                rfi->ui_handler = 0;
 
902
                UNLOCK_BUFFER(FALSE)
 
903
                return FALSE;
 
904
        }
 
905
}
 
906
 
 
907
void remmina_rdp_event_unfocus(RemminaProtocolWidget* gp)
 
908
{
 
909
        remmina_rdp_event_release_key(gp, 0);
 
910
}
 
911