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