FreeRDP
wlfreerdp.c
1 
22 #include <math.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <locale.h>
26 #include <float.h>
27 
28 #include <winpr/sysinfo.h>
29 #include <winpr/cast.h>
30 
31 #include <freerdp/client/cmdline.h>
32 #include <freerdp/channels/channels.h>
33 #include <freerdp/gdi/gdi.h>
34 #include <freerdp/client.h>
35 #include <freerdp/utils/signal.h>
36 #include <freerdp/locale/keyboard.h>
37 
38 #include <linux/input.h>
39 
40 #include <uwac/uwac.h>
41 
42 #include "wlfreerdp.h"
43 #include "wlf_input.h"
44 #include "wlf_cliprdr.h"
45 #include "wlf_disp.h"
46 #include "wlf_channels.h"
47 #include "wlf_pointer.h"
48 
49 #define TAG CLIENT_TAG("wayland")
50 
51 static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw, INT32 ih)
52 {
53  BOOL res = FALSE;
54  rdpGdi* gdi = NULL;
55  char* data = NULL;
56  UwacSize geometry = { 0 };
57  size_t stride = 0;
58  UwacReturnCode rc = UWAC_ERROR_INTERNAL;
59  RECTANGLE_16 area = { 0 };
60 
61  if (!context_w)
62  return FALSE;
63 
64  if ((ix < 0) || (iy < 0) || (iw < 0) || (ih < 0))
65  return FALSE;
66 
67  EnterCriticalSection(&context_w->critical);
68  UINT32 x = WINPR_ASSERTING_INT_CAST(UINT16, ix);
69  UINT32 y = WINPR_ASSERTING_INT_CAST(UINT16, iy);
70  UINT32 w = WINPR_ASSERTING_INT_CAST(UINT16, iw);
71  UINT32 h = WINPR_ASSERTING_INT_CAST(UINT16, ih);
72  rc = UwacWindowGetDrawingBufferGeometry(context_w->window, &geometry, &stride);
73  data = UwacWindowGetDrawingBuffer(context_w->window);
74 
75  if (!data || (rc != UWAC_SUCCESS))
76  goto fail;
77 
78  gdi = context_w->common.context.gdi;
79 
80  if (!gdi)
81  goto fail;
82 
83  /* Ignore output if the surface size does not match. */
84  if (((INT64)x > geometry.width) || ((INT64)y > geometry.height))
85  {
86  res = TRUE;
87  goto fail;
88  }
89 
90  area.left = WINPR_ASSERTING_INT_CAST(UINT16, x);
91  area.top = WINPR_ASSERTING_INT_CAST(UINT16, y);
92  area.right = WINPR_ASSERTING_INT_CAST(UINT16, x + w);
93  area.bottom = WINPR_ASSERTING_INT_CAST(UINT16, y + h);
94 
95  if (!wlf_copy_image(
96  gdi->primary_buffer, gdi->stride, WINPR_ASSERTING_INT_CAST(size_t, gdi->width),
97  WINPR_ASSERTING_INT_CAST(size_t, gdi->height), data, stride,
98  WINPR_ASSERTING_INT_CAST(size_t, geometry.width),
99  WINPR_ASSERTING_INT_CAST(size_t, geometry.height), &area,
100  freerdp_settings_get_bool(context_w->common.context.settings, FreeRDP_SmartSizing)))
101  goto fail;
102 
103  if (!wlf_scale_coordinates(&context_w->common.context, &x, &y, FALSE))
104  goto fail;
105 
106  if (!wlf_scale_coordinates(&context_w->common.context, &w, &h, FALSE))
107  goto fail;
108 
109  if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS)
110  goto fail;
111 
112  if (UwacWindowSubmitBuffer(context_w->window, false) != UWAC_SUCCESS)
113  goto fail;
114 
115  res = TRUE;
116 fail:
117  LeaveCriticalSection(&context_w->critical);
118  return res;
119 }
120 
121 static BOOL wl_end_paint(rdpContext* context)
122 {
123  rdpGdi* gdi = NULL;
124  wlfContext* context_w = NULL;
125  INT32 x = 0;
126  INT32 y = 0;
127  INT32 w = 0;
128  INT32 h = 0;
129 
130  if (!context || !context->gdi || !context->gdi->primary)
131  return FALSE;
132 
133  gdi = context->gdi;
134 
135  if (gdi->primary->hdc->hwnd->invalid->null)
136  return TRUE;
137 
138  x = gdi->primary->hdc->hwnd->invalid->x;
139  y = gdi->primary->hdc->hwnd->invalid->y;
140  w = gdi->primary->hdc->hwnd->invalid->w;
141  h = gdi->primary->hdc->hwnd->invalid->h;
142  context_w = (wlfContext*)context;
143  if (!wl_update_buffer(context_w, x, y, w, h))
144  {
145  return FALSE;
146  }
147 
148  gdi->primary->hdc->hwnd->invalid->null = TRUE;
149  gdi->primary->hdc->hwnd->ninvalid = 0;
150  return TRUE;
151 }
152 
153 static BOOL wl_refresh_display(wlfContext* context)
154 {
155  rdpGdi* gdi = NULL;
156 
157  if (!context || !context->common.context.gdi)
158  return FALSE;
159 
160  gdi = context->common.context.gdi;
161  return wl_update_buffer(context, 0, 0, gdi->width, gdi->height);
162 }
163 
164 static BOOL wl_resize_display(rdpContext* context)
165 {
166  wlfContext* wlc = (wlfContext*)context;
167  rdpGdi* gdi = context->gdi;
168  rdpSettings* settings = context->settings;
169 
170  if (!gdi_resize(gdi, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
171  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)))
172  return FALSE;
173 
174  return wl_refresh_display(wlc);
175 }
176 
177 static BOOL wl_pre_connect(freerdp* instance)
178 {
179  rdpSettings* settings = NULL;
180  wlfContext* context = NULL;
181  const UwacOutput* output = NULL;
182  UwacSize resolution;
183 
184  if (!instance)
185  return FALSE;
186 
187  context = (wlfContext*)instance->context;
188  WINPR_ASSERT(context);
189 
190  settings = instance->context->settings;
191  WINPR_ASSERT(settings);
192 
193  if (!freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, TRUE))
194  return FALSE;
195 
196  if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX))
197  return FALSE;
198  if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_NATIVE_WAYLAND))
199  return FALSE;
200  PubSub_SubscribeChannelConnected(instance->context->pubSub, wlf_OnChannelConnectedEventHandler);
201  PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
202  wlf_OnChannelDisconnectedEventHandler);
203 
204  if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
205  {
206  // Use the resolution of the first display output
207  output = UwacDisplayGetOutput(context->display, 0);
208 
209  if ((output != NULL) && (UwacOutputGetResolution(output, &resolution) == UWAC_SUCCESS))
210  {
211  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth,
212  (UINT32)resolution.width))
213  return FALSE;
214  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight,
215  (UINT32)resolution.height))
216  return FALSE;
217  }
218  else
219  {
220  WLog_WARN(TAG, "Failed to get output resolution! Check your display settings");
221  }
222  }
223 
224  return TRUE;
225 }
226 
227 static BOOL wl_post_connect(freerdp* instance)
228 {
229  if (!instance || !instance->context)
230  return FALSE;
231 
232  wlfContext* context = (wlfContext*)instance->context;
233  WINPR_ASSERT(context);
234 
235  rdpSettings* settings = instance->context->settings;
236  WINPR_ASSERT(settings);
237 
238  const char* title = "FreeRDP";
239  const char* wtitle = freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
240  if (wtitle)
241  title = wtitle;
242 
243  const char* app_id = "wlfreerdp";
244  const char* wmclass = freerdp_settings_get_string(settings, FreeRDP_WmClass);
245  if (wmclass)
246  app_id = wmclass;
247 
248  if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
249  return FALSE;
250 
251  rdpGdi* gdi = instance->context->gdi;
252 
253  if (!gdi || (gdi->width < 0) || (gdi->height < 0))
254  return FALSE;
255 
256  if (!wlf_register_pointer(instance->context->graphics))
257  return FALSE;
258 
259  UINT32 w = (UINT32)gdi->width;
260  UINT32 h = (UINT32)gdi->height;
261 
262  if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) && !context->fullscreen)
263  {
264  const UINT32 sw = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth);
265  if (sw > 0)
266  w = sw;
267 
268  const UINT32 sh = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight);
269  if (sh > 0)
270  h = sh;
271  }
272 
273  context->window = UwacCreateWindowShm(context->display, w, h, WL_SHM_FORMAT_XRGB8888);
274 
275  if (!context->window)
276  return FALSE;
277 
278  UwacWindowSetFullscreenState(
279  context->window, NULL,
280  freerdp_settings_get_bool(instance->context->settings, FreeRDP_Fullscreen));
281  UwacWindowSetTitle(context->window, title);
282  UwacWindowSetAppId(context->window, app_id);
283  UwacWindowSetOpaqueRegion(context->window, 0, 0, w, h);
284  instance->context->update->EndPaint = wl_end_paint;
285  instance->context->update->DesktopResize = wl_resize_display;
286  const char* KeyboardRemappingList =
287  freerdp_settings_get_string(instance->context->settings, FreeRDP_KeyboardRemappingList);
288 
289  context->remap_table = freerdp_keyboard_remap_string_to_list(KeyboardRemappingList);
290  if (!context->remap_table)
291  return FALSE;
292 
293  if (!(context->disp = wlf_disp_new(context)))
294  return FALSE;
295 
296  context->clipboard = wlf_clipboard_new(context);
297 
298  if (!context->clipboard)
299  return FALSE;
300 
301  return wl_refresh_display(context);
302 }
303 
304 static void wl_post_disconnect(freerdp* instance)
305 {
306  if (!instance)
307  return;
308 
309  if (!instance->context)
310  return;
311 
312  wlfContext* context = (wlfContext*)instance->context;
313  gdi_free(instance);
314  wlf_clipboard_free(context->clipboard);
315  wlf_disp_free(context->disp);
316 
317  if (context->window)
318  UwacDestroyWindow(&context->window);
319  freerdp_keyboard_remap_free(context->remap_table);
320  context->remap_table = NULL;
321 }
322 
323 static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
324 {
325  UwacEvent event;
326  wlfContext* context = NULL;
327 
328  if (UwacDisplayDispatch(display, 1) < 0)
329  return FALSE;
330 
331  context = (wlfContext*)instance->context;
332 
333  while (UwacHasEvent(display))
334  {
335  if (UwacNextEvent(display, &event) != UWAC_SUCCESS)
336  return FALSE;
337 
338  /*printf("UWAC event type %d\n", event.type);*/
339  switch (event.type)
340  {
341  case UWAC_EVENT_NEW_SEAT:
342  context->seat = event.seat_new.seat;
343  break;
344 
345  case UWAC_EVENT_REMOVED_SEAT:
346  context->seat = NULL;
347  break;
348 
349  case UWAC_EVENT_FRAME_DONE:
350  {
351  EnterCriticalSection(&context->critical);
352  UwacReturnCode r = UwacWindowSubmitBuffer(context->window, false);
353  LeaveCriticalSection(&context->critical);
354  if (r != UWAC_SUCCESS)
355  return FALSE;
356  }
357  break;
358 
359  case UWAC_EVENT_POINTER_ENTER:
360  if (!wlf_handle_pointer_enter(instance, &event.mouse_enter_leave))
361  return FALSE;
362 
363  break;
364 
365  case UWAC_EVENT_POINTER_MOTION:
366  if (!wlf_handle_pointer_motion(instance, &event.mouse_motion))
367  return FALSE;
368 
369  break;
370 
371  case UWAC_EVENT_POINTER_BUTTONS:
372  if (!wlf_handle_pointer_buttons(instance, &event.mouse_button))
373  return FALSE;
374 
375  break;
376 
377  case UWAC_EVENT_POINTER_AXIS:
378  if (!wlf_handle_pointer_axis(instance, &event.mouse_axis))
379  return FALSE;
380  break;
381 
382  case UWAC_EVENT_POINTER_AXIS_DISCRETE:
383  if (!wlf_handle_pointer_axis_discrete(instance, &event.mouse_axis))
384  return FALSE;
385  break;
386 
387  case UWAC_EVENT_POINTER_FRAME:
388  if (!wlf_handle_pointer_frame(instance, &event.mouse_frame))
389  return FALSE;
390  break;
391  case UWAC_EVENT_POINTER_SOURCE:
392  if (!wlf_handle_pointer_source(instance, &event.mouse_source))
393  return FALSE;
394  break;
395 
396  case UWAC_EVENT_KEY:
397  if (!wlf_handle_key(instance, &event.key))
398  return FALSE;
399 
400  break;
401 
402  case UWAC_EVENT_TOUCH_UP:
403  if (!wlf_handle_touch_up(instance, &event.touchUp))
404  return FALSE;
405 
406  break;
407 
408  case UWAC_EVENT_TOUCH_DOWN:
409  if (!wlf_handle_touch_down(instance, &event.touchDown))
410  return FALSE;
411 
412  break;
413 
414  case UWAC_EVENT_TOUCH_MOTION:
415  if (!wlf_handle_touch_motion(instance, &event.touchMotion))
416  return FALSE;
417 
418  break;
419 
420  case UWAC_EVENT_KEYBOARD_ENTER:
421  if (freerdp_settings_get_bool(instance->context->settings, FreeRDP_GrabKeyboard))
422  UwacSeatInhibitShortcuts(event.keyboard_enter_leave.seat, true);
423 
424  if (!wlf_keyboard_enter(instance, &event.keyboard_enter_leave))
425  return FALSE;
426 
427  break;
428 
429  case UWAC_EVENT_KEYBOARD_MODIFIERS:
430  if (!wlf_keyboard_modifiers(instance, &event.keyboard_modifiers))
431  return FALSE;
432 
433  break;
434 
435  case UWAC_EVENT_CONFIGURE:
436  if (!wlf_disp_handle_configure(context->disp, event.configure.width,
437  event.configure.height))
438  return FALSE;
439 
440  if (!wl_refresh_display(context))
441  return FALSE;
442 
443  break;
444 
445  case UWAC_EVENT_CLIPBOARD_AVAILABLE:
446  case UWAC_EVENT_CLIPBOARD_OFFER:
447  case UWAC_EVENT_CLIPBOARD_SELECT:
448  if (!wlf_cliprdr_handle_event(context->clipboard, &event.clipboard))
449  return FALSE;
450 
451  break;
452 
453  case UWAC_EVENT_CLOSE:
454  context->closed = TRUE;
455 
456  break;
457 
458  default:
459  break;
460  }
461  }
462 
463  return TRUE;
464 }
465 
466 static BOOL handle_window_events(freerdp* instance)
467 {
468  if (!instance)
469  return FALSE;
470 
471  return TRUE;
472 }
473 
474 static int wlfreerdp_run(freerdp* instance)
475 {
476  wlfContext* context = NULL;
477  HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
478  DWORD status = WAIT_ABANDONED;
479  HANDLE timer = NULL;
480  LARGE_INTEGER due = { 0 };
481 
482  TimerEventArgs timerEvent;
483  EventArgsInit(&timerEvent, "xfreerdp");
484 
485  if (!instance)
486  return -1;
487 
488  context = (wlfContext*)instance->context;
489 
490  if (!context)
491  return -1;
492 
493  if (!freerdp_connect(instance))
494  {
495  WLog_Print(context->log, WLOG_ERROR, "Failed to connect");
496  return -1;
497  }
498 
499  timer = CreateWaitableTimerA(NULL, FALSE, "mainloop-periodic-timer");
500 
501  if (!timer)
502  {
503  WLog_ERR(TAG, "failed to create timer");
504  goto disconnect;
505  }
506 
507  due.QuadPart = 0;
508 
509  if (!SetWaitableTimer(timer, &due, 20, NULL, NULL, FALSE))
510  {
511  goto disconnect;
512  }
513 
514  while (!freerdp_shall_disconnect_context(instance->context))
515  {
516  DWORD count = 0;
517  handles[count++] = timer;
518  handles[count++] = context->displayHandle;
519  count += freerdp_get_event_handles(instance->context, &handles[count],
520  ARRAYSIZE(handles) - count);
521 
522  if (count <= 2)
523  {
524  WLog_Print(context->log, WLOG_ERROR, "Failed to get FreeRDP file descriptor");
525  break;
526  }
527 
528  status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
529 
530  if (WAIT_FAILED == status)
531  {
532  WLog_Print(context->log, WLOG_ERROR, "WaitForMultipleObjects failed");
533  break;
534  }
535 
536  if (!handle_uwac_events(instance, context->display))
537  {
538  WLog_Print(context->log, WLOG_ERROR, "error handling UWAC events");
539  break;
540  }
541 
542  if (context->closed)
543  {
544  WLog_Print(context->log, WLOG_INFO, "Closed from Wayland");
545  break;
546  }
547 
548  if (freerdp_check_event_handles(instance->context) != TRUE)
549  {
550  if (client_auto_reconnect_ex(instance, handle_window_events))
551  continue;
552  else
553  {
554  /*
555  * Indicate an unsuccessful connection attempt if reconnect
556  * did not succeed and no other error was specified.
557  */
558  if (freerdp_error_info(instance) == 0)
559  status = 42;
560  }
561 
562  if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
563  WLog_Print(context->log, WLOG_ERROR, "Failed to check FreeRDP file descriptor");
564 
565  break;
566  }
567 
568  if ((status != WAIT_TIMEOUT) && (status == WAIT_OBJECT_0))
569  {
570  timerEvent.now = GetTickCount64();
571  PubSub_OnTimer(context->common.context.pubSub, context, &timerEvent);
572  }
573  }
574 
575 disconnect:
576  if (timer)
577  (void)CloseHandle(timer);
578  freerdp_disconnect(instance);
579  return WINPR_ASSERTING_INT_CAST(int, status);
580 }
581 
582 static BOOL wlf_client_global_init(void)
583 {
584  (void)setlocale(LC_ALL, "");
585 
586  if (freerdp_handle_signals() != 0)
587  return FALSE;
588 
589  return TRUE;
590 }
591 
592 static void wlf_client_global_uninit(void)
593 {
594 }
595 
596 static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
597 {
598  wlfContext* wlf = NULL;
599  const char* str_data = freerdp_get_logon_error_info_data(data);
600  const char* str_type = freerdp_get_logon_error_info_type(type);
601 
602  if (!instance || !instance->context)
603  return -1;
604 
605  wlf = (wlfContext*)instance->context;
606  WLog_Print(wlf->log, WLOG_INFO, "Logon Error Info %s [%s]", str_data, str_type);
607  return 1;
608 }
609 
610 static void wlf_client_free(freerdp* instance, rdpContext* context)
611 {
612  wlfContext* wlf = (wlfContext*)instance->context;
613 
614  if (!context)
615  return;
616 
617  if (wlf->display)
618  UwacCloseDisplay(&wlf->display);
619 
620  if (wlf->displayHandle)
621  (void)CloseHandle(wlf->displayHandle);
622  ArrayList_Free(wlf->events);
623  DeleteCriticalSection(&wlf->critical);
624 }
625 
626 static void* uwac_event_clone(const void* val)
627 {
628  UwacEvent* copy = NULL;
629  const UwacEvent* ev = (const UwacEvent*)val;
630 
631  copy = calloc(1, sizeof(UwacEvent));
632  if (!copy)
633  return NULL;
634  *copy = *ev;
635  return copy;
636 }
637 
638 static BOOL wlf_client_new(freerdp* instance, rdpContext* context)
639 {
640  wObject* obj = NULL;
641  UwacReturnCode status = UWAC_ERROR_INTERNAL;
642  wlfContext* wfl = (wlfContext*)context;
643 
644  if (!instance || !context)
645  return FALSE;
646 
647  instance->PreConnect = wl_pre_connect;
648  instance->PostConnect = wl_post_connect;
649  instance->PostDisconnect = wl_post_disconnect;
650  instance->LogonErrorInfo = wlf_logon_error_info;
651  wfl->log = WLog_Get(TAG);
652  wfl->display = UwacOpenDisplay(NULL, &status);
653 
654  if (!wfl->display || (status != UWAC_SUCCESS) || !wfl->log)
655  return FALSE;
656 
657  wfl->displayHandle = CreateFileDescriptorEvent(NULL, FALSE, FALSE,
658  UwacDisplayGetFd(wfl->display), WINPR_FD_READ);
659 
660  if (!wfl->displayHandle)
661  return FALSE;
662 
663  wfl->events = ArrayList_New(FALSE);
664  if (!wfl->events)
665  return FALSE;
666 
667  obj = ArrayList_Object(wfl->events);
668  obj->fnObjectNew = uwac_event_clone;
669  obj->fnObjectFree = free;
670 
671  InitializeCriticalSection(&wfl->critical);
672 
673  return TRUE;
674 }
675 
676 static int wfl_client_start(rdpContext* context)
677 {
678  WINPR_UNUSED(context);
679  return 0;
680 }
681 
682 static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
683 {
684  WINPR_ASSERT(pEntryPoints);
685  ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
686  pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
687  pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
688  pEntryPoints->GlobalInit = wlf_client_global_init;
689  pEntryPoints->GlobalUninit = wlf_client_global_uninit;
690  pEntryPoints->ContextSize = sizeof(wlfContext);
691  pEntryPoints->ClientNew = wlf_client_new;
692  pEntryPoints->ClientFree = wlf_client_free;
693  pEntryPoints->ClientStart = wfl_client_start;
694  pEntryPoints->ClientStop = freerdp_client_common_stop;
695  return 0;
696 }
697 
698 int main(int argc, char* argv[])
699 {
700  int rc = -1;
701  int status = 0;
702  RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
703  rdpContext* context = NULL;
704  rdpSettings* settings = NULL;
705  wlfContext* wlc = NULL;
706 
707  freerdp_client_warn_deprecated(argc, argv);
708 
709  RdpClientEntry(&clientEntryPoints);
710  context = freerdp_client_context_new(&clientEntryPoints);
711  if (!context)
712  goto fail;
713  wlc = (wlfContext*)context;
714  settings = context->settings;
715 
716  status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
717  if (status)
718  {
719  rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
720 
721  if (freerdp_settings_get_bool(settings, FreeRDP_ListMonitors))
722  wlf_list_monitors(wlc);
723 
724  goto fail;
725  }
726 
727  if (freerdp_client_start(context) != 0)
728  goto fail;
729 
730  rc = wlfreerdp_run(context->instance);
731 
732  if (freerdp_client_stop(context) != 0)
733  rc = -1;
734 
735 fail:
736  freerdp_client_context_free(context);
737  return rc;
738 }
739 
740 BOOL wlf_copy_image(const void* src, size_t srcStride, size_t srcWidth, size_t srcHeight, void* dst,
741  size_t dstStride, size_t dstWidth, size_t dstHeight, const RECTANGLE_16* area,
742  BOOL scale)
743 {
744  BOOL rc = FALSE;
745 
746  if (!src || !dst || !area)
747  return FALSE;
748 
749  if (scale)
750  {
751  WINPR_ASSERT(dstStride <= UINT32_MAX);
752  WINPR_ASSERT(dstWidth <= UINT32_MAX);
753  WINPR_ASSERT(dstHeight <= UINT32_MAX);
754  WINPR_ASSERT(srcStride <= UINT32_MAX);
755  WINPR_ASSERT(srcWidth <= UINT32_MAX);
756  WINPR_ASSERT(srcHeight <= UINT32_MAX);
757  return freerdp_image_scale(dst, PIXEL_FORMAT_BGRA32, (UINT32)dstStride, 0, 0,
758  (UINT32)dstWidth, (UINT32)dstHeight, src, PIXEL_FORMAT_BGRA32,
759  (UINT32)srcStride, 0, 0, (UINT32)srcWidth, (UINT32)srcHeight);
760  }
761  else
762  {
763  const size_t baseSrcOffset = 1ULL * area->top * srcStride + 4ULL * area->left;
764  const size_t baseDstOffset = 1ULL * area->top * dstStride + 4ULL * area->left;
765  const size_t width = MIN((size_t)area->right - area->left, dstWidth - area->left);
766  const size_t height = MIN((size_t)area->bottom - area->top, dstHeight - area->top);
767  const BYTE* psrc = (const BYTE*)src;
768  BYTE* pdst = (BYTE*)dst;
769 
770  for (size_t i = 0; i < height; i++)
771  {
772  const size_t srcOffset = i * srcStride + baseSrcOffset;
773  const size_t dstOffset = i * dstStride + baseDstOffset;
774  memcpy(&pdst[dstOffset], &psrc[srcOffset], width * 4);
775  }
776 
777  rc = TRUE;
778  }
779 
780  return rc;
781 }
782 
783 BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP)
784 {
785  wlfContext* wlf = (wlfContext*)context;
786  UwacSize geometry = { 0 };
787 
788  if (!context || !px || !py || !context->gdi)
789  return FALSE;
790 
791  if (!freerdp_settings_get_bool(context->settings, FreeRDP_SmartSizing))
792  return TRUE;
793 
794  rdpGdi* gdi = context->gdi;
795 
796  if (UwacWindowGetDrawingBufferGeometry(wlf->window, &geometry, NULL) != UWAC_SUCCESS)
797  return FALSE;
798 
799  const double sx = 1.0 * geometry.width / (double)gdi->width;
800  const double sy = 1.0 * geometry.height / (double)gdi->height;
801 
802  if (!fromLocalToRDP)
803  {
804  *px *= (UINT32)lround(sx);
805  *py *= (UINT32)lround(sy);
806  }
807  else
808  {
809  *px /= (UINT32)lround(sx);
810  *py /= (UINT32)lround(sy);
811  }
812 
813  return TRUE;
814 }
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57