FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 return glyph_bmp;
122}
123
124static void wf_glyph_free(wfBitmap* glyph)
125{
126 wf_image_free(glyph);
127}
128
129static 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
152static 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
204BOOL 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
251void 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
269void 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
316void 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
424void 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 // Re-enable window tracking AFTER resizing it back, otherwise it can lean to repositioning
443 // errors.
444 wfc->disablewindowtracking = FALSE;
445 }
446}
447
448static BOOL wf_gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette)
449{
450 return TRUE;
451}
452
453void wf_set_null_clip_rgn(wfContext* wfc)
454{
455 SelectClipRgn(wfc->drawing->hdc, NULL);
456}
457
458void 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
466static 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
486static 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
501static 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
543static 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
559static 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
587static 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
621static 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
655static 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
705static 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
730static 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;
786fail:
787
788 if (brush)
789 SelectObject(hdc, orgBrush);
790
791 SetTextColor(hdc, orgColor);
792 return rc;
793}
794
795static 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
817void 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
834void 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.