Merge pull request #10629 from akallabeth/rail-modal

[client,X11] Fix RAILS modal dialog handling
This commit is contained in:
Norbert Federa 2024-09-20 13:38:46 +02:00 committed by GitHub
commit d3a7629734
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 215 additions and 4 deletions

View File

@ -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);

View File

@ -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)
{

View File

@ -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;
}

View File

@ -25,6 +25,8 @@
#include <X11/Xlib.h>
#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))

View File

@ -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)));
}
}

View File

@ -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 */

View File

@ -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;

View File

@ -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