Skip to content

Commit bd71f60

Browse files
authored
Merge pull request #6883 from AvaloniaUI/linux-shutdown-prevention-xsmp
Implement IPlatformLifetimeEvents for X11/Linux
2 parents 4f31cfc + 3eef67a commit bd71f60

File tree

4 files changed

+467
-2
lines changed

4 files changed

+467
-2
lines changed

src/Avalonia.X11/ICELib.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Avalonia.X11
5+
{
6+
internal static class ICELib
7+
{
8+
private const string LibIce = "libICE.so.6";
9+
10+
[DllImport(LibIce, CallingConvention = CallingConvention.StdCall)]
11+
public static extern int IceAddConnectionWatch(
12+
IntPtr watchProc,
13+
IntPtr clientData
14+
);
15+
16+
[DllImport(LibIce, CallingConvention = CallingConvention.StdCall)]
17+
public static extern void IceRemoveConnectionWatch(
18+
IntPtr watchProc,
19+
IntPtr clientData
20+
);
21+
22+
[DllImport(LibIce, CallingConvention = CallingConvention.StdCall)]
23+
public static extern IceProcessMessagesStatus IceProcessMessages(
24+
IntPtr iceConn,
25+
out IntPtr replyWait,
26+
out bool replyReadyRet
27+
);
28+
29+
[DllImport(LibIce, CallingConvention = CallingConvention.StdCall)]
30+
public static extern IntPtr IceSetErrorHandler(
31+
IntPtr handler
32+
);
33+
34+
[DllImport(LibIce, CallingConvention = CallingConvention.StdCall)]
35+
public static extern IntPtr IceSetIOErrorHandler(
36+
IntPtr handler
37+
);
38+
39+
public enum IceProcessMessagesStatus
40+
{
41+
IceProcessMessagesIoError = 1
42+
}
43+
44+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
45+
public delegate void IceErrorHandler(
46+
IntPtr iceConn,
47+
bool swap,
48+
int offendingMinorOpcode,
49+
ulong offendingSequence,
50+
int errorClass,
51+
int severity,
52+
IntPtr values
53+
);
54+
55+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
56+
public delegate void IceIOErrorHandler(
57+
IntPtr iceConn
58+
);
59+
}
60+
}

