FreeRDP/client/X11/xf_gdi.c

1143 lines
28 KiB
C
Raw Normal View History

2011-08-26 02:07:52 +04:00
/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
2011-08-26 02:07:52 +04:00
* X11 GDI
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Thincast Technologies GmbH
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
2011-08-26 02:07:52 +04:00
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2022-02-16 13:20:38 +03:00
#include <freerdp/config.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <winpr/assert.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/constants.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
2011-08-26 02:07:52 +04:00
#include "xf_gdi.h"
2016-08-03 11:54:50 +03:00
#include "xf_graphics.h"
2011-08-26 02:07:52 +04:00
2014-09-12 19:13:01 +04:00
#include <freerdp/log.h>
#define TAG CLIENT_TAG("x11")
2019-11-06 17:24:51 +03:00
static const UINT8 GDI_BS_HATCHED_PATTERNS[] = {
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, /* HS_HORIZONTAL */
0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_VERTICAL */
0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F, /* HS_FDIAGONAL */
0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE, /* HS_BDIAGONAL */
0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_CROSS */
2019-11-06 17:24:51 +03:00
0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E /* HS_DIACROSS */
};
2019-11-06 17:24:51 +03:00
static const BYTE xf_rop2_table[] = {
2011-08-26 02:07:52 +04:00
0,
GXclear, /* 0 */
GXnor, /* DPon */
GXandInverted, /* DPna */
GXcopyInverted, /* Pn */
GXandReverse, /* PDna */
GXinvert, /* Dn */
GXxor, /* DPx */
GXnand, /* DPan */
GXand, /* DPa */
GXequiv, /* DPxn */
GXnoop, /* D */
GXorInverted, /* DPno */
GXcopy, /* P */
GXorReverse, /* PDno */
GXor, /* DPo */
GXset /* 1 */
};
2016-07-18 15:16:13 +03:00
static BOOL xf_set_rop2(xfContext* xfc, int rop2)
2011-08-26 02:07:52 +04:00
{
if ((rop2 < 0x01) || (rop2 > 0x10))
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Unsupported ROP2: %d", rop2);
return FALSE;
2011-08-26 02:07:52 +04:00
}
XSetFunction(xfc->display, xfc->gc, xf_rop2_table[rop2]);
return TRUE;
2011-08-26 02:07:52 +04:00
}
2016-08-03 11:54:50 +03:00
static BOOL xf_set_rop3(xfContext* xfc, UINT32 rop3)
2011-08-26 02:07:52 +04:00
{
int function = -1;
switch (rop3)
{
case GDI_BLACKNESS:
function = GXclear;
break;
2012-02-13 03:12:28 +04:00
case GDI_DPon:
2011-08-26 02:07:52 +04:00
function = GXnor;
break;
2012-02-13 03:12:28 +04:00
case GDI_DPna:
2011-08-26 02:07:52 +04:00
function = GXandInverted;
break;
2012-02-13 03:12:28 +04:00
case GDI_Pn:
2011-08-26 02:07:52 +04:00
function = GXcopyInverted;
break;
case GDI_NOTSRCERASE:
function = GXnor;
break;
case GDI_DSna:
function = GXandInverted;
break;
case GDI_NOTSRCCOPY:
function = GXcopyInverted;
break;
case GDI_SRCERASE:
function = GXandReverse;
break;
2012-02-13 03:12:28 +04:00
case GDI_PDna:
2011-08-26 02:07:52 +04:00
function = GXandReverse;
break;
case GDI_DSTINVERT:
function = GXinvert;
break;
case GDI_PATINVERT:
function = GXxor;
break;
2012-02-13 03:12:28 +04:00
case GDI_DPan:
2011-08-26 02:07:52 +04:00
function = GXnand;
break;
case GDI_SRCINVERT:
function = GXxor;
break;
2012-02-13 03:12:28 +04:00
case GDI_DSan:
2011-08-26 02:07:52 +04:00
function = GXnand;
break;
case GDI_SRCAND:
function = GXand;
break;
2012-02-13 03:12:28 +04:00
case GDI_DSxn:
2011-08-26 02:07:52 +04:00
function = GXequiv;
break;
2012-02-13 03:12:28 +04:00
case GDI_DPa:
2011-08-26 02:07:52 +04:00
function = GXand;
break;
case GDI_PDxn:
function = GXequiv;
break;
case GDI_DSTCOPY:
2011-08-26 02:07:52 +04:00
function = GXnoop;
break;
2012-02-13 03:12:28 +04:00
case GDI_DPno:
2011-08-26 02:07:52 +04:00
function = GXorInverted;
break;
case GDI_MERGEPAINT:
function = GXorInverted;
break;
case GDI_SRCCOPY:
function = GXcopy;
break;
2012-02-13 03:12:28 +04:00
case GDI_SDno:
2011-08-26 02:07:52 +04:00
function = GXorReverse;
break;
case GDI_SRCPAINT:
function = GXor;
break;
case GDI_PATCOPY:
function = GXcopy;
break;
2012-02-13 03:12:28 +04:00
case GDI_PDno:
2011-08-26 02:07:52 +04:00
function = GXorReverse;
break;
2012-02-13 03:12:28 +04:00
case GDI_DPo:
2011-08-26 02:07:52 +04:00
function = GXor;
break;
case GDI_WHITENESS:
function = GXset;
break;
2012-02-13 03:12:28 +04:00
case GDI_PSDPxax:
function = GXand;
break;
2011-08-26 02:07:52 +04:00
default:
break;
}
if (function < 0)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Unsupported ROP3: 0x%08" PRIX32 "", rop3);
XSetFunction(xfc->display, xfc->gc, GXclear);
return FALSE;
2011-08-26 02:07:52 +04:00
}
XSetFunction(xfc->display, xfc->gc, function);
return TRUE;
2011-08-26 02:07:52 +04:00
}
2019-11-06 17:24:51 +03:00
static Pixmap xf_brush_new(xfContext* xfc, UINT32 width, UINT32 height, UINT32 bpp, BYTE* data)
{
GC gc;
Pixmap bitmap;
BYTE* cdata;
XImage* image;
2016-08-03 15:16:20 +03:00
rdpGdi* gdi;
UINT32 brushFormat;
WINPR_ASSERT(xfc);
gdi = xfc->common.context.gdi;
WINPR_ASSERT(gdi);
bitmap = XCreatePixmap(xfc->display, xfc->drawable, width, height, xfc->depth);
if (data)
{
2016-10-14 11:01:02 +03:00
brushFormat = gdi_get_pixel_format(bpp);
cdata = (BYTE*)winpr_aligned_malloc(width * height * 4ULL, 16);
2019-11-06 17:24:51 +03:00
freerdp_image_copy(cdata, gdi->dstFormat, 0, 0, 0, width, height, data, brushFormat, 0, 0,
0, &gdi->palette, FREERDP_FLIP_NONE);
2019-11-06 17:24:51 +03:00
image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*)cdata, width,
height, xfc->scanline_pad, 0);
Fix colors on big endian (#4135) * client/x11: Fix colors on big endian The bitmaps are recieved in little endian byte order (LSBFirst in terms of X11). This is a problem on systems, where bitmaps are expected in big endian byte order (MSBFirst). X11 client tries to handle this situation by different color formats (e.g. RGBX vs. BGRX), but this doesn't work. BGRX is not MSBFirst variant of RGBX, it should be XRGB. But this would work only for 32/24 depths, where color channels matches bytes. Let's say to the XServer that all the bitmaps are in LSBFirst encoding instead of changing the color formats on big endian systems. https://github.com/FreeRDP/FreeRDP/issues/2520 * client/x11: Fix cursor color on big endian The cursor color is wrong on big endian systems. It is not probably possible to force bitmap_order for XcursorImage as it is possible for XImage. Fortunately, cursors are always 32 bit so we can use ABGR instead of BGRA to deal with. https://github.com/FreeRDP/FreeRDP/issues/2520 * client/x11: Fix comment indentation The comment has wrong indentation for some reason, let's fix it. * client/x11: Fix BGR vs. RGB detection The BGR vs. RGB detection code is leftover from history and I am conviced that it is wrong with the current color handling, where invert flag is TRUE by default. However, I suppose that the detection still makes sense and XServer may use the inverted formats in some cases. Maybe we can force XServer to use our masks somehow, but let's just fix the value to FALSE now. * client/x11: Remove unused color shifts The color shifts are lefover from history and are not used in current code. Let's remove them.
2017-09-18 11:47:56 +03:00
image->byte_order = LSBFirst;
image->bitmap_bit_order = LSBFirst;
gc = XCreateGC(xfc->display, xfc->drawable, 0, NULL);
XPutImage(xfc->display, bitmap, gc, image, 0, 0, 0, 0, width, height);
2018-02-12 13:14:54 +03:00
image->data = NULL;
XDestroyImage(image);
2012-02-13 03:12:28 +04:00
if (cdata != data)
winpr_aligned_free(cdata);
XFreeGC(xfc->display, gc);
}
return bitmap;
}
2019-11-06 17:24:51 +03:00
static Pixmap xf_mono_bitmap_new(xfContext* xfc, int width, int height, const BYTE* data)
{
2022-04-27 22:02:18 +03:00
union
{
const BYTE* cpv;
char* pv;
} cnv;
const int scanline = (width + 7) / 8;
XImage* image;
Pixmap bitmap;
2022-04-27 22:02:18 +03:00
cnv.cpv = data;
bitmap = XCreatePixmap(xfc->display, xfc->drawable, width, height, 1);
2022-04-27 22:02:18 +03:00
image =
XCreateImage(xfc->display, xfc->visual, 1, ZPixmap, 0, cnv.pv, width, height, 8, scanline);
Fix colors on big endian (#4135) * client/x11: Fix colors on big endian The bitmaps are recieved in little endian byte order (LSBFirst in terms of X11). This is a problem on systems, where bitmaps are expected in big endian byte order (MSBFirst). X11 client tries to handle this situation by different color formats (e.g. RGBX vs. BGRX), but this doesn't work. BGRX is not MSBFirst variant of RGBX, it should be XRGB. But this would work only for 32/24 depths, where color channels matches bytes. Let's say to the XServer that all the bitmaps are in LSBFirst encoding instead of changing the color formats on big endian systems. https://github.com/FreeRDP/FreeRDP/issues/2520 * client/x11: Fix cursor color on big endian The cursor color is wrong on big endian systems. It is not probably possible to force bitmap_order for XcursorImage as it is possible for XImage. Fortunately, cursors are always 32 bit so we can use ABGR instead of BGRA to deal with. https://github.com/FreeRDP/FreeRDP/issues/2520 * client/x11: Fix comment indentation The comment has wrong indentation for some reason, let's fix it. * client/x11: Fix BGR vs. RGB detection The BGR vs. RGB detection code is leftover from history and I am conviced that it is wrong with the current color handling, where invert flag is TRUE by default. However, I suppose that the detection still makes sense and XServer may use the inverted formats in some cases. Maybe we can force XServer to use our masks somehow, but let's just fix the value to FALSE now. * client/x11: Remove unused color shifts The color shifts are lefover from history and are not used in current code. Let's remove them.
2017-09-18 11:47:56 +03:00
image->byte_order = LSBFirst;
image->bitmap_bit_order = LSBFirst;
XPutImage(xfc->display, bitmap, xfc->gc_mono, image, 0, 0, 0, 0, width, height);
2018-02-12 13:14:54 +03:00
image->data = NULL;
XDestroyImage(image);
return bitmap;
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)
2011-08-26 02:07:52 +04:00
{
XRectangle clip;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
xf_lock_x11(xfc);
if (bounds)
{
clip.x = bounds->left;
clip.y = bounds->top;
clip.width = bounds->right - bounds->left + 1;
clip.height = bounds->bottom - bounds->top + 1;
XSetClipRectangles(xfc->display, xfc->gc, 0, 0, &clip, 1, YXBanded);
}
else
{
XSetClipMask(xfc->display, xfc->gc, None);
}
xf_unlock_x11(xfc);
return TRUE;
2011-08-26 02:07:52 +04:00
}
static BOOL xf_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
2011-08-26 02:07:52 +04:00
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2016-08-03 11:54:50 +03:00
BOOL ret = FALSE;
xf_lock_x11(xfc);
2016-08-03 11:54:50 +03:00
if (!xf_set_rop3(xfc, gdi_rop3_code(dstblt->bRop)))
goto fail;
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2019-11-06 17:24:51 +03:00
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, dstblt->nLeftRect, dstblt->nTopRect,
2016-07-14 17:08:06 +03:00
dstblt->nWidth, dstblt->nHeight);
ret = TRUE;
if (xfc->drawing == xfc->primary)
2019-11-06 17:24:51 +03:00
ret = gdi_InvalidateRegion(xfc->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
dstblt->nHeight);
2016-08-03 11:54:50 +03:00
fail:
XSetFunction(xfc->display, xfc->gc, GXcopy);
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
2016-07-13 14:13:28 +03:00
static BOOL xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
2011-08-26 02:07:52 +04:00
{
const rdpBrush* brush;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2016-08-03 11:54:50 +03:00
BOOL ret = FALSE;
2017-01-25 10:33:36 +03:00
XColor xfg, xbg;
2016-07-18 13:36:22 +03:00
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, patblt->foreColor, &xfg))
2016-07-18 13:36:22 +03:00
return FALSE;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, patblt->backColor, &xbg))
2016-07-18 13:36:22 +03:00
return FALSE;
xf_lock_x11(xfc);
brush = &patblt->brush;
2016-08-03 11:54:50 +03:00
if (!xf_set_rop3(xfc, gdi_rop3_code(patblt->bRop)))
goto fail;
switch (brush->style)
{
2016-08-03 11:54:50 +03:00
case GDI_BS_SOLID:
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2017-01-25 10:33:36 +03:00
XSetBackground(xfc->display, xfc->gc, xbg.pixel);
XSetForeground(xfc->display, xfc->gc, xfg.pixel);
2019-11-06 17:24:51 +03:00
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect, patblt->nTopRect,
patblt->nWidth, patblt->nHeight);
2016-08-03 11:54:50 +03:00
break;
case GDI_BS_HATCHED:
2019-11-06 17:24:51 +03:00
{
Pixmap pattern =
xf_mono_bitmap_new(xfc, 8, 8, &GDI_BS_HATCHED_PATTERNS[8 * brush->hatch]);
XSetBackground(xfc->display, xfc->gc, xbg.pixel);
XSetForeground(xfc->display, xfc->gc, xfg.pixel);
XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled);
XSetStipple(xfc->display, xfc->gc, pattern);
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect, patblt->nTopRect,
patblt->nWidth, patblt->nHeight);
XFreePixmap(xfc->display, pattern);
}
break;
2016-08-03 11:54:50 +03:00
case GDI_BS_PATTERN:
if (brush->bpp > 1)
{
UINT32 bpp = brush->bpp;
if ((bpp == 16) &&
(freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth) == 15))
bpp = 15;
Pixmap pattern = xf_brush_new(xfc, 8, 8, bpp, brush->data);
2016-08-03 11:54:50 +03:00
XSetFillStyle(xfc->display, xfc->gc, FillTiled);
XSetTile(xfc->display, xfc->gc, pattern);
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
2019-11-06 17:24:51 +03:00
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect,
patblt->nTopRect, patblt->nWidth, patblt->nHeight);
2016-08-03 11:54:50 +03:00
XSetTile(xfc->display, xfc->gc, xfc->primary);
XFreePixmap(xfc->display, pattern);
}
else
{
Pixmap pattern = xf_mono_bitmap_new(xfc, 8, 8, brush->data);
2017-01-25 10:33:36 +03:00
XSetBackground(xfc->display, xfc->gc, xfg.pixel);
XSetForeground(xfc->display, xfc->gc, xbg.pixel);
2016-08-03 11:54:50 +03:00
XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled);
XSetStipple(xfc->display, xfc->gc, pattern);
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
2019-11-06 17:24:51 +03:00
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect,
patblt->nTopRect, patblt->nWidth, patblt->nHeight);
2016-08-03 11:54:50 +03:00
XFreePixmap(xfc->display, pattern);
}
break;
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "unimplemented brush style:%" PRIu32 "", brush->style);
2016-08-03 11:54:50 +03:00
goto fail;
}
2011-08-26 02:07:52 +04:00
ret = TRUE;
if (xfc->drawing == xfc->primary)
2019-11-06 17:24:51 +03:00
ret = gdi_InvalidateRegion(xfc->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
patblt->nHeight);
2016-08-03 11:54:50 +03:00
fail:
XSetFunction(xfc->display, xfc->gc, GXcopy);
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
static BOOL xf_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
2011-08-26 02:07:52 +04:00
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2016-08-03 11:54:50 +03:00
BOOL ret = FALSE;
if (!xfc->display || !xfc->drawing)
return FALSE;
xf_lock_x11(xfc);
2016-08-03 11:54:50 +03:00
if (!xf_set_rop3(xfc, gdi_rop3_code(scrblt->bRop)))
goto fail;
2019-11-06 17:24:51 +03:00
XCopyArea(xfc->display, xfc->primary, xfc->drawing, xfc->gc, scrblt->nXSrc, scrblt->nYSrc,
2016-07-14 17:08:06 +03:00
scrblt->nWidth, scrblt->nHeight, scrblt->nLeftRect, scrblt->nTopRect);
ret = TRUE;
2011-08-26 02:07:52 +04:00
if (xfc->drawing == xfc->primary)
2019-11-06 17:24:51 +03:00
ret = gdi_InvalidateRegion(xfc->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
scrblt->nHeight);
XSetFunction(xfc->display, xfc->gc, GXcopy);
2016-08-03 11:54:50 +03:00
fail:
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
2011-08-26 02:07:52 +04:00
{
2017-01-25 10:33:36 +03:00
XColor color;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, opaque_rect->color, &color))
2016-08-03 11:54:50 +03:00
return FALSE;
xf_lock_x11(xfc);
XSetFunction(xfc->display, xfc->gc, GXcopy);
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, color.pixel);
2019-11-06 17:24:51 +03:00
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, opaque_rect->nLeftRect,
opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight);
if (xfc->drawing == xfc->primary)
2019-11-06 17:24:51 +03:00
ret = gdi_InvalidateRegion(xfc->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect,
2016-07-14 17:08:06 +03:00
opaque_rect->nWidth, opaque_rect->nHeight);
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
static BOOL xf_gdi_multi_opaque_rect(rdpContext* context,
2016-07-14 17:08:06 +03:00
const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
2011-08-26 02:07:52 +04:00
{
UINT32 i;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
2017-01-25 10:33:36 +03:00
XColor color;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, multi_opaque_rect->color, &color))
2016-08-03 11:54:50 +03:00
return FALSE;
xf_lock_x11(xfc);
XSetFunction(xfc->display, xfc->gc, GXcopy);
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, color.pixel);
2016-07-19 14:02:08 +03:00
for (i = 0; i < multi_opaque_rect->numRectangles; i++)
{
const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
2019-11-06 17:24:51 +03:00
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, rectangle->left, rectangle->top,
2016-07-14 17:08:06 +03:00
rectangle->width, rectangle->height);
if (xfc->drawing == xfc->primary)
{
if (!(ret = gdi_InvalidateRegion(xfc->hdc, rectangle->left, rectangle->top,
2016-07-14 17:08:06 +03:00
rectangle->width, rectangle->height)))
break;
}
}
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
static BOOL xf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to)
2011-08-26 02:07:52 +04:00
{
2017-01-25 10:33:36 +03:00
XColor color;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
2016-07-18 13:36:22 +03:00
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, line_to->penColor, &color))
2016-07-18 13:36:22 +03:00
return FALSE;
xf_lock_x11(xfc);
xf_set_rop2(xfc, line_to->bRop2);
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, color.pixel);
2019-11-06 17:24:51 +03:00
XDrawLine(xfc->display, xfc->drawing, xfc->gc, line_to->nXStart, line_to->nYStart,
line_to->nXEnd, line_to->nYEnd);
if (xfc->drawing == xfc->primary)
{
int x, y, w, h;
x = MIN(line_to->nXStart, line_to->nXEnd);
y = MIN(line_to->nYStart, line_to->nYEnd);
w = abs(line_to->nXEnd - line_to->nXStart) + 1;
h = abs(line_to->nYEnd - line_to->nYStart) + 1;
ret = gdi_InvalidateRegion(xfc->hdc, x, y, w, h);
}
XSetFunction(xfc->display, xfc->gc, GXcopy);
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_invalidate_poly_region(xfContext* xfc, XPoint* points, int npoints)
{
int x, y, x1, y1, x2, y2;
if (npoints < 2)
return FALSE;
x = x1 = x2 = points->x;
y = y1 = y2 = points->y;
while (--npoints)
{
points++;
x += points->x;
y += points->y;
if (x > x2)
x2 = x;
if (x < x1)
x1 = x;
if (y > y2)
y2 = y;
if (y < y1)
y1 = y;
}
x2++;
y2++;
return gdi_InvalidateRegion(xfc->hdc, x1, y1, x2 - x1, y2 - y1);
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)
2011-08-26 02:07:52 +04:00
{
2018-10-24 14:20:46 +03:00
UINT32 i;
int npoints;
2017-01-25 10:33:36 +03:00
XColor color;
XPoint* points;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
2016-07-18 13:36:22 +03:00
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, polyline->penColor, &color))
2016-07-18 13:36:22 +03:00
return FALSE;
xf_lock_x11(xfc);
xf_set_rop2(xfc, polyline->bRop2);
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, color.pixel);
2014-10-09 14:11:38 +04:00
npoints = polyline->numDeltaEntries + 1;
points = calloc(npoints, sizeof(XPoint));
if (!points)
{
xf_unlock_x11(xfc);
return FALSE;
}
points[0].x = polyline->xStart;
points[0].y = polyline->yStart;
2014-10-09 14:11:38 +04:00
for (i = 0; i < polyline->numDeltaEntries; i++)
{
points[i + 1].x = polyline->points[i].x;
points[i + 1].y = polyline->points[i].y;
}
2019-11-06 17:24:51 +03:00
XDrawLines(xfc->display, xfc->drawing, xfc->gc, points, npoints, CoordModePrevious);
2011-08-26 02:07:52 +04:00
if (xfc->drawing == xfc->primary)
{
if (!xf_gdi_invalidate_poly_region(xfc, points, npoints))
ret = FALSE;
}
XSetFunction(xfc->display, xfc->gc, GXcopy);
free(points);
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
static BOOL xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
{
2016-07-21 14:00:57 +03:00
xfBitmap* bitmap;
xfContext* xfc;
BOOL ret = TRUE;
2016-07-21 14:00:57 +03:00
if (!context || !memblt)
return FALSE;
2019-11-06 17:24:51 +03:00
bitmap = (xfBitmap*)memblt->bitmap;
xfc = (xfContext*)context;
2016-07-21 14:00:57 +03:00
if (!bitmap || !xfc || !xfc->display || !xfc->drawing)
return FALSE;
xf_lock_x11(xfc);
if (xf_set_rop3(xfc, gdi_rop3_code(memblt->bRop)))
{
2019-11-06 17:24:51 +03:00
XCopyArea(xfc->display, bitmap->pixmap, xfc->drawing, xfc->gc, memblt->nXSrc, memblt->nYSrc,
memblt->nWidth, memblt->nHeight, memblt->nLeftRect, memblt->nTopRect);
if (xfc->drawing == xfc->primary)
2019-11-06 17:24:51 +03:00
ret = gdi_InvalidateRegion(xfc->hdc, memblt->nLeftRect, memblt->nTopRect,
memblt->nWidth, memblt->nHeight);
}
2016-08-03 11:54:50 +03:00
XSetFunction(xfc->display, xfc->gc, GXcopy);
xf_unlock_x11(xfc);
return ret;
}
static BOOL xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
{
const rdpBrush* brush;
2012-02-13 03:12:28 +04:00
xfBitmap* bitmap;
2017-01-25 10:33:36 +03:00
XColor foreColor;
XColor backColor;
2012-02-13 03:12:28 +04:00
Pixmap pattern = 0;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2016-08-03 11:54:50 +03:00
BOOL ret = FALSE;
2012-02-13 03:12:28 +04:00
if (!xfc->display || !xfc->drawing)
return FALSE;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, mem3blt->foreColor, &foreColor))
2016-07-18 13:36:22 +03:00
return FALSE;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, mem3blt->backColor, &backColor))
2016-07-18 13:36:22 +03:00
return FALSE;
xf_lock_x11(xfc);
2012-02-13 03:12:28 +04:00
brush = &mem3blt->brush;
2019-11-06 17:24:51 +03:00
bitmap = (xfBitmap*)mem3blt->bitmap;
2012-02-13 03:12:28 +04:00
2016-08-03 11:54:50 +03:00
if (!xf_set_rop3(xfc, gdi_rop3_code(mem3blt->bRop)))
goto fail;
switch (brush->style)
2012-02-13 03:12:28 +04:00
{
2016-08-03 11:54:50 +03:00
case GDI_BS_PATTERN:
if (brush->bpp > 1)
{
UINT32 bpp = brush->bpp;
if ((bpp == 16) &&
(freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth) == 15))
bpp = 15;
pattern = xf_brush_new(xfc, 8, 8, bpp, brush->data);
2016-08-03 11:54:50 +03:00
XSetFillStyle(xfc->display, xfc->gc, FillTiled);
XSetTile(xfc->display, xfc->gc, pattern);
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
}
else
{
pattern = xf_mono_bitmap_new(xfc, 8, 8, brush->data);
2017-01-25 10:33:36 +03:00
XSetBackground(xfc->display, xfc->gc, backColor.pixel);
XSetForeground(xfc->display, xfc->gc, foreColor.pixel);
2016-08-03 11:54:50 +03:00
XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled);
XSetStipple(xfc->display, xfc->gc, pattern);
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
}
break;
case GDI_BS_SOLID:
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2017-01-25 10:33:36 +03:00
XSetBackground(xfc->display, xfc->gc, backColor.pixel);
XSetForeground(xfc->display, xfc->gc, foreColor.pixel);
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
2016-08-03 11:54:50 +03:00
break;
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%" PRIu32 "", brush->style);
2016-08-03 11:54:50 +03:00
goto fail;
2012-02-13 03:12:28 +04:00
}
2019-11-06 17:24:51 +03:00
XCopyArea(xfc->display, bitmap->pixmap, xfc->drawing, xfc->gc, mem3blt->nXSrc, mem3blt->nYSrc,
mem3blt->nWidth, mem3blt->nHeight, mem3blt->nLeftRect, mem3blt->nTopRect);
ret = TRUE;
2012-02-13 03:12:28 +04:00
if (xfc->drawing == xfc->primary)
2019-11-06 17:24:51 +03:00
ret = gdi_InvalidateRegion(xfc->hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth,
mem3blt->nHeight);
2012-02-13 03:12:28 +04:00
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
XSetTSOrigin(xfc->display, xfc->gc, 0, 0);
2012-02-13 03:12:28 +04:00
if (pattern != 0)
XFreePixmap(xfc->display, pattern);
2012-02-13 03:12:28 +04:00
2016-08-03 11:54:50 +03:00
fail:
XSetFunction(xfc->display, xfc->gc, GXcopy);
xf_unlock_x11(xfc);
return ret;
2012-02-13 02:14:59 +04:00
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc)
2012-02-13 02:14:59 +04:00
{
2019-02-07 16:40:36 +03:00
UINT32 i;
int npoints;
2012-02-13 02:14:59 +04:00
XPoint* points;
2017-01-25 10:33:36 +03:00
XColor brush_color;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
2016-07-18 13:36:22 +03:00
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, polygon_sc->brushColor, &brush_color))
2016-07-18 13:36:22 +03:00
return FALSE;
xf_lock_x11(xfc);
xf_set_rop2(xfc, polygon_sc->bRop2);
2012-02-13 02:14:59 +04:00
npoints = polygon_sc->numPoints + 1;
points = calloc(npoints, sizeof(XPoint));
if (!points)
{
xf_unlock_x11(xfc);
return FALSE;
}
2012-02-13 02:14:59 +04:00
points[0].x = polygon_sc->xStart;
points[0].y = polygon_sc->yStart;
for (i = 0; i < polygon_sc->numPoints; i++)
{
points[i + 1].x = polygon_sc->points[i].x;
points[i + 1].y = polygon_sc->points[i].y;
}
switch (polygon_sc->fillMode)
{
case 1: /* alternate */
XSetFillRule(xfc->display, xfc->gc, EvenOddRule);
2012-02-13 02:14:59 +04:00
break;
case 2: /* winding */
XSetFillRule(xfc->display, xfc->gc, WindingRule);
2012-02-13 02:14:59 +04:00
break;
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "PolygonSC unknown fillMode: %" PRIu32 "", polygon_sc->fillMode);
2012-02-13 02:14:59 +04:00
break;
}
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, brush_color.pixel);
2019-11-06 17:24:51 +03:00
XFillPolygon(xfc->display, xfc->drawing, xfc->gc, points, npoints, Complex, CoordModePrevious);
2012-02-13 02:14:59 +04:00
if (xfc->drawing == xfc->primary)
2012-02-13 02:14:59 +04:00
{
if (!xf_gdi_invalidate_poly_region(xfc, points, npoints))
ret = FALSE;
2012-02-13 02:14:59 +04:00
}
XSetFunction(xfc->display, xfc->gc, GXcopy);
free(points);
xf_unlock_x11(xfc);
return ret;
2012-02-13 02:14:59 +04:00
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
2012-02-13 02:14:59 +04:00
{
2019-02-07 16:40:36 +03:00
UINT32 i;
int npoints;
2012-02-13 02:14:59 +04:00
XPoint* points;
Pixmap pattern;
const rdpBrush* brush;
2017-01-25 10:33:36 +03:00
XColor foreColor;
XColor backColor;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
2016-07-18 13:36:22 +03:00
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, polygon_cb->foreColor, &foreColor))
2016-07-18 13:36:22 +03:00
return FALSE;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, polygon_cb->backColor, &backColor))
2016-07-18 13:36:22 +03:00
return FALSE;
xf_lock_x11(xfc);
2012-02-13 02:14:59 +04:00
brush = &(polygon_cb->brush);
xf_set_rop2(xfc, polygon_cb->bRop2);
2012-02-13 02:14:59 +04:00
npoints = polygon_cb->numPoints + 1;
points = calloc(npoints, sizeof(XPoint));
if (!points)
{
xf_unlock_x11(xfc);
return FALSE;
}
2012-02-13 02:14:59 +04:00
points[0].x = polygon_cb->xStart;
points[0].y = polygon_cb->yStart;
for (i = 0; i < polygon_cb->numPoints; i++)
{
points[i + 1].x = polygon_cb->points[i].x;
points[i + 1].y = polygon_cb->points[i].y;
}
switch (polygon_cb->fillMode)
{
case GDI_FILL_ALTERNATE: /* alternate */
XSetFillRule(xfc->display, xfc->gc, EvenOddRule);
2012-02-13 02:14:59 +04:00
break;
case GDI_FILL_WINDING: /* winding */
XSetFillRule(xfc->display, xfc->gc, WindingRule);
2012-02-13 02:14:59 +04:00
break;
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "PolygonCB unknown fillMode: %" PRIu32 "", polygon_cb->fillMode);
2012-02-13 02:14:59 +04:00
break;
}
if (brush->style == GDI_BS_PATTERN)
{
if (brush->bpp > 1)
{
UINT32 bpp = brush->bpp;
if ((bpp == 16) &&
(freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth) == 15))
bpp = 15;
pattern = xf_brush_new(xfc, 8, 8, bpp, brush->data);
XSetFillStyle(xfc->display, xfc->gc, FillTiled);
XSetTile(xfc->display, xfc->gc, pattern);
2012-02-13 02:14:59 +04:00
}
else
{
pattern = xf_mono_bitmap_new(xfc, 8, 8, brush->data);
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, backColor.pixel);
XSetBackground(xfc->display, xfc->gc, foreColor.pixel);
2012-02-13 02:14:59 +04:00
if (polygon_cb->backMode == BACKMODE_TRANSPARENT)
XSetFillStyle(xfc->display, xfc->gc, FillStippled);
2012-02-13 02:14:59 +04:00
else if (polygon_cb->backMode == BACKMODE_OPAQUE)
XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled);
2012-02-13 02:14:59 +04:00
XSetStipple(xfc->display, xfc->gc, pattern);
}
2012-02-13 02:14:59 +04:00
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
2019-11-06 17:24:51 +03:00
XFillPolygon(xfc->display, xfc->drawing, xfc->gc, points, npoints, Complex,
CoordModePrevious);
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
XSetTSOrigin(xfc->display, xfc->gc, 0, 0);
XFreePixmap(xfc->display, pattern);
if (xfc->drawing == xfc->primary)
{
if (!xf_gdi_invalidate_poly_region(xfc, points, npoints))
ret = FALSE;
2012-02-13 02:14:59 +04:00
}
}
else
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "PolygonCB unimplemented brush style:%" PRIu32 "", brush->style);
2012-02-13 02:14:59 +04:00
}
XSetFunction(xfc->display, xfc->gc, GXcopy);
free(points);
xf_unlock_x11(xfc);
return ret;
2012-02-13 02:14:59 +04:00
}
static BOOL xf_gdi_surface_frame_marker(rdpContext* context,
2016-07-14 17:08:06 +03:00
const SURFACE_FRAME_MARKER* surface_frame_marker)
{
rdpSettings* settings;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
WINPR_ASSERT(xfc);
settings = xfc->common.context.settings;
WINPR_ASSERT(settings);
xf_lock_x11(xfc);
2012-05-26 10:41:38 +04:00
switch (surface_frame_marker->frameAction)
{
case SURFACECMD_FRAMEACTION_BEGIN:
xfc->frame_begin = TRUE;
xfc->frame_x1 = 0;
xfc->frame_y1 = 0;
xfc->frame_x2 = 0;
xfc->frame_y2 = 0;
2012-05-26 10:41:38 +04:00
break;
case SURFACECMD_FRAMEACTION_END:
xfc->frame_begin = FALSE;
if ((xfc->frame_x2 > xfc->frame_x1) && (xfc->frame_y2 > xfc->frame_y1))
ret = gdi_InvalidateRegion(xfc->hdc, xfc->frame_x1, xfc->frame_y1,
2019-11-06 17:24:51 +03:00
xfc->frame_x2 - xfc->frame_x1,
xfc->frame_y2 - xfc->frame_y1);
if (settings->FrameAcknowledge > 0)
{
WINPR_ASSERT(xfc->common.context.update);
IFCALL(xfc->common.context.update->SurfaceFrameAcknowledge, context,
2016-07-14 17:08:06 +03:00
surface_frame_marker->frameId);
}
2012-05-26 10:41:38 +04:00
break;
}
xf_unlock_x11(xfc);
return ret;
2012-05-26 10:41:38 +04:00
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_surface_update_frame(xfContext* xfc, UINT16 tx, UINT16 ty, UINT16 width,
UINT16 height)
2012-05-26 10:41:38 +04:00
{
BOOL ret = TRUE;
if (!xfc->remote_app)
2012-05-26 10:41:38 +04:00
{
if (xfc->frame_begin)
2012-05-26 10:41:38 +04:00
{
if (xfc->frame_x2 > xfc->frame_x1 && xfc->frame_y2 > xfc->frame_y1)
2012-05-26 10:41:38 +04:00
{
xfc->frame_x1 = MIN(xfc->frame_x1, tx);
xfc->frame_y1 = MIN(xfc->frame_y1, ty);
xfc->frame_x2 = MAX(xfc->frame_x2, tx + width);
xfc->frame_y2 = MAX(xfc->frame_y2, ty + height);
2012-05-26 10:41:38 +04:00
}
else
{
xfc->frame_x1 = tx;
xfc->frame_y1 = ty;
xfc->frame_x2 = tx + width;
xfc->frame_y2 = ty + height;
2012-05-26 10:41:38 +04:00
}
}
else
{
ret = gdi_InvalidateRegion(xfc->hdc, tx, ty, width, height);
2012-05-26 10:41:38 +04:00
}
}
else
{
ret = gdi_InvalidateRegion(xfc->hdc, tx, ty, width, height);
2012-05-26 10:41:38 +04:00
}
return ret;
}
static BOOL xf_gdi_update_screen(xfContext* xfc, BYTE* pSrcData, UINT32 scanline,
2019-11-06 17:24:51 +03:00
const REGION16* pRegion)
2016-10-11 15:34:07 +03:00
{
2016-10-19 12:06:47 +03:00
BOOL ret = FALSE;
2016-10-11 15:34:07 +03:00
XImage* image;
UINT32 i, nbRects;
const RECTANGLE_16* rects;
2017-11-20 16:02:41 +03:00
UINT32 bpp;
2016-10-11 15:34:07 +03:00
if (!xfc || !pSrcData)
return FALSE;
if (!(rects = region16_rects(pRegion, &nbRects)))
return TRUE;
2017-11-20 16:02:41 +03:00
if (xfc->depth > 16)
bpp = 4;
else if (xfc->depth > 8)
bpp = 2;
else
bpp = 1;
2018-10-24 14:20:46 +03:00
2016-10-11 15:34:07 +03:00
XSetFunction(xfc->display, xfc->gc, GXcopy);
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
for (i = 0; i < nbRects; i++)
{
UINT32 left = rects[i].left;
UINT32 top = rects[i].top;
UINT32 width = rects[i].right - rects[i].left;
UINT32 height = rects[i].bottom - rects[i].top;
BYTE* src = pSrcData + top * scanline + bpp * left;
2022-04-27 22:02:18 +03:00
union
{
BYTE* cev;
char* ev;
2022-04-27 22:02:18 +03:00
} cnv;
cnv.cev = src;
image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0,
2022-04-27 22:02:18 +03:00
/* API does not modify */ cnv.ev, width, height, xfc->scanline_pad,
scanline);
2018-10-24 14:20:46 +03:00
if (!image)
break;
Fix colors on big endian (#4135) * client/x11: Fix colors on big endian The bitmaps are recieved in little endian byte order (LSBFirst in terms of X11). This is a problem on systems, where bitmaps are expected in big endian byte order (MSBFirst). X11 client tries to handle this situation by different color formats (e.g. RGBX vs. BGRX), but this doesn't work. BGRX is not MSBFirst variant of RGBX, it should be XRGB. But this would work only for 32/24 depths, where color channels matches bytes. Let's say to the XServer that all the bitmaps are in LSBFirst encoding instead of changing the color formats on big endian systems. https://github.com/FreeRDP/FreeRDP/issues/2520 * client/x11: Fix cursor color on big endian The cursor color is wrong on big endian systems. It is not probably possible to force bitmap_order for XcursorImage as it is possible for XImage. Fortunately, cursors are always 32 bit so we can use ABGR instead of BGRA to deal with. https://github.com/FreeRDP/FreeRDP/issues/2520 * client/x11: Fix comment indentation The comment has wrong indentation for some reason, let's fix it. * client/x11: Fix BGR vs. RGB detection The BGR vs. RGB detection code is leftover from history and I am conviced that it is wrong with the current color handling, where invert flag is TRUE by default. However, I suppose that the detection still makes sense and XServer may use the inverted formats in some cases. Maybe we can force XServer to use our masks somehow, but let's just fix the value to FALSE now. * client/x11: Remove unused color shifts The color shifts are lefover from history and are not used in current code. Let's remove them.
2017-09-18 11:47:56 +03:00
image->byte_order = LSBFirst;
image->bitmap_bit_order = LSBFirst;
XPutImage(xfc->display, xfc->primary, xfc->gc, image, 0, 0, left, top, width, height);
2018-02-12 13:14:54 +03:00
image->data = NULL;
XDestroyImage(image);
ret = xf_gdi_surface_update_frame(xfc, left, top, width, height);
}
2016-10-11 15:34:07 +03:00
XSetClipMask(xfc->display, xfc->gc, None);
return ret;
}
2019-11-06 17:24:51 +03:00
static BOOL xf_gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd)
2011-08-26 02:07:52 +04:00
{
2014-09-17 22:29:56 +04:00
BYTE* pSrcData;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2016-10-11 15:34:07 +03:00
BOOL ret = FALSE;
2016-10-11 19:44:50 +03:00
DWORD format;
rdpGdi* gdi;
size_t size;
REGION16 region;
RECTANGLE_16 cmdRect;
if (!context || !cmd || !context->gdi)
return FALSE;
region16_init(&region);
cmdRect.left = cmd->destLeft;
cmdRect.top = cmd->destTop;
cmdRect.right = cmdRect.left + cmd->bmp.width;
cmdRect.bottom = cmdRect.top + cmd->bmp.height;
gdi = context->gdi;
xf_lock_x11(xfc);
switch (cmd->bmp.codecID)
{
2016-07-14 17:08:06 +03:00
case RDP_CODEC_ID_REMOTEFX:
if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
2018-10-24 14:20:46 +03:00
cmd->bmp.bitmapDataLength, cmd->destLeft, cmd->destTop,
2019-11-06 17:24:51 +03:00
gdi->primary_buffer, gdi->dstFormat, gdi->stride, gdi->height,
&region))
2016-10-11 15:34:07 +03:00
goto fail;
2016-07-14 17:08:06 +03:00
break;
2016-07-14 17:08:06 +03:00
case RDP_CODEC_ID_NSCODEC:
if (!nsc_process_message(context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width,
2019-11-06 17:24:51 +03:00
cmd->bmp.height, cmd->bmp.bitmapData,
cmd->bmp.bitmapDataLength, gdi->primary_buffer, gdi->dstFormat,
gdi->stride, 0, 0, cmd->bmp.width, cmd->bmp.height,
FREERDP_FLIP_VERTICAL))
2016-10-11 15:34:07 +03:00
goto fail;
region16_union_rect(&region, &region, &cmdRect);
2016-07-14 17:08:06 +03:00
break;
2014-09-12 09:03:19 +04:00
2016-07-14 17:08:06 +03:00
case RDP_CODEC_ID_NONE:
pSrcData = cmd->bmp.bitmapData;
format = gdi_get_pixel_format(cmd->bmp.bpp);
size = cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format) * 1ULL;
if (size > cmd->bmp.bitmapDataLength)
{
WLog_ERR(TAG, "Short nocodec message: got %" PRIu32 " bytes, require %" PRIuz,
cmd->bmp.bitmapDataLength, size);
goto fail;
}
2016-10-11 15:34:07 +03:00
2019-11-06 17:24:51 +03:00
if (!freerdp_image_copy(gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmd->destLeft,
cmd->destTop, cmd->bmp.width, cmd->bmp.height, pSrcData, format,
0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
2016-10-11 15:34:07 +03:00
goto fail;
region16_union_rect(&region, &region, &cmdRect);
2016-07-14 17:08:06 +03:00
break;
2016-04-11 15:14:17 +03:00
2016-07-14 17:08:06 +03:00
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Unsupported codecID %" PRIu16 "", cmd->bmp.codecID);
goto fail;
}
ret = xf_gdi_update_screen(xfc, gdi->primary_buffer, gdi->stride, &region);
2016-10-11 15:34:07 +03:00
fail:
region16_uninit(&region);
xf_unlock_x11(xfc);
return ret;
2011-08-26 02:07:52 +04:00
}
void xf_gdi_register_update_callbacks(rdpUpdate* update)
{
rdpPrimaryUpdate* primary = update->primary;
2011-08-26 02:07:52 +04:00
update->SetBounds = xf_gdi_set_bounds;
primary->DstBlt = xf_gdi_dstblt;
primary->PatBlt = xf_gdi_patblt;
primary->ScrBlt = xf_gdi_scrblt;
primary->OpaqueRect = xf_gdi_opaque_rect;
primary->MultiOpaqueRect = xf_gdi_multi_opaque_rect;
primary->LineTo = xf_gdi_line_to;
primary->Polyline = xf_gdi_polyline;
primary->MemBlt = xf_gdi_memblt;
primary->Mem3Blt = xf_gdi_mem3blt;
2012-02-13 02:14:59 +04:00
primary->PolygonSC = xf_gdi_polygon_sc;
primary->PolygonCB = xf_gdi_polygon_cb;
2011-08-26 02:07:52 +04:00
update->SurfaceBits = xf_gdi_surface_bits;
update->SurfaceFrameMarker = xf_gdi_surface_frame_marker;
2011-08-26 02:07:52 +04:00
}