22 #include <freerdp/config.h>
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>
38 #include "wf_client.h"
39 #include "wf_graphics.h"
42 #define TAG CLIENT_TAG("windows.gdi")
44 static const BYTE wf_rop2_table[] = {
63 static BOOL wf_decode_color(wfContext* wfc,
const UINT32 srcColor, COLORREF* color, UINT32* format)
66 rdpSettings* settings;
67 UINT32 SrcFormat, DstFormat;
72 gdi = wfc->common.context.gdi;
73 settings = wfc->common.context.settings;
75 if (!gdi || !settings)
83 switch (FreeRDPGetBitsPerPixel(gdi->dstFormat))
86 DstFormat = PIXEL_FORMAT_ABGR32;
90 DstFormat = PIXEL_FORMAT_BGR24;
94 DstFormat = PIXEL_FORMAT_RGB16;
101 *color = FreeRDPConvertColor(srcColor, SrcFormat, DstFormat, &gdi->palette);
105 static BOOL wf_set_rop2(HDC hdc,
int rop2)
107 if ((rop2 < 0x01) || (rop2 > 0x10))
109 WLog_ERR(TAG,
"Unsupported ROP2: %d", rop2);
113 SetROP2(hdc, wf_rop2_table[rop2 - 1]);
120 glyph_bmp = wf_image_new(wfc, glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, glyph->aj);
124 static void wf_glyph_free(
wfBitmap* glyph)
126 wf_image_free(glyph);
129 static BYTE* wf_glyph_convert(wfContext* wfc,
int width,
int height,
const BYTE* data)
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;
136 for (
int indexy = 0; indexy < height; indexy++)
138 BYTE* dst = &cdata[1ull * indexy * dst_bytes_per_row];
140 for (
int indexx = 0; indexx < dst_bytes_per_row; indexx++)
142 if (indexx < src_bytes_per_row)
152 static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, UINT32 bpp)
158 HBITMAP pattern = NULL;
159 lbr.lbStyle = brush->style;
161 if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 ||
162 lbr.lbStyle == BS_DIBPATTERNPT)
163 lbr.lbColor = DIB_RGB_COLORS;
167 if (lbr.lbStyle == BS_PATTERN || lbr.lbStyle == BS_PATTERN8X8)
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;
177 for (UINT32 i = 0; i != 8; i++)
178 ipattern[7 - i] = brush->data[i];
180 cdata = wf_glyph_convert(wfc, 8, 8, ipattern);
181 pattern = CreateBitmap(8, 8, 1, 1, cdata);
182 lbr.lbHatch = (ULONG_PTR)pattern;
186 else if (lbr.lbStyle == BS_HATCHED)
188 lbr.lbHatch = brush->hatch;
195 br = CreateBrushIndirect(&lbr);
196 SetBrushOrgEx(wfc->drawing->hdc, brush->x, brush->y, NULL);
199 DeleteObject(pattern);
204 BOOL wf_scale_rect(wfContext* wfc, RECT* source)
206 UINT32 ww, wh, dw, dh;
207 rdpSettings* settings;
209 if (!wfc || !source || !wfc->common.context.settings)
212 settings = wfc->common.context.settings;
220 if (!wfc->client_width)
221 wfc->client_width = dw;
223 if (!wfc->client_height)
224 wfc->client_height = dh;
226 ww = wfc->client_width;
227 wh = wfc->client_height;
236 (ww != dw || wh != dh))
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;
244 source->bottom -= wfc->yCurrentScroll;
245 source->top -= wfc->yCurrentScroll;
246 source->left -= wfc->xCurrentScroll;
247 source->right -= wfc->xCurrentScroll;
251 void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
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);
264 rect.bottom = height;
265 wf_scale_rect(wfc, &rect);
266 gdi_InvalidateRegion(gdi->primary->hdc, rect.left, rect.top, rect.right, rect.bottom);
269 void wf_update_offset(wfContext* wfc)
271 rdpSettings* settings;
272 settings = wfc->common.context.settings;
278 int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
279 int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
280 int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
281 int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
284 if (wfc->offset_x < x)
289 if (wfc->offset_y < y)
294 wfc->offset_x = (GetSystemMetrics(SM_CXSCREEN) -
298 if (wfc->offset_x < 0)
301 wfc->offset_y = (GetSystemMetrics(SM_CYSCREEN) -
305 if (wfc->offset_y < 0)
316 void wf_resize_window(wfContext* wfc)
318 rdpSettings* settings;
319 settings = wfc->common.context.settings;
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);
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);
341 SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_CHILD);
345 if (!wfc->client_height)
348 if (!wfc->client_width)
351 wf_update_canvas_diff(wfc);
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,
360 SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0,
364 wf_update_canvas_diff(wfc);
365 SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1,
368 SWP_NOMOVE | SWP_FRAMECHANGED);
373 SetWindowLongPtr(wfc->hwnd, GWL_STYLE,
374 WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX |
377 if (!wfc->client_height)
380 if (!wfc->client_width)
389 wf_update_canvas_diff(wfc);
401 width = wfc->client_width + wfc->diff.x;
402 height = wfc->client_height + wfc->diff.y;
414 xpos = wfc->client_x;
415 ypos = wfc->client_y;
417 SetWindowPos(wfc->hwnd, HWND_TOP, xpos, ypos, width, height, 0 );
421 wf_update_offset(wfc);
424 void wf_toggle_fullscreen(wfContext* wfc)
426 ShowWindow(wfc->hwnd, SW_HIDE);
427 wfc->fullscreen = !wfc->fullscreen;
431 wfc->disablewindowtracking = TRUE;
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);
440 if (!wfc->fullscreen)
444 wfc->disablewindowtracking = FALSE;
448 static BOOL wf_gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
453 void wf_set_null_clip_rgn(wfContext* wfc)
455 SelectClipRgn(wfc->drawing->hdc, NULL);
458 void wf_set_clip_rgn(wfContext* wfc,
int x,
int y,
int width,
int height)
461 clip = CreateRectRgn(x, y, x + width, y + height);
462 SelectClipRgn(wfc->drawing->hdc, clip);
466 static BOOL wf_gdi_set_bounds(rdpContext* context,
const rdpBounds* bounds)
469 wfContext* wfc = (wfContext*)context;
471 if (!context || !bounds)
476 hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, bounds->bottom + 1);
477 SelectClipRgn(wfc->drawing->hdc, hrgn);
481 SelectClipRgn(wfc->drawing->hdc, NULL);
486 static BOOL wf_gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
488 wfContext* wfc = (wfContext*)context;
490 if (!context || !dstblt)
493 if (!BitBlt(wfc->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
494 dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop)))
497 wf_invalidate_region(wfc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
501 static BOOL wf_gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
508 COLORREF org_bkcolor;
509 COLORREF org_textcolor;
511 wfContext* wfc = (wfContext*)context;
513 if (!context || !patblt)
516 if (!wf_decode_color(wfc, patblt->foreColor, &fgcolor, NULL))
519 if (!wf_decode_color(wfc, patblt->backColor, &bgcolor, NULL))
522 brush = wf_create_brush(wfc, &patblt->brush, fgcolor,
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);
532 SetBkMode(wfc->drawing->hdc, org_bkmode);
533 SetBkColor(wfc->drawing->hdc, org_bkcolor);
534 SetTextColor(wfc->drawing->hdc, org_textcolor);
536 if (wfc->drawing == wfc->primary)
537 wf_invalidate_region(wfc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
543 static BOOL wf_gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
545 wfContext* wfc = (wfContext*)context;
547 if (!context || !scrblt || !wfc->drawing)
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)))
555 wf_invalidate_region(wfc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight);
559 static BOOL wf_gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
563 COLORREF brush_color;
564 wfContext* wfc = (wfContext*)context;
566 if (!context || !opaque_rect)
569 if (!wf_decode_color(wfc, opaque_rect->color, &brush_color, NULL))
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);
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);
587 static BOOL wf_gdi_multi_opaque_rect(rdpContext* context,
592 COLORREF brush_color;
593 wfContext* wfc = (wfContext*)context;
595 if (!context || !multi_opaque_rect)
598 if (!wf_decode_color(wfc, multi_opaque_rect->color, &brush_color, NULL))
601 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
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);
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);
621 static BOOL wf_gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* line_to)
627 wfContext* wfc = (wfContext*)context;
629 if (!context || !line_to)
632 if (!wf_decode_color(wfc, line_to->penColor, &pen_color, NULL))
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);
647 if (wfc->drawing == wfc->primary)
648 wf_invalidate_region(wfc, x, y, w, h);
650 SelectObject(wfc->drawing->hdc, org_pen);
655 static BOOL wf_gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
661 wfContext* wfc = (wfContext*)context;
663 if (!context || !polyline)
666 if (!wf_decode_color(wfc, polyline->penColor, &pen_color, NULL))
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);
673 if (polyline->numDeltaEntries > 0)
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;
683 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
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;
691 if (wfc->drawing == wfc->primary)
692 wf_invalidate_region(wfc, wfc->client_x, wfc->client_y, wfc->client_width,
695 Polyline(wfc->drawing->hdc, pts, numPoints);
699 SelectObject(wfc->drawing->hdc, org_hpen);
700 wf_set_rop2(wfc->drawing->hdc, org_rop2);
705 static BOOL wf_gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
708 wfContext* wfc = (wfContext*)context;
710 if (!context || !memblt)
715 if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
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)))
723 if (wfc->drawing == wfc->primary)
724 wf_invalidate_region(wfc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
730 static BOOL wf_gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
735 wfContext* wfc = (wfContext*)context;
736 COLORREF fgcolor, bgcolor, orgColor;
737 HBRUSH orgBrush = NULL, brush = NULL;
739 if (!context || !mem3blt)
742 bitmap = (
wfBitmap*)mem3blt->bitmap;
744 if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
747 hdc = wfc->drawing->hdc;
749 if (!wf_decode_color(wfc, mem3blt->foreColor, &fgcolor, NULL))
752 if (!wf_decode_color(wfc, mem3blt->backColor, &bgcolor, NULL))
755 orgColor = SetTextColor(hdc, fgcolor);
757 switch (mem3blt->brush.style)
760 brush = CreateSolidBrush(fgcolor);
766 HBITMAP bmp = CreateBitmap(8, 8, 1, mem3blt->brush.bpp, mem3blt->brush.data);
767 brush = CreatePatternBrush(bmp);
775 orgBrush = SelectObject(hdc, brush);
777 if (!BitBlt(hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight,
778 bitmap->hdc, mem3blt->nXSrc, mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop)))
781 if (wfc->drawing == wfc->primary)
782 wf_invalidate_region(wfc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth,
789 SelectObject(hdc, orgBrush);
791 SetTextColor(hdc, orgColor);
795 static BOOL wf_gdi_surface_frame_marker(rdpContext* context,
798 rdpSettings* settings;
800 if (!context || !surface_frame_marker || !context->instance)
803 settings = context->settings;
808 if (surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END &&
811 IFCALL(context->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId);
817 void wf_gdi_register_update_callbacks(rdpUpdate* update)
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;
834 void wf_update_canvas_diff(wfContext* wfc)
836 RECT rc_client, rc_wnd;
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;
843 if (!wfc->disablewindowtracking)
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.