src/Avalonia.X11/SMLib.cs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Avalonia.X11
5+
{
6+
internal static unsafe class SMLib
7+
{
8+
private const string LibSm = "libSM.so.6";
9+
10+
[DllImport(LibSm, CharSet = CharSet.Ansi)]
11+
public static extern IntPtr SmcOpenConnection(
12+
[MarshalAs(UnmanagedType.LPWStr)] string networkId,
13+
IntPtr content,
14+
int xsmpMajorRev,
15+
int xsmpMinorRev,
16+
ulong mask,
17+
ref SmcCallbacks callbacks,
18+
[MarshalAs(UnmanagedType.LPWStr)] [Out]
19+
out string previousId,
20+
[MarshalAs(UnmanagedType.LPWStr)] [Out]
21+
out string clientIdRet,
22+
int errorLength,
23+
[Out] char[] errorStringRet);
24+
25+
[DllImport(LibSm, CallingConvention = CallingConvention.StdCall)]
26+
public static extern int SmcCloseConnection(
27+
IntPtr smcConn,
28+
int count,
29+
string[] reasonMsgs
30+
);
31+
32+
[DllImport(LibSm, CallingConvention = CallingConvention.StdCall)]
33+
public static extern void SmcSaveYourselfDone(
34+
IntPtr smcConn,
35+
bool success
36+
);
37+
38+
[DllImport(LibSm, CallingConvention = CallingConvention.StdCall)]
39+
public static extern int SmcInteractRequest(
40+
IntPtr smcConn,
41+
SmDialogValue dialogType,
42+
IntPtr interactProc,
43+
IntPtr clientData
44+
);
45+
46+
[DllImport(LibSm, CallingConvention = CallingConvention.StdCall)]
47+
public static extern void SmcInteractDone(
48+
IntPtr smcConn,
49+
bool success
50+
);
51+
52+
[DllImport(LibSm, CallingConvention = CallingConvention.StdCall)]
53+
public static extern IntPtr SmcGetIceConnection(
54+
IntPtr smcConn
55+
);
56+
57+
[DllImport(LibSm, CallingConvention = CallingConvention.StdCall)]
58+
public static extern IntPtr SmcSetErrorHandler(
59+
IntPtr handler
60+
);
61+
62+
public enum SmDialogValue
63+
{
64+
SmDialogError = 0
65+
}
66+
67+
[StructLayout(LayoutKind.Sequential)]
68+
public struct SmcCallbacks
69+
{
70+
public IntPtr SaveYourself;
71+
private readonly IntPtr Unused0;
72+
public IntPtr Die;
73+
private readonly IntPtr Unused1;
74+
public IntPtr SaveComplete;
75+
private readonly IntPtr Unused2;
76+
public IntPtr ShutdownCancelled;
77+
private readonly IntPtr Unused3;
78+
}
79+
80+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
81+
public delegate void IceWatchProc(
82+
IntPtr iceConn,
83+
IntPtr clientData,
84+
bool opening,
85+
IntPtr* watchData
86+
);
87+
88+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
89+
public delegate void SmcDieProc(
90+
IntPtr smcConn,
91+
IntPtr clientData
92+
);
93+
94+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
95+
public delegate void SmcInteractProc(
96+
IntPtr smcConn,
97+
IntPtr clientData
98+
);
99+
100+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
101+
public delegate void SmcSaveCompleteProc(
102+
IntPtr smcConn,
103+
IntPtr clientData
104+
);
105+
106+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
107+
public delegate void SmcSaveYourselfProc(
108+
IntPtr smcConn,
109+
IntPtr clientData,
110+
int saveType,
111+
bool shutdown,
112+
int interactStyle,
113+
bool fast
114+
);
115+
116+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
117+
public delegate void SmcShutdownCancelledProc(
118+
IntPtr smcConn,
119+
IntPtr clientData
120+
);
121+
122+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
123+
public delegate void SmcErrorHandler(
124+
IntPtr smcConn,
125+
bool swap,
126+
int offendingMinorOpcode,
127+
ulong offendingSequence,
128+
int errorClass,
129+
int severity,
130+
IntPtr values
131+
);
132+
}
133+
}

src/Avalonia.X11/X11Platform.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ public void Initialize(X11PlatformOptions options)
8080
.Bind<IPlatformSettings>().ToConstant(new PlatformSettingsStub())
8181
.Bind<IPlatformIconLoader>().ToConstant(new X11IconLoader(Info))
8282
.Bind<ISystemDialogImpl>().ToConstant(new GtkSystemDialog())
83-
.Bind<IMountedVolumeInfoProvider>().ToConstant(new LinuxMountedVolumeInfoProvider());
83+
.Bind<IMountedVolumeInfoProvider>().ToConstant(new LinuxMountedVolumeInfoProvider())
84+
.Bind<IPlatformLifetimeEventsImpl>().ToConstant(new X11PlatformLifetimeEvents(this));
8485

8586
X11Screens = Avalonia.X11.X11Screens.Init(this);
8687
Screens = new X11Screens(X11Screens);
@@ -230,7 +231,19 @@ public class X11PlatformOptions
230231
/// on their input devices by using sequences of characters or mouse operations that are natively available on their input devices.
231232
/// </remarks>
232233
public bool? EnableIme { get; set; }
233-
234+
235+
/// <summary>
236+
/// Determines whether to enable support for the
237+
/// X Session Management Protocol.
238+
/// </summary>
239+
/// <remarks>
240+
/// X Session Management Protocol is a standard implemented on most
241+
/// Linux systems that uses Xorg. This enables apps to control how they
242+
/// can control and/or cancel the pending shutdown requested by the user.
243+
/// </remarks>
244+
public bool EnableSessionManagement { get; set; } =
245+
Environment.GetEnvironmentVariable("AVALONIA_X11_USE_SESSION_MANAGEMENT") != "0";
246+
234247
public IList<GlVersion> GlProfiles { get; set; } = new List<GlVersion>
235248
{
236249
new GlVersion(GlProfileType.OpenGL, 4, 0),

0 commit comments

Comments
 (0)