Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,769 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* X11 helper utilities
*
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
* Copyringht 2023 Thincast Technologies GmbH
*
* 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.
*/
#include <string.h>
#include <winpr/assert.h>
#include <winpr/wtypes.h>
#include <winpr/path.h>
#include "xf_utils.h"
#include "xfreerdp.h"
#include <freerdp/utils/helpers.h>
#include <freerdp/log.h>
#define TAG CLIENT_TAG("xfreerdp.utils")
static const DWORD log_level = WLOG_TRACE;
static const char* error_to_string(wLog* log, Display* display, int error, char* buffer,
size_t size)
{
WINPR_ASSERT(size <= INT32_MAX);
const int rc = XGetErrorText(display, error, buffer, (int)size);
if (rc != Success)
WLog_Print(log, WLOG_WARN, "XGetErrorText returned %d", rc);
return buffer;
}
WINPR_ATTR_FORMAT_ARG(6, 7)
static void write_log(wLog* log, DWORD level, const char* fname, const char* fkt, size_t line,
WINPR_FORMAT_ARG const char* fmt, ...)
{
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, fmt);
WLog_PrintTextMessageVA(log, level, line, fname, fkt, fmt, ap);
va_end(ap);
}
static BOOL ignore_code(int rc, size_t count, va_list ap)
{
for (size_t x = 0; x < count; x++)
{
const int val = va_arg(ap, int);
if (rc == val)
return TRUE;
}
return FALSE;
}
/* libx11 return codes are not really well documented, so checked against
* https://gitlab.freedesktop.org/xorg/lib/libx11.git */
static int write_result_log_va(wLog* log, DWORD level, const char* fname, const char* fkt,
size_t line, Display* display, char* name, int rc, size_t count,
va_list ap)
{
const BOOL ignore = ignore_code(rc, count, ap);
if (!ignore)
{
char buffer[128] = WINPR_C_ARRAY_INIT;
if (WLog_IsLevelActive(log, level))
{
WLog_PrintTextMessage(log, level, line, fname, fkt, "%s returned %s", name,
error_to_string(log, display, rc, buffer, sizeof(buffer)));
}
}
return rc;
}
static int write_result_log_expect_success(wLog* log, DWORD level, const char* fname,
const char* fkt, size_t line, Display* display,
char* name, int rc)
{
if (rc != Success)
{
va_list ap = WINPR_C_ARRAY_INIT;
(void)write_result_log_va(log, level, fname, fkt, line, display, name, rc, 0, ap);
}
return rc;
}
static int write_result_log_expect_one(wLog* log, DWORD level, const char* fname, const char* fkt,
size_t line, Display* display, char* name, int rc)
{
if (rc != 1)
{
va_list ap = WINPR_C_ARRAY_INIT;
(void)write_result_log_va(log, level, fname, fkt, line, display, name, rc, 0, ap);
}
return rc;
}
char* Safe_XGetAtomNameEx(wLog* log, Display* display, Atom atom, const char* varname)
{
WLog_Print(log, log_level, "XGetAtomName(%s, 0x%08lx)", varname, atom);
if (atom == None)
return strdup("Atom_None");
return XGetAtomName(display, atom);
}
Atom Logging_XInternAtom(wLog* log, Display* display, _Xconst char* atom_name, Bool only_if_exists)
{
Atom atom = XInternAtom(display, atom_name, only_if_exists);
if (WLog_IsLevelActive(log, log_level))
{
WLog_Print(log, log_level, "XInternAtom(%p, %s, %s) -> 0x%08" PRIx32, (void*)display,
atom_name, only_if_exists ? "True" : "False",
WINPR_CXX_COMPAT_CAST(UINT32, atom));
}
return atom;
}
const char* x11_error_to_string(xfContext* xfc, int error, char* buffer, size_t size)
{
WINPR_ASSERT(xfc);
return error_to_string(xfc->log, xfc->display, error, buffer, size);
}
int LogDynAndXChangeProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, Atom property, Atom type, int format,
int mode, const unsigned char* data, int nelements)
{
if (WLog_IsLevelActive(log, log_level))
{
char* propstr = Safe_XGetAtomName(log, display, property);
char* typestr = Safe_XGetAtomName(log, display, type);
write_log(log, log_level, file, fkt, line,
"XChangeProperty(%p, %lu, %s [%lu], %s [%lu], %d, %d, %p, %d)", (void*)display, w,
propstr, property, typestr, type, format, mode, (const void*)data, nelements);
XFree(propstr);
XFree(typestr);
}
const int rc = XChangeProperty(display, w, property, type, format, mode, data, nelements);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XChangeProperty",
rc);
}
int LogDynAndXDeleteProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, Atom property)
{
if (WLog_IsLevelActive(log, log_level))
{
char* propstr = Safe_XGetAtomName(log, display, property);
write_log(log, log_level, file, fkt, line, "XDeleteProperty(%p, %lu, %s [%lu])",
(void*)display, w, propstr, property);
XFree(propstr);
}
const int rc = XDeleteProperty(display, w, property);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XDeleteProperty",
rc);
}
int LogDynAndXConvertSelection_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Atom selection, Atom target, Atom property,
Window requestor, Time time)
{
if (WLog_IsLevelActive(log, log_level))
{
char* selectstr = Safe_XGetAtomName(log, display, selection);
char* targetstr = Safe_XGetAtomName(log, display, target);
char* propstr = Safe_XGetAtomName(log, display, property);
write_log(log, log_level, file, fkt, line,
"XConvertSelection(%p, %s [%lu], %s [%lu], %s [%lu], %lu, %lu)", (void*)display,
selectstr, selection, targetstr, target, propstr, property, requestor, time);
XFree(propstr);
XFree(targetstr);
XFree(selectstr);
}
const int rc = XConvertSelection(display, selection, target, property, requestor, time);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
"XConvertSelection", rc);
}
int LogDynAndXGetWindowProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, Atom property, long long_offset,
long long_length, int c_delete, Atom req_type,
Atom* actual_type_return, int* actual_format_return,
unsigned long* nitems_return, unsigned long* bytes_after_return,
unsigned char** prop_return)
{
if (WLog_IsLevelActive(log, log_level))
{
char* propstr = Safe_XGetAtomName(log, display, property);
char* req_type_str = Safe_XGetAtomName(log, display, req_type);
write_log(
log, log_level, file, fkt, line,
"XGetWindowProperty(%p, %lu, %s [%lu], %ld, %ld, %d, %s [%lu], %p, %p, %p, %p, %p)",
(void*)display, w, propstr, property, long_offset, long_length, c_delete, req_type_str,
req_type, (void*)actual_type_return, (void*)actual_format_return, (void*)nitems_return,
(void*)bytes_after_return, (void*)prop_return);
XFree(propstr);
XFree(req_type_str);
}
const int rc = XGetWindowProperty(display, w, property, long_offset, long_length, c_delete,
req_type, actual_type_return, actual_format_return,
nitems_return, bytes_after_return, prop_return);
return write_result_log_expect_success(log, WLOG_WARN, file, fkt, line, display,
"XGetWindowProperty", rc);
}
BOOL IsGnome(void)
{
// NOLINTNEXTLINE(concurrency-mt-unsafe)
char* env = getenv("DESKTOP_SESSION");
return (env != nullptr && strcmp(env, "gnome") == 0);
}
BOOL run_action_script(xfContext* xfc, const char* what, const char* arg, fn_action_script_run fkt,
void* user)
{
BOOL rc = FALSE;
FILE* keyScript = nullptr;
WINPR_ASSERT(xfc);
rdpSettings* settings = xfc->common.context.settings;
WINPR_ASSERT(settings);
const char* ActionScript = freerdp_settings_get_string(settings, FreeRDP_ActionScript);
xfc->actionScriptExists = winpr_PathFileExists(ActionScript);
if (!xfc->actionScriptExists)
{
WLog_DBG(TAG, "[ActionScript] no such script '%s'", ActionScript);
goto fail;
}
{
char command[2048] = WINPR_C_ARRAY_INIT;
(void)sprintf_s(command, sizeof(command), "%s %s", ActionScript, what);
keyScript = popen(command, "r");
if (!keyScript)
{
WLog_ERR(TAG, "[ActionScript] Failed to execute '%s'", command);
goto fail;
}
{
BOOL read_data = FALSE;
char buffer[2048] = WINPR_C_ARRAY_INIT;
while (fgets(buffer, sizeof(buffer), keyScript) != nullptr)
{
char* context = nullptr;
(void)strtok_s(buffer, "\n", &context);
if (fkt)
{
if (!fkt(xfc, buffer, strnlen(buffer, sizeof(buffer)), user, what, arg))
goto fail;
}
read_data = TRUE;
}
rc = read_data;
}
if (!rc)
WLog_ERR(TAG, "[ActionScript] No data returned from command '%s'", command);
}
fail:
if (keyScript)
pclose(keyScript);
const BOOL res = rc || !xfc->actionScriptExists;
if (!rc)
xfc->actionScriptExists = FALSE;
return res;
}
int LogDynAndXCopyArea_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Pixmap src, Window dest, GC gc, int src_x, int src_y,
unsigned int width, unsigned int height, int dest_x, int dest_y)
{
if (WLog_IsLevelActive(log, log_level))
{
XWindowAttributes attr = WINPR_C_ARRAY_INIT;
const Status rc = XGetWindowAttributes(display, dest, &attr);
write_log(log, log_level, file, fkt, line,
"XCopyArea(%p, src: {%lu}, dest: [%d]{%lu, %lu, %d}, gc: {%p}, src_x: {%d}, "
"src_y: {%d}, "
"width: {%u}, "
"height: {%u}, dest_x: {%d}, dest_y: {%d})",
(void*)display, src, rc, dest, attr.root, attr.depth, (void*)gc, src_x, src_y,
width, height, dest_x, dest_y);
}
if ((width == 0) || (height == 0))
{
const DWORD lvl = WLOG_WARN;
if (WLog_IsLevelActive(log, lvl))
write_log(log, lvl, file, fkt, line, "XCopyArea(width=%u, height=%u) !", width, height);
return Success;
}
const int rc = XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XCopyArea", rc);
}
int LogDynAndXPutImage_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Drawable d, GC gc, XImage* image, int src_x, int src_y,
int dest_x, int dest_y, unsigned int width, unsigned int height)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line,
"XPutImage(%p, d: {%lu}, gc: {%p}, image: [%p]{%d}, src_x: {%d}, src_y: {%d}, "
"dest_x: {%d}, "
"dest_y: {%d}, width: {%u}, "
"height: {%u})",
(void*)display, d, (void*)gc, (void*)image, image ? image->depth : -1, src_x,
src_y, dest_x, dest_y, width, height);
}
if ((width == 0) || (height == 0))
{
const DWORD lvl = WLOG_WARN;
if (WLog_IsLevelActive(log, lvl))
write_log(log, lvl, file, fkt, line, "XPutImage(width=%u, height=%u) !", width, height);
return Success;
}
const int rc = XPutImage(display, d, gc, image, src_x, src_y, dest_x, dest_y, width, height);
return write_result_log_expect_success(log, WLOG_WARN, file, fkt, line, display, "XPutImage",
rc);
}
/* be careful here.
* XSendEvent returns Status, but implementation always returns 1
*/
Status LogDynAndXSendEvent_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, int propagate, long event_mask,
XEvent* event_send)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line,
"XSendEvent(d: {%p}, w: {%lu}, propagate: {%d}, event_mask: {%ld}, "
"event_send: [%p]{TODO})",
(void*)display, w, propagate, event_mask, (void*)event_send);
}
const int rc = XSendEvent(display, w, propagate, event_mask, event_send);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSendEvent", rc);
}
int LogDynAndXFlush_ex(wLog* log, const char* file, const char* fkt, size_t line, Display* display)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XFlush(%p)", (void*)display);
}
const int rc = XFlush(display);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFlush", rc);
}
Window LogDynAndXGetSelectionOwner_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Atom selection)
{
if (WLog_IsLevelActive(log, log_level))
{
char* selectionstr = Safe_XGetAtomName(log, display, selection);
write_log(log, log_level, file, fkt, line, "XGetSelectionOwner(%p, %s)", (void*)display,
selectionstr);
XFree(selectionstr);
}
return XGetSelectionOwner(display, selection);
}
int LogDynAndXDestroyWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window window)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XDestroyWindow(%p, %lu)", (void*)display,
window);
}
const int rc = XDestroyWindow(display, window);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XDestroyWindow",
rc);
}
int LogDynAndXSync_ex(wLog* log, const char* file, const char* fkt, size_t line, Display* display,
Bool discard)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSync(%p, %d)", (void*)display, discard);
}
const int rc = XSync(display, discard);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSync", rc);
}
int LogDynAndXChangeWindowAttributes_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window window, unsigned long valuemask,
XSetWindowAttributes* attributes)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XChangeWindowAttributes(%p, %lu, 0x%08lu, %p)",
(void*)display, window, valuemask, (void*)attributes);
}
const int rc = XChangeWindowAttributes(display, window, valuemask, attributes);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
"XChangeWindowAttributes", rc);
}
int LogDynAndXSetTransientForHint_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window window, Window prop_window)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSetTransientForHint(%p, %lu, %lu)",
(void*)display, window, prop_window);
}
const int rc = XSetTransientForHint(display, window, prop_window);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
"XSetTransientForHint", rc);
}
int LogDynAndXCloseDisplay_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XCloseDisplay(%p)", (void*)display);
}
const int rc = XCloseDisplay(display);
return write_result_log_expect_success(log, WLOG_WARN, file, fkt, line, display,
"XCloseDisplay", rc);
}
XImage* LogDynAndXCreateImage_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Visual* visual, unsigned int depth, int format,
int offset, char* data, unsigned int width, unsigned int height,
int bitmap_pad, int bytes_per_line)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XCreateImage(%p)", (void*)display);
}
return XCreateImage(display, visual, depth, format, offset, data, width, height, bitmap_pad,
bytes_per_line);
}
Window LogDynAndXCreateWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window parent, int x, int y, unsigned int width,
unsigned int height, unsigned int border_width, int depth,
unsigned int c_class, Visual* visual, unsigned long valuemask,
XSetWindowAttributes* attributes)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XCreateWindow(%p)", (void*)display);
}
return XCreateWindow(display, parent, x, y, width, height, border_width, depth, c_class, visual,
valuemask, attributes);
}
GC LogDynAndXCreateGC_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Drawable d, unsigned long valuemask, XGCValues* values)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XCreateGC(%p)", (void*)display);
}
return XCreateGC(display, d, valuemask, values);
}
int LogDynAndXFreeGC_ex(wLog* log, const char* file, const char* fkt, size_t line, Display* display,
GC gc)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XFreeGC(%p)", (void*)display);
}
const int rc = XFreeGC(display, gc);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFreeGC", rc);
}
Pixmap LogDynAndXCreatePixmap_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Drawable d, unsigned int width,
unsigned int height, unsigned int depth)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XCreatePixmap(%p, 0x%08lu, %u, %u, %u)",
(void*)display, d, width, height, depth);
}
return XCreatePixmap(display, d, width, height, depth);
}
int LogDynAndXFreePixmap_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Pixmap pixmap)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XFreePixmap(%p)", (void*)display);
}
const int rc = XFreePixmap(display, pixmap);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFreePixmap", rc);
}
int LogDynAndXSetSelectionOwner_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Atom selection, Window owner, Time time)
{
if (WLog_IsLevelActive(log, log_level))
{
char* selectionstr = Safe_XGetAtomName(log, display, selection);
write_log(log, log_level, file, fkt, line, "XSetSelectionOwner(%p, %s, 0x%08lu, %lu)",
(void*)display, selectionstr, owner, time);
XFree(selectionstr);
}
const int rc = XSetSelectionOwner(display, selection, owner, time);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
"XSetSelectionOwner", rc);
}
int LogDynAndXSetForeground_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, GC gc, unsigned long foreground)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSetForeground(%p, %p, 0x%08lu)",
(void*)display, (void*)gc, foreground);
}
const int rc = XSetForeground(display, gc, foreground);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetForeground",
rc);
}
int LogDynAndXMoveWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, int x, int y)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XMoveWindow(%p, 0x%08lu, %d, %d)",
(void*)display, w, x, y);
}
const int rc = XMoveWindow(display, w, x, y);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XMoveWindow", rc);
}
int LogDynAndXSetFillStyle_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, GC gc, int fill_style)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSetFillStyle(%p, %p, %d)", (void*)display,
(void*)gc, fill_style);
}
const int rc = XSetFillStyle(display, gc, fill_style);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetFillStyle",
rc);
}
int LogDynAndXSetFunction_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, GC gc, int function)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSetFunction(%p, %p, %d)", (void*)display,
(void*)gc, function);
}
const int rc = XSetFunction(display, gc, function);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetFunction",
rc);
}
int LogDynAndXRaiseWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XRaiseWindow(%p, %lu)", (void*)display, w);
}
const int rc = XRaiseWindow(display, w);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XRaiseWindow",
rc);
}
int LogDynAndXMapWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XMapWindow(%p, %lu)", (void*)display, w);
}
const int rc = XMapWindow(display, w);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XMapWindow", rc);
}
int LogDynAndXUnmapWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XUnmapWindow(%p, %lu)", (void*)display, w);
}
const int rc = XUnmapWindow(display, w);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XUnmapWindow",
rc);
}
int LogDynAndXMoveResizeWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, int x, int y, unsigned int width,
unsigned int height)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XMoveResizeWindow(%p, %lu, %d, %d, %u, %u)",
(void*)display, w, x, y, width, height);
}
const int rc = XMoveResizeWindow(display, w, x, y, width, height);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display,
"XMoveResizeWindow", rc);
}
Status LogDynAndXWithdrawWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, int screen_number)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XWithdrawWindow(%p, %lu, %d)", (void*)display,
w, screen_number);
}
const Status rc = XWithdrawWindow(display, w, screen_number);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XWithdrawWindow",
rc);
}
int LogDynAndXResizeWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, unsigned int width, unsigned int height)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XResizeWindow(%p, %lu, %u, %u)", (void*)display,
w, width, height);
}
const int rc = XResizeWindow(display, w, width, height);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XResizeWindow",
rc);
}
int LogDynAndXClearWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XClearWindow(%p, %lu)", (void*)display, w);
}
const int rc = XClearWindow(display, w);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XClearWindow",
rc);
}
int LogDynAndXSetBackground_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, GC gc, unsigned long background)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSetBackground(%p, %p, %lu)", (void*)display,
(void*)gc, background);
}
const int rc = XSetBackground(display, gc, background);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetBackground",
rc);
}
int LogDynAndXSetClipMask_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, GC gc, Pixmap pixmap)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSetClipMask(%p, %p, %lu)", (void*)display,
(void*)gc, pixmap);
}
const int rc = XSetClipMask(display, gc, pixmap);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetClipMask",
rc);
}
int LogDynAndXFillRectangle_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, GC gc, int x, int y, unsigned int width,
unsigned int height)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XFillRectangle(%p, %lu, %p, %d, %d, %u, %u)",
(void*)display, w, (void*)gc, x, y, width, height);
}
const int rc = XFillRectangle(display, w, gc, x, y, width, height);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XFillRectangle",
rc);
}
int LogDynAndXSetRegion_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, GC gc, Region r)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XSetRegion(%p, %p, %p)", (void*)display,
(void*)gc, (void*)r);
}
const int rc = XSetRegion(display, gc, r);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XSetRegion", rc);
}
int LogDynAndXReparentWindow_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, Window parent, int x, int y)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XReparentWindow(%p, %lu, %lu, %d, %d)",
(void*)display, w, parent, x, y);
}
const int rc = XReparentWindow(display, w, parent, x, y);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XReparentWindow",
rc);
}
char* getConfigOption(BOOL system, const char* option)
{
char* res = nullptr;
WINPR_JSON* file = freerdp_GetJSONConfigFile(system, "xfreerdp.json");
if (!file)
return nullptr;
WINPR_JSON* obj = WINPR_JSON_GetObjectItemCaseSensitive(file, option);
if (obj)
{
const char* val = WINPR_JSON_GetStringValue(obj);
if (val)
res = _strdup(val);
}
WINPR_JSON_Delete(file);
return res;
}
int LogDynAndXRestackWindows_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window* windows, int nwindows)
{
if (WLog_IsLevelActive(log, log_level))
{
write_log(log, log_level, file, fkt, line, "XRestackWindows(%p, %p, %d)", (void*)display,
(const void*)windows, nwindows);
}
const int rc = XRestackWindows(display, windows, nwindows);
return write_result_log_expect_one(log, WLOG_WARN, file, fkt, line, display, "XRestackWindows",
rc);
}