Blame client/Windows/wf_gdi.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Windows GDI
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2009-2011 Jay Sorg
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
Packit 1fb8d4
 * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <conio.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/gdi/gdi.h>
Packit 1fb8d4
#include <freerdp/constants.h>
Packit 1fb8d4
#include <freerdp/codec/color.h>
Packit 1fb8d4
#include <freerdp/codec/bitmap.h>
Packit 1fb8d4
#include <freerdp/codec/rfx.h>
Packit 1fb8d4
#include <freerdp/codec/nsc.h>
Packit 1fb8d4
#include <freerdp/gdi/gdi.h>
Packit 1fb8d4
Packit 1fb8d4
#include "wf_client.h"
Packit 1fb8d4
#include "wf_graphics.h"
Packit 1fb8d4
#include "wf_gdi.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG CLIENT_TAG("windows.gdi")
Packit 1fb8d4
Packit Service 5a9772
static const BYTE wf_rop2_table[] = {
Packit 1fb8d4
	R2_BLACK,       /* 0 */
Packit 1fb8d4
	R2_NOTMERGEPEN, /* DPon */
Packit 1fb8d4
	R2_MASKNOTPEN,  /* DPna */
Packit 1fb8d4
	R2_NOTCOPYPEN,  /* Pn */
Packit 1fb8d4
	R2_MASKPENNOT,  /* PDna */
Packit 1fb8d4
	R2_NOT,         /* Dn */
Packit 1fb8d4
	R2_XORPEN,      /* DPx */
Packit 1fb8d4
	R2_NOTMASKPEN,  /* DPan */
Packit 1fb8d4
	R2_MASKPEN,     /* DPa */
Packit 1fb8d4
	R2_NOTXORPEN,   /* DPxn */
Packit 1fb8d4
	R2_NOP,         /* D */
Packit 1fb8d4
	R2_MERGENOTPEN, /* DPno */
Packit 1fb8d4
	R2_COPYPEN,     /* P */
Packit 1fb8d4
	R2_MERGEPENNOT, /* PDno */
Packit 1fb8d4
	R2_MERGEPEN,    /* PDo */
Packit 1fb8d4
	R2_WHITE,       /* 1 */
Packit 1fb8d4
};
Packit 1fb8d4
Packit Service 5a9772
static BOOL wf_decode_color(wfContext* wfc, const UINT32 srcColor, COLORREF* color, UINT32* format)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpGdi* gdi;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	UINT32 SrcFormat, DstFormat;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	gdi = wfc->context.gdi;
Packit 1fb8d4
	settings = wfc->context.settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!gdi || !settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	SrcFormat = gdi_get_pixel_format(gdi->context->settings->ColorDepth);
Packit 1fb8d4
Packit 1fb8d4
	if (format)
Packit 1fb8d4
		*format = SrcFormat;
Packit 1fb8d4
Packit 1fb8d4
	switch (GetBitsPerPixel(gdi->dstFormat))
