FreeRDP/client/X11/xf_graphics.c

808 lines
19 KiB
C
Raw Normal View History

/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
* X11 Graphical Objects
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2016 Thincast Technologies GmbH
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
*
* 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>
2011-10-21 02:18:45 +04:00
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef WITH_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
2022-06-29 15:18:36 +03:00
#include <float.h>
#include <math.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <freerdp/codec/bitmap.h>
#include <freerdp/codec/rfx.h>
#include "xf_graphics.h"
#include "xf_gdi.h"
#include "xf_event.h"
2014-09-12 19:13:01 +04:00
#include <freerdp/log.h>
#define TAG CLIENT_TAG("x11")
2022-07-04 09:52:17 +03:00
static BOOL xf_Pointer_Set(rdpContext* context, rdpPointer* pointer);
2017-01-25 10:33:36 +03:00
BOOL xf_decode_color(xfContext* xfc, const UINT32 srcColor, XColor* color)
2016-08-03 11:54:50 +03:00
{
2017-01-25 10:33:36 +03:00
rdpGdi* gdi;
rdpSettings* settings;
2016-08-03 11:54:50 +03:00
UINT32 SrcFormat;
2017-01-25 10:33:36 +03:00
BYTE r, g, b, a;
if (!xfc || !color)
return FALSE;
gdi = xfc->common.context.gdi;
2016-08-03 11:54:50 +03:00
2017-01-25 10:33:36 +03:00
if (!gdi)
2016-08-03 11:54:50 +03:00
return FALSE;
settings = xfc->common.context.settings;
2016-08-03 11:54:50 +03:00
2017-01-25 10:33:36 +03:00
if (!settings)
return FALSE;
switch (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth))
2017-02-01 13:00:24 +03:00
{
case 32:
case 24:
SrcFormat = PIXEL_FORMAT_BGR24;
break;
case 16:
SrcFormat = PIXEL_FORMAT_RGB16;
break;
case 15:
SrcFormat = PIXEL_FORMAT_RGB15;
break;
case 8:
SrcFormat = PIXEL_FORMAT_RGB8;
break;
default:
return FALSE;
}
FreeRDPSplitColor(srcColor, SrcFormat, &r, &g, &b, &a, &gdi->palette);
2017-01-25 10:33:36 +03:00
color->blue = (unsigned short)(b << 8);
color->green = (unsigned short)(g << 8);
color->red = (unsigned short)(r << 8);
color->flags = DoRed | DoGreen | DoBlue;
if (XAllocColor(xfc->display, xfc->colormap, color) == 0)
return FALSE;
2016-08-03 11:54:50 +03:00
return TRUE;
}
2011-10-21 02:18:45 +04:00
/* Bitmap Class */
static BOOL xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
{
BOOL rc = FALSE;
UINT32 depth;
BYTE* data;
2016-08-03 15:16:20 +03:00
rdpGdi* gdi;
xfBitmap* xbitmap = (xfBitmap*)bitmap;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
if (!context || !bitmap || !context->gdi)
return FALSE;
2016-08-03 15:16:20 +03:00
gdi = context->gdi;
xf_lock_x11(xfc);
depth = FreeRDPGetBitsPerPixel(bitmap->format);
WINPR_ASSERT(xfc->depth != 0);
2019-11-06 17:24:51 +03:00
xbitmap->pixmap =
XCreatePixmap(xfc->display, xfc->drawable, bitmap->width, bitmap->height, xfc->depth);
if (!xbitmap->pixmap)
goto unlock;
if (bitmap->data)
{
2014-09-12 09:03:19 +04:00
XSetFunction(xfc->display, xfc->gc, GXcopy);
2019-02-07 16:40:36 +03:00
if ((INT64)depth != xfc->depth)
{
if (!(data = winpr_aligned_malloc(bitmap->width * bitmap->height * 4ULL, 16)))
goto unlock;
2019-11-06 17:24:51 +03:00
if (!freerdp_image_copy(data, gdi->dstFormat, 0, 0, 0, bitmap->width, bitmap->height,
bitmap->data, bitmap->format, 0, 0, 0, &context->gdi->palette,
FREERDP_FLIP_NONE))
{
winpr_aligned_free(data);
goto unlock;
}
winpr_aligned_free(bitmap->data);
bitmap->data = data;
2016-08-03 15:16:20 +03:00
bitmap->format = gdi->dstFormat;
}
WINPR_ASSERT(xfc->depth != 0);
2019-11-06 17:24:51 +03:00
xbitmap->image =
XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*)bitmap->data,
bitmap->width, bitmap->height, xfc->scanline_pad, 0);
if (!xbitmap->image)
goto unlock;
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
xbitmap->image->byte_order = LSBFirst;
xbitmap->image->bitmap_bit_order = LSBFirst;
XPutImage(xfc->display, xbitmap->pixmap, xfc->gc, xbitmap->image, 0, 0, 0, 0, bitmap->width,
2016-10-04 10:00:00 +03:00
bitmap->height);
}
rc = TRUE;
unlock:
xf_unlock_x11(xfc);
return rc;
}
static void xf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
xfBitmap* xbitmap = (xfBitmap*)bitmap;
if (!xfc || !xbitmap)
return;
xf_lock_x11(xfc);
2018-04-04 11:46:14 +03:00
if (xbitmap->pixmap != 0)
2018-02-12 13:14:54 +03:00
{
XFreePixmap(xfc->display, xbitmap->pixmap);
2018-04-04 11:46:14 +03:00
xbitmap->pixmap = 0;
2018-02-12 13:14:54 +03:00
}
if (xbitmap->image)
2018-02-12 13:14:54 +03:00
{
xbitmap->image->data = NULL;
XDestroyImage(xbitmap->image);
2018-02-12 13:14:54 +03:00
xbitmap->image = NULL;
}
xf_unlock_x11(xfc);
winpr_aligned_free(bitmap->data);
free(xbitmap);
}
static BOOL xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
{
int width, height;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
xfBitmap* xbitmap = (xfBitmap*)bitmap;
BOOL ret;
if (!context || !xbitmap)
return FALSE;
width = bitmap->right - bitmap->left + 1;
height = bitmap->bottom - bitmap->top + 1;
xf_lock_x11(xfc);
XSetFunction(xfc->display, xfc->gc, GXcopy);
2019-11-06 17:24:51 +03:00
XPutImage(xfc->display, xfc->primary, xfc->gc, xbitmap->image, 0, 0, bitmap->left, bitmap->top,
width, height);
ret = gdi_InvalidateRegion(xfc->hdc, bitmap->left, bitmap->top, width, height);
xf_unlock_x11(xfc);
return ret;
}
2019-11-06 17:24:51 +03:00
static BOOL xf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
2011-10-21 02:18:45 +04:00
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
if (!context || (!bitmap && !primary))
return FALSE;
xf_lock_x11(xfc);
2011-10-21 02:18:45 +04:00
if (primary)
xfc->drawing = xfc->primary;
2011-10-21 02:18:45 +04:00
else
2019-11-06 17:24:51 +03:00
xfc->drawing = ((xfBitmap*)bitmap)->pixmap;
xf_unlock_x11(xfc);
return TRUE;
2011-10-21 02:18:45 +04:00
}
2022-07-04 09:52:17 +03:00
static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, rdpPointer* pointer,
Cursor* cursor)
{
#ifdef WITH_XCURSOR
UINT32 CursorFormat;
xfContext* xfc = (xfContext*)context;
2022-04-29 15:21:31 +03:00
xfPointer* xpointer = (xfPointer*)pointer;
2020-10-05 10:45:45 +03:00
XcursorImage ci = { 0 };
rdpSettings* settings;
UINT32 xTargetSize;
UINT32 yTargetSize;
double xscale;
double yscale;
size_t size;
2020-11-10 10:14:56 +03:00
int cursorIndex = -1;
UINT32 i;
2020-10-05 10:45:45 +03:00
void* tmp;
if (!context || !pointer || !context->gdi)
return FALSE;
settings = xfc->common.context.settings;
if (!settings)
return FALSE;
xscale = (settings->SmartSizing ? xfc->scaledWidth / (double)settings->DesktopWidth : 1);
yscale = (settings->SmartSizing ? xfc->scaledHeight / (double)settings->DesktopHeight : 1);
xTargetSize = MAX(1, pointer->width * xscale);
yTargetSize = MAX(1, pointer->height * yscale);
WLog_DBG(TAG, "scaled: %" PRIu32 "x%" PRIu32 ", desktop: %" PRIu32 "x%" PRIu32,
xfc->scaledWidth, xfc->scaledHeight, settings->DesktopWidth, settings->DesktopHeight);
2020-09-22 08:43:56 +03:00
for (i = 0; i < xpointer->nCursors; i++)
{
2022-07-04 09:52:17 +03:00
if ((xpointer->cursorWidths[i] == xTargetSize) &&
(xpointer->cursorHeights[i] == yTargetSize))
{
cursorIndex = i;
}
}
if (cursorIndex == -1)
{
xf_lock_x11(xfc);
if (!xfc->invert)
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_ABGR32;
else
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_ARGB32;
if (xpointer->nCursors == xpointer->mCursors)
{
2020-10-05 10:45:45 +03:00
void* tmp2;
xpointer->mCursors = (xpointer->mCursors == 0 ? 1 : xpointer->mCursors * 2);
2020-10-05 10:45:45 +03:00
tmp2 = realloc(xpointer->cursorWidths, sizeof(UINT32) * xpointer->mCursors);
if (!tmp2)
{
xf_unlock_x11(xfc);
return FALSE;
}
2020-10-05 10:45:45 +03:00
xpointer->cursorWidths = tmp2;
tmp2 = realloc(xpointer->cursorHeights, sizeof(UINT32) * xpointer->mCursors);
if (!tmp2)
{
xf_unlock_x11(xfc);
return FALSE;
}
2020-10-05 10:45:45 +03:00
xpointer->cursorHeights = (UINT32*)tmp2;
tmp2 = realloc(xpointer->cursors, sizeof(Cursor) * xpointer->mCursors);
if (!tmp2)
{
xf_unlock_x11(xfc);
return FALSE;
}
2020-10-05 10:45:45 +03:00
xpointer->cursors = (Cursor*)tmp2;
}
ci.version = XCURSOR_IMAGE_VERSION;
ci.size = sizeof(ci);
ci.width = xTargetSize;
ci.height = yTargetSize;
ci.xhot = pointer->xPos * xscale;
ci.yhot = pointer->yPos * yscale;
size = ci.height * ci.width * FreeRDPGetBytesPerPixel(CursorFormat) * 1ULL;
tmp = winpr_aligned_malloc(size, 16);
2020-10-05 10:45:45 +03:00
if (!tmp)
{
xf_unlock_x11(xfc);
return FALSE;
}
2020-10-05 10:45:45 +03:00
ci.pixels = (XcursorPixel*)tmp;
const double xs = fabs(fabs(xscale) - 1.0);
const double ys = fabs(fabs(yscale) - 1.0);
2022-07-04 13:13:20 +03:00
WLog_DBG(TAG,
"cursorIndex %" PRId32 " scaling pointer %" PRIu32 "x%" PRIu32 " --> %" PRIu32
2022-07-04 13:13:20 +03:00
"x%" PRIu32 " [%lfx%lf]",
cursorIndex, pointer->width, pointer->height, ci.width, ci.height, xscale, yscale);
if ((xs > DBL_EPSILON) || (ys > DBL_EPSILON))
{
if (!freerdp_image_scale((BYTE*)ci.pixels, CursorFormat, 0, 0, 0, ci.width, ci.height,
(BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0,
pointer->width, pointer->height))
{
winpr_aligned_free(tmp);
xf_unlock_x11(xfc);
return FALSE;
}
}
else
{
ci.pixels = xpointer->cursorPixels;
}
cursorIndex = xpointer->nCursors;
xpointer->cursorWidths[cursorIndex] = ci.width;
xpointer->cursorHeights[cursorIndex] = ci.height;
xpointer->cursors[cursorIndex] = XcursorImageLoadCursor(xfc->display, &ci);
xpointer->nCursors += 1;
2020-10-05 10:45:45 +03:00
winpr_aligned_free(tmp);
xf_unlock_x11(xfc);
}
2022-07-04 13:13:20 +03:00
else
{
WLog_DBG(TAG, "using cached cursor %" PRId32, cursorIndex);
2022-07-04 13:13:20 +03:00
}
cursor[0] = xpointer->cursors[cursorIndex];
#endif
return TRUE;
}
2011-10-21 02:18:45 +04:00
/* Pointer Class */
static Window xf_Pointer_get_window(xfContext* xfc)
{
if (!xfc)
{
WLog_WARN(TAG, "xf_Pointer: Invalid context");
return 0;
}
if (xfc->remote_app)
{
if (!xfc->appWindow)
{
WLog_WARN(TAG, "xf_Pointer: Invalid appWindow");
return 0;
}
return xfc->appWindow->handle;
}
else
{
if (!xfc->window)
{
WLog_WARN(TAG, "xf_Pointer: Invalid window");
return 0;
}
return xfc->window->handle;
}
}
2022-07-04 09:52:17 +03:00
BOOL xf_pointer_update_scale(xfContext* xfc)
{
xfPointer* pointer;
WINPR_ASSERT(xfc);
pointer = xfc->pointer;
if (!pointer)
return TRUE;
return xf_Pointer_Set(&xfc->common.context, &xfc->pointer->pointer);
}
static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer)
2011-10-21 02:18:45 +04:00
{
2022-07-04 13:13:20 +03:00
BOOL rc = FALSE;
2016-09-09 09:58:26 +03:00
#ifdef WITH_XCURSOR
2016-10-10 10:19:43 +03:00
UINT32 CursorFormat;
2016-09-09 09:58:26 +03:00
size_t size;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2016-09-09 09:58:26 +03:00
xfPointer* xpointer = (xfPointer*)pointer;
2016-08-03 15:16:20 +03:00
if (!context || !pointer || !context->gdi)
2022-07-04 13:13:20 +03:00
goto fail;
2016-08-03 15:16:20 +03:00
2016-10-10 10:19:43 +03:00
if (!xfc->invert)
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
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_ABGR32;
2016-10-10 10:19:43 +03:00
else
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
CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_ARGB32;
2016-10-10 10:19:43 +03:00
xpointer->nCursors = 0;
xpointer->mCursors = 0;
size = pointer->height * pointer->width * FreeRDPGetBytesPerPixel(CursorFormat) * 1ULL;
if (!(xpointer->cursorPixels = (XcursorPixel*)winpr_aligned_malloc(size, 16)))
2022-07-04 13:13:20 +03:00
goto fail;
2011-10-21 02:18:45 +04:00
2016-10-04 15:14:39 +03:00
if (!freerdp_image_copy_from_pointer_data(
(BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0, pointer->width, pointer->height,
2019-11-06 17:24:51 +03:00
pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData,
pointer->lengthAndMask, pointer->xorBpp, &context->gdi->palette))
2015-08-05 18:32:46 +03:00
{
winpr_aligned_free(xpointer->cursorPixels);
2022-07-04 13:13:20 +03:00
goto fail;
2011-10-21 02:18:45 +04:00
}
#endif
2022-07-04 13:13:20 +03:00
rc = TRUE;
2022-07-04 13:13:20 +03:00
fail:
WLog_DBG(TAG, "%p", rc ? pointer : NULL);
2022-07-04 13:13:20 +03:00
return rc;
2011-10-21 02:18:45 +04:00
}
static void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
2011-10-21 02:18:45 +04:00
{
WLog_DBG(TAG, "%p", pointer);
2022-07-04 13:13:20 +03:00
#ifdef WITH_XCURSOR
2020-09-16 10:30:37 +03:00
UINT32 i;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
xfPointer* xpointer = (xfPointer*)pointer;
xf_lock_x11(xfc);
winpr_aligned_free(xpointer->cursorPixels);
free(xpointer->cursorWidths);
free(xpointer->cursorHeights);
2020-09-16 10:30:37 +03:00
for (i = 0; i < xpointer->nCursors; i++)
{
XFreeCursor(xfc->display, xpointer->cursors[i]);
}
free(xpointer->cursors);
xpointer->nCursors = 0;
xpointer->mCursors = 0;
xf_unlock_x11(xfc);
#endif
2011-10-21 02:18:45 +04:00
}
static BOOL xf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
2011-10-21 02:18:45 +04:00
{
WLog_DBG(TAG, "%p", pointer);
#ifdef WITH_XCURSOR
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
Window handle = xf_Pointer_get_window(xfc);
2022-04-27 22:02:18 +03:00
2022-07-04 09:52:17 +03:00
WINPR_ASSERT(xfc);
WINPR_ASSERT(pointer);
2022-04-29 15:21:31 +03:00
xfc->pointer = (xfPointer*)pointer;
2011-11-24 22:01:34 +04:00
/* in RemoteApp mode, window can be null if none has had focus */
if (handle)
{
2022-07-04 09:52:17 +03:00
if (!xf_Pointer_GetCursorForCurrentScale(context, pointer, &(xfc->pointer->cursor)))
return FALSE;
xf_lock_x11(xfc);
XDefineCursor(xfc->display, handle, xfc->pointer->cursor);
xf_unlock_x11(xfc);
}
2022-07-04 13:13:20 +03:00
else
{
WLog_WARN(TAG, "handle=%ld", handle);
2022-07-04 13:13:20 +03:00
}
#endif
return TRUE;
2011-10-21 02:18:45 +04:00
}
static BOOL xf_Pointer_SetNull(rdpContext* context)
{
WLog_DBG(TAG, "called");
#ifdef WITH_XCURSOR
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
static Cursor nullcursor = None;
Window handle = xf_Pointer_get_window(xfc);
xf_lock_x11(xfc);
if (nullcursor == None)
{
XcursorImage ci = { 0 };
XcursorPixel xp = 0;
ci.version = XCURSOR_IMAGE_VERSION;
ci.size = sizeof(ci);
ci.width = ci.height = 1;
ci.xhot = ci.yhot = 0;
ci.pixels = &xp;
nullcursor = XcursorImageLoadCursor(xfc->display, &ci);
}
xfc->pointer = NULL;
if ((handle) && (nullcursor != None))
XDefineCursor(xfc->display, handle, nullcursor);
xf_unlock_x11(xfc);
#endif
return TRUE;
}
static BOOL xf_Pointer_SetDefault(rdpContext* context)
{
WLog_DBG(TAG, "called");
#ifdef WITH_XCURSOR
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
Window handle = xf_Pointer_get_window(xfc);
xf_lock_x11(xfc);
xfc->pointer = NULL;
if (handle)
XUndefineCursor(xfc->display, handle);
xf_unlock_x11(xfc);
#endif
return TRUE;
}
static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
2015-02-02 17:32:49 +03:00
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
XWindowAttributes current;
XSetWindowAttributes tmp;
BOOL ret = FALSE;
Status rc;
Window handle = xf_Pointer_get_window(xfc);
2015-02-02 17:32:49 +03:00
if (!handle)
{
WLog_WARN(TAG, "focus %d, handle%lu", xfc->focused, handle);
return TRUE;
}
WLog_DBG(TAG, "%" PRIu32 "x%" PRIu32, x, y);
if (xfc->remote_app && !xfc->focused)
return TRUE;
2015-02-02 17:32:49 +03:00
xf_adjust_coordinates_to_screen(xfc, &x, &y);
xf_lock_x11(xfc);
2015-02-02 17:32:49 +03:00
rc = XGetWindowAttributes(xfc->display, handle, &current);
if (rc == 0)
{
WLog_WARN(TAG, "XGetWindowAttributes==%d", rc);
goto out;
}
tmp.event_mask = (current.your_event_mask & ~(PointerMotionMask));
2016-07-14 17:08:06 +03:00
rc = XChangeWindowAttributes(xfc->display, handle, CWEventMask, &tmp);
if (rc == 0)
{
WLog_WARN(TAG, "XChangeWindowAttributes==%d", rc);
goto out;
}
rc = XWarpPointer(xfc->display, None, handle, 0, 0, 0, 0, x, y);
if (rc == 0)
WLog_WARN(TAG, "XWarpPointer==%d", rc);
tmp.event_mask = current.your_event_mask;
rc = XChangeWindowAttributes(xfc->display, handle, CWEventMask, &tmp);
if (rc == 0)
WLog_WARN(TAG, "2.try XChangeWindowAttributes==%d", rc);
ret = TRUE;
out:
xf_unlock_x11(xfc);
return ret;
2015-02-02 17:32:49 +03:00
}
/* Glyph Class */
2021-08-02 13:13:34 +03:00
static BOOL xf_Glyph_New(rdpContext* context, rdpGlyph* glyph)
{
int scanline;
XImage* image;
2021-08-02 13:13:34 +03:00
xfGlyph* xf_glyph = (xfGlyph*)glyph;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
xf_lock_x11(xfc);
scanline = (glyph->cx + 7) / 8;
2019-11-06 17:24:51 +03:00
xf_glyph->pixmap = XCreatePixmap(xfc->display, xfc->drawing, glyph->cx, glyph->cy, 1);
image = XCreateImage(xfc->display, xfc->visual, 1, ZPixmap, 0, (char*)glyph->aj, glyph->cx,
glyph->cy, 8, scanline);
image->byte_order = MSBFirst;
image->bitmap_bit_order = MSBFirst;
XInitImage(image);
2019-11-06 17:24:51 +03:00
XPutImage(xfc->display, xf_glyph->pixmap, xfc->gc_mono, image, 0, 0, 0, 0, glyph->cx,
glyph->cy);
2018-02-12 13:14:54 +03:00
image->data = NULL;
XDestroyImage(image);
xf_unlock_x11(xfc);
return TRUE;
}
static void xf_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
xf_lock_x11(xfc);
2019-11-06 17:24:51 +03:00
if (((xfGlyph*)glyph)->pixmap != 0)
XFreePixmap(xfc->display, ((xfGlyph*)glyph)->pixmap);
xf_unlock_x11(xfc);
2016-07-20 11:06:45 +03:00
free(glyph->aj);
free(glyph);
}
2019-11-06 17:24:51 +03:00
static BOOL xf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w,
INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
{
2021-08-02 13:13:34 +03:00
const xfGlyph* xf_glyph = (const xfGlyph*)glyph;
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2021-08-02 13:13:34 +03:00
xf_lock_x11(xfc);
2016-08-17 10:26:59 +03:00
if (!fOpRedundant)
{
XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled);
XFillRectangle(xfc->display, xfc->drawable, xfc->gc, x, y, w, h);
}
XSetFillStyle(xfc->display, xfc->gc, FillStippled);
XSetStipple(xfc->display, xfc->gc, xf_glyph->pixmap);
2016-08-17 10:26:59 +03:00
if (sx || sy)
WLog_ERR(TAG, "");
2019-11-06 17:24:51 +03:00
// XSetClipOrigin(xfc->display, xfc->gc, sx, sy);
XSetTSOrigin(xfc->display, xfc->gc, x, y);
2016-08-17 10:26:59 +03:00
XFillRectangle(xfc->display, xfc->drawing, xfc->gc, x, y, w, h);
xf_unlock_x11(xfc);
return TRUE;
}
2019-11-06 17:24:51 +03:00
static BOOL xf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
2017-01-25 10:33:36 +03:00
XColor xbgcolor, xfgcolor;
2016-07-18 13:36:22 +03:00
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, bgcolor, &xbgcolor))
2016-07-18 13:36:22 +03:00
return FALSE;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, fgcolor, &xfgcolor))
2016-07-18 13:36:22 +03:00
return FALSE;
xf_lock_x11(xfc);
2016-08-17 10:26:59 +03:00
if (!fOpRedundant)
{
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, xfgcolor.pixel);
XSetBackground(xfc->display, xfc->gc, xfgcolor.pixel);
2016-08-17 10:26:59 +03:00
XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled);
XFillRectangle(xfc->display, xfc->drawable, xfc->gc, x, y, width, height);
}
2017-01-25 10:33:36 +03:00
XSetForeground(xfc->display, xfc->gc, xbgcolor.pixel);
XSetBackground(xfc->display, xfc->gc, xfgcolor.pixel);
xf_unlock_x11(xfc);
return TRUE;
}
2019-11-06 17:24:51 +03:00
static BOOL xf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
2016-10-04 10:00:00 +03:00
UINT32 bgcolor, UINT32 fgcolor)
{
2019-11-06 17:24:51 +03:00
xfContext* xfc = (xfContext*)context;
BOOL ret = TRUE;
2017-01-25 10:33:36 +03:00
XColor xfgcolor, xbgcolor;
2016-08-10 18:01:54 +03:00
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, bgcolor, &xbgcolor))
2016-08-10 18:01:54 +03:00
return FALSE;
2017-01-25 10:33:36 +03:00
if (!xf_decode_color(xfc, fgcolor, &xfgcolor))
2016-08-10 18:01:54 +03:00
return FALSE;
if (xfc->drawing == xfc->primary)
ret = gdi_InvalidateRegion(xfc->hdc, x, y, width, height);
return ret;
}
2011-10-21 02:18:45 +04:00
/* Graphics Module */
2016-07-18 15:16:13 +03:00
BOOL xf_register_pointer(rdpGraphics* graphics)
{
rdpPointer* pointer = NULL;
2019-11-06 17:24:51 +03:00
if (!(pointer = (rdpPointer*)calloc(1, sizeof(rdpPointer))))
2016-07-18 15:16:13 +03:00
return FALSE;
pointer->size = sizeof(xfPointer);
pointer->New = xf_Pointer_New;
pointer->Free = xf_Pointer_Free;
pointer->Set = xf_Pointer_Set;
pointer->SetNull = xf_Pointer_SetNull;
pointer->SetDefault = xf_Pointer_SetDefault;
pointer->SetPosition = xf_Pointer_SetPosition;
graphics_register_pointer(graphics, pointer);
free(pointer);
return TRUE;
}
2011-10-21 02:18:45 +04:00
BOOL xf_register_graphics(rdpGraphics* graphics)
{
2016-07-21 11:07:42 +03:00
rdpBitmap bitmap;
rdpGlyph glyph;
2016-07-21 11:07:42 +03:00
if (!graphics || !graphics->Bitmap_Prototype || !graphics->Glyph_Prototype)
return FALSE;
2016-07-21 11:07:42 +03:00
bitmap = *graphics->Bitmap_Prototype;
glyph = *graphics->Glyph_Prototype;
bitmap.size = sizeof(xfBitmap);
bitmap.New = xf_Bitmap_New;
bitmap.Free = xf_Bitmap_Free;
bitmap.Paint = xf_Bitmap_Paint;
bitmap.SetSurface = xf_Bitmap_SetSurface;
graphics_register_bitmap(graphics, &bitmap);
glyph.size = sizeof(xfGlyph);
glyph.New = xf_Glyph_New;
glyph.Free = xf_Glyph_Free;
glyph.Draw = xf_Glyph_Draw;
glyph.BeginDraw = xf_Glyph_BeginDraw;
glyph.EndDraw = xf_Glyph_EndDraw;
graphics_register_glyph(graphics, &glyph);
return TRUE;
}
2016-08-03 15:16:20 +03:00
UINT32 xf_get_local_color_format(xfContext* xfc, BOOL aligned)
{
UINT32 DstFormat;
make cppcheck even more happier: [channels/tsmf/client/gstreamer/tsmf_X11.c:317] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:322]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:470] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:472] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/tsmf_media.c:179] -> [channels/tsmf/client/tsmf_media.c:181]: (warning) Either the condition '!stream' is redundant or there is possible null pointer dereference: stream. [client/Windows/wf_cliprdr.c:2219] -> [client/Windows/wf_cliprdr.c:2222]: (warning) Either the condition '!formatDataResponse' is redundant or there is possible null pointer dereference: formatDataResponse [client/Windows/wf_cliprdr.c:2445] -> [client/Windows/wf_cliprdr.c:2448]: (warning) Either the condition '!fileContentsResponse' is redundant or there is possible null pointer dereference: fileContentsResponse. [client/X11/xf_cliprdr.c:911] -> [client/X11/xf_cliprdr.c:913]: (warning) Either the condition '!clipboard' is redundant or there is possible null pointer dereference: clipboard. [client/X11/xf_graphics.c:504] -> [client/X11/xf_graphics.c:506]: (warning) Either the condition '!xfc' is redundant or there is possible null pointer dereference: xfc. [libfreerdp/core/transport.c:861] -> [libfreerdp/core/transport.c:863]: (warning) Either the condition '!transport' is redundant or there is possible null pointer dereference: transport. [server/shadow/shadow_server.c:777] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:778] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:779] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:781] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:782] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:783] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:784] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:785] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:787] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:789] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server.
2017-01-26 12:44:19 +03:00
BOOL invert = FALSE;
2016-08-03 15:16:20 +03:00
if (!xfc)
return 0;
make cppcheck even more happier: [channels/tsmf/client/gstreamer/tsmf_X11.c:317] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:322]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:470] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:472] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/tsmf_media.c:179] -> [channels/tsmf/client/tsmf_media.c:181]: (warning) Either the condition '!stream' is redundant or there is possible null pointer dereference: stream. [client/Windows/wf_cliprdr.c:2219] -> [client/Windows/wf_cliprdr.c:2222]: (warning) Either the condition '!formatDataResponse' is redundant or there is possible null pointer dereference: formatDataResponse [client/Windows/wf_cliprdr.c:2445] -> [client/Windows/wf_cliprdr.c:2448]: (warning) Either the condition '!fileContentsResponse' is redundant or there is possible null pointer dereference: fileContentsResponse. [client/X11/xf_cliprdr.c:911] -> [client/X11/xf_cliprdr.c:913]: (warning) Either the condition '!clipboard' is redundant or there is possible null pointer dereference: clipboard. [client/X11/xf_graphics.c:504] -> [client/X11/xf_graphics.c:506]: (warning) Either the condition '!xfc' is redundant or there is possible null pointer dereference: xfc. [libfreerdp/core/transport.c:861] -> [libfreerdp/core/transport.c:863]: (warning) Either the condition '!transport' is redundant or there is possible null pointer dereference: transport. [server/shadow/shadow_server.c:777] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:778] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:779] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:781] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:782] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:783] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:784] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:785] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:787] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:789] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server.
2017-01-26 12:44:19 +03:00
invert = xfc->invert;
WINPR_ASSERT(xfc->depth != 0);
2016-08-03 15:16:20 +03:00
if (xfc->depth == 32)
2016-08-03 22:22:06 +03:00
DstFormat = (!invert) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_BGRA32;
2022-03-19 15:19:41 +03:00
else if (xfc->depth == 30)
DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32_DEPTH30 : PIXEL_FORMAT_BGRX32_DEPTH30;
2016-08-03 15:16:20 +03:00
else if (xfc->depth == 24)
{
if (aligned)
2016-08-03 22:22:06 +03:00
DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32 : PIXEL_FORMAT_BGRX32;
2016-08-03 15:16:20 +03:00
else
2016-08-03 22:22:06 +03:00
DstFormat = (!invert) ? PIXEL_FORMAT_RGB24 : PIXEL_FORMAT_BGR24;
2016-08-03 15:16:20 +03:00
}
else if (xfc->depth == 16)
2017-01-19 19:14:16 +03:00
DstFormat = PIXEL_FORMAT_RGB16;
2016-08-03 15:16:20 +03:00
else if (xfc->depth == 15)
2017-01-19 19:14:16 +03:00
DstFormat = PIXEL_FORMAT_RGB15;
2016-08-03 15:16:20 +03:00
else
2016-08-03 22:22:06 +03:00
DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32 : PIXEL_FORMAT_BGRX32;
2016-08-03 15:16:20 +03:00
return DstFormat;
}