@@ -6,6 +6,7 @@ use hyprland::prelude::*;
6
6
use hyprland:: shared:: WorkspaceType ;
7
7
use inotify:: { Inotify , WatchMask } ;
8
8
use rustc_hash:: { FxHashMap , FxHashSet } ;
9
+ use serde:: Deserialize ;
9
10
use signal_hook:: consts:: { SIGINT , SIGTERM } ;
10
11
use signal_hook:: iterator:: Signals ;
11
12
use std:: error:: Error ;
@@ -24,36 +25,71 @@ struct Args {
24
25
}
25
26
26
27
struct Config {
27
- icons : FxHashMap < String , String > ,
28
+ config : ConfigFile ,
28
29
cfg_path : PathBuf ,
29
30
}
30
31
32
+ #[ derive( Deserialize ) ]
33
+ struct ConfigFile {
34
+ icons : FxHashMap < String , String > ,
35
+ #[ serde( default ) ]
36
+ exclude : FxHashMap < String , String > ,
37
+ }
38
+
31
39
impl Config {
32
40
fn new ( ) -> Result < Config , Box < dyn Error > > {
33
41
let mut config_file: File ;
34
42
let xdg_dirs = xdg:: BaseDirectories :: with_prefix ( "hyprland-autoname-workspaces" ) ?;
35
43
let cfg_path = xdg_dirs. place_config_file ( "config.toml" ) ?;
36
44
if !cfg_path. exists ( ) {
37
45
config_file = File :: create ( & cfg_path) ?;
38
- let default_icons = r#"# Add your icons mapping
46
+ let default_config = r#"[icons]
47
+ # Add your icons mapping
39
48
# use double quote the key and the value
40
49
# take class name from 'hyprctl clients'
41
50
"DEFAULT" = ""
42
51
"kitty" = "term"
43
52
"firefox" = "browser"
44
- "# ;
45
- write ! ( & mut config_file, "{default_icons}" ) ?;
53
+
54
+ # Add your applications that need to be exclude
55
+ # You can put what you want as value, "" make the job.
56
+ [exclude]
57
+ fcitx5 = ""
58
+ fcitx = ""
59
+ "# ;
60
+ write ! ( & mut config_file, "{default_config}" ) ?;
46
61
println ! ( "Default config created in {cfg_path:?}" ) ;
47
62
}
48
- let config = fs:: read_to_string ( cfg_path. clone ( ) ) ?;
49
- let icons: FxHashMap < String , String > =
50
- toml:: from_str ( & config) . map_err ( |e| format ! ( "Unable to parse: {e:?}" ) ) ?;
51
- let icons_uppercase = icons
63
+ let mut config_string = fs:: read_to_string ( cfg_path. clone ( ) ) ?;
64
+
65
+ // config file migration if needed
66
+ // can be remove "later" ...
67
+ if !config_string. contains ( "[icons]" ) {
68
+ config_string = "[icons]\n " . to_owned ( ) + & config_string;
69
+ fs:: write ( & cfg_path, & config_string)
70
+ . map_err ( |e| format ! ( "Cannot migrate config file: {e:?}" ) ) ?;
71
+ println ! ( "Config file migrated from v1 to v2" ) ;
72
+ }
73
+
74
+ let config: ConfigFile =
75
+ toml:: from_str ( & config_string) . map_err ( |e| format ! ( "Unable to parse: {e:?}" ) ) ?;
76
+
77
+ let icons = config
78
+ . icons
79
+ . iter ( )
80
+ . map ( |( k, v) | ( k. to_uppercase ( ) , v. clone ( ) ) )
81
+ . collect :: < FxHashMap < _ , _ > > ( ) ;
82
+
83
+ let exclude = config
84
+ . exclude
52
85
. iter ( )
53
86
. map ( |( k, v) | ( k. to_uppercase ( ) , v. clone ( ) ) )
54
87
. collect :: < FxHashMap < _ , _ > > ( ) ;
55
- let icons = icons. into_iter ( ) . chain ( icons_uppercase) . collect ( ) ;
56
- Ok ( Config { cfg_path, icons } )
88
+
89
+ Ok ( Config {
90
+ config : ConfigFile { icons, exclude } ,
91
+ cfg_path,
92
+ } )
57
93
}
58
94
}
59
95
@@ -118,24 +154,35 @@ impl Renamer {
118
154
119
155
for client in clients {
120
156
let class = client. class ;
157
+
121
158
if class. is_empty ( ) {
122
159
continue ;
123
160
}
161
+
162
+ if self
163
+ . cfg
164
+ . lock ( ) ?
165
+ . config
166
+ . exclude
167
+ . contains_key ( & class. to_uppercase ( ) )
168
+ {
169
+ continue ;
170
+ }
171
+
124
172
let workspace_id = client. workspace . id ;
125
173
let icon = self . class_to_icon ( & class) ;
126
- let fullscreen = client. fullscreen ;
127
174
let is_dup = !deduper. insert ( format ! ( "{workspace_id}-{icon}" ) ) ;
128
175
let should_dedup = self . args . dedup && is_dup;
129
176
130
- self . workspaces . lock ( ) ?. insert ( client . workspace . id ) ;
177
+ self . workspaces . lock ( ) ?. insert ( workspace_id ) ;
131
178
132
179
let workspace = workspaces
133
180
. entry ( workspace_id)
134
181
. or_insert_with ( || "" . to_string ( ) ) ;
135
182
136
- if fullscreen && should_dedup {
183
+ if client . fullscreen && should_dedup {
137
184
* workspace = workspace. replace ( & icon, & format ! ( "[{icon}]" ) ) ;
138
- } else if fullscreen && !should_dedup {
185
+ } else if client . fullscreen && !should_dedup {
139
186
* workspace = format ! ( "{workspace} [{icon}]" ) ;
140
187
} else if !should_dedup {
141
188
* workspace = format ! ( "{workspace} {icon}" ) ;
@@ -197,7 +244,7 @@ impl Renamer {
197
244
// Clojure to force quick release of lock
198
245
{
199
246
match Config :: new ( ) {
200
- Ok ( config) => self . cfg . lock ( ) ?. icons = config. icons ,
247
+ Ok ( config) => self . cfg . lock ( ) ?. config = config. config ,
201
248
Err ( err) => println ! ( "Unable to reload config: {err:?}" ) ,
202
249
}
203
250
}
@@ -210,11 +257,12 @@ impl Renamer {
210
257
211
258
fn class_to_icon ( & self , class : & str ) -> String {
212
259
let default_value = String :: from ( "no default icon" ) ;
213
- let cfg = self . cfg . lock ( ) . expect ( "Unable to obtain lock for config" ) ;
214
- cfg. icons
260
+ let cfg = & self . cfg . lock ( ) . expect ( "Unable to obtain lock for config" ) ;
261
+ cfg. config
262
+ . icons
215
263
. get ( class)
216
- . or_else ( || cfg. icons . get ( class. to_uppercase ( ) . as_str ( ) ) )
217
- . unwrap_or_else ( || cfg. icons . get ( "DEFAULT" ) . unwrap_or ( & default_value) )
264
+ . or_else ( || cfg. config . icons . get ( class. to_uppercase ( ) . as_str ( ) ) )
265
+ . unwrap_or_else ( || cfg. config . icons . get ( "DEFAULT" ) . unwrap_or ( & default_value) )
218
266
. into ( )
219
267
}
220
268
0 commit comments