FreeRDP / FreeRDP

FreeRDP is a free remote desktop protocol library and clients

Home Page:http://www.freerdp.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Popup menus and window actions do not work correctly in RemoteApp

toreonify opened this issue · comments

Describe the bug

  • Context menus in some applications disappear almost instantly, cannot use then (issues #2662, #1528, #4660)
  • Window state and allowed actions are not syncronized correctly with Windows side

To Reproduce
Steps to reproduce the behavior (context menus):

  1. Connect to Windows Server with 1C 8.3 through RemoteApp
  2. Open 1C client
  3. Try to open context menu in database list with right mouse click

Steps to reproduce the behavior (window state):

  1. Connect to Windows Server through RemoteApp
  2. Open some application, for example Task Manager
  3. Maximize window by clicking "maximize" in titlebar
  4. Restore windows by clicking "restore" in titlebar
  5. Switch to any other window

Steps to reproduce the behavior (allowed actions):

  1. Connect to Windows Server with 1C 8.3 through RemoteApp
  2. Open 1C client
  3. Ensure that only close action is available on titlebar and in titlebar context menu.
  4. Maximize window through context menu in taskbar.

Expected behavior
Context menus: menus are shown on screen and do not disappear.

Window state: window stays "restored", not maximizing on its own.

Allowed actions: actions are identical to actions in Windows titlebar context menu.

Screenshots

Videos were recored earlier, but the same happens on later versions.

1-dropdown-menu.mp4
2-maximize-window.mp4
3-incorrect-actions.mp4

Application details

  • FreeRDP version: 2.10.0, 2.11.1, 2.11.7, 3.5.0
  • Command line used: xfreerdp /v: /u: /app:"||1cestart"
  • Output of xfreerdp /buildconfig:
This is FreeRDP version 2.11.7 (2.11.7)
Build configuration: BUILD_TESTING=OFF BUILTIN_CHANNELS=OFF HAVE_AIO_H=1 HAVE_EXECINFO_BACKTRACE=1 HAVE_EXECINFO_BACKTRACE_SYMBOLS=1 HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD=1 HAVE_EXECINFO_H=ON HAVE_EXECINFO_HEADER=1 HAVE_FCNTL_H=1 HAVE_GETLOGIN_R=1 HAVE_GETPWUID_R=1 HAVE_INTTYPES_H=1 HAVE_JOURNALD_H=TRUE HAVE_MATH_C99_LONG_DOUBLE=1 HAVE_PIXMAN_REGION=OFF HAVE_POLL_H=1 HAVE_PTHREAD_MUTEX_TIMEDLOCK=ON HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB=1 HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL= HAVE_SYSLOG_H=1 HAVE_SYS_EVENTFD_H=1 HAVE_SYS_FILIO_H= HAVE_SYS_MODEM_H= HAVE_SYS_SELECT_H=1 HAVE_SYS_SOCKIO_H= HAVE_SYS_STRTIO_H= HAVE_SYS_TIMERFD_H=1 HAVE_TM_GMTOFF=1 HAVE_UNISTD_H=1 HAVE_XI_TOUCH_CLASS=1 WITH_ALSA=ON WITH_CAIRO=ON WITH_CCACHE=ON WITH_CHANNELS=ON WITH_CLANG_FORMAT=ON WITH_CLIENT=ON WITH_CLIENT_AVAILABLE=1 WITH_CLIENT_CHANNELS=ON WITH_CLIENT_CHANNELS_AVAILABLE=1 WITH_CLIENT_COMMON=ON WITH_CLIENT_INTERFACE=OFF WITH_CUPS=ON WITH_DEBUG_ALL=OFF WITH_DEBUG_CAPABILITIES=OFF WITH_DEBUG_CERTIFICATE=OFF WITH_DEBUG_CHANNELS=OFF WITH_DEBUG_CLIPRDR=OFF WITH_DEBUG_DVC=OFF WITH_DEBUG_KBD=OFF WITH_DEBUG_LICENSE=OFF WITH_DEBUG_MUTEX=OFF WITH_DEBUG_NEGO=OFF WITH_DEBUG_NLA=OFF WITH_DEBUG_NTLM=OFF WITH_DEBUG_RAIL=OFF WITH_DEBUG_RDP=OFF WITH_DEBUG_RDPDR=OFF WITH_DEBUG_RDPEI=OFF WITH_DEBUG_RDPGFX=OFF WITH_DEBUG_REDIR=OFF WITH_DEBUG_RFX=OFF WITH_DEBUG_RINGBUFFER=OFF WITH_DEBUG_SCARD=OFF WITH_DEBUG_SND=OFF WITH_DEBUG_SVC=OFF WITH_DEBUG_SYMBOLS=OFF WITH_DEBUG_THREADS=OFF WITH_DEBUG_TIMEZONE=OFF WITH_DEBUG_TRANSPORT=OFF WITH_DEBUG_TSG=OFF WITH_DEBUG_TSMF=OFF WITH_DEBUG_TSMF=OFF WITH_DEBUG_TSMF_AVAILABLE=0 WITH_DEBUG_URBDRC=OFF WITH_DEBUG_WND=OFF WITH_DEBUG_X11=OFF WITH_DEBUG_X11_CLIPRDR=OFF WITH_DEBUG_X11_LOCAL_MOVESIZE=OFF WITH_DEBUG_XV=OFF WITH_DIRECTFB=OFF WITH_DSP_EXPERIMENTAL=OFF WITH_DSP_FFMPEG=OFF WITH_EVENTFD_READ_WRITE=1 WITH_FAAC=ON WITH_FAAD2=ON WITH_FFMPEG=TRUE WITH_FFMPEG=TRUE WITH_GFX_H264=ON WITH_GPROF=OFF WITH_GSM=ON WITH_GSSAPI=OFF WITH_GSTREAMER_1_0=ON WITH_ICU=ON WITH_INTERNAL_MD4=OFF WITH_INTERNAL_MD5=OFF WITH_IPP=OFF WITH_JPEG=ON WITH_KERBEROS=OFF WITH_LAME=ON WITH_LIBRARY_VERSIONING=ON WITH_LIBRARY_VERSIONING=ON WITH_LIBSYSTEMD=ON WITH_MACAUDIO=OFF WITH_MACAUDIO=OFF WITH_MACAUDIO_AVAILABLE=0 WITH_MANPAGES=ON WITH_MBEDTLS=OFF WITH_OPENCL=OFF WITH_OPENH264=OFF WITH_OPENSLES=OFF WITH_OPENSSL=ON WITH_OSS=ON WITH_PAM=ON WITH_PCSC=ON WITH_PROFILER=OFF WITH_PROXY=ON WITH_PROXY_MODULES=OFF WITH_PULSE=ON WITH_SAMPLE=OFF WITH_SANITIZE_ADDRESS=OFF WITH_SANITIZE_ADDRESS_AVAILABLE=1 WITH_SANITIZE_MEMORY=OFF WITH_SANITIZE_MEMORY_AVAILABLE=1 WITH_SANITIZE_THREAD=OFF WITH_SANITIZE_THREAD_AVAILABLE=1 WITH_SERVER=ON WITH_SERVER_CHANNELS=ON WITH_SERVER_INTERFACE=ON WITH_SHADOW=ON WITH_SHADOW_MAC=ON WITH_SHADOW_X11=ON WITH_SMARTCARD_INSPECT=OFF WITH_SOXR=ON WITH_SSE2=ON WITH_SWSCALE=OFF WITH_THIRD_PARTY=OFF WITH_VAAPI=ON WITH_VALGRIND_MEMCHECK=OFF WITH_VALGRIND_MEMCHECK_AVAILABLE=1 WITH_VERBOSE_WINPR_ASSERT=ON WITH_WAYLAND=ON WITH_WINPR_TOOLS=ON WITH_X11=ON WITH_X264=OFF WITH_XCURSOR=ON WITH_XDAMAGE=ON WITH_XEXT=ON WITH_XFIXES=ON WITH_XI=ON WITH_XINERAMA=ON WITH_XKBFILE=ON WITH_XRANDR=ON WITH_XRENDER=ON WITH_XSHM=ON WITH_XTEST=ON WITH_XV=ON WITH_ZLIB=ON
Build type:          Release
CFLAGS:              -pipe -frecord-gcc-switches -Wall -g -O2 -fPIC -Wall -Wno-unused-result -Wno-unused-but-set-variable -Wno-deprecated-declarations -fvisibility=hidden -Wimplicit-function-declaration -Wredundant-decls -fno-omit-frame-pointer -DWINPR_DLL
Compiler:            GNU, 10.3.1
Target architecture: x64
  • OS version connecting to (server side): Windows Server 2008 R2

Environment:

  • OS: Linux, KDE Plasma DE
  • Version/Distribution: ALT Linux Workstation K 10.3, latest update from 02.05.2024
  • Architecture: x86_64

Additional context
On Windows Server 2008 R2 Task Manager window has WS_POPUP flag but on Windows Server 2012 R2 doesn't.

Provided patch for 2.10.0 fixes described problems (though, not tested on many apps).

diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c
index bd3eb0d56..44092fac3 100644
--- a/client/X11/xf_client.c
+++ b/client/X11/xf_client.c
@@ -1998,6 +1998,17 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
 	xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False);
 	xfc->x11event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds, WINPR_FD_READ);
 