Packit 1fb8d4
	{
Packit 1fb8d4
		case 32:
Packit 1fb8d4
			DstFormat = PIXEL_FORMAT_ABGR32;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case 24:
Packit 1fb8d4
			DstFormat = PIXEL_FORMAT_BGR24;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case 16:
Packit 1fb8d4
			DstFormat = PIXEL_FORMAT_RGB16;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	*color = FreeRDPConvertColor(srcColor, SrcFormat, DstFormat, &gdi->palette);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_set_rop2(HDC hdc, int rop2)
Packit 1fb8d4
{
Packit 1fb8d4
	if ((rop2 < 0x01) || (rop2 > 0x10))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Unsupported ROP2: %d", rop2);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SetROP2(hdc, wf_rop2_table[rop2 - 1]);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static wfBitmap* wf_glyph_new(wfContext* wfc, GLYPH_DATA* glyph)
Packit 1fb8d4
{
Packit 1fb8d4
	wfBitmap* glyph_bmp;
Packit Service 5a9772
	glyph_bmp = wf_image_new(wfc, glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, glyph->aj);
Packit 1fb8d4
	return glyph_bmp;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void wf_glyph_free(wfBitmap* glyph)
Packit 1fb8d4
{
Packit 1fb8d4
	wf_image_free(glyph);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BYTE* wf_glyph_convert(wfContext* wfc, int width, int height, BYTE* data)
Packit 1fb8d4
{
Packit 1fb8d4
	int indexx;
Packit 1fb8d4
	int indexy;
Packit 1fb8d4
	BYTE* src;
Packit 1fb8d4
	BYTE* dst;
Packit 1fb8d4
	BYTE* cdata;
Packit 1fb8d4
	int src_bytes_per_row;
Packit 1fb8d4
	int dst_bytes_per_row;
Packit 1fb8d4
	src_bytes_per_row = (width + 7) / 8;
Packit 1fb8d4
	dst_bytes_per_row = src_bytes_per_row + (src_bytes_per_row % 2);
Packit Service 5a9772
	cdata = (BYTE*)malloc(dst_bytes_per_row * height);
Packit 1fb8d4
	src = data;
Packit 1fb8d4
Packit 1fb8d4
	for (indexy = 0; indexy < height; indexy++)
Packit 1fb8d4
	{
Packit 1fb8d4
		dst = cdata + indexy * dst_bytes_per_row;
Packit 1fb8d4
Packit 1fb8d4
		for (indexx = 0; indexx < dst_bytes_per_row; indexx++)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (indexx < src_bytes_per_row)
Packit 1fb8d4
				*dst++ = *src++;
Packit 1fb8d4
			else
Packit 1fb8d4
				*dst++ = 0;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return cdata;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, UINT32 bpp)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
	HBRUSH br;
Packit 1fb8d4
	LOGBRUSH lbr;
Packit 1fb8d4
	BYTE* cdata;
Packit 1fb8d4
	BYTE ipattern[8];
Packit 1fb8d4
	HBITMAP pattern = NULL;
Packit 1fb8d4
	lbr.lbStyle = brush->style;
Packit 1fb8d4
Packit Service 5a9772
	if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 ||
Packit Service 5a9772
	    lbr.lbStyle == BS_DIBPATTERNPT)
Packit 1fb8d4
		lbr.lbColor = DIB_RGB_COLORS;
Packit 1fb8d4
	else
Packit 1fb8d4
		lbr.lbColor = color;
Packit 1fb8d4
Packit 1fb8d4
	if (lbr.lbStyle == BS_PATTERN || lbr.lbStyle == BS_PATTERN8X8)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (brush->bpp > 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			UINT32 format = gdi_get_pixel_format(bpp);
Packit 1fb8d4
			pattern = wf_create_dib(wfc, 8, 8, format, brush->data, NULL);
Packit Service 5a9772
			lbr.lbHatch = (ULONG_PTR)pattern;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			for (i = 0; i != 8; i++)
Packit 1fb8d4
				ipattern[7 - i] = brush->data[i];
Packit 1fb8d4
Packit 1fb8d4
			cdata = wf_glyph_convert(wfc, 8, 8, ipattern);
Packit 1fb8d4
			pattern = CreateBitmap(8, 8, 1, 1, cdata);
Packit Service 5a9772
			lbr.lbHatch = (ULONG_PTR)pattern;
Packit 1fb8d4
			free(cdata);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (lbr.lbStyle == BS_HATCHED)
Packit 1fb8d4
	{
Packit 1fb8d4
		lbr.lbHatch = brush->hatch;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		lbr.lbHatch = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	br = CreateBrushIndirect(&lbr);
Packit 1fb8d4
	SetBrushOrgEx(wfc->drawing->hdc, brush->x, brush->y, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (pattern != NULL)
Packit 1fb8d4
		DeleteObject(pattern);
Packit 1fb8d4
Packit 1fb8d4
	return br;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_scale_rect(wfContext* wfc, RECT* source)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 ww, wh, dw, dh;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc || !source || !wfc->context.settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	settings = wfc->context.settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	dw = settings->DesktopWidth;
Packit 1fb8d4
	dh = settings->DesktopHeight;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->client_width)
Packit 1fb8d4
		wfc->client_width = dw;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->client_height)
Packit 1fb8d4
		wfc->client_height = dh;
Packit 1fb8d4
Packit 1fb8d4
	ww = wfc->client_width;
Packit 1fb8d4
	wh = wfc->client_height;
Packit 1fb8d4
Packit 1fb8d4
	if (!ww)
Packit 1fb8d4
		ww = dw;
Packit 1fb8d4
Packit 1fb8d4
	if (!wh)
Packit 1fb8d4
		wh = dh;
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->context.settings->SmartSizing && (ww != dw || wh != dh))
Packit 1fb8d4
	{
Packit 1fb8d4
		source->bottom = source->bottom * wh / dh + 20;
Packit 1fb8d4
		source->top = source->top * wh / dh - 20;
Packit 1fb8d4
		source->left = source->left * ww / dw - 20;
Packit 1fb8d4
		source->right = source->right * ww / dw + 20;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	source->bottom -= wfc->yCurrentScroll;
Packit 1fb8d4
	source->top -= wfc->yCurrentScroll;
Packit 1fb8d4
	source->left -= wfc->xCurrentScroll;
Packit 1fb8d4
	source->right -= wfc->xCurrentScroll;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
Packit 1fb8d4
{
Packit 1fb8d4
	RECT rect;
Packit 1fb8d4
	rdpGdi* gdi = wfc->context.gdi;
Packit 1fb8d4
	wfc->update_rect.left = x + wfc->offset_x;
Packit 1fb8d4
	wfc->update_rect.top = y + wfc->offset_y;
Packit 1fb8d4
	wfc->update_rect.right = wfc->update_rect.left + width;
Packit 1fb8d4
	wfc->update_rect.bottom = wfc->update_rect.top + height;
Packit 1fb8d4
	wf_scale_rect(wfc, &(wfc->update_rect));
Packit 1fb8d4
	InvalidateRect(wfc->hwnd, &(wfc->update_rect), FALSE);
Packit 1fb8d4
	rect.left = x;
Packit 1fb8d4
	rect.right = width;
Packit 1fb8d4
	rect.top = y;
Packit 1fb8d4
	rect.bottom = height;
Packit 1fb8d4
	wf_scale_rect(wfc, &rect);
Packit Service 5a9772
	gdi_InvalidateRegion(gdi->primary->hdc, rect.left, rect.top, rect.right, rect.bottom);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_update_offset(wfContext* wfc)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	settings = wfc->context.settings;
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->fullscreen)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (wfc->context.settings->UseMultimon)
Packit 1fb8d4
		{
Packit 1fb8d4
			int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
Packit 1fb8d4
			int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
Packit 1fb8d4
			int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
Packit 1fb8d4
			int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
Packit 1fb8d4
			wfc->offset_x = (w - settings->DesktopWidth) / 2;
Packit 1fb8d4
Packit 1fb8d4
			if (wfc->offset_x < x)
Packit 1fb8d4
				wfc->offset_x = x;
Packit 1fb8d4
Packit 1fb8d4
			wfc->offset_y = (h - settings->DesktopHeight) / 2;
Packit 1fb8d4
Packit 1fb8d4
			if (wfc->offset_y < y)
Packit 1fb8d4
				wfc->offset_y = y;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			wfc->offset_x = (GetSystemMetrics(SM_CXSCREEN) - settings->DesktopWidth) / 2;
Packit 1fb8d4
Packit 1fb8d4
			if (wfc->offset_x < 0)
Packit 1fb8d4
				wfc->offset_x = 0;
Packit 1fb8d4
Packit 1fb8d4
			wfc->offset_y = (GetSystemMetrics(SM_CYSCREEN) - settings->DesktopHeight) / 2;
Packit 1fb8d4
Packit 1fb8d4
			if (wfc->offset_y < 0)
Packit 1fb8d4
				wfc->offset_y = 0;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		wfc->offset_x = 0;
Packit 1fb8d4
		wfc->offset_y = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_resize_window(wfContext* wfc)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	settings = wfc->context.settings;
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->fullscreen)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (wfc->context.settings->UseMultimon)
Packit 1fb8d4
		{
Packit 1fb8d4
			int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
Packit 1fb8d4
			int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
Packit 1fb8d4
			int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
Packit 1fb8d4
			int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
Packit 1fb8d4
			SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_POPUP);
Packit 1fb8d4
			SetWindowPos(wfc->hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_POPUP);
Packit 1fb8d4
			SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
Packit 1fb8d4
			             GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!wfc->context.settings->Decorations)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_CHILD);
Packit Service 5a9772
Packit 1fb8d4
		if (settings->EmbeddedWindow)
Packit 1fb8d4
		{
Packit Service 5a9772
			if (!wfc->client_height)
Packit Service 5a9772
				wfc->client_height = settings->DesktopHeight;
Packit Service 5a9772
Packit Service 5a9772
			if (!wfc->client_width)
Packit Service 5a9772
				wfc->client_width = settings->DesktopWidth;
Packit Service 5a9772
Packit 1fb8d4
			wf_update_canvas_diff(wfc);
Packit Service 5a9772
			/* Now resize to get full canvas size and room for caption and borders */
Packit Service 5a9772
			SetWindowPos(wfc->hwnd, HWND_TOP, wfc->client_x, wfc->client_y,
Packit Service 5a9772
			             wfc->client_width + wfc->diff.x, wfc->client_height + wfc->diff.y,
Packit Service 5a9772
			             0 /*SWP_FRAMECHANGED*/);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Now resize to get full canvas size and room for caption and borders */
Packit Service 5a9772
			SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, settings->DesktopWidth, settings->DesktopHeight,
Packit Service 5a9772
			             SWP_FRAMECHANGED);
Packit 1fb8d4
			wf_update_canvas_diff(wfc);
Packit 1fb8d4
			SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1, settings->DesktopWidth + wfc->diff.x,
Packit Service 5a9772
			             settings->DesktopHeight + wfc->diff.y, SWP_NOMOVE | SWP_FRAMECHANGED);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		SetWindowLongPtr(wfc->hwnd, GWL_STYLE,
Packit 1fb8d4
		                 WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX |
Packit Service 5a9772
		                     WS_MAXIMIZEBOX);
Packit 1fb8d4
Packit 1fb8d4
		if (!wfc->client_height)
Packit 1fb8d4
			wfc->client_height = settings->DesktopHeight;
Packit 1fb8d4
Packit 1fb8d4
		if (!wfc->client_width)
Packit 1fb8d4
			wfc->client_width = settings->DesktopWidth;
Packit 1fb8d4
Packit 1fb8d4
		if (!wfc->client_x)
Packit 1fb8d4
			wfc->client_x = 10;
Packit 1fb8d4
Packit 1fb8d4
		if (!wfc->client_y)
Packit 1fb8d4
			wfc->client_y = 10;
Packit 1fb8d4
Packit 1fb8d4
		wf_update_canvas_diff(wfc);
Packit 1fb8d4
		/* Now resize to get full canvas size and room for caption and borders */
Packit 1fb8d4
		SetWindowPos(wfc->hwnd, HWND_TOP, wfc->client_x, wfc->client_y,
Packit 1fb8d4
		             wfc->client_width + wfc->diff.x, wfc->client_height + wfc->diff.y,
Packit 1fb8d4
		             0 /*SWP_FRAMECHANGED*/);
Packit Service 5a9772
		// wf_size_scrollbars(wfc,  wfc->client_width, wfc->client_height);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	wf_update_offset(wfc);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_toggle_fullscreen(wfContext* wfc)
Packit 1fb8d4
{
Packit 1fb8d4
	ShowWindow(wfc->hwnd, SW_HIDE);
Packit 1fb8d4
	wfc->fullscreen = !wfc->fullscreen;
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->fullscreen)
Packit 1fb8d4
	{
Packit 1fb8d4
		wfc->disablewindowtracking = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	wf_floatbar_toggle_fullscreen(wfc->floatbar, wfc->fullscreen);
Packit 1fb8d4
	SetParent(wfc->hwnd, wfc->fullscreen ? NULL : wfc->hWndParent);
Packit 1fb8d4
	wf_resize_window(wfc);
Packit 1fb8d4
	ShowWindow(wfc->hwnd, SW_SHOW);
Packit 1fb8d4
	SetForegroundWindow(wfc->hwnd);
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->fullscreen)
Packit 1fb8d4
	{
Packit Service 5a9772
		// Reenable window tracking AFTER resizing it back, otherwise it can lean to repositioning
Packit Service 5a9772
		// errors.
Packit 1fb8d4
		wfc->disablewindowtracking = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL wf_gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette)
Packit 1fb8d4
{
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_set_null_clip_rgn(wfContext* wfc)
Packit 1fb8d4
{
Packit 1fb8d4
	SelectClipRgn(wfc->drawing->hdc, NULL);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_set_clip_rgn(wfContext* wfc, int x, int y, int width, int height)
Packit 1fb8d4
{
Packit 1fb8d4
	HRGN clip;
Packit 1fb8d4
	clip = CreateRectRgn(x, y, x + width, y + height);
Packit 1fb8d4
	SelectClipRgn(wfc->drawing->hdc, clip);
Packit 1fb8d4
	DeleteObject(clip);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)
Packit 1fb8d4
{
Packit 1fb8d4
	HRGN hrgn;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !bounds)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (bounds != NULL)
Packit 1fb8d4
	{
Packit Service 5a9772
		hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, bounds->bottom + 1);
Packit 1fb8d4
		SelectClipRgn(wfc->drawing->hdc, hrgn);
Packit 1fb8d4
		DeleteObject(hrgn);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		SelectClipRgn(wfc->drawing->hdc, NULL);
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
Packit 1fb8d4
{
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !dstblt)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (!BitBlt(wfc->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
Packit Service 5a9772
	            dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop)))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	wf_invalidate_region(wfc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
Packit 1fb8d4
{
Packit 1fb8d4
	HBRUSH brush;
Packit 1fb8d4
	HBRUSH org_brush;
Packit 1fb8d4
	int org_bkmode;
Packit 1fb8d4
	UINT32 fgcolor;
Packit 1fb8d4
	UINT32 bgcolor;
Packit 1fb8d4
	COLORREF org_bkcolor;
Packit 1fb8d4
	COLORREF org_textcolor;
Packit 1fb8d4
	BOOL rc;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !patblt)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_decode_color(wfc, patblt->foreColor, &fgcolor, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_decode_color(wfc, patblt->backColor, &bgcolor, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	brush = wf_create_brush(wfc, &patblt->brush, fgcolor, context->settings->ColorDepth);
Packit 1fb8d4
	org_bkmode = SetBkMode(wfc->drawing->hdc, OPAQUE);
Packit 1fb8d4
	org_bkcolor = SetBkColor(wfc->drawing->hdc, bgcolor);
Packit 1fb8d4
	org_textcolor = SetTextColor(wfc->drawing->hdc, fgcolor);
Packit 1fb8d4
	org_brush = (HBRUSH)SelectObject(wfc->drawing->hdc, brush);
Packit Service 5a9772
	rc = PatBlt(wfc->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
Packit Service 5a9772
	            patblt->nHeight, gdi_rop3_code(patblt->bRop));
Packit 1fb8d4
	SelectObject(wfc->drawing->hdc, org_brush);
Packit 1fb8d4
	DeleteObject(brush);
Packit 1fb8d4
	SetBkMode(wfc->drawing->hdc, org_bkmode);
Packit 1fb8d4
	SetBkColor(wfc->drawing->hdc, org_bkcolor);
Packit 1fb8d4
	SetTextColor(wfc->drawing->hdc, org_textcolor);
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->drawing == wfc->primary)
Packit 1fb8d4
		wf_invalidate_region(wfc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
Packit 1fb8d4
		                     patblt->nHeight);
Packit 1fb8d4
Packit 1fb8d4
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
Packit 1fb8d4
{
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !scrblt || !wfc->drawing)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (!BitBlt(wfc->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
Packit Service 5a9772
	            scrblt->nHeight, wfc->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
Packit Service 5a9772
	            gdi_rop3_code(scrblt->bRop)))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	wf_invalidate_region(wfc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL wf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
Packit 1fb8d4
{
Packit 1fb8d4
	RECT rect;
Packit 1fb8d4
	HBRUSH brush;
Packit 1fb8d4
	UINT32 brush_color;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !opaque_rect)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_decode_color(wfc, opaque_rect->color, &brush_color, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	rect.left = opaque_rect->nLeftRect;
Packit 1fb8d4
	rect.top = opaque_rect->nTopRect;
Packit 1fb8d4
	rect.right = opaque_rect->nLeftRect + opaque_rect->nWidth;
Packit 1fb8d4
	rect.bottom = opaque_rect->nTopRect + opaque_rect->nHeight;
Packit 1fb8d4
	brush = CreateSolidBrush(brush_color);
Packit 1fb8d4
	FillRect(wfc->drawing->hdc, &rect, brush);
Packit 1fb8d4
	DeleteObject(brush);
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->drawing == wfc->primary)
Packit 1fb8d4
		wf_invalidate_region(wfc, rect.left, rect.top, rect.right - rect.left + 1,
Packit 1fb8d4
		                     rect.bottom - rect.top + 1);
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_multi_opaque_rect(rdpContext* context,
Packit 1fb8d4
                                     const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
	RECT rect;
Packit 1fb8d4
	HBRUSH brush;
Packit 1fb8d4
	UINT32 brush_color;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !multi_opaque_rect)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (!wf_decode_color(wfc, multi_opaque_rect->color, &brush_color, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < multi_opaque_rect->numRectangles; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
Packit 1fb8d4
		rect.left = rectangle->left;
Packit 1fb8d4
		rect.top = rectangle->top;
Packit 1fb8d4
		rect.right = rectangle->left + rectangle->width;
Packit 1fb8d4
		rect.bottom = rectangle->top + rectangle->height;
Packit 1fb8d4
		brush = CreateSolidBrush(brush_color);
Packit 1fb8d4
		FillRect(wfc->drawing->hdc, &rect, brush);
Packit 1fb8d4
Packit 1fb8d4
		if (wfc->drawing == wfc->primary)
Packit 1fb8d4
			wf_invalidate_region(wfc, rect.left, rect.top, rect.right - rect.left + 1,
Packit 1fb8d4
			                     rect.bottom - rect.top + 1);
Packit 1fb8d4
Packit 1fb8d4
		DeleteObject(brush);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to)
Packit 1fb8d4
{
Packit 1fb8d4
	HPEN pen;
Packit 1fb8d4
	HPEN org_pen;
Packit 1fb8d4
	int x, y, w, h;
Packit 1fb8d4
	UINT32 pen_color;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !line_to)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_decode_color(wfc, line_to->penColor, &pen_color, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pen = CreatePen(line_to->penStyle, line_to->penWidth, pen_color);
Packit 1fb8d4
	wf_set_rop2(wfc->drawing->hdc, line_to->bRop2);
Packit Service 5a9772
	org_pen = (HPEN)SelectObject(wfc->drawing->hdc, pen);
Packit 1fb8d4
	MoveToEx(wfc->drawing->hdc, line_to->nXStart, line_to->nYStart, NULL);
Packit 1fb8d4
	LineTo(wfc->drawing->hdc, line_to->nXEnd, line_to->nYEnd);
Packit 1fb8d4
	x = (line_to->nXStart < line_to->nXEnd) ? line_to->nXStart : line_to->nXEnd;
Packit 1fb8d4
	y = (line_to->nYStart < line_to->nYEnd) ? line_to->nYStart : line_to->nYEnd;
Packit 1fb8d4
	w = (line_to->nXStart < line_to->nXEnd) ? (line_to->nXEnd - line_to->nXStart)
Packit Service 5a9772
	                                        : (line_to->nXStart - line_to->nXEnd);
Packit 1fb8d4
	h = (line_to->nYStart < line_to->nYEnd) ? (line_to->nYEnd - line_to->nYStart)
Packit Service 5a9772
	                                        : (line_to->nYStart - line_to->nYEnd);
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->drawing == wfc->primary)
Packit 1fb8d4
		wf_invalidate_region(wfc, x, y, w, h);
Packit 1fb8d4
Packit 1fb8d4
	SelectObject(wfc->drawing->hdc, org_pen);
Packit 1fb8d4
	DeleteObject(pen);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)
Packit 1fb8d4
{
Packit 1fb8d4
	int org_rop2;
Packit 1fb8d4
	HPEN hpen;
Packit 1fb8d4
	HPEN org_hpen;
Packit 1fb8d4
	UINT32 pen_color;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !polyline)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_decode_color(wfc, polyline->penColor, &pen_color, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	hpen = CreatePen(0, 1, pen_color);
Packit 1fb8d4
	org_rop2 = wf_set_rop2(wfc->drawing->hdc, polyline->bRop2);
Packit Service 5a9772
	org_hpen = (HPEN)SelectObject(wfc->drawing->hdc, hpen);
Packit 1fb8d4
Packit 1fb8d4
	if (polyline->numDeltaEntries > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		POINT* pts;
Packit Service 5a9772
		POINT temp;
Packit Service 5a9772
		int numPoints;
Packit Service 5a9772
		int i;
Packit 1fb8d4
		numPoints = polyline->numDeltaEntries + 1;
Packit Service 5a9772
		pts = (POINT*)malloc(sizeof(POINT) * numPoints);
Packit 1fb8d4
		pts[0].x = temp.x = polyline->xStart;
Packit 1fb8d4
		pts[0].y = temp.y = polyline->yStart;
Packit 1fb8d4
Packit Service 5a9772
		for (i = 0; i < (int)polyline->numDeltaEntries; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			temp.x += polyline->points[i].x;
Packit 1fb8d4
			temp.y += polyline->points[i].y;
Packit 1fb8d4
			pts[i + 1].x = temp.x;
Packit 1fb8d4
			pts[i + 1].y = temp.y;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (wfc->drawing == wfc->primary)
Packit 1fb8d4
			wf_invalidate_region(wfc, wfc->client_x, wfc->client_y, wfc->client_width,
Packit 1fb8d4
			                     wfc->client_height);
Packit 1fb8d4
Packit 1fb8d4
		Polyline(wfc->drawing->hdc, pts, numPoints);
Packit 1fb8d4
		free(pts);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SelectObject(wfc->drawing->hdc, org_hpen);
Packit 1fb8d4
	wf_set_rop2(wfc->drawing->hdc, org_rop2);
Packit 1fb8d4
	DeleteObject(hpen);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
Packit 1fb8d4
{
Packit 1fb8d4
	wfBitmap* bitmap;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !memblt)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	bitmap = (wfBitmap*)memblt->bitmap;
Packit 1fb8d4
Packit 1fb8d4
	if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (!BitBlt(wfc->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
Packit Service 5a9772
	            memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
Packit Service 5a9772
	            gdi_rop3_code(memblt->bRop)))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->drawing == wfc->primary)
Packit 1fb8d4
		wf_invalidate_region(wfc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
Packit 1fb8d4
		                     memblt->nHeight);
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL rc = FALSE;
Packit 1fb8d4
	HDC hdc;
Packit 1fb8d4
	wfBitmap* bitmap;
Packit 1fb8d4
	wfContext* wfc = (wfContext*)context;
Packit 1fb8d4
	COLORREF fgcolor, bgcolor, orgColor;
Packit 1fb8d4
	HBRUSH orgBrush = NULL, brush = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !mem3blt)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	bitmap = (wfBitmap*)mem3blt->bitmap;
Packit 1fb8d4
Packit 1fb8d4
	if (!bitmap || !wfc->drawing || !wfc->drawing->hdc)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	hdc = wfc->drawing->hdc;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_decode_color(wfc, mem3blt->foreColor, &fgcolor, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_decode_color(wfc, mem3blt->backColor, &bgcolor, NULL))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	orgColor = SetTextColor(hdc, fgcolor);
Packit 1fb8d4
Packit 1fb8d4
	switch (mem3blt->brush.style)
Packit 1fb8d4
	{
Packit 1fb8d4
		case GDI_BS_SOLID:
Packit 1fb8d4
			brush = CreateSolidBrush(fgcolor);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_BS_HATCHED:
Packit 1fb8d4
		case GDI_BS_PATTERN:
Packit Service 5a9772
		{
Packit Service 5a9772
			HBITMAP bmp = CreateBitmap(8, 8, 1, mem3blt->brush.bpp, mem3blt->brush.data);
Packit Service 5a9772
			brush = CreatePatternBrush(bmp);
Packit Service 5a9772
		}
Packit Service 5a9772
		break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	orgBrush = SelectObject(hdc, brush);
Packit 1fb8d4
Packit Service 5a9772
	if (!BitBlt(hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight,
Packit Service 5a9772
	            bitmap->hdc, mem3blt->nXSrc, mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop)))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	if (wfc->drawing == wfc->primary)
Packit Service 5a9772
		wf_invalidate_region(wfc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth,
Packit 1fb8d4
		                     mem3blt->nHeight);
Packit 1fb8d4
Packit 1fb8d4
	rc = TRUE;
Packit 1fb8d4
fail:
Packit 1fb8d4
Packit 1fb8d4
	if (brush)
Packit 1fb8d4
		SelectObject(hdc, orgBrush);
Packit 1fb8d4
Packit 1fb8d4
	SetTextColor(hdc, orgColor);
Packit 1fb8d4
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_gdi_surface_frame_marker(rdpContext* context,
Packit 1fb8d4
                                        const SURFACE_FRAME_MARKER* surface_frame_marker)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !surface_frame_marker || !context->instance)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	settings = context->instance->settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END &&
Packit Service 5a9772
	    settings->FrameAcknowledge > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALL(context->instance->update->SurfaceFrameAcknowledge, context,
Packit 1fb8d4
		       surface_frame_marker->frameId);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_gdi_register_update_callbacks(rdpUpdate* update)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpPrimaryUpdate* primary = update->primary;
Packit 1fb8d4
	update->Palette = wf_gdi_palette_update;
Packit 1fb8d4
	update->SetBounds = wf_gdi_set_bounds;
Packit 1fb8d4
	primary->DstBlt = wf_gdi_dstblt;
Packit 1fb8d4
	primary->PatBlt = wf_gdi_patblt;
Packit 1fb8d4
	primary->ScrBlt = wf_gdi_scrblt;
Packit 1fb8d4
	primary->OpaqueRect = wf_gdi_opaque_rect;
Packit 1fb8d4
	primary->MultiOpaqueRect = wf_gdi_multi_opaque_rect;
Packit 1fb8d4
	primary->LineTo = wf_gdi_line_to;
Packit 1fb8d4
	primary->Polyline = wf_gdi_polyline;
Packit 1fb8d4
	primary->MemBlt = wf_gdi_memblt;
Packit 1fb8d4
	primary->Mem3Blt = wf_gdi_mem3blt;
Packit 1fb8d4
	update->SurfaceFrameMarker = wf_gdi_surface_frame_marker;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_update_canvas_diff(wfContext* wfc)
Packit 1fb8d4
{
Packit 1fb8d4
	RECT rc_client, rc_wnd;
Packit 1fb8d4
	int dx, dy;
Packit 1fb8d4
	GetClientRect(wfc->hwnd, &rc_client);
Packit 1fb8d4
	GetWindowRect(wfc->hwnd, &rc_wnd);
Packit 1fb8d4
	dx = (rc_wnd.right - rc_wnd.left) - rc_client.right;
Packit 1fb8d4
	dy = (rc_wnd.bottom - rc_wnd.top) - rc_client.bottom;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->disablewindowtracking)
Packit 1fb8d4
	{
Packit 1fb8d4
		wfc->diff.x = dx;
Packit 1fb8d4
		wfc->diff.y = dy;
Packit 1fb8d4
	}
Packit 1fb8d4
}