FreeRDP
wf_gdi.c
1 
22 #include <freerdp/config.h>
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <conio.h>
28 
29 #include <freerdp/log.h>
30 #include <freerdp/gdi/gdi.h>
31 #include <freerdp/constants.h>
32 #include <freerdp/codec/color.h>
33 #include <freerdp/codec/bitmap.h>
34 #include <freerdp/codec/rfx.h>
35 #include <freerdp/codec/nsc.h>
36 #include <freerdp/gdi/gdi.h>
37 
38 #include "wf_client.h"
39 #include "wf_graphics.h"
40 #include "wf_gdi.h"
41 
42 #define TAG CLIENT_TAG("windows.gdi")
43 
44 static const BYTE wf_rop2_table[] = {
45  R2_BLACK, /* 0 */
46  R2_NOTMERGEPEN, /* DPon */
47  R2_MASKNOTPEN, /* DPna */
48  R2_NOTCOPYPEN, /* Pn */
49  R2_MASKPENNOT, /* PDna */
50  R2_NOT, /* Dn */
51  R2_XORPEN, /* DPx */
52  R2_NOTMASKPEN, /* DPan */
53  R2_MASKPEN, /* DPa */
54  R2_NOTXORPEN, /* DPxn */
55  R2_NOP, /* D */
56  R2_MERGENOTPEN, /* DPno */
57  R2_COPYPEN, /* P */
58  R2_MERGEPENNOT, /* PDno */
59  R2_MERGEPEN, /* PDo */
60  R2_WHITE, /* 1 */
61 };
62 
63 static BOOL wf_decode_color(wfContext* wfc, const UINT32 srcColor, COLORREF* color, UINT32* format)
64 {
65  rdpGdi* gdi;
66  rdpSettings* settings;
67  UINT32 SrcFormat, DstFormat;
68 
69  if (!wfc)
70  return FALSE;
71 
72  gdi = wfc->common.context.gdi;
73  settings = wfc->common.context.settings;
74 
75  if (!gdi || !settings)
76  return FALSE;
77 
78  SrcFormat = gdi_get_pixel_format(freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
79 
80  if (format)
81  *format = SrcFormat;
82 
83  switch (FreeRDPGetBitsPerPixel(gdi->dstFormat))
84  {
85  case 32:
86  DstFormat = PIXEL_FORMAT_ABGR32;
87  break;
88 
89  case 24:
90  DstFormat = PIXEL_FORMAT_BGR24;
91  break;
92 
93  case 16:
94  DstFormat = PIXEL_FORMAT_RGB16;
95  break;
96 
97  default:
98  return FALSE;
99  }
100 
101  *color = FreeRDPConvertColor(srcColor, SrcFormat, DstFormat, &gdi->palette);
102  return TRUE;
103 }
104 
105 static BOOL wf_set_rop2(HDC hdc, int rop2)
106 {
107  if ((rop2 < 0x01) || (rop2 > 0x10))
108  {
109  WLog_ERR(TAG, "Unsupported ROP2: %d", rop2);
110  return FALSE;
111  }
112 
113  SetROP2(hdc, wf_rop2_table[rop2 - 1]);
114  return TRUE;
115 }
116 
117 static wfBitmap* wf_glyph_new(wfContext* wfc, GLYPH_DATA* glyph)
118 {
119  wfBitmap* glyph_bmp;
120  glyph_bmp = wf_image_new(wfc, glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, glyph->aj);
121  return glyph_bmp;
122 }
123 
124 static void wf_glyph_free(wfBitmap* glyph)
125 {
126  wf_image_free(glyph);
127 }
128 
129 static BYTE* wf_glyph_convert(wfContext* wfc, int width, int height, const BYTE* data)
130 {
131  const int src_bytes_per_row = (width + 7) / 8;
132  const int dst_bytes_per_row = src_bytes_per_row + (src_bytes_per_row % 2);
133  BYTE* cdata = (BYTE*)malloc(dst_bytes_per_row * height);
134  const BYTE* src = data;
135 
136  for (int indexy = 0; indexy < height; indexy++)
137  {
138  BYTE* dst = &cdata[1ull * indexy * dst_bytes_per_row];
139 
140  for (int indexx = 0; indexx < dst_bytes_per_row; indexx++)
141  {
142  if (indexx < src_bytes_per_row)
143  *dst++ = *src++;
144  else
145  *dst++ = 0;
146  }
147  }
148 
149  return cdata;
150 }
151 
152 static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, UINT32 bpp)
153 {
154  HBRUSH br;
155  LOGBRUSH lbr;
156  BYTE* cdata;
157  BYTE ipattern[8];
158  HBITMAP pattern = NULL;
159  lbr.lbStyle = brush->style;
160 
161  if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 ||
162  lbr.lbStyle == BS_DIBPATTERNPT)
163  lbr.lbColor = DIB_RGB_COLORS;
164  else
165  lbr.lbColor = color;
166 
167  if (lbr.lbStyle == BS_PATTERN || lbr.lbStyle == BS_PATTERN8X8)
168  {
169  if (brush->bpp > 1)
170  {
171  UINT32 format = gdi_get_pixel_format(bpp);
172  pattern = wf_create_dib(wfc, 8, 8, format, brush->data, NULL);
173  lbr.lbHatch = (ULONG_PTR)pattern;
174  }
175  else
176  {
177  for (UINT32 i = 0; i != 8; i++)
178  ipattern[7 - i] = brush->data[i];
179 
180  cdata = wf_glyph_convert(wfc, 8, 8, ipattern);
181  pattern = CreateBitmap(8, 8, 1, 1, cdata);
182  lbr.lbHatch = (ULONG_PTR)pattern;
183  free(cdata);
184  }
185  }
186  else if (lbr.lbStyle == BS_HATCHED)
187  {
188  lbr.lbHatch = brush->hatch;
189  }
190  else
191  {
192  lbr.lbHatch = 0;
193  }
194 
195  br = CreateBrushIndirect(&lbr);
196  SetBrushOrgEx(wfc->drawing->hdc, brush->x, brush->y, NULL);
197 
198  if (pattern != NULL)
199  DeleteObject(pattern);
200 
201  return br;
202 }
203 
204 BOOL wf_scale_rect(wfContext* wfc, RECT* source)
205 {
206  UINT32 ww, wh, dw, dh;
207  rdpSettings* settings;
208 
209  if (!wfc || !source || !wfc->common.context.settings)
210  return FALSE;
211 
212  settings = wfc->common.context.settings;
213 
214  if (!settings)
215  return FALSE;
216 
217  dw = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
218  dh = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
219 
220  if (!wfc->client_width)
221  wfc->client_width = dw;
222 
223  if (!wfc->client_height)
224  wfc->client_height = dh;
225 
226  ww = wfc->client_width;
227  wh = wfc->client_height;
228 
229  if (!ww)
230  ww = dw;
231 
232  if (!wh)
233  wh = dh;
234 
235  if (freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_SmartSizing) &&
236  (ww != dw || wh != dh))
237  {
238  source->bottom = source->bottom * wh / dh + 20;
239  source->top = source->top * wh / dh - 20;
240  source->left = source->left * ww / dw - 20;
241  source->right = source->right * ww / dw + 20;
242  }
243 
244  source->bottom -= wfc->yCurrentScroll;
245  source->top -= wfc->yCurrentScroll;
246  source->left -= wfc->xCurrentScroll;
247  source->right -= wfc->xCurrentScroll;
248  return TRUE;
249 }
250 
251 void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
252 {
253  RECT rect;
254  rdpGdi* gdi = wfc->common.context.gdi;
255  wfc->update_rect.left = x + wfc->offset_x;
256  wfc->update_rect.top = y + wfc->offset_y;
257  wfc->update_rect.right = wfc->update_rect.left + width;
258  wfc->update_rect.bottom = wfc->update_rect.top + height;
259  wf_scale_rect(wfc, &(wfc->update_rect));
260  InvalidateRect(wfc->hwnd, &(wfc->update_rect), FALSE);
261  rect.left = x;
262  rect.right = width;
263  rect.top = y;
264  rect.bottom = height;
265  wf_scale_rect(wfc, &rect);
266  gdi_InvalidateRegion(gdi->primary->hdc, rect.left, rect.top, rect.right, rect.bottom);
267 }
268 
269 void wf_update_offset(wfContext* wfc)
270 {
271  rdpSettings* settings;
272  settings = wfc->common.context.settings;
273 
274  if (wfc->fullscreen)
275  {
276  if (freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_UseMultimon))
277  {
278  int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
279  int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
280  int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
281  int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
282  wfc->offset_x = (w - freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)) / 2;
283 
284  if (wfc->offset_x < x)
285  wfc->offset_x = x;
286 
287  wfc->offset_y = (h - freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)) / 2;
288 
289  if (wfc->offset_y < y)
290  wfc->offset_y = y;
291  }
292  else
293  {
294  wfc->offset_x = (GetSystemMetrics(SM_CXSCREEN) -
295  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)) /
296  2;
297 
298  if (wfc->offset_x < 0)
299  wfc->offset_x = 0;
300 
301  wfc->offset_y = (GetSystemMetrics(SM_CYSCREEN) -
302  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)) /
303  2;
304 
305  if (wfc->offset_y < 0)
306  wfc->offset_y = 0;
307  }
308  }
309  else
310  {
311  wfc->offset_x = 0;
312  wfc->offset_y = 0;
313  }
314 }
315 
316 void wf_resize_window(wfContext* wfc)
317 {
318  rdpSettings* settings;
319  settings = wfc->common.context.settings;
320 
321  if (wfc->fullscreen)
322  {
323  if (freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_UseMultimon))
324  {
325  int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
326  int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
327  int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
328  int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
329  SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_POPUP);
330  SetWindowPos(wfc->hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED);
331  }
332  else
333  {
334  SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_POPUP);
335  SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
336  GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED);
337  }
338  }
339  else if (!freerdp_settings_get_bool(wfc->common.context.settings, FreeRDP_Decorations))
340  {
341  SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_CHILD);
342 
343  if (freerdp_settings_get_bool(settings, FreeRDP_EmbeddedWindow))
344  {
345  if (!wfc->client_height)
346  wfc->client_height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
347 
348  if (!wfc->client_width)
349  wfc->client_width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
350 
351  wf_update_canvas_diff(wfc);
352  /* Now resize to get full canvas size and room for caption and borders */
353  SetWindowPos(wfc->hwnd, HWND_TOP, wfc->client_x, wfc->client_y,
354  wfc->client_width + wfc->diff.x, wfc->client_height + wfc->diff.y,
355  0 /*SWP_FRAMECHANGED*/);
356  }
357  else
358  {
359  /* Now resize to get full canvas size and room for caption and borders */
360  SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0,
361  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
362  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
363  SWP_FRAMECHANGED);
364  wf_update_canvas_diff(wfc);
365  SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1,
366  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) + wfc->diff.x,
367  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) + wfc->diff.y,
368  SWP_NOMOVE | SWP_FRAMECHANGED);
369  }
370  }
371  else
372  {
373  SetWindowLongPtr(wfc->hwnd, GWL_STYLE,
374  WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX |
375  WS_MAXIMIZEBOX);
376 
377  if (!wfc->client_height)
378  wfc->client_height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
379 
380  if (!wfc->client_width)
381  wfc->client_width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
382 
383  if (!wfc->client_x)
384  wfc->client_x = 10;
385 
386  if (!wfc->client_y)
387  wfc->client_y = 10;
388 
389  wf_update_canvas_diff(wfc);
390  /* Now resize to get full canvas size and room for caption and borders */
391  int width, height;
392  if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) &&
393  freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth) &&
394  freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight))
395  {
396  width = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth);
397  height = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight);
398  }
399  else
400  {
401  width = wfc->client_width + wfc->diff.x;
402  height = wfc->client_height + wfc->diff.y;
403  }
404 
405  int xpos, ypos;
406  if ((freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosX) != UINT32_MAX) &&
407  (freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosY) != UINT32_MAX))
408  {
409  xpos = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosX);
410  ypos = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPosY);
411  }
412  else
413  {
414  xpos = wfc->client_x;
415  ypos = wfc->client_y;
416  }
417  SetWindowPos(wfc->hwnd, HWND_TOP, xpos, ypos, width, height, 0 /*SWP_FRAMECHANGED*/);
418  // wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height);
419  }
420 
421  wf_update_offset(wfc);
422 }
423 
424 void wf_toggle_fullscreen(wfContext* wfc)
425 {
426  ShowWindow(wfc->hwnd, SW_HIDE);
427  wfc->fullscreen = !wfc->fullscreen;
428 
429  if (wfc->fullscreen)
430  {
431  wfc->disablewindowtracking = TRUE;
432  }
433 
434  wf_floatbar_toggle_fullscreen(wfc->floatbar, wfc->fullscreen);
435  SetParent(wfc->hwnd, wfc->fullscreen ? NULL : wfc->hWndParent);
436  wf_resize_window(wfc);
437  ShowWindow(wfc->hwnd, SW_SHOW);
438  SetForegroundWindow(wfc->hwnd);
439 
440  if (!wfc->fullscreen)
441  {
442  // Reenable window tracking AFTER resizing it back, otherwise it can lean to repositioning
443  // errors.
444  wfc->disablewindowtracking = FALSE;
445  }
446 }
447 
448 static BOOL wf_gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette)
449 {
450  return TRUE;
451 }
452 
453 void wf_set_null_clip_rgn(wfContext* wfc)
454 {
455  SelectClipRgn(wfc->drawing->hdc, NULL);
456 }
457 
458 void wf_set_clip_rgn(wfContext* wfc, int x, int y, int width, int height)
459 {
460  HRGN clip;
461  clip = CreateRectRgn(x, y, x + width, y + height);
462  SelectClipRgn(wfc->drawing->hdc, clip);
463  DeleteObject(clip);
464 }
465 
466 static BOOL wf_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)
467 {
468  HRGN hrgn;
469  wfContext* wfc = (wfContext*)context;
470 
471  if (!context || !bounds)
472  return FALSE;
473 
474  if (bounds != NULL)
475  {
476  hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, bounds->bottom + 1);
477  SelectClipRgn(wfc->drawing->hdc, hrgn);
478  DeleteObject(hrgn);
479  }
480  else
481  SelectClipRgn(wfc->drawing->hdc, NULL);
482 
483  return TRUE;
484 }
485 
486 static BOOL wf_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
487 {
488  wfContext* wfc = (wfContext*)context;
489 
490  if (!context || !dstblt)
491  return FALSE;
492 
493  if (!BitBlt(wfc->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
494  dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop)))
495  return FALSE;
496 
497  wf_invalidate_region(wfc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
498  return TRUE;
499 }
500 
501 static BOOL wf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
502 {
503  HBRUSH brush;
504  HBRUSH org_brush;
505  int org_bkmode;
506  COLORREF fgcolor;
507  COLORREF bgcolor;
508  COLORREF org_bkcolor;
509  COLORREF org_textcolor;
510  BOOL rc;
511  wfContext* wfc = (wfContext*)context;
512 
513  if (!context || !patblt)
514  return FALSE;
515 
516  if (!wf_decode_color(wfc, patblt->foreColor, &fgcolor, NULL))
517  return FALSE;
518 
519  if (!wf_decode_color(wfc, patblt->backColor, &bgcolor, NULL))
520  return FALSE;
521 
522  brush = wf_create_brush(wfc, &patblt->brush, fgcolor,
523  freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth));
524  org_bkmode = SetBkMode(wfc->drawing->hdc, OPAQUE);
525  org_bkcolor = SetBkColor(wfc->drawing->hdc, bgcolor);
526  org_textcolor = SetTextColor(wfc->drawing->hdc, fgcolor);
527  org_brush = (HBRUSH)SelectObject(wfc->drawing->hdc, brush);
528  rc = PatBlt(wfc->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
529  patblt->nHeight, gdi_rop3_code(patblt->bRop));
530  SelectObject(wfc->drawing->hdc, org_brush);
531  DeleteObject(brush);
532  SetBkMode(wfc->drawing->hdc, org_bkmode);
533  SetBkColor(wfc->drawing->hdc, org_bkcolor);
534  SetTextColor(wfc->drawing->hdc, org_textcolor);
535 
536  if (wfc->drawing == wfc->primary)
537  wf_invalidate_region(wfc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
538  patblt->nHeight);
539 
540  return rc;
541 }
542 
543 static BOOL wf_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
544 {
545  wfContext* wfc = (wfContext*)context;
546 
547  if (!context || !scrblt || !wfc->drawing)
548  return FALSE;
549 
550  if (!BitBlt(wfc->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
551  scrblt->nHeight, wfc->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
552  gdi_rop3_code(scrblt->bRop)))
553  return FALSE;
554 
555  wf_invalidate_region(wfc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight);
556  return TRUE;
557 }
558 
559 static BOOL wf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
560 {
561  RECT rect;
562  HBRUSH brush;
563  COLORREF brush_color;
564  wfContext* wfc = (wfContext*)context;
565 
566  if (!context || !opaque_rect)
567  return FALSE;
568 
569  if (!wf_decode_color(wfc, opaque_rect->color, &brush_color, NULL))
570  return FALSE;
571 
572  rect.left = opaque_rect->nLeftRect;
573  rect.top = opaque_rect->nTopRect;
574  rect.right = opaque_rect->nLeftRect + opaque_rect->nWidth;
575  rect.bottom = opaque_rect->nTopRect + opaque_rect->nHeight;
576  brush = CreateSolidBrush(brush_color);
577  FillRect(wfc->drawing->hdc, &rect, brush);
578  DeleteObject(brush);
579 
580  if (wfc->drawing == wfc->primary)
581  wf_invalidate_region(wfc, rect.left, rect.top, rect.right - rect.left + 1,
582  rect.bottom - rect.top + 1);
583 
584  return TRUE;
585 }
586 
587 static BOOL wf_gdi_multi_opaque_rect(rdpContext* context,
588  const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
589 {
590  RECT rect;
591  HBRUSH brush;
592  COLORREF brush_color;
593  wfContext* wfc = (wfContext*)context;
594 
595  if (!context || !multi_opaque_rect)
596  return FALSE;
597 
598  if (!wf_decode_color(wfc, multi_opaque_rect->color, &brush_color, NULL))
599  return FALSE;
600 
601  for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
602  {
603  const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
604  rect.left = rectangle->left;
605  rect.top = rectangle->top;
606  rect.right = rectangle->left + rectangle->width;
607  rect.bottom = rectangle->top + rectangle->height;
608  brush = CreateSolidBrush(brush_color);
609  FillRect(wfc->drawing->hdc, &rect, brush);
610 
611  if (wfc->drawing == wfc->primary)
612  wf_invalidate_region(wfc, rect.left, rect.top, rect.right - rect.left + 1,
613  rect.bottom - rect.top + 1);
614 
615  DeleteObject(brush);
616  }
617 
618  return TRUE;
619 }
620 
621 static BOOL wf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to)
622 {
623  HPEN pen;
624  HPEN org_pen;
625  int x, y, w, h;
626  COLORREF pen_color;
627  wfContext* wfc = (wfContext*)context;
628 
629  if (!context || !line_to)
630  return FALSE;
631 
632  if (!wf_decode_color(wfc, line_to->penColor, &pen_color, NULL))
633  return FALSE;
634 
635  pen = CreatePen(line_to->penStyle, line_to->penWidth, pen_color);
636  wf_set_rop2(wfc->drawing->hdc, line_to->bRop2);
637  org_pen = (HPEN)SelectObject(wfc->drawing->hdc, pen);
638  MoveToEx(wfc->drawing->hdc, line_to->nXStart, line_to->nYStart, NULL);
639  LineTo(wfc->drawing->hdc, line_to->nXEnd, line_to->nYEnd);
640  x = (line_to->nXStart < line_to->nXEnd) ? line_to->nXStart : line_to->nXEnd;
641  y = (line_to->nYStart < line_to->nYEnd) ? line_to->nYStart : line_to->nYEnd;
642  w = (line_to->nXStart < line_to->nXEnd) ? (line_to->nXEnd - line_to->nXStart)
643  : (line_to->nXStart - line_to->nXEnd);
644  h = (line_to->nYStart < line_to->nYEnd) ? (line_to->nYEnd - line_to->nYStart)
645  : (line_to->nYStart - line_to->nYEnd);
646 
647  if (wfc->drawing == wfc->primary)
648  wf_invalidate_region(wfc, x, y, w, h);
649 
650  SelectObject(wfc->drawing->hdc, org_pen);
651  DeleteObject(pen);
652  return TRUE;
653 }
654 
655 static BOOL wf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)
656 {
657  int org_rop2;
658  HPEN hpen;
659  HPEN org_hpen;
660  COLORREF pen_color;
661  wfContext* wfc = (wfContext*)context;
662 
663  if (!context || !polyline)
664  return FALSE;
665 
666  if (!wf_decode_color(wfc, polyline->penColor, &pen_color, NULL))
667  return FALSE;
668 
669  hpen = CreatePen(0, 1, pen_color);
670  org_rop2 = wf_set_rop2(wfc->drawing->hdc, polyline->bRop2);
671  org_hpen = (HPEN)SelectObject(wfc->drawing->hdc, hpen);
672 
673  if (polyline->numDeltaEntries > 0)
674  {
675  POINT* pts;
676  POINT temp;
677  int numPoints;
678  numPoints = polyline->numDeltaEntries + 1;
679  pts = (POINT*)malloc(sizeof(POINT) * numPoints);
680  pts[0].x = temp.x = polyline->xStart;
681  pts[0].y = temp.y = polyline->yStart;
682 
683  for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
684  {
685  temp.x += polyline->points[i].x;
686  temp.y += polyline->points[i].y;
687  pts[i + 1].x = temp.x;
688  pts[i + 1].y = temp.y;
689  }
690 
691  if (wfc->drawing == wfc->primary)
692  wf_invalidate_region(wfc, wfc->client_x, wfc->client_y, wfc->client_width,
693  wfc->client_height);
694 
695  Polyline(wfc->drawing->hdc, pts, numPoints);
696  free(pts);
697  }
698 
699  SelectObject(wfc->drawing->hdc, org_hpen);
700  wf_set_rop2(wfc->drawing->hdc, org_rop2);
701  DeleteObject(hpen);
702  return TRUE;
703 }
704 
705 static BOOL wf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
706 {
707  wfBitmap* bitmap;
708  wfContext* wfc = (wfContext*)context;
709 
710  if (!context || !memblt)
711  return FALSE;
712 
713  bitmap = (wfBitmap*)memblt->bitmap;
714 
715  if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
716  return FALSE;
717 
718  if (!BitBlt(wfc->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
719  memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
720  gdi_rop3_code(memblt->bRop)))
721  return FALSE;
722 
723  if (wfc->drawing == wfc->primary)
724  wf_invalidate_region(wfc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
725  memblt->nHeight);
726 
727  return TRUE;
728 }
729 
730 static BOOL wf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
731 {
732  BOOL rc = FALSE;
733  HDC hdc;
734  wfBitmap* bitmap;
735  wfContext* wfc = (wfContext*)context;
736  COLORREF fgcolor, bgcolor, orgColor;
737  HBRUSH orgBrush = NULL, brush = NULL;
738 
739  if (!context || !mem3blt)
740  return FALSE;
741 
742  bitmap = (wfBitmap*)mem3blt->bitmap;
743 
744  if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
745  return FALSE;
746 
747  hdc = wfc->drawing->hdc;
748 
749  if (!wf_decode_color(wfc, mem3blt->foreColor, &fgcolor, NULL))
750  return FALSE;
751 
752  if (!wf_decode_color(wfc, mem3blt->backColor, &bgcolor, NULL))
753  return FALSE;
754 
755  orgColor = SetTextColor(hdc, fgcolor);
756 
757  switch (mem3blt->brush.style)
758  {
759  case GDI_BS_SOLID:
760  brush = CreateSolidBrush(fgcolor);
761  break;
762 
763  case GDI_BS_HATCHED:
764  case GDI_BS_PATTERN:
765  {
766  HBITMAP bmp = CreateBitmap(8, 8, 1, mem3blt->brush.bpp, mem3blt->brush.data);
767  brush = CreatePatternBrush(bmp);
768  }
769  break;
770 
771  default:
772  goto fail;
773  }
774 
775  orgBrush = SelectObject(hdc, brush);
776 
777  if (!BitBlt(hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight,
778  bitmap->hdc, mem3blt->nXSrc, mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop)))
779  goto fail;
780 
781  if (wfc->drawing == wfc->primary)
782  wf_invalidate_region(wfc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth,
783  mem3blt->nHeight);
784 
785  rc = TRUE;
786 fail:
787 
788  if (brush)
789  SelectObject(hdc, orgBrush);
790 
791  SetTextColor(hdc, orgColor);
792  return rc;
793 }
794 
795 static BOOL wf_gdi_surface_frame_marker(rdpContext* context,
796  const SURFACE_FRAME_MARKER* surface_frame_marker)
797 {
798  rdpSettings* settings;
799 
800  if (!context || !surface_frame_marker || !context->instance)
801  return FALSE;
802 
803  settings = context->settings;
804 
805  if (!settings)
806  return FALSE;
807 
808  if (surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END &&
809  freerdp_settings_get_uint32(settings, FreeRDP_FrameAcknowledge) > 0)
810  {
811  IFCALL(context->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId);
812  }
813 
814  return TRUE;
815 }
816 
817 void wf_gdi_register_update_callbacks(rdpUpdate* update)
818 {
819  rdpPrimaryUpdate* primary = update->primary;
820  update->Palette = wf_gdi_palette_update;
821  update->SetBounds = wf_gdi_set_bounds;
822  primary->DstBlt = wf_gdi_dstblt;
823  primary->PatBlt = wf_gdi_patblt;
824  primary->ScrBlt = wf_gdi_scrblt;
825  primary->OpaqueRect = wf_gdi_opaque_rect;
826  primary->MultiOpaqueRect = wf_gdi_multi_opaque_rect;
827  primary->LineTo = wf_gdi_line_to;
828  primary->Polyline = wf_gdi_polyline;
829  primary->MemBlt = wf_gdi_memblt;
830  primary->Mem3Blt = wf_gdi_mem3blt;
831  update->SurfaceFrameMarker = wf_gdi_surface_frame_marker;
832 }
833 
834 void wf_update_canvas_diff(wfContext* wfc)
835 {
836  RECT rc_client, rc_wnd;
837  int dx, dy;
838  GetClientRect(wfc->hwnd, &rc_client);
839  GetWindowRect(wfc->hwnd, &rc_wnd);
840  dx = (rc_wnd.right - rc_wnd.left) - rc_client.right;
841  dy = (rc_wnd.bottom - rc_wnd.top) - rc_client.bottom;
842 
843  if (!wfc->disablewindowtracking)
844  {
845  wfc->diff.x = dx;
846  wfc->diff.y = dy;
847  }
848 }
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.