diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index f1c92ade5..efbe9df46 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1938,11 +1938,21 @@ BOOL xf_setup_x11(xfContext* xfc) Logging_XInternAtom(xfc->log, xfc->display, "_NET_CURRENT_DESKTOP", False); xfc->_NET_WORKAREA = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WORKAREA", False); xfc->_NET_WM_STATE = get_supported_atom(xfc, "_NET_WM_STATE"); - xfc->_NET_WM_STATE_FULLSCREEN = get_supported_atom(xfc, "_NET_WM_STATE_FULLSCREEN"); + xfc->_NET_WM_STATE_MODAL = get_supported_atom(xfc, "_NET_WM_STATE_MODAL"); + xfc->_NET_WM_STATE_STICKY = get_supported_atom(xfc, "_NET_WM_STATE_STICKY"); xfc->_NET_WM_STATE_MAXIMIZED_HORZ = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); xfc->_NET_WM_STATE_MAXIMIZED_VERT = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + xfc->_NET_WM_STATE_SHADED = get_supported_atom(xfc, "_NET_WM_STATE_SHADED"); + xfc->_NET_WM_STATE_SKIP_TASKBAR = get_supported_atom(xfc, "_NET_WM_STATE_SKIP_TASKBAR"); + xfc->_NET_WM_STATE_SKIP_PAGER = get_supported_atom(xfc, "_NET_WM_STATE_SKIP_PAGER"); + xfc->_NET_WM_STATE_HIDDEN = get_supported_atom(xfc, "_NET_WM_STATE_HIDDEN"); + xfc->_NET_WM_STATE_FULLSCREEN = get_supported_atom(xfc, "_NET_WM_STATE_FULLSCREEN"); + xfc->_NET_WM_STATE_ABOVE = get_supported_atom(xfc, "_NET_WM_STATE_ABOVE"); + xfc->_NET_WM_STATE_BELOW = get_supported_atom(xfc, "_NET_WM_STATE_BELOW"); + xfc->_NET_WM_STATE_DEMANDS_ATTENTION = + get_supported_atom(xfc, "_NET_WM_STATE_DEMANDS_ATTENTION"); xfc->_NET_WM_FULLSCREEN_MONITORS = get_supported_atom(xfc, "_NET_WM_FULLSCREEN_MONITORS"); xfc->_NET_WM_NAME = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_NAME", False); xfc->_NET_WM_PID = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_PID", False); diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index d86c06961..049164524 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -273,6 +273,27 @@ BOOL xf_rail_paint(xfContext* xfc, const RECTANGLE_16* rect) return HashTable_Foreach(xfc->railWindows, rail_paint_fn, &arg); } +#define window_state_log_style(log, windowState) \ + window_state_log_style_int((log), (windowState), __FILE__, __func__, __LINE__) +static void window_state_log_style_int(wLog* log, const WINDOW_STATE_ORDER* windowState, + const char* file, const char* fkt, size_t line) +{ + const DWORD log_level = WLOG_DEBUG; + + WINPR_ASSERT(log); + WINPR_ASSERT(windowState); + if (WLog_IsLevelActive(log, log_level)) + { + char buffer1[128] = { 0 }; + char buffer2[128] = { 0 }; + + window_styles_to_string(windowState->style, buffer1, sizeof(buffer1)); + window_styles_ex_to_string(windowState->extendedStyle, buffer2, sizeof(buffer2)); + WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, log_level, line, file, fkt, + "windowStyle={%s, %s}", buffer1, buffer2); + } +} + /* RemoteApp Core Protocol Extension */ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, @@ -296,6 +317,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* appWindow->dwStyle = windowState->style; appWindow->dwExStyle = windowState->extendedStyle; + window_state_log_style(xfc->log, windowState); /* Ensure window always gets a window title */ if (fieldFlags & WINDOW_ORDER_FIELD_TITLE) @@ -390,6 +412,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* { appWindow->dwStyle = windowState->style; appWindow->dwExStyle = windowState->extendedStyle; + window_state_log_style(xfc->log, windowState); } if (fieldFlags & WINDOW_ORDER_FIELD_SHOW) @@ -557,6 +580,9 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* } } + if ((fieldFlags & WINDOW_ORDER_STATE_NEW) == 0) + xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle); + /* We should only be using the visibility rects for shaping the window */ /*if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) { diff --git a/client/X11/xf_utils.c b/client/X11/xf_utils.c index 1fe52a163..e9e28c904 100644 --- a/client/X11/xf_utils.c +++ b/client/X11/xf_utils.c @@ -226,3 +226,13 @@ fail: pclose(keyScript); return rc; } + +const char* x11_error_to_string(xfContext* xfc, int error, char* buffer, size_t size) +{ + WINPR_ASSERT(xfc); + WINPR_ASSERT(size <= INT32_MAX); + const int rc = XGetErrorText(xfc->display, error, buffer, (int)size); + if (rc) + WLog_WARN(TAG, "XGetErrorText returned %d", rc); + return buffer; +} diff --git a/client/X11/xf_utils.h b/client/X11/xf_utils.h index 5da645238..81b020eff 100644 --- a/client/X11/xf_utils.h +++ b/client/X11/xf_utils.h @@ -25,6 +25,8 @@ #include #include "xfreerdp.h" +const char* x11_error_to_string(xfContext* xfc, int error, char* buffer, size_t size); + #define X_GET_ATOM_VAR_NAME(x) #x #define Safe_XGetAtomName(log, display, atom) \ Safe_XGetAtomNameEx((log), (display), (atom), X_GET_ATOM_VAR_NAME(atom)) diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 0516b4569..83ac4f911 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -99,6 +99,10 @@ #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 +#define ENTRY(x) \ + case x: \ + return #x + typedef struct { unsigned long flags; @@ -108,6 +112,114 @@ typedef struct unsigned long status; } PropMotifWmHints; +static void xf_XSetTransientForHint(xfContext* xfc, xfAppWindow* window); + +static const char* window_style_to_string(UINT32 style) +{ + switch (style) + { + ENTRY(WS_NONE); + ENTRY(WS_BORDER); + ENTRY(WS_CAPTION); + ENTRY(WS_CHILD); + ENTRY(WS_CLIPCHILDREN); + ENTRY(WS_CLIPSIBLINGS); + ENTRY(WS_DISABLED); + ENTRY(WS_DLGFRAME); + ENTRY(WS_GROUP); + ENTRY(WS_HSCROLL); + ENTRY(WS_MAXIMIZE); + ENTRY(WS_MAXIMIZEBOX); + ENTRY(WS_MINIMIZE); + ENTRY(WS_OVERLAPPEDWINDOW); + ENTRY(WS_POPUP); + ENTRY(WS_POPUPWINDOW); + ENTRY(WS_SIZEBOX); + ENTRY(WS_SYSMENU); + ENTRY(WS_VISIBLE); + ENTRY(WS_VSCROLL); + default: + return NULL; + } +} + +const char* window_styles_to_string(UINT32 style, char* buffer, size_t length) +{ + (void)_snprintf(buffer, length, "style[0x%08" PRIx32 "] {", style); + const char* sep = ""; + for (size_t x = 0; x < 32; x++) + { + const UINT32 val = 1 << x; + if ((style & val) != 0) + { + const char* str = window_style_to_string(val); + if (str) + { + winpr_str_append(str, buffer, length, sep); + sep = "|"; + } + } + } + winpr_str_append("}", buffer, length, ""); + + return buffer; +} + +static const char* window_style_ex_to_string(UINT32 styleEx) +{ + switch (styleEx) + { + ENTRY(WS_EX_ACCEPTFILES); + ENTRY(WS_EX_APPWINDOW); + ENTRY(WS_EX_CLIENTEDGE); + ENTRY(WS_EX_COMPOSITED); + ENTRY(WS_EX_CONTEXTHELP); + ENTRY(WS_EX_CONTROLPARENT); + ENTRY(WS_EX_DLGMODALFRAME); + ENTRY(WS_EX_LAYERED); + ENTRY(WS_EX_LAYOUTRTL); + ENTRY(WS_EX_LEFTSCROLLBAR); + ENTRY(WS_EX_MDICHILD); + ENTRY(WS_EX_NOACTIVATE); + ENTRY(WS_EX_NOINHERITLAYOUT); + ENTRY(WS_EX_NOPARENTNOTIFY); + ENTRY(WS_EX_OVERLAPPEDWINDOW); + ENTRY(WS_EX_PALETTEWINDOW); + ENTRY(WS_EX_RIGHT); + ENTRY(WS_EX_RIGHTSCROLLBAR); + ENTRY(WS_EX_RTLREADING); + ENTRY(WS_EX_STATICEDGE); + ENTRY(WS_EX_TOOLWINDOW); + ENTRY(WS_EX_TOPMOST); + ENTRY(WS_EX_TRANSPARENT); + ENTRY(WS_EX_WINDOWEDGE); + default: + return NULL; + } +} + +const char* window_styles_ex_to_string(UINT32 styleEx, char* buffer, size_t length) +{ + (void)_snprintf(buffer, length, "styleEx[0x%08" PRIx32 "] {", styleEx); + const char* sep = ""; + for (size_t x = 0; x < 32; x++) + { + const UINT32 val = 1 << x; + if ((styleEx & val) != 0) + { + const char* str = window_style_ex_to_string(val); + if (str) + { + winpr_str_append(str, buffer, length, sep); + sep = "|"; + } + } + } + winpr_str_append("}", buffer, length, ""); + + return buffer; +} + static void xf_SetWindowTitleText(xfContext* xfc, Window window, const char* name) { WINPR_ASSERT(xfc); @@ -749,13 +861,27 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UIN * sees that as a focus out event from the window owning the * dropdown. */ - XSetWindowAttributes attrs; + XSetWindowAttributes attrs = { 0 }; attrs.override_redirect = redirect ? True : False; XChangeWindowAttributes(xfc->display, appWindow->handle, CWOverrideRedirect, &attrs); } LogTagAndXChangeProperty(TAG, xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (BYTE*)&window_type, 1); + + if (ex_style & (WS_EX_CONTROLPARENT | WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME)) + xf_XSetTransientForHint(xfc, appWindow); + + if (((ex_style & WS_EX_TOPMOST) != 0) && ((ex_style & WS_EX_TOOLWINDOW) == 0)) + { + xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD, + xfc->_NET_WM_STATE_ABOVE, 0, 0); + } + else + { + xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_REMOVE, + xfc->_NET_WM_STATE_ABOVE, 0, 0); + } } void xf_SetWindowActions(xfContext* xfc, xfAppWindow* appWindow) @@ -1364,3 +1490,24 @@ BOOL xf_AppWindowResize(xfContext* xfc, xfAppWindow* appWindow) return appWindow->pixmap != 0; } + +void xf_XSetTransientForHint(xfContext* xfc, xfAppWindow* window) +{ + WINPR_ASSERT(xfc); + WINPR_ASSERT(window); + + if (window->ownerWindowId == 0) + return; + + xfAppWindow* parent = xf_rail_get_window(xfc, window->ownerWindowId); + if (!parent) + return; + + const int rc = XSetTransientForHint(xfc->display, window->handle, parent->handle); + if (rc) + { + char buffer[128] = { 0 }; + WLog_WARN(TAG, "XSetTransientForHint [%d]{%s}", rc, + x11_error_to_string(xfc, rc, buffer, sizeof(buffer))); + } +} diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index d30ba81df..314905d63 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -205,4 +205,7 @@ void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow); xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd); +const char* window_styles_to_string(UINT32 style, char* buffer, size_t length); +const char* window_styles_ex_to_string(UINT32 styleEx, char* buffer, size_t length); + #endif /* FREERDP_CLIENT_X11_WINDOW_H */ diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 182c8d3ba..626b9afa4 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -230,11 +230,18 @@ struct xf_context Atom _NET_SUPPORTING_WM_CHECK; Atom _NET_WM_STATE; - Atom _NET_WM_STATE_FULLSCREEN; - Atom _NET_WM_STATE_MAXIMIZED_HORZ; + Atom _NET_WM_STATE_MODAL; + Atom _NET_WM_STATE_STICKY; Atom _NET_WM_STATE_MAXIMIZED_VERT; + Atom _NET_WM_STATE_MAXIMIZED_HORZ; + Atom _NET_WM_STATE_SHADED; Atom _NET_WM_STATE_SKIP_TASKBAR; Atom _NET_WM_STATE_SKIP_PAGER; + Atom _NET_WM_STATE_HIDDEN; + Atom _NET_WM_STATE_FULLSCREEN; + Atom _NET_WM_STATE_ABOVE; + Atom _NET_WM_STATE_BELOW; + Atom _NET_WM_STATE_DEMANDS_ATTENTION; Atom _NET_WM_FULLSCREEN_MONITORS; diff --git a/include/freerdp/window.h b/include/freerdp/window.h index 4f62dfdf4..bc56e59d8 100644 --- a/include/freerdp/window.h +++ b/include/freerdp/window.h @@ -80,9 +80,11 @@ /* Window Styles */ #ifndef _WIN32 +#define WS_NONE 0x00000000 #define WS_BORDER 0x00800000 #define WS_CAPTION 0x00C00000 #define WS_CHILD 0x40000000 +#define WS_CHILDWINDOW 0x40000000 #define WS_CLIPCHILDREN 0x02000000 #define WS_CLIPSIBLINGS 0x04000000 #define WS_DISABLED 0x08000000 @@ -105,10 +107,13 @@ #define WS_THICKFRAME 0x00040000 #define WS_VISIBLE 0x10000000 #define WS_VSCROLL 0x00200000 +#define WS_TILEDWINDOW \ + (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) #endif /* Extended Window Styles */ #ifndef _WIN32 +#define WS_EX_NONE 0x00000000 #define WS_EX_ACCEPTFILES 0x00000010 #define WS_EX_APPWINDOW 0x00040000 #define WS_EX_CLIENTEDGE 0x00000200 @@ -125,6 +130,7 @@ #define WS_EX_NOACTIVATE 0x08000000 #define WS_EX_NOINHERITLAYOUT 0x00100000 #define WS_EX_NOPARENTNOTIFY 0x00000004 +#define WS_EX_NOREDIRECTIONBITMAP 0x00200000 #define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) #define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) #define WS_EX_RIGHT 0x00001000