@@ -227,27 +227,38 @@ static bool append_bare(char **buf, const char *key, const char *value) {
227227 return written >= 0 ;
228228}
229229
230- // i3-save-tree emits window_type as a regex-anchored enum name like
231- // "^normal$". The criteria parser treats window_type as a bare enum token,
232- // not a regex, so the anchored form fails. Strip a single leading ^ and a
233- // single trailing $ before passing through.
234- static char * unanchor_enum (const char * value ) {
230+ // window_type is parsed as an enum, not a regex. Accept i3-save-tree's
231+ // "^name$" form and bare names; reject anything else (including alternation)
232+ // rather than letting the criteria parser silently fall through to ATOM_LAST.
233+ static const char * known_window_types [] = {
234+ "normal" , "dialog" , "utility" , "toolbar" , "splash" , "menu" ,
235+ "dropdown_menu" , "popup_menu" , "tooltip" , "notification" , NULL ,
236+ };
237+
238+ static char * parse_window_type_value (const char * value , char * * error_out ) {
235239 size_t n = strlen (value );
236- size_t start = 0 ;
237- size_t end = n ;
238- if (n > 0 && value [0 ] == '^' ) {
239- start = 1 ;
240- }
241- if (end > start && value [end - 1 ] == '$' ) {
242- end -- ;
243- }
244- char * out = malloc (end - start + 1 );
245- if (!out ) {
240+ size_t start = (n > 0 && value [0 ] == '^' ) ? 1 : 0 ;
241+ size_t end = (n > start && value [n - 1 ] == '$' ) ? n - 1 : n ;
242+ size_t bare_len = end - start ;
243+ char * bare = malloc (bare_len + 1 );
244+ if (!bare ) {
245+ * error_out = format_str ("append_layout: out of memory" );
246246 return NULL ;
247247 }
248- memcpy (out , value + start , end - start );
249- out [end - start ] = '\0' ;
250- return out ;
248+ memcpy (bare , value + start , bare_len );
249+ bare [bare_len ] = '\0' ;
250+ for (int i = 0 ; known_window_types [i ]; i ++ ) {
251+ if (strcasecmp (bare , known_window_types [i ]) == 0 ) {
252+ return bare ;
253+ }
254+ }
255+ * error_out = format_str ("append_layout: window_type %s is not a "
256+ "supported literal value (use one of: normal, dialog, "
257+ "utility, toolbar, splash, menu, dropdown_menu, popup_menu, "
258+ "tooltip, notification; regex alternation is not supported, "
259+ "split into multiple swallow entries instead)" , value );
260+ free (bare );
261+ return NULL ;
251262}
252263
253264// app_id is a sway extension over i3's swallows schema; machine is ignored.
@@ -287,8 +298,13 @@ static struct criteria *build_swallow_criteria(struct json_object *entry,
287298 "append_layout: swallows.window_type is not a string" );
288299 return NULL ;
289300 }
290- char * bare = unanchor_enum (json_object_get_string (wt ));
291- if (!bare || !append_bare (& body , "window_type" , bare )) {
301+ char * bare = parse_window_type_value (json_object_get_string (wt ),
302+ error_out );
303+ if (!bare ) {
304+ free (body );
305+ return NULL ;
306+ }
307+ if (!append_bare (& body , "window_type" , bare )) {
292308 free (bare );
293309 free (body );
294310 * error_out = format_str ("append_layout: out of memory" );
0 commit comments