/** * FreeRDP: A Remote Desktop Protocol Implementation * X11 helper utilities * * Copyright 2023 Armin Novak * 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 #include #include #include #include "xf_utils.h" #include "xfreerdp.h" #include #include #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); }