55 * @LastEditTime: 2023-10-30 22:22:22
66 * @FilePath: /processforlinux/src/get_active_window.rs
77*/
8+
9+ /*
10+ * It seems that 'xprop' can get the title directly.
11+ */
812use std:: error:: Error ;
913use std:: io:: { BufRead , BufReader } ;
1014use std:: process:: { Command , Stdio } ;
1115
1216enum WindowTitle {
1317 Code ,
14- _WebStorm , //TODO: how to get it?
15- _Telgram , //TODO: how to get it?
16- _WeChat , // Linux not have it
18+ WebStorm ,
19+ Telegram ,
20+ WeChat ,
1721 Discord ,
1822 Mail ,
1923 QQ ,
2024 Chrome ,
2125 QQ音乐 ,
2226 NetEaseMusic ,
23- iTerm2, //TODO: why it not CamalCase?
27+ iTerm2,
2428 Typora ,
2529 None ,
2630}
31+
2732impl std:: fmt:: Display for WindowTitle {
2833 fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
2934 match self {
3035 WindowTitle :: Code => write ! ( f, "Code" ) ,
31- // WindowTitle::WebStorm => write!(f, "WebStorm"), //TODO: how to get it?
32- // WindowTitle::Telgram => write!(f, "Telgram "),
33- // WindowTitle::WeChat => write!(f, "WeChat"),
36+ WindowTitle :: WebStorm => write ! ( f, "WebStorm" ) ,
37+ WindowTitle :: Telegram => write ! ( f, "Telegram " ) ,
38+ WindowTitle :: WeChat => write ! ( f, "WeChat" ) ,
3439 WindowTitle :: Discord => write ! ( f, "Discord" ) ,
3540 WindowTitle :: Mail => write ! ( f, "Mail" ) ,
3641 WindowTitle :: QQ => write ! ( f, "QQ" ) ,
@@ -40,96 +45,77 @@ impl std::fmt::Display for WindowTitle {
4045 WindowTitle :: iTerm2 => write ! ( f, "iTerm2" ) ,
4146 WindowTitle :: Typora => write ! ( f, "Typora" ) ,
4247 WindowTitle :: None => write ! ( f, "None" ) ,
43- _ => write ! ( f, "None" ) ,
4448 }
4549 }
4650}
4751
4852impl WindowTitle {
4953 fn from_string ( s : & str ) -> WindowTitle {
5054 match s {
51- "Code " => WindowTitle :: Code ,
52- "Telgram " => WindowTitle :: None , //TODO: can't get it
53- "WebStorm " => WindowTitle :: None , // TODO: can 't get it
54- "WeChat " => WindowTitle :: None , //TODO: can't get it
55- "Discord " => WindowTitle :: Discord , //TODO: not test
56- "Thunderbird " => WindowTitle :: Mail ,
57- "Kmail " => WindowTitle :: Mail ,
58- "QQ " => WindowTitle :: QQ ,
59- "Chrome " => WindowTitle :: Chrome ,
60- "Chromium " => WindowTitle :: Chrome ,
61- "Thorium " => WindowTitle :: Chrome ,
55+ "code " => WindowTitle :: Code ,
56+ "jetbrains-webstorm " => WindowTitle :: WebStorm ,
57+ "telegram " => WindowTitle :: Telegram , // TODO: Can 't get the title of Telegram
58+ "wechat " => WindowTitle :: WeChat ,
59+ "discord " => WindowTitle :: Discord , // TODO: Can't test
60+ "thunderbird " => WindowTitle :: Mail ,
61+ "kmail " => WindowTitle :: Mail , // TODO: Can't get the title of KMail
62+ "qq " => WindowTitle :: QQ ,
63+ "google-chrome " => WindowTitle :: Chrome ,
64+ "chromium " => WindowTitle :: Chrome ,
65+ "thorium " => WindowTitle :: Chrome ,
6266 "qqmusic" => WindowTitle :: QQ音乐 ,
63- "Music " => WindowTitle :: NetEaseMusic ,
64- "YesPlayMusic " => WindowTitle :: NetEaseMusic ,
65- "Yakuake " => WindowTitle :: iTerm2,
66- "Konsole " => WindowTitle :: iTerm2,
67- "Typora " => WindowTitle :: Typora ,
68- _ => WindowTitle :: None , // Default
67+ "music " => WindowTitle :: NetEaseMusic ,
68+ "yesplaymusic " => WindowTitle :: NetEaseMusic ,
69+ "yakuake " => WindowTitle :: iTerm2, // TODO: Can't get the title of Yakuake
70+ "konsole " => WindowTitle :: iTerm2, // TODO: Can't get the title of Konsole
71+ "typora " => WindowTitle :: Typora ,
72+ _ => WindowTitle :: None ,
6973 }
7074 }
7175}
7276
7377pub fn get_active_window_process_and_title ( ) -> Result < String , Box < dyn Error > > {
74- let active_window_id = get_active_window_id ( ) ?;
75- let window_title = get_window_title_by_id ( & active_window_id) ?;
76- let process_name = get_last_part ( & window_title) . unwrap_or ( "None" . to_string ( ) ) ;
77- let window_title_enum = WindowTitle :: from_string ( & process_name) ;
78-
79- Ok ( window_title_enum. to_string ( ) )
80- }
81-
82- fn get_active_window_id ( ) -> Result < String , Box < dyn Error > > {
8378 let xprop_output = Command :: new ( "xprop" )
8479 . arg ( "-root" )
8580 . arg ( "_NET_ACTIVE_WINDOW" )
8681 . stdout ( Stdio :: piped ( ) )
87- . spawn ( ) ?;
88-
89- let xprop_stdout = xprop_output
82+ . spawn ( ) ?
9083 . stdout
9184 . ok_or ( "Failed to capture xprop stdout" ) ?;
9285
93- let xprop_reader = BufReader :: new ( xprop_stdout) ;
86+ let xprop_reader = BufReader :: new ( xprop_output) ;
87+ let mut window_id = String :: new ( ) ;
9488 for line in xprop_reader. lines ( ) {
9589 let line = line?;
9690 if line. contains ( "_NET_ACTIVE_WINDOW(WINDOW)" ) {
97- return Ok ( line. split_whitespace ( ) . nth ( 4 ) . unwrap_or ( "" ) . to_string ( ) ) ;
91+ window_id = line. split_whitespace ( ) . nth ( 4 ) . unwrap_or ( "" ) . to_string ( ) ;
92+ break ;
9893 }
9994 }
10095
101- Err ( "Failed to get active window ID" . into ( ) )
102- }
96+ if window_id. is_empty ( ) {
97+ return Err ( "Failed to get active window ID" . into ( ) ) ;
98+ }
10399
104- fn get_window_title_by_id ( window_id : & str ) -> Result < String , Box < dyn Error > > {
105- let xwininfo_output = Command :: new ( "xwininfo" )
100+ let xprop_output = Command :: new ( "xprop" )
106101 . arg ( "-id" )
107- . arg ( window_id)
102+ . arg ( & window_id)
103+ . arg ( "WM_CLASS" )
108104 . stdout ( Stdio :: piped ( ) )
109105 . spawn ( ) ?
110106 . stdout
111- . ok_or ( "Failed to capture xwininfo stdout" ) ?;
107+ . ok_or ( "Failed to capture xprop stdout" ) ?;
112108
113- let xwininfo_reader = BufReader :: new ( xwininfo_output ) ;
114- for line in xwininfo_reader . lines ( ) {
109+ let xprop_reader = BufReader :: new ( xprop_output ) ;
110+ for line in xprop_reader . lines ( ) {
115111 let line = line?;
116- if line. contains ( "xwininfo: Window id:" ) {
117- let window_name_parts: Vec < & str > = line. split ( '"' ) . collect ( ) ;
118- return Ok ( window_name_parts[ 1 ] . to_string ( ) ) ;
112+ if line. contains ( "WM_CLASS(STRING)" ) {
113+ let class_name = line. split ( '"' ) . nth ( 1 ) . unwrap_or ( "" ) ;
114+ println ! ( "class_name: {}" , class_name) ;
115+ let window_title_enum = WindowTitle :: from_string ( class_name) ;
116+ return Ok ( window_title_enum. to_string ( ) ) ;
119117 }
120118 }
121119
122- Err ( "Failed to get window title" . into ( ) )
123- }
124-
125- fn get_last_part ( original_string : & str ) -> Option < String > {
126- let last_space_index = match original_string. rfind ( ' ' ) {
127- Some ( index) => index,
128- None => {
129- return Some ( original_string. to_string ( ) ) ;
130- }
131- } ;
132-
133- let result_string = & original_string[ ( last_space_index + 1 ) ..] ;
134- Some ( result_string. to_string ( ) )
120+ Err ( "Failed to get window class" . into ( ) )
135121}
0 commit comments