+	xfc->_NET_WM_ALLOWED_ACTIONS = XInternAtom(xfc->display, "_NET_WM_ALLOWED_ACTIONS", False);
+
+	xfc->_NET_WM_ACTION_CLOSE = XInternAtom(xfc->display, "_NET_WM_ACTION_CLOSE", False);
+	xfc->_NET_WM_ACTION_MINIMIZE = XInternAtom(xfc->display, "_NET_WM_ACTION_MINIMIZE", False);
+	xfc->_NET_WM_ACTION_MOVE = XInternAtom(xfc->display, "_NET_WM_ACTION_MOVE", False);
+	xfc->_NET_WM_ACTION_RESIZE = XInternAtom(xfc->display, "_NET_WM_ACTION_RESIZE", False);
+	xfc->_NET_WM_ACTION_MAXIMIZE_HORZ = XInternAtom(xfc->display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
+	xfc->_NET_WM_ACTION_MAXIMIZE_VERT = XInternAtom(xfc->display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
+	xfc->_NET_WM_ACTION_FULLSCREEN = XInternAtom(xfc->display, "_NET_WM_ACTION_FULLSCREEN", False);
+	xfc->_NET_WM_ACTION_CHANGE_DESKTOP = XInternAtom(xfc->display, "_NET_WM_ACTION_CHANGE_DESKTOP", False);
+
 	if (!xfc->x11event)
 	{
 		WLog_ERR(TAG, "Could not create xfds event");
diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c
index 090f599a0..b981ba4a7 100644
--- a/client/X11/xf_rail.c
+++ b/client/X11/xf_rail.c
@@ -97,8 +97,6 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
 
 	if (enabled)
 		xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
-	else
-		xf_SetWindowStyle(xfc, appWindow, 0, 0);
 
 	activate.windowId = appWindow->windowId;
 	activate.enabled = enabled;
@@ -518,6 +516,12 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO*
 			                            visibilityRectsOffsetY, appWindow->visibilityRects,
 			                            appWindow->numVisibilityRects);
 		}
+
+		if (appWindow->rail_state == WINDOW_SHOW_MAXIMIZED)
+		{
+			xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD,
+			   xfc->_NET_WM_STATE_MAXIMIZED_VERT, xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0, 0);
+		}
 	}
 
 	/* We should only be using the visibility rects for shaping the window */
diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c
index 9b5b1c4a6..25910b954 100644
--- a/client/X11/xf_window.c
+++ b/client/X11/xf_window.c
@@ -654,6 +654,8 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UIN
 	Atom window_type;
 	BOOL redirect = FALSE;
 
+	window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL;
+
 	if ((ex_style & WS_EX_NOACTIVATE) || (ex_style & WS_EX_TOOLWINDOW))
 	{
 		redirect = TRUE;
@@ -669,16 +671,24 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UIN
 	{
 		window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL;
 	}
-	else if (style & WS_POPUP)
+
+	if (style & WS_POPUP)
 	{
-		/* this includes dialogs, popups, etc, that need to be full-fledged windows */
-		appWindow->is_transient = TRUE;
 		window_type = xfc->_NET_WM_WINDOW_TYPE_DIALOG;
-		xf_SetWindowUnlisted(xfc, appWindow->handle);
+		/* this includes dialogs, popups, etc, that need to be full-fledged windows */
+
+		if (!((ex_style & WS_EX_DLGMODALFRAME) || (ex_style & WS_EX_LAYERED) || (style & WS_SYSMENU)))
+		{
+			appWindow->is_transient = TRUE;
+			redirect = TRUE;
+
+			xf_SetWindowUnlisted(xfc, appWindow->handle);
+		}
 	}
-	else
+
+	if (!(style == 0 && ex_style == 0))
 	{
-		window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL;
+		xf_SetWindowActions(xfc, appWindow);
 	}
 
 	{
@@ -700,6 +710,39 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UIN
 	                PropModeReplace, (BYTE*)&window_type, 1);
 }
 
