1- using System . Diagnostics ;
1+ using System . Runtime . InteropServices ;
22using YMouseButtonControl . Core . Services . Processes ;
33
44namespace YMouseButtonControl . Linux . Services ;
@@ -7,36 +7,93 @@ public class CurrentWindowServiceX11 : ICurrentWindowService
77{
88 public string ForegroundWindow => GetForegroundWindow ( ) ;
99
10- private string GetForegroundWindow ( )
10+ private static string GetForegroundWindow ( )
1111 {
12- var startInfo = new ProcessStartInfo
12+ var display = X11 . XOpenDisplay ( nint . Zero ) ;
13+ if ( display == nint . Zero )
1314 {
14- FileName = "/bin/bash" ,
15- Arguments = "-c \" xdotool getwindowfocus getwindowpid\" " ,
16- RedirectStandardOutput = true ,
17- } ;
18- using var xdoProc = new Process ( ) ;
19- xdoProc . StartInfo = startInfo ;
20- xdoProc . Start ( ) ;
21- var pid = xdoProc . StandardOutput . ReadToEnd ( ) . TrimEnd ( ) ;
22- xdoProc . WaitForExit ( ) ;
23-
24- if ( string . IsNullOrWhiteSpace ( pid ) )
15+ throw new Exception ( "Error opening display" ) ;
16+ }
17+
18+ try
19+ {
20+ var pid = GetForegroundWindowPid ( display ) ;
21+ if ( pid is null )
22+ {
23+ return "" ;
24+ }
25+
26+ return GetPathFromPid ( pid ) ?? "" ;
27+ }
28+ finally
29+ {
30+ X11 . XCloseDisplay ( display ) ;
31+ }
32+ }
33+
34+ private static string ? GetPathFromPid ( int ? pid )
35+ {
36+ var fi = new FileInfo ( $ "/proc/{ pid } /exe") ;
37+ return fi . LinkTarget ;
38+ }
39+
40+ private static unsafe int ? GetForegroundWindowPid ( nint display )
41+ {
42+ var root = X11 . XDefaultRootWindow ( display ) ;
43+ var prop = X11 . XInternAtom ( display , Marshal . StringToHGlobalAnsi ( "_NET_ACTIVE_WINDOW" ) , 0 ) ;
44+ var pidProp = X11 . XInternAtom ( display , Marshal . StringToHGlobalAnsi ( "_NET_WM_PID" ) , 1 ) ;
45+
46+ if ( X11 . XGetWindowProperty ( display , root , prop , 0 , sizeof ( ulong ) , 0 , 0 ,
47+ out _ , out _ , out _ ,
48+ out _ , out var outProp ) != 0 || outProp == nint . Zero )
2549 {
26- return "" ;
50+ return null ;
2751 }
2852
29- startInfo = new ProcessStartInfo
53+ var activeWindow = * ( nint * ) outProp ;
54+ X11 . XFree ( outProp ) ;
55+
56+ if ( X11 . XGetWindowProperty ( display , activeWindow , pidProp , 0 , sizeof ( int ) , 0 , 0 , out _ , out _ , out _ , out _ ,
57+ out var prop2 ) != 0 || prop2 == nint . Zero )
3058 {
31- FileName = "/bin/bash" ,
32- Arguments = $ "-c \" ls -l /proc/{ pid } /exe\" ",
33- RedirectStandardOutput = true ,
34- } ;
35- using var proc = new Process ( ) ;
36- proc . StartInfo = startInfo ;
37- proc . Start ( ) ;
38- var path = proc . StandardOutput . ReadToEnd ( ) . Split ( "-> " ) [ 1 ] . Trim ( ) ;
39- proc . WaitForExit ( ) ;
40- return path ;
59+ return null ;
60+ }
61+
62+ var pid = * ( int * ) prop2 ;
63+ X11 . XFree ( prop2 ) ;
64+ return pid ;
4165 }
4266}
67+
68+ internal static partial class X11
69+ {
70+ [ LibraryImport ( "libX11.so" ) ]
71+ internal static partial int XFree ( nint data ) ;
72+
73+ [ LibraryImport ( "libX11.so" ) ]
74+ internal static partial nint XOpenDisplay ( nint display ) ;
75+
76+ [ LibraryImport ( "libX11.so" ) ]
77+ internal static partial void XCloseDisplay ( nint display ) ;
78+
79+ [ LibraryImport ( "libX11.so" ) ]
80+ internal static partial nint XDefaultRootWindow ( nint display ) ;
81+
82+ [ LibraryImport ( "libX11.so" ) ]
83+ internal static partial nint XInternAtom ( nint display , nint atomName , int onlyIfExists ) ;
84+
85+ [ LibraryImport ( "libX11.so" ) ]
86+ internal static partial int XGetWindowProperty (
87+ IntPtr display ,
88+ IntPtr window ,
89+ IntPtr property ,
90+ long longOffset ,
91+ long longLength ,
92+ int delete ,
93+ ulong reqType ,
94+ out ulong actualTypeReturn ,
95+ out int actualFormatReturn ,
96+ out ulong nItemsReturn ,
97+ out ulong bytesAfterReturn ,
98+ out IntPtr propReturn ) ;
99+ }
0 commit comments