Remmina - The GTK+ Remote Desktop Client  v1.4.2
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
rdp_event.c
Go to the documentation of this file.
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  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
7  * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  * In addition, as a special exception, the copyright holders give
25  * permission to link the code of portions of this program with the
26  * OpenSSL library under certain conditions as described in each
27  * individual source file, and distribute linked combinations
28  * including the two.
29  * You must obey the GNU General Public License in all respects
30  * for all of the code used other than OpenSSL. * If you modify
31  * file(s) with this exception, you may extend this exception to your
32  * version of the file(s), but you are not obligated to do so. * If you
33  * do not wish to do so, delete this exception statement from your
34  * version. * If you delete this exception statement from all source
35  * files in the program, then also delete it here.
36  *
37  */
38 
39 #include "rdp_plugin.h"
40 #include "rdp_event.h"
41 #include "rdp_cliprdr.h"
42 #include "rdp_settings.h"
43 #include <gdk/gdkkeysyms.h>
44 #include <cairo/cairo-xlib.h>
45 #include <freerdp/locale/keyboard.h>
46 
47 static gboolean remmina_rdp_event_on_focus_in(GtkWidget* widget, GdkEventKey* event, RemminaProtocolWidget* gp)
48 {
49  TRACE_CALL(__func__);
50  rfContext* rfi = GET_PLUGIN_DATA(gp);
51  rdpInput* input;
52  GdkModifierType state;
53 
54 #if GTK_CHECK_VERSION(3, 20, 0)
55  GdkSeat *seat;
56 #else
57  GdkDeviceManager *manager;
58 #endif
59  GdkDevice *keyboard = NULL;
60 
61  if (!rfi || !rfi->connected || rfi->is_reconnecting)
62  return FALSE;
63 
64  input = rfi->instance->input;
65  UINT32 toggle_keys_state = 0;
66 
67 #if GTK_CHECK_VERSION(3, 20, 0)
68  seat = gdk_display_get_default_seat(gdk_display_get_default());
69  keyboard = gdk_seat_get_pointer(seat);
70 #else
71  manager = gdk_display_get_device_manager(gdk_display_get_default());
72  keyboard = gdk_device_manager_get_client_pointer(manager);
73 #endif
74  gdk_window_get_device_position(gdk_get_default_root_window(), keyboard, NULL, NULL, &state);
75 
76  if (state & GDK_LOCK_MASK) {
77  toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
78  }
79  if (state & GDK_MOD2_MASK) {
80  toggle_keys_state |= KBD_SYNC_NUM_LOCK;
81  }
82  if (state & GDK_MOD5_MASK) {
83  toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
84  }
85 
86  input->SynchronizeEvent(input, toggle_keys_state);
87  input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F);
88 
89  return FALSE;
90 }
91 
93 {
94  TRACE_CALL(__func__);
95  rfContext* rfi = GET_PLUGIN_DATA(gp);
96  RemminaPluginRdpEvent* event;
97 
98  /* Called by the main GTK thread to send an event to the libfreerdp thread */
99 
100  if (!rfi || !rfi->connected || rfi->is_reconnecting)
101  return;
102 
103  if (rfi->event_queue) {
104  event = g_memdup(e, sizeof(RemminaPluginRdpEvent));
105  g_async_queue_push(rfi->event_queue, event);
106 
107  if (write(rfi->event_pipe[1], "\0", 1)) {
108  }
109  }
110 }
111 
113 {
114  TRACE_CALL(__func__);
115  rfContext* rfi = GET_PLUGIN_DATA(gp);
116  RemminaPluginRdpEvent rdp_event = { 0 };
117  int i;
118 
119  /* Send all release key events for previously pressed keys */
120  for (i = 0; i < rfi->pressed_keys->len; i++) {
121  rdp_event = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
122  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
124  rdp_event.key_event.up == False) {
125  rdp_event.key_event.up = True;
126  remmina_rdp_event_event_push(gp, &rdp_event);
127  }
128  }
129 
130  g_array_set_size(rfi->pressed_keys, 0);
131 }
132 
134 {
135  TRACE_CALL(__func__);
136  gint i;
137  rfContext* rfi = GET_PLUGIN_DATA(gp);
138  RemminaPluginRdpEvent rdp_event_2 = { 0 };
139 
141 
142  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
144  rdp_event.key_event.up ) {
145  /* Unregister the keycode only */
146  for (i = 0; i < rfi->pressed_keys->len; i++) {
147  rdp_event_2 = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
148 
149  if (rdp_event_2.key_event.key_code == rdp_event.key_event.key_code &&
150  rdp_event_2.key_event.unicode_code == rdp_event.key_event.unicode_code &&
151  rdp_event_2.key_event.extended == rdp_event.key_event.extended) {
152  g_array_remove_index_fast(rfi->pressed_keys, i);
153  break;
154  }
155  }
156  }
157 }
158 
160 {
161  TRACE_CALL(__func__);
162  rfContext* rfi = GET_PLUGIN_DATA(gp);
163  if (!rdp_event.key_event.key_code)
164  return;
165 
166  if (rdp_event.key_event.up) {
167  remmina_rdp_event_release_key(gp, rdp_event);
168  } else {
169  g_array_append_val(rfi->pressed_keys, rdp_event);
170  }
171 
172 }
173 
174 
175 static void remmina_rdp_event_scale_area(RemminaProtocolWidget* gp, gint* x, gint* y, gint* w, gint* h)
176 {
177  TRACE_CALL(__func__);
178  gint width, height;
179  gint sx, sy, sw, sh;
180  rfContext* rfi = GET_PLUGIN_DATA(gp);
181 
182  if (!rfi || !rfi->connected || rfi->is_reconnecting || !rfi->surface)
183  return;
184 
187 
188  if ((width == 0) || (height == 0))
189  return;
190 
191  if ((rfi->scale_width == width) && (rfi->scale_height == height)) {
192  /* Same size, just copy the pixels */
193  *x = MIN(MAX(0, *x), width - 1);
194  *y = MIN(MAX(0, *y), height - 1);
195  *w = MIN(width - *x, *w);
196  *h = MIN(height - *y, *h);
197  return;
198  }
199 
200  /* We have to extend the scaled region one scaled pixel, to avoid gaps */
201 
202  sx = MIN(MAX(0, (*x) * rfi->scale_width / width
203  - rfi->scale_width / width - 2), rfi->scale_width - 1);
204 
205  sy = MIN(MAX(0, (*y) * rfi->scale_height / height
206  - rfi->scale_height / height - 2), rfi->scale_height - 1);
207 
208  sw = MIN(rfi->scale_width - sx, (*w) * rfi->scale_width / width
209  + rfi->scale_width / width + 4);
210 
211  sh = MIN(rfi->scale_height - sy, (*h) * rfi->scale_height / height
212  + rfi->scale_height / height + 4);
213 
214  *x = sx;
215  *y = sy;
216  *w = sw;
217  *h = sh;
218 }
219 
221 {
222  TRACE_CALL(__func__);
223  rfContext* rfi = GET_PLUGIN_DATA(gp);
224  gint x, y, w, h, i;
225 
226  for(i = 0; i < ui->reg.ninvalid; i++) {
227  x = ui->reg.ureg[i].x;
228  y = ui->reg.ureg[i].y;
229  w = ui->reg.ureg[i].w;
230  h = ui->reg.ureg[i].h;
231 
233  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
234 
235  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
236  }
237  g_free(ui->reg.ureg);
238 }
239 
240 void remmina_rdp_event_update_rect(RemminaProtocolWidget* gp, gint x, gint y, gint w, gint h)
241 {
242  TRACE_CALL(__func__);
243  rfContext* rfi = GET_PLUGIN_DATA(gp);
244 
246  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
247 
248  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
249 }
250 
252 {
253  TRACE_CALL(__func__);
254  GtkAllocation a;
255  gint rdwidth, rdheight;
256  gint gpwidth, gpheight;
257  rfContext* rfi = GET_PLUGIN_DATA(gp);
258 
259  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
260  gpwidth = a.width;
261  gpheight = a.height;
262 
264  if ((gpwidth > 1) && (gpheight > 1)) {
267 
268  rfi->scale_width = gpwidth;
269  rfi->scale_height = gpheight;
270 
271  rfi->scale_x = (gdouble)rfi->scale_width / (gdouble)rdwidth;
272  rfi->scale_y = (gdouble)rfi->scale_height / (gdouble)rdheight;
273  }
274  }else {
275  rfi->scale_width = 0;
276  rfi->scale_height = 0;
277  rfi->scale_x = 0;
278  rfi->scale_y = 0;
279  }
280 
281 }
282 
283 static gboolean remmina_rdp_event_on_draw(GtkWidget* widget, cairo_t* context, RemminaProtocolWidget* gp)
284 {
285  TRACE_CALL(__func__);
286  rfContext* rfi = GET_PLUGIN_DATA(gp);
287  guint width, height;
288  gchar *msg;
289  cairo_text_extents_t extents;
290 
291  if (!rfi || !rfi->connected)
292  return FALSE;
293 
294 
295  if (rfi->is_reconnecting) {
296  /* FreeRDP is reconnecting, just show a message to the user */
297 
298  width = gtk_widget_get_allocated_width(widget);
299  height = gtk_widget_get_allocated_height(widget);
300 
301  /* Draw text */
302  msg = g_strdup_printf(_("Reconnection attempt %d of %d…"),
304 
305  cairo_select_font_face(context, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
306  cairo_set_font_size(context, 24);
307  cairo_set_source_rgb(context, 0.9, 0.9, 0.9);
308  cairo_text_extents(context, msg, &extents);
309  cairo_move_to(context, (width - (extents.width + extents.x_bearing)) / 2, (height - (extents.height + extents.y_bearing)) / 2);
310  cairo_show_text(context, msg);
311  g_free(msg);
312 
313  }else {
314  /* Standard drawing: We copy the surface from RDP */
315 
316  if (!rfi->surface)
317  return FALSE;
318 
320  cairo_scale(context, rfi->scale_x, rfi->scale_y);
321 
322  cairo_set_source_surface(context, rfi->surface, 0, 0);
323 
324  cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); // Ignore alpha channel from FreeRDP
325  cairo_paint(context);
326  }
327 
328  return TRUE;
329 }
330 
332 {
333  TRACE_CALL(__func__);
334  rfContext* rfi = GET_PLUGIN_DATA(gp);
335 
336  RemminaPluginRdpEvent rdp_event = { 0 };
337  GtkAllocation a;
338  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
339 
340  if (!rfi || !rfi->connected || rfi->is_reconnecting)
341  return FALSE;
342 
344  return FALSE;
345 
347  gint gpwidth, gpheight, prevwidth, prevheight;
348 
349  if (rfi->dispcontext && rfi->dispcontext->SendMonitorLayout) {
350  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
351  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
352  gpwidth = a.width;
353  gpheight = a.height;
356 
357  if ((gpwidth != prevwidth || gpheight != prevheight) &&
358  gpwidth >= 200 && gpwidth < 8192 &&
359  gpheight >= 200 && gpheight < 8192
360  ) {
361  if (rfi->rdpgfxchan) {
362  /* Workaround for FreeRDP issue #5417 */
363  if (gpwidth < AVC_MIN_DESKTOP_WIDTH)
364  gpwidth = AVC_MIN_DESKTOP_WIDTH;
365  if (gpheight < AVC_MIN_DESKTOP_HEIGHT)
366  gpheight = AVC_MIN_DESKTOP_HEIGHT;
367  }
369  rdp_event.monitor_layout.width = gpwidth;
370  rdp_event.monitor_layout.height = gpheight;
371  rdp_event.monitor_layout.desktopOrientation = desktopOrientation;
372  rdp_event.monitor_layout.desktopScaleFactor = desktopScaleFactor;
373  rdp_event.monitor_layout.deviceScaleFactor = deviceScaleFactor;
374  remmina_rdp_event_event_push(gp, &rdp_event);
375  }
376  }
377 
378  return FALSE;
379 }
380 
382 {
383  TRACE_CALL(__func__);
384  rfContext* rfi = GET_PLUGIN_DATA(gp);
385  if (!rfi || !rfi->connected || rfi->is_reconnecting)
386  return;
388  g_source_remove(rfi->delayed_monitor_layout_handler);
390  }
392  rfi->delayed_monitor_layout_handler = g_timeout_add(500, (GSourceFunc)remmina_rdp_event_delayed_monitor_layout, gp);
393  }
394 
395 }
396 
397 static gboolean remmina_rdp_event_on_configure(GtkWidget* widget, GdkEventConfigure* event, RemminaProtocolWidget* gp)
398 {
399  TRACE_CALL(__func__);
400  /* Called when gp changes its size or position */
401 
402  rfContext* rfi = GET_PLUGIN_DATA(gp);
403  if (!rfi || !rfi->connected || rfi->is_reconnecting)
404  return FALSE;
405 
407 
408  /* If the scaler is not active, schedule a delayed remote resolution change */
410 
411 
412  return FALSE;
413 }
414 
415 static void remmina_rdp_event_translate_pos(RemminaProtocolWidget* gp, int ix, int iy, UINT16* ox, UINT16* oy)
416 {
417  TRACE_CALL(__func__);
418  rfContext* rfi = GET_PLUGIN_DATA(gp);
419 
420  /*
421  * Translate a position from local window coordinates (ix,iy) to
422  * RDP coordinates and put result on (*ox,*uy)
423  * */
424 
425  if (!rfi || !rfi->connected || rfi->is_reconnecting)
426  return;
427 
428  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
429  *ox = (UINT16)(ix * remmina_plugin_service->protocol_plugin_get_width(gp) / rfi->scale_width);
430  *oy = (UINT16)(iy * remmina_plugin_service->protocol_plugin_get_height(gp) / rfi->scale_height);
431  }else {
432  *ox = (UINT16)ix;
433  *oy = (UINT16)iy;
434  }
435 }
436 
437 static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget* gp, int ix, int iy, int* ox, int* oy)
438 {
439  TRACE_CALL(__func__);
440  rfContext* rfi = GET_PLUGIN_DATA(gp);
441 
442  /*
443  * Translate a position from RDP coordinates (ix,iy) to
444  * local window coordinates and put result on (*ox,*uy)
445  * */
446 
447  if (!rfi || !rfi->connected || rfi->is_reconnecting)
448  return;
449 
450  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
453  }else {
454  *ox = ix;
455  *oy = iy;
456  }
457 }
458 
459 static gboolean remmina_rdp_event_on_motion(GtkWidget* widget, GdkEventMotion* event, RemminaProtocolWidget* gp)
460 {
461  TRACE_CALL(__func__);
462  RemminaPluginRdpEvent rdp_event = { 0 };
463 
465  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
466  rdp_event.mouse_event.extended = FALSE;
467 
468  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
469  remmina_rdp_event_event_push(gp, &rdp_event);
470 
471  return TRUE;
472 }
473 
474 static gboolean remmina_rdp_event_on_button(GtkWidget* widget, GdkEventButton* event, RemminaProtocolWidget* gp)
475 {
476  TRACE_CALL(__func__);
477  gint flag;
478  gboolean extended = FALSE;
479  RemminaPluginRdpEvent rdp_event = { 0 };
480 
481  /* We bypass 2button-press and 3button-press events */
482  if ((event->type != GDK_BUTTON_PRESS) && (event->type != GDK_BUTTON_RELEASE))
483  return TRUE;
484 
485  flag = 0;
486 
487  switch (event->button) {
488  case 1:
489  flag |= PTR_FLAGS_BUTTON1;
490  break;
491  case 2:
492  flag |= PTR_FLAGS_BUTTON3;
493  break;
494  case 3:
495  flag |= PTR_FLAGS_BUTTON2;
496  break;
497  case 8: /* back */
498  case 97: /* Xming */
499  extended = TRUE;
500  flag |= PTR_XFLAGS_BUTTON1;
501  break;
502  case 9: /* forward */
503  case 112: /* Xming */
504  extended = TRUE;
505  flag |= PTR_XFLAGS_BUTTON2;
506  break;
507  default:
508  return FALSE;
509  }
510 
511  if (event->type == GDK_BUTTON_PRESS) {
512  if (extended)
513  flag |= PTR_XFLAGS_DOWN;
514  else
515  flag |= PTR_FLAGS_DOWN;
516  }
517 
519  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
520 
521  if (flag != 0) {
522  rdp_event.mouse_event.flags = flag;
523  rdp_event.mouse_event.extended = extended;
524  remmina_rdp_event_event_push(gp, &rdp_event);
525  }
526 
527  return TRUE;
528 }
529 
530 static gboolean remmina_rdp_event_on_scroll(GtkWidget* widget, GdkEventScroll* event, RemminaProtocolWidget* gp)
531 {
532  TRACE_CALL(__func__);
533  gint flag;
534  RemminaPluginRdpEvent rdp_event = { 0 };
535 
536  flag = 0;
538 
539  switch (event->direction) {
540  case GDK_SCROLL_UP:
541  flag = PTR_FLAGS_WHEEL | 0x0078;
542  break;
543 
544  case GDK_SCROLL_DOWN:
545  flag = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088;
546  break;
547 
548 #ifdef GDK_SCROLL_SMOOTH
549  case GDK_SCROLL_SMOOTH:
550  if (event->delta_y < 0)
551  flag = PTR_FLAGS_WHEEL | 0x0078;
552  if (event->delta_y > 0)
553  flag = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088;
554  if (!flag)
555  return FALSE;
556  break;
557 #endif
558 
559  default:
560  return FALSE;
561  }
562 
563  rdp_event.mouse_event.flags = flag;
564  rdp_event.mouse_event.extended = FALSE;
565  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
566  remmina_rdp_event_event_push(gp, &rdp_event);
567 
568  return TRUE;
569 }
570 
571 static void remmina_rdp_event_init_keymap(rfContext* rfi, const gchar* strmap)
572 {
573  long int v1, v2;
574  const char *s;
575  char *endptr;
577 
578  if (strmap == NULL || strmap[0] == 0) {
579  rfi->keymap = NULL;
580  return;
581  }
582  s = strmap;
583  rfi->keymap = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpKeymapEntry));
584  while(1) {
585  v1 = strtol(s, &endptr, 10);
586  if (endptr == s) break;
587  s = endptr;
588  if (*s != ':') break;
589  s++;
590  v2 = strtol(s, &endptr, 10);
591  if (endptr == s) break;
592  s = endptr;
593  ke.orig_keycode = v1 & 0x7fffffff;
594  ke.translated_keycode = v2 & 0x7fffffff;
595  g_array_append_val(rfi->keymap, ke);
596  if (*s != ',') break;
597  s++;
598  }
599  if (rfi->keymap->len == 0) {
600  g_array_unref(rfi->keymap);
601  rfi->keymap = NULL;
602  }
603 
604 }
605 
606 static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, RemminaProtocolWidget* gp)
607 {
608  TRACE_CALL(__func__);
609  guint32 unicode_keyval;
610  guint16 hardware_keycode;
611  rfContext* rfi = GET_PLUGIN_DATA(gp);
612  RemminaPluginRdpEvent rdp_event;
614  DWORD scancode = 0;
615  int ik;
616 
617  if (!rfi || !rfi->connected || rfi->is_reconnecting)
618  return FALSE;
619 
620 #ifdef ENABLE_GTK_INSPECTOR_KEY
621  /* GTK inspector key is propagated up. Disabled by default.
622  * enable it by defining ENABLE_GTK_INSPECTOR_KEY */
623  if ( ( event->state & GDK_CONTROL_MASK ) != 0 && ( event->keyval == GDK_KEY_I || event->keyval == GDK_KEY_D ) ) {
624  return FALSE;
625  }
626 #endif
627 
629  rdp_event.key_event.up = (event->type == GDK_KEY_PRESS ? False : True);
630  rdp_event.key_event.extended = False;
631 
632  switch (event->keyval) {
633  case GDK_KEY_Pause:
634  /*
635  * See https://msdn.microsoft.com/en-us/library/cc240584.aspx
636  * 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT)
637  * for pause key management
638  */
639  rdp_event.key_event.key_code = 0x1D;
640  rdp_event.key_event.up = False;
641  remmina_rdp_event_event_push(gp, &rdp_event);
642  rdp_event.key_event.key_code = 0x45;
643  rdp_event.key_event.up = False;
644  remmina_rdp_event_event_push(gp, &rdp_event);
645  rdp_event.key_event.key_code = 0x1D;
646  rdp_event.key_event.up = True;
647  remmina_rdp_event_event_push(gp, &rdp_event);
648  rdp_event.key_event.key_code = 0x45;
649  rdp_event.key_event.up = True;
650  remmina_rdp_event_event_push(gp, &rdp_event);
651  break;
652 
653  default:
654  if (!rfi->use_client_keymap) {
655  hardware_keycode = event->hardware_keycode;
656  if (rfi->keymap) {
657  for(ik = 0; ik < rfi->keymap->len; ik++) {
658  kep = &g_array_index(rfi->keymap, RemminaPluginRdpKeymapEntry, ik);
659  if (hardware_keycode == kep->orig_keycode) {
660  hardware_keycode = kep->translated_keycode;
661  break;
662  }
663  }
664  }
665  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(hardware_keycode);
666  if (scancode) {
667  rdp_event.key_event.key_code = scancode & 0xFF;
668  rdp_event.key_event.extended = scancode & 0x100;
669  remmina_rdp_event_event_push(gp, &rdp_event);
670  keypress_list_add(gp, rdp_event);
671  }
672  } else {
673  unicode_keyval = gdk_keyval_to_unicode(event->keyval);
674  /* Decide when whe should send a keycode or a Unicode character.
675  * - All non char keys (Shift, Alt, Super) should be sent as keycode
676  * - Space should be sent as keycode (see issue #1364)
677  * - All special keys (F1-F10, numeric pad, Home/End/Arrows/PgUp/PgDn/Insert/Delete) keycode
678  * - All key pressed while Ctrl or Alt or Super is down are not decoded by gdk_keyval_to_unicode(), so send it as keycode
679  * - All keycodes not translatable to unicode chars, as keycode
680  * - The rest as Unicode char
681  */
682  if (event->keyval >= 0xfe00 || // Arrows, Shift, Alt, Fn, num keypad…
683  event->hardware_keycode == 0x41 || // Spacebar
684  unicode_keyval == 0 || // Impossible to translate
685  (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK)) != 0 // A modifier not recognized by gdk_keyval_to_unicode()
686  ) {
687  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode);
688  rdp_event.key_event.key_code = scancode & 0xFF;
689  rdp_event.key_event.extended = scancode & 0x100;
690  if (rdp_event.key_event.key_code) {
691  remmina_rdp_event_event_push(gp, &rdp_event);
692  keypress_list_add(gp, rdp_event);
693  }
694  } else {
696  rdp_event.key_event.unicode_code = unicode_keyval;
697  rdp_event.key_event.extended = False;
698  remmina_rdp_event_event_push(gp, &rdp_event);
699  keypress_list_add(gp, rdp_event);
700  }
701  }
702  break;
703  }
704 
705  return TRUE;
706 }
707 
708 gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
709 {
710  /* Signal handler for GTK clipboard owner-change */
711  TRACE_CALL(__func__);
712  RemminaPluginRdpEvent rdp_event = { 0 };
713  CLIPRDR_FORMAT_LIST* pFormatList;
714 
715  /* Usually "owner-change" is fired when a user pres "COPY" on the client
716  * OR when this plugin calls gtk_clipboard_set_with_owner()
717  * after receivina a RDP server format list in remmina_rdp_cliprdr_server_format_list()
718  * In the latter case, we must ignore owner change */
719 
720  remmina_plugin_service->debug("owner-change event received");
721 
722  rfContext *rfi = GET_PLUGIN_DATA(gp);
723  if (rfi)
725 
726  if (gtk_clipboard_get_owner(gtkClipboard) != (GObject*)gp) {
727  /* To do: avoid this when the new owner is another remmina protocol widget of
728  * the same remmina application */
729  remmina_plugin_service->debug(" new owner is different than me: new=%p me=%p. Sending local clipboard format list to server.",
730  gtk_clipboard_get_owner(gtkClipboard), (GObject*)gp);
731 
734  rdp_event.clipboard_formatlist.pFormatList = pFormatList;
735  remmina_rdp_event_event_push(gp, &rdp_event);
736  } else {
737  remmina_plugin_service->debug(" ... but I'm the owner!");
738  }
739  return TRUE;
740 }
741 
743 {
744  TRACE_CALL(__func__);
745  gchar* s;
746  gint flags;
747  rfContext* rfi = GET_PLUGIN_DATA(gp);
748  GtkClipboard* clipboard;
749  RemminaFile* remminafile;
750 
751  if (!rfi) return;
753 
754  rfi->drawing_area = gtk_drawing_area_new();
755  gtk_widget_show(rfi->drawing_area);
756  gtk_container_add(GTK_CONTAINER(gp), rfi->drawing_area);
757 
758  gtk_widget_add_events(rfi->drawing_area, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK
759  | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK);
760  gtk_widget_set_can_focus(rfi->drawing_area, TRUE);
761 
763 
764  s = remmina_plugin_service->pref_get_value("rdp_use_client_keymap");
765  rfi->use_client_keymap = (s && s[0] == '1' ? TRUE : FALSE);
766  g_free(s);
767 
768  /* Read special keymap from profile file, if exists */
770 
771  if (rfi->use_client_keymap && rfi->keymap) {
772  fprintf(stderr, "RDP profile error: you cannot define both rdp_map_hardware_keycode and have 'Use client keuboard mapping' enabled\n");
773  }
774 
775  g_signal_connect(G_OBJECT(rfi->drawing_area), "draw",
776  G_CALLBACK(remmina_rdp_event_on_draw), gp);
777  g_signal_connect(G_OBJECT(rfi->drawing_area), "configure-event",
778  G_CALLBACK(remmina_rdp_event_on_configure), gp);
779  g_signal_connect(G_OBJECT(rfi->drawing_area), "motion-notify-event",
780  G_CALLBACK(remmina_rdp_event_on_motion), gp);
781  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-press-event",
782  G_CALLBACK(remmina_rdp_event_on_button), gp);
783  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-release-event",
784  G_CALLBACK(remmina_rdp_event_on_button), gp);
785  g_signal_connect(G_OBJECT(rfi->drawing_area), "scroll-event",
786  G_CALLBACK(remmina_rdp_event_on_scroll), gp);
787  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-press-event",
788  G_CALLBACK(remmina_rdp_event_on_key), gp);
789  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event",
790  G_CALLBACK(remmina_rdp_event_on_key), gp);
791  g_signal_connect(G_OBJECT(rfi->drawing_area), "focus-in-event",
792  G_CALLBACK(remmina_rdp_event_on_focus_in), gp);
793 
794  if (!remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE)) {
795  clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
796  rfi->clipboard.clipboard_handler = g_signal_connect(clipboard, "owner-change", G_CALLBACK(remmina_rdp_event_on_clipboard), gp);
797  }
798 
799  rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpEvent));
800  rfi->event_queue = g_async_queue_new_full(g_free);
801  rfi->ui_queue = g_async_queue_new();
802  pthread_mutex_init(&rfi->ui_queue_mutex, NULL);
803 
804  if (pipe(rfi->event_pipe)) {
805  g_print("Error creating pipes.\n");
806  rfi->event_pipe[0] = -1;
807  rfi->event_pipe[1] = -1;
808  rfi->event_handle = NULL;
809  }else {
810  flags = fcntl(rfi->event_pipe[0], F_GETFL, 0);
811  fcntl(rfi->event_pipe[0], F_SETFL, flags | O_NONBLOCK);
812  rfi->event_handle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, rfi->event_pipe[0], WINPR_FD_READ);
813  if (!rfi->event_handle) {
814  g_print("CreateFileDescriptorEvent() failed\n");
815  }
816  }
817 
818  rfi->object_table = g_hash_table_new_full(NULL, NULL, NULL, g_free);
819 
820  rfi->display = gdk_display_get_default();
821 
822 #if GTK_CHECK_VERSION(3, 22, 0)
823  GdkVisual *visual = gdk_screen_get_system_visual(
824  gdk_display_get_default_screen(rfi->display));
825  rfi->bpp = gdk_visual_get_depth (visual);
826 #else
827  rfi->bpp = gdk_visual_get_best_depth();
828 #endif
829 }
830 
831 
832 
834 {
835  TRACE_CALL(__func__);
836  rfContext* rfi = GET_PLUGIN_DATA(gp);
837 
838  switch (obj->type) {
839  case REMMINA_RDP_UI_RFX:
840  rfx_message_free(rfi->rfx_context, obj->rfx.message);
841  break;
842 
844  free(obj->nocodec.bitmap);
845  break;
846 
847  default:
848  break;
849  }
850 
851  g_free(obj);
852 }
853 
854 
856 {
857  TRACE_CALL(__func__);
858  rfContext* rfi = GET_PLUGIN_DATA(gp);
860 
861  if (!rfi) return;
862 
863  /* unregister the clipboard monitor */
864  if (rfi->clipboard.clipboard_handler) {
865  g_signal_handler_disconnect(G_OBJECT(gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD)), rfi->clipboard.clipboard_handler);
866  rfi->clipboard.clipboard_handler = 0;
867  }
869  g_source_remove(rfi->delayed_monitor_layout_handler);
871  }
872  if (rfi->ui_handler) {
873  g_source_remove(rfi->ui_handler);
874  rfi->ui_handler = 0;
875  }
876  while ((ui = (RemminaPluginRdpUiObject*)g_async_queue_try_pop(rfi->ui_queue)) != NULL) {
878  }
879  if (rfi->surface) {
880  cairo_surface_destroy(rfi->surface);
881  rfi->surface = NULL;
882  }
883 
884  g_hash_table_destroy(rfi->object_table);
885 
886  g_array_free(rfi->pressed_keys, TRUE);
887  if (rfi->keymap) {
888  g_array_free(rfi->keymap, TRUE);
889  rfi->keymap = NULL;
890  }
891  g_async_queue_unref(rfi->event_queue);
892  rfi->event_queue = NULL;
893  g_async_queue_unref(rfi->ui_queue);
894  rfi->ui_queue = NULL;
895  pthread_mutex_destroy(&rfi->ui_queue_mutex);
896 
897  if (rfi->event_handle) {
898  CloseHandle(rfi->event_handle);
899  rfi->event_handle = NULL;
900  }
901 
902  close(rfi->event_pipe[0]);
903  close(rfi->event_pipe[1]);
904 }
905 
907 {
908  int stride;
909  rdpGdi* gdi;
910 
911  if (!rfi)
912  return;
913 
914  gdi = ((rdpContext *)rfi)->gdi;
915 
916  if (!gdi)
917  return;
918 
919  if (rfi->surface) {
920  cairo_surface_destroy(rfi->surface);
921  rfi->surface = NULL;
922  }
923  stride = cairo_format_stride_for_width(rfi->cairo_format, gdi->width);
924  rfi->surface = cairo_image_surface_create_for_data((unsigned char*)gdi->primary_buffer, rfi->cairo_format, gdi->width, gdi->height, stride);
925 }
926 
928 {
929  TRACE_CALL(__func__);
930  gint width, height;
931  rdpGdi* gdi;
932  rfContext* rfi = GET_PLUGIN_DATA(gp);
933 
936 
937  gdi = ((rdpContext*)rfi)->gdi;
938 
940 
941  /* See if we also must rellocate rfi->surface with different width and height,
942  * this usually happens after a DesktopResize RDP event*/
943 
944  if ( rfi->surface && (cairo_image_surface_get_width(rfi->surface) != gdi->width ||
945  cairo_image_surface_get_height(rfi->surface) != gdi->height) ) {
946  /* Destroys and recreate rfi->surface with new width and height */
947  cairo_surface_destroy(rfi->surface);
948  rfi->surface = NULL;
950  } else if ( rfi->surface == NULL ) {
952  }
953 
954  /* Send gdi->width and gdi->height obtained from remote server to gp plugin,
955  * so they will be saved when closing connection */
956  if (width != gdi->width)
958  if (height != gdi->height)
960 
962 
964  /* In scaled mode and autores mode, drawing_area will get its dimensions from its parent */
965  gtk_widget_set_size_request(rfi->drawing_area, -1, -1 );
966  }else {
967  /* In non scaled mode, the plugins forces dimensions of drawing area */
968  gtk_widget_set_size_request(rfi->drawing_area, width, height);
969  }
971 }
972 
974 {
975  TRACE_CALL(__func__);
976  rfContext* rfi = GET_PLUGIN_DATA(gp);
977  rdpGdi* gdi;
978 
979  gdi = ((rdpContext *)rfi)->gdi;
980 
981  gtk_widget_realize(rfi->drawing_area);
982 
984  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0, gdi->width, gdi->height);
985 
987 
989 }
990 
992 {
993  TRACE_CALL(__func__);
994  rfContext* rfi = GET_PLUGIN_DATA(gp);
995  gdk_window_invalidate_rect(gtk_widget_get_window(rfi->drawing_area), NULL, TRUE);
996 }
997 
999 {
1000  TRACE_CALL(__func__);
1001  GdkPixbuf* pixbuf;
1002  rfContext* rfi = GET_PLUGIN_DATA(gp);
1003  rdpPointer* pointer = (rdpPointer*)ui->cursor.pointer;
1004  cairo_surface_t* surface;
1005  UINT8* data = malloc(pointer->width * pointer->height * 4);
1006 
1007  if (freerdp_image_copy_from_pointer_data(
1008  (BYTE*)data, PIXEL_FORMAT_BGRA32,
1009  pointer->width * 4, 0, 0, pointer->width, pointer->height,
1010  pointer->xorMaskData, pointer->lengthXorMask,
1011  pointer->andMaskData, pointer->lengthAndMask,
1012  pointer->xorBpp, &(ui->cursor.context->gdi->palette)) < 0) {
1013  free(data);
1014  return FALSE;
1015  }
1016 
1017  surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, pointer->width, pointer->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pointer->width));
1018  pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, pointer->width, pointer->height);
1019  cairo_surface_destroy(surface);
1020  free(data);
1021  ((rfPointer*)ui->cursor.pointer)->cursor = gdk_cursor_new_from_pixbuf(rfi->display, pixbuf, pointer->xPos, pointer->yPos);
1022  g_object_unref(pixbuf);
1023 
1024  return TRUE;
1025 }
1026 
1028 {
1029  TRACE_CALL(__func__);
1030  g_object_unref(ui->cursor.pointer->cursor);
1031  ui->cursor.pointer->cursor = NULL;
1032 }
1033 
1035 {
1036  TRACE_CALL(__func__);
1037  GdkWindow *w, *nw;
1038  gint nx, ny, wx, wy;
1039 #if GTK_CHECK_VERSION(3, 20, 0)
1040  GdkSeat *seat;
1041 #else
1042  GdkDeviceManager *manager;
1043 #endif
1044  GdkDevice *dev;
1045  rfContext* rfi = GET_PLUGIN_DATA(gp);
1046 
1047  if (rfi == NULL)
1048  return FALSE;
1049 
1050  w = gtk_widget_get_window(rfi->drawing_area);
1051 #if GTK_CHECK_VERSION(3, 20, 0)
1052  seat = gdk_display_get_default_seat(gdk_display_get_default());
1053  dev = gdk_seat_get_pointer(seat);
1054 #else
1055  manager = gdk_display_get_device_manager(gdk_display_get_default());
1056  dev = gdk_device_manager_get_client_pointer(manager);
1057 #endif
1058 
1059  nw = gdk_device_get_window_at_position(dev, NULL, NULL);
1060 
1061  if (nw == w) {
1062  nx = 0;
1063  ny = 0;
1065  gdk_window_get_root_coords(w, nx, ny, &wx, &wy);
1066  gdk_device_warp(dev, gdk_window_get_screen(w), wx, wy);
1067  }
1068  return TRUE;
1069 }
1070 
1072 {
1073  TRACE_CALL(__func__);
1074  rfContext* rfi = GET_PLUGIN_DATA(gp);
1075 
1076  switch (ui->cursor.type) {
1078  ui->retval = remmina_rdp_event_create_cursor(gp, ui) ? 1 : 0;
1079  break;
1080 
1083  break;
1084 
1086  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), ui->cursor.pointer->cursor);
1087  ui->retval = 1;
1088  break;
1089 
1091  ui->retval = remmina_rdp_event_set_pointer_position(gp, ui->pos.x, ui->pos.y) ? 1 : 0;
1092  break;
1093 
1095  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area),
1096  gdk_cursor_new_for_display(gdk_display_get_default(),
1097  GDK_BLANK_CURSOR));
1098  ui->retval = 1;
1099  break;
1100 
1102  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), NULL);
1103  ui->retval = 1;
1104  break;
1105  }
1106 }
1107 
1109 {
1110  TRACE_CALL(__func__);
1112 }
1113 
1115 {
1116  TRACE_CALL(__func__);
1117  rfContext* rfi = GET_PLUGIN_DATA(gp);
1118 
1119  if (!rfi || !rfi->connected || rfi->is_reconnecting)
1120  return;
1122 }
1123 
1125 {
1126  TRACE_CALL(__func__);
1127  rfContext* rfi = GET_PLUGIN_DATA(gp);
1128  cairo_surface_destroy(rfi->surface);
1129  rfi->surface = NULL;
1130 }
1131 
1133 {
1134  TRACE_CALL(__func__);
1135  switch (ui->event.type) {
1138  break;
1141  break;
1142  }
1143 }
1144 
1146 {
1147  TRACE_CALL(__func__);
1148  switch (ui->type) {
1151  break;
1152 
1155  break;
1156 
1159  break;
1160 
1161  case REMMINA_RDP_UI_CURSOR:
1162  remmina_rdp_event_cursor(gp, ui);
1163  break;
1164 
1167  break;
1168 
1169  case REMMINA_RDP_UI_EVENT:
1171  break;
1172 
1173  default:
1174  break;
1175  }
1176 }
1177 
1179 {
1180  TRACE_CALL(__func__);
1181 
1182  rfContext* rfi = GET_PLUGIN_DATA(gp);
1184 
1185  pthread_mutex_lock(&rfi->ui_queue_mutex);
1186  ui = (RemminaPluginRdpUiObject*)g_async_queue_try_pop(rfi->ui_queue);
1187  if (ui) {
1188  pthread_mutex_lock(&ui->sync_wait_mutex);
1189  if (!rfi->thread_cancelled) {
1191  }
1192  // Should we signal the caller thread to unlock ?
1193  if (ui->sync) {
1194  ui->complete = TRUE;
1195  pthread_cond_signal(&ui->sync_wait_cond);
1196  pthread_mutex_unlock(&ui->sync_wait_mutex);
1197 
1198  } else {
1200  }
1201 
1202  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1203  return TRUE;
1204  }else {
1205  rfi->ui_handler = 0;
1206  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1207  return FALSE;
1208  }
1209 }
1210 
1212 {
1213  TRACE_CALL(__func__);
1214  rfContext* rfi = GET_PLUGIN_DATA(gp);
1215  gboolean ui_sync_save;
1216  int oldcanceltype;
1217 
1218  if (rfi->thread_cancelled) {
1219  return;
1220  }
1221 
1224  return;
1225  }
1226 
1227  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldcanceltype);
1228 
1229  pthread_mutex_lock(&rfi->ui_queue_mutex);
1230 
1231  ui_sync_save = ui->sync;
1232  ui->complete = FALSE;
1233 
1234  if (ui_sync_save) {
1235  pthread_mutex_init(&ui->sync_wait_mutex, NULL);
1236  pthread_cond_init(&ui->sync_wait_cond, NULL);
1237  }
1238 
1239  ui->complete = FALSE;
1240 
1241  g_async_queue_push(rfi->ui_queue, ui);
1242 
1243  if (!rfi->ui_handler) {
1244  rfi->ui_handler = IDLE_ADD((GSourceFunc)remmina_rdp_event_process_ui_queue, gp);
1245  }
1246 
1247  if (ui_sync_save) {
1248  /* Wait for main thread function completion before returning */
1249  pthread_mutex_lock(&ui->sync_wait_mutex);
1250  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1251  while (!ui->complete) {
1252  pthread_cond_wait(&ui->sync_wait_cond, &ui->sync_wait_mutex);
1253  }
1254  pthread_cond_destroy(&ui->sync_wait_cond);
1255  pthread_mutex_destroy(&ui->sync_wait_mutex);
1256  } else {
1257  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1258  }
1259  pthread_setcanceltype(oldcanceltype, NULL);
1260 }
1261 
1263 {
1264  ui->sync = FALSE;
1266 }
1267 
1269 {
1270  TRACE_CALL(__func__);
1271  int retval;
1272  ui->sync = TRUE;
1274  retval = ui->retval;
1276  return retval;
1277 }
1278 
1280 {
1281  TRACE_CALL(__func__);
1282  void *rp;
1283  ui->sync = TRUE;
1285  rp = ui->retptr;
1287  return rp;
1288 }
struct remmina_plugin_rdp_event::@40::@44 clipboard_formatlist
gboolean thread_cancelled
Definition: rdp_plugin.h:256
static void remmina_rdp_event_free_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1027
gboolean is_reconnecting
Definition: rdp_plugin.h:269
gulong clipboard_handler
Definition: rdp_plugin.h:77
static void remmina_rdp_event_create_cairo_surface(rfContext *rfi)
Definition: rdp_event.c:906
RemminaScaleMode(* remmina_protocol_widget_get_current_scale_mode)(RemminaProtocolWidget *gp)
Definition: plugin.h:154
static void remmina_rdp_event_process_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1132
guint delayed_monitor_layout_handler
Definition: rdp_plugin.h:284
static void remmina_rdp_event_update_scale_factor(RemminaProtocolWidget *gp)
Definition: rdp_event.c:251
void(* debug)(const gchar *fmt,...)
Definition: plugin.h:214
struct remmina_plugin_rdp_ui_object::@48::@52 rfx
gint event_pipe[2]
Definition: rdp_plugin.h:305
gdouble scale_y
Definition: rdp_plugin.h:283
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:41
cairo_surface_t * surface
Definition: rdp_plugin.h:290
gboolean rdpgfxchan
Definition: rdp_plugin.h:266
void(* protocol_plugin_set_width)(RemminaProtocolWidget *gp, gint width)
Definition: plugin.h:151
guint ui_handler
Definition: rdp_plugin.h:301
void remmina_rdp_settings_get_orientation_scale_prefs(int *desktopOrientation, int *desktopScaleFactor, int *deviceScaleFactor)
Definition: rdp_settings.c:608
GdkDisplay * display
Definition: rdp_plugin.h:288
void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1279
GAsyncQueue * ui_queue
Definition: rdp_plugin.h:299
void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
Definition: rdp_event.c:240
pthread_mutex_t sync_wait_mutex
Definition: rdp_plugin.h:193
int reconnect_nattempt
Definition: rdp_plugin.h:276
static gboolean remmina_rdp_event_process_ui_queue(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1178
static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:998
static void remmina_rdp_event_release_key(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event)
Definition: rdp_event.c:133
static void remmina_rdp_event_queue_ui(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1211
gint(* protocol_plugin_get_width)(RemminaProtocolWidget *gp)
Definition: plugin.h:150
gdouble scale_x
Definition: rdp_plugin.h:282
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: plugin.h:203
static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:606
void remmina_rdp_event_free_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj)
Definition: rdp_event.c:833
static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:459
struct remmina_plugin_rdp_ui_object::@48::@50 reg
void(* protocol_plugin_update_align)(RemminaProtocolWidget *gp)
Definition: plugin.h:169
void(* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp)
Definition: plugin.h:168
void remmina_rdp_event_process_clipboard(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_cliprdr.c:779
struct remmina_plugin_rdp_event::@40::@43 mouse_event
int reconnect_maxattempts
Definition: rdp_plugin.h:275
static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1108
static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:47
RemminaPluginRdpEventType type
Definition: rdp_plugin.h:118
void remmina_rdp_event_update_regions(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:220
static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget *gp)
Definition: rdp_event.c:331
static RemminaPluginService * remmina_plugin_service
unsigned translated_keycode
Definition: rdp_plugin.h:240
GtkWidget * drawing_area
Definition: rdp_plugin.h:279
cairo_format_t cairo_format
Definition: rdp_plugin.h:291
static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:397
struct remmina_plugin_rdp_event::@40::@42 key_event
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1268
void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:742
void remmina_rdp_clipboard_abort_transfer(rfContext *rfi)
Definition: rdp_cliprdr.c:814
gboolean use_client_keymap
Definition: rdp_plugin.h:285
static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:530
gchar *(* pref_get_value)(const gchar *key)
Definition: plugin.h:207
static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:991
GArray * keymap
Definition: rdp_plugin.h:310
unsigned orig_keycode
Definition: rdp_plugin.h:239
static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
Definition: rdp_event.c:175
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1262
static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:474
gint(* protocol_plugin_get_height)(RemminaProtocolWidget *gp)
Definition: plugin.h:152
struct remmina_plugin_rdp_ui_object::@48::@53 nocodec
void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
Definition: rdp_event.c:381
GAsyncQueue * event_queue
Definition: rdp_plugin.h:304
static void remmina_rdp_event_release_all_keys(RemminaProtocolWidget *gp)
Definition: rdp_event.c:112
CLIPRDR_FORMAT_LIST * remmina_rdp_cliprdr_get_client_format_list(RemminaProtocolWidget *gp)
Definition: rdp_cliprdr.c:561
pthread_cond_t sync_wait_cond
Definition: rdp_plugin.h:194
rfClipboard clipboard
Definition: rdp_plugin.h:308
static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
Definition: rdp_event.c:571
HANDLE event_handle
Definition: rdp_plugin.h:306
static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
Definition: rdp_event.c:415
static void remmina_rdp_ui_event_destroy_cairo_surface(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1124
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:855
RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
Definition: plugin.h:160
struct remmina_plugin_rdp_event::@40::@47 monitor_layout
GHashTable * object_table
Definition: rdp_plugin.h:297
gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:708
static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
Definition: rdp_event.c:437
static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1145
static void keypress_list_add(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event)
Definition: rdp_event.c:159
gboolean connected
Definition: rdp_plugin.h:268
RemminaScaleMode scale
Definition: rdp_plugin.h:254
freerdp * instance
Definition: rdp_plugin.h:251
DispClientContext * dispcontext
Definition: rdp_plugin.h:259
static BOOL remmina_rdp_event_set_pointer_position(RemminaProtocolWidget *gp, gint x, gint y)
Definition: rdp_event.c:1034
void(* protocol_plugin_register_hostkey)(RemminaProtocolWidget *gp, GtkWidget *widget)
Definition: plugin.h:162
struct remmina_plugin_rdp_ui_object::@48::@55 event
static void remmina_rdp_event_connected(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:973
GArray * pressed_keys
Definition: rdp_plugin.h:303
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:927
gint scale_height
Definition: rdp_plugin.h:281
void(* protocol_plugin_set_height)(RemminaProtocolWidget *gp, gint height)
Definition: plugin.h:153
Definition: rdp_plugin.h:238
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1114
struct remmina_plugin_rdp_ui_object::@48::@51 cursor
void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
Definition: rdp_event.c:92
struct remmina_plugin_rdp_ui_object::@48::@56 pos
RFX_CONTEXT * rfx_context
Definition: rdp_plugin.h:265
static void remmina_rdp_event_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1071
gboolean(* is_main_thread)(void)
Definition: plugin.h:222
static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp)
Definition: rdp_event.c:283
gint scale_width
Definition: rdp_plugin.h:280
pthread_mutex_t ui_queue_mutex
Definition: rdp_plugin.h:300
RemminaPluginRdpUiType type
Definition: rdp_plugin.h:190