+void xf_SetWindowActions(xfContext* xfc, xfAppWindow* appWindow)
+{
+	Atom allowed_actions[] = {
+		xfc->_NET_WM_ACTION_CLOSE,
+		xfc->_NET_WM_ACTION_MINIMIZE,
+		xfc->_NET_WM_ACTION_MOVE,
+		xfc->_NET_WM_ACTION_RESIZE,
+		xfc->_NET_WM_ACTION_MAXIMIZE_HORZ,
+		xfc->_NET_WM_ACTION_MAXIMIZE_VERT,
+		xfc->_NET_WM_ACTION_FULLSCREEN,
+		xfc->_NET_WM_ACTION_CHANGE_DESKTOP
+	};
+
+	if (!(appWindow->dwStyle & WS_SYSMENU))
+		allowed_actions[0] = 0;
+
+	if (!(appWindow->dwStyle & WS_MINIMIZEBOX))
+		allowed_actions[1] = 0;
+
+	if (!(appWindow->dwStyle & WS_SIZEBOX))
+		allowed_actions[3] = 0;
+
+	if (!(appWindow->dwStyle & WS_MAXIMIZEBOX))
+	{
+		allowed_actions[4] = 0;
+		allowed_actions[5] = 0;
+		allowed_actions[6] = 0;
+	}
+
+	XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_ALLOWED_ACTIONS, XA_ATOM, 32,
+		PropModeReplace, (unsigned char *) &allowed_actions, 8);
+}
+
 void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, const char* name)
 {
 	xf_SetWindowTitleText(xfc, appWindow->handle, name);
diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h
index 0f85af1d2..b9bb5deeb 100644
--- a/client/X11/xf_window.h
+++ b/client/X11/xf_window.h
@@ -179,6 +179,7 @@ void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rec
 void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX,
                                  UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects);
 void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style);
+void xf_SetWindowActions(xfContext* xfc, xfAppWindow* appWindow);
 void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width,
                          int height);
 void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow);
diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h
index 636e60ad1..514d7597e 100644
--- a/client/X11/xfreerdp.h
+++ b/client/X11/xfreerdp.h
@@ -245,6 +245,18 @@ struct xf_context
 	Atom WM_PROTOCOLS;
 	Atom WM_DELETE_WINDOW;
 
+	/* Allow actions */
+	Atom _NET_WM_ALLOWED_ACTIONS;
+
+	Atom _NET_WM_ACTION_CLOSE;
+	Atom _NET_WM_ACTION_MINIMIZE;
+	Atom _NET_WM_ACTION_MOVE;
+	Atom _NET_WM_ACTION_RESIZE;
+	Atom _NET_WM_ACTION_MAXIMIZE_HORZ;
+	Atom _NET_WM_ACTION_MAXIMIZE_VERT;
+	Atom _NET_WM_ACTION_FULLSCREEN;
+	Atom _NET_WM_ACTION_CHANGE_DESKTOP;
+
 	/* Channels */
 #if defined(CHANNEL_TSMF_CLIENT)
 	TsmfClientContext* tsmf;

One regression that I've found - dialog windows ("Run As", "Open file", etc) show up on taskbar, but work normally. On Windows they are not shown in taskbar. Maybe there is another way to check window type to not confuse them as normal windows.

@toreonify thank you for the report.

  • the patch is for 2.x version, right? could you create a pr for current master? (currently away and will check when back, but with a pr we can have an easier discussion about implementation details)
  • if we´ve got something for the current 3.x release we can backport that to 2.x if required

could you create a pr for current master?

#10160