From 7bb5e55cbde772c6c6369175c8b60159fedd30f2 Mon Sep 17 00:00:00 2001 From: walterlv Date: Wed, 4 Sep 2024 22:33:36 +0800 Subject: [PATCH 1/4] Fix window invisible after WindowState has changed to Maximized or FullScreen --- src/Avalonia.X11/X11Window.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 6c1b381a40f..45f85fb424e 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -686,6 +686,8 @@ public WindowState WindowState ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(true, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); + SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp, + IntPtr.Zero); } else if (value == WindowState.FullScreen) { @@ -693,6 +695,8 @@ public WindowState WindowState ChangeWMAtoms(true, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); + SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp, + IntPtr.Zero); } else { From b321dd62ce75f68b6f9790cbdcde9a4847f981f3 Mon Sep 17 00:00:00 2001 From: walterlv Date: Tue, 10 Sep 2024 10:51:35 +0800 Subject: [PATCH 2/4] map the window using XMapRequestEvent instead of XMapWindow or SendNetWMMessage --- src/Avalonia.X11/X11Window.cs | 38 +++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 45f85fb424e..2d5a6f21b56 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -686,8 +686,7 @@ public WindowState WindowState ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(true, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); - SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp, - IntPtr.Zero); + MapWindow(); } else if (value == WindowState.FullScreen) { @@ -695,8 +694,7 @@ public WindowState WindowState ChangeWMAtoms(true, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); - SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp, - IntPtr.Zero); + MapWindow(); } else { @@ -704,8 +702,7 @@ public WindowState WindowState ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); - SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp, - IntPtr.Zero); + MapWindow(); } WindowStateChanged?.Invoke(value); } @@ -1209,6 +1206,35 @@ private void SendNetWMMessage(IntPtr message_type, IntPtr l0, } + /// + /// Map the window to the screen. + /// + /// + /// Why we map the window using XMapRequestEvent instead of XMapWindow or SendNetWMMessage?
+ /// See details at https://github.com/AvaloniaUI/Avalonia/pull/16922 + ///
+ private void MapWindow() + { + var e = new XEvent + { + MapRequestEvent = new XMapRequestEvent + { + type = XEventName.MapRequest, + serial = 0, + display = _x11.Display, + send_event = 1, + parent = _x11.RootWindow, + window = _handle, + }, + }; + XSendEvent( + _x11.Display, + _x11.RootWindow, + false, + new IntPtr((int)EventMask.SubstructureRedirectMask), + ref e); + } + private void BeginMoveResize(NetWmMoveResize side, PointerPressedEventArgs e) { var pos = GetCursorPos(_x11); From 1946a7c76ab28ed05bdbcbbcfe82a04b2ecd2828 Mon Sep 17 00:00:00 2001 From: walterlv Date: Tue, 10 Sep 2024 14:25:39 +0800 Subject: [PATCH 3/4] Fix compiling error on net6.0 --- src/Avalonia.X11/X11Window.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 2d5a6f21b56..556dbdfec11 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -1220,7 +1220,7 @@ private void MapWindow() MapRequestEvent = new XMapRequestEvent { type = XEventName.MapRequest, - serial = 0, + serial = new IntPtr(0), display = _x11.Display, send_event = 1, parent = _x11.RootWindow, From e0b8da8e8559e7347276a43b2d5d7216504ea9d0 Mon Sep 17 00:00:00 2001 From: walterlv Date: Thu, 12 Sep 2024 18:01:10 +0800 Subject: [PATCH 4/4] Fix an issue that if WindowState is been set in the constructor, the contents that not been layouted or rendered will be shown. --- src/Avalonia.X11/X11Window.cs | 59 +++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 556dbdfec11..bc159087b32 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -686,7 +686,7 @@ public WindowState WindowState ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(true, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); - MapWindow(); + MapOrActiveWindow(); } else if (value == WindowState.FullScreen) { @@ -694,7 +694,7 @@ public WindowState WindowState ChangeWMAtoms(true, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); - MapWindow(); + MapOrActiveWindow(); } else { @@ -702,7 +702,7 @@ public WindowState WindowState ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_FULLSCREEN); ChangeWMAtoms(false, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); - MapWindow(); + MapOrActiveWindow(); } WindowStateChanged?.Invoke(value); } @@ -1206,33 +1206,38 @@ private void SendNetWMMessage(IntPtr message_type, IntPtr l0, } - /// - /// Map the window to the screen. - /// - /// - /// Why we map the window using XMapRequestEvent instead of XMapWindow or SendNetWMMessage?
- /// See details at https://github.com/AvaloniaUI/Avalonia/pull/16922 - ///
- private void MapWindow() + private void MapOrActiveWindow() { - var e = new XEvent + if (_wasMappedAtLeastOnce) { - MapRequestEvent = new XMapRequestEvent + // If the window has been mapped at least once, we should use XMapRequestEvent instead of XMapWindow or SendNetWMMessage. + // See details at https://github.com/AvaloniaUI/Avalonia/pull/16922 + var e = new XEvent { - type = XEventName.MapRequest, - serial = new IntPtr(0), - display = _x11.Display, - send_event = 1, - parent = _x11.RootWindow, - window = _handle, - }, - }; - XSendEvent( - _x11.Display, - _x11.RootWindow, - false, - new IntPtr((int)EventMask.SubstructureRedirectMask), - ref e); + MapRequestEvent = new XMapRequestEvent + { + type = XEventName.MapRequest, + serial = new IntPtr(0), + display = _x11.Display, + send_event = 1, + parent = _x11.RootWindow, + window = _handle, + }, + }; + XSendEvent( + _x11.Display, + _x11.RootWindow, + false, + new IntPtr((int)EventMask.SubstructureRedirectMask), + ref e); + } + else + { + // If the window has never been mapped, we should send _NET_ACTIVE_WINDOW message. + // Otherwise, the window will show too early so that content that not been layouted or rendered will be shown. + SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp, + IntPtr.Zero); + } } private void BeginMoveResize(NetWmMoveResize side, PointerPressedEventArgs e)