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