aboutsummaryrefslogtreecommitdiffstats
path: root/sway/criteria.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-05-11 14:58:24 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-05-12 12:34:12 +1000
commit94e42f985778ce402b4c47bf8c38ee4233b6204d (patch)
treefff764c0ef0b28466bb55ceeefa7e617a37cef5d /sway/criteria.c
parentMerge pull request #1943 from RyanDwyer/criteria-improvements (diff)
downloadsway-94e42f985778ce402b4c47bf8c38ee4233b6204d.tar.gz
sway-94e42f985778ce402b4c47bf8c38ee4233b6204d.tar.zst
sway-94e42f985778ce402b4c47bf8c38ee4233b6204d.zip
Implement __focused__ criteria
Diffstat (limited to 'sway/criteria.c')
-rw-r--r--sway/criteria.c204
1 files changed, 162 insertions, 42 deletions
diff --git a/sway/criteria.c b/sway/criteria.c
index 7da790e6..294b2922 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -190,19 +190,128 @@ static bool generate_regex(pcre **regex, char *value) {
190 return true; 190 return true;
191} 191}
192 192
193enum criteria_token {
194 T_APP_ID,
195 T_CLASS,
196 T_CON_ID,
197 T_CON_MARK,
198 T_FLOATING,
199 T_ID,
200 T_INSTANCE,
201 T_TILING,
202 T_TITLE,
203 T_URGENT,
204 T_WINDOW_ROLE,
205 T_WINDOW_TYPE,
206 T_WORKSPACE,
207
208 T_INVALID,
209};
210
211static enum criteria_token token_from_name(char *name) {
212 if (strcmp(name, "app_id") == 0) {
213 return T_APP_ID;
214 } else if (strcmp(name, "class") == 0) {
215 return T_CLASS;
216 } else if (strcmp(name, "con_id") == 0) {
217 return T_CON_ID;
218 } else if (strcmp(name, "con_mark") == 0) {
219 return T_CON_MARK;
220 } else if (strcmp(name, "id") == 0) {
221 return T_ID;
222 } else if (strcmp(name, "instance") == 0) {
223 return T_INSTANCE;
224 } else if (strcmp(name, "title") == 0) {
225 return T_TITLE;
226 } else if (strcmp(name, "urgent") == 0) {
227 return T_URGENT;
228 } else if (strcmp(name, "window_role") == 0) {
229 return T_WINDOW_ROLE;
230 } else if (strcmp(name, "window_type") == 0) {
231 return T_WINDOW_TYPE;
232 } else if (strcmp(name, "workspace") == 0) {
233 return T_WORKSPACE;
234 }
235 return T_INVALID;
236}
237
238/**
239 * Get a property of the focused view.
240 *
241 * Note that we are taking the focused view at the time of criteria parsing, not
242 * at the time of execution. This is because __focused__ only makes sense when
243 * using criteria via IPC. Using __focused__ in config is not useful because
244 * criteria is only executed once per view.
245 */
246static char *get_focused_prop(enum criteria_token token) {
247 struct sway_seat *seat = input_manager_current_seat(input_manager);
248 struct sway_container *focus = seat_get_focus(seat);
249
250 if (!focus || focus->type != C_VIEW) {
251 return NULL;
252 }
253 struct sway_view *view = focus->sway_view;
254 const char *value = NULL;
255
256 switch (token) {
257 case T_APP_ID:
258 value = view_get_app_id(view);
259 break;
260 case T_CLASS:
261 value = view_get_class(view);
262 break;
263 case T_INSTANCE:
264 value = view_get_instance(view);
265 break;
266 case T_TITLE:
267 value = view_get_class(view);
268 break;
269 case T_WINDOW_ROLE:
270 value = view_get_class(view);
271 break;
272 case T_WORKSPACE:
273 {
274 struct sway_container *ws = container_parent(focus, C_WORKSPACE);
275 if (ws) {
276 value = ws->name;
277 }
278 }
279 break;
280 case T_CON_ID: // These do not support __focused__
281 case T_CON_MARK:
282 case T_FLOATING:
283 case T_ID:
284 case T_TILING:
285 case T_URGENT:
286 case T_WINDOW_TYPE:
287 case T_INVALID:
288 break;
289 }
290 if (value) {
291 return strdup(value);
292 }
293 return NULL;
294}
295
193static bool parse_token(struct criteria *criteria, char *name, char *value) { 296static bool parse_token(struct criteria *criteria, char *name, char *value) {
297 enum criteria_token token = token_from_name(name);
298 if (token == T_INVALID) {
299 const char *fmt = "Token '%s' is not recognized";
300 int len = strlen(fmt) + strlen(name) - 1;
301 error = malloc(len);
302 snprintf(error, len, fmt, name);
303 return false;
304 }
305
306 char *effective_value = NULL;
307 if (value && strcmp(value, "__focused__") == 0) {
308 effective_value = get_focused_prop(token);
309 } else if (value) {
310 effective_value = strdup(value);
311 }
312
194 // Require value, unless token is floating or tiled 313 // Require value, unless token is floating or tiled
195 if (!value && (strcmp(name, "title") == 0 314 if (!effective_value && token != T_FLOATING && token != T_TILING) {
196 || strcmp(name, "app_id") == 0
197 || strcmp(name, "class") == 0
198 || strcmp(name, "instance") == 0
199 || strcmp(name, "con_id") == 0
200 || strcmp(name, "con_mark") == 0
201 || strcmp(name, "window_role") == 0
202 || strcmp(name, "window_type") == 0
203 || strcmp(name, "id") == 0
204 || strcmp(name, "urgent") == 0
205 || strcmp(name, "workspace") == 0)) {
206 const char *fmt = "Token '%s' requires a value"; 315 const char *fmt = "Token '%s' requires a value";
207 int len = strlen(fmt) + strlen(name) - 1; 316 int len = strlen(fmt) + strlen(name) - 1;
208 error = malloc(len); 317 error = malloc(len);
@@ -210,53 +319,64 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
210 return false; 319 return false;
211 } 320 }
212 321
213 if (strcmp(name, "title") == 0) { 322 char *endptr = NULL;
214 generate_regex(&criteria->title, value); 323 switch (token) {
215 } else if (strcmp(name, "app_id") == 0) { 324 case T_TITLE:
216 generate_regex(&criteria->app_id, value); 325 generate_regex(&criteria->title, effective_value);
217 } else if (strcmp(name, "class") == 0) { 326 break;
218 generate_regex(&criteria->class, value); 327 case T_APP_ID:
219 } else if (strcmp(name, "instance") == 0) { 328 generate_regex(&criteria->app_id, effective_value);
220 generate_regex(&criteria->instance, value); 329 break;
221 } else if (strcmp(name, "con_id") == 0) { 330 case T_CLASS:
222 char *endptr; 331 generate_regex(&criteria->class, effective_value);
223 criteria->con_id = strtoul(value, &endptr, 10); 332 break;
333 case T_INSTANCE:
334 generate_regex(&criteria->instance, effective_value);
335 break;
336 case T_CON_ID:
337 criteria->con_id = strtoul(effective_value, &endptr, 10);
224 if (*endptr != 0) { 338 if (*endptr != 0) {
225 error = strdup("The value for 'con_id' should be numeric"); 339 error = strdup("The value for 'con_id' should be numeric");
226 } 340 }
227 } else if (strcmp(name, "con_mark") == 0) { 341 break;
228 generate_regex(&criteria->con_mark, value); 342 case T_CON_MARK:
229 } else if (strcmp(name, "window_role") == 0) { 343 generate_regex(&criteria->con_mark, effective_value);
230 generate_regex(&criteria->window_role, value); 344 break;
231 } else if (strcmp(name, "window_type") == 0) { 345 case T_WINDOW_ROLE:
346 generate_regex(&criteria->window_role, effective_value);
347 break;
348 case T_WINDOW_TYPE:
232 // TODO: This is a string but will be stored as an enum or integer 349 // TODO: This is a string but will be stored as an enum or integer
233 } else if (strcmp(name, "id") == 0) { 350 break;
234 char *endptr; 351 case T_ID:
235 criteria->id = strtoul(value, &endptr, 10); 352 criteria->id = strtoul(effective_value, &endptr, 10);
236 if (*endptr != 0) { 353 if (*endptr != 0) {
237 error = strdup("The value for 'id' should be numeric"); 354 error = strdup("The value for 'id' should be numeric");
238 } 355 }
239 } else if (strcmp(name, "floating") == 0) { 356 break;
357 case T_FLOATING:
240 criteria->floating = true; 358 criteria->floating = true;
241 } else if (strcmp(name, "tiling") == 0) { 359 break;
360 case T_TILING:
242 criteria->tiling = true; 361 criteria->tiling = true;
243 } else if (strcmp(name, "urgent") == 0) { 362 break;
244 if (strcmp(value, "latest") == 0) { 363 case T_URGENT:
364 if (strcmp(effective_value, "latest") == 0) {
245 criteria->urgent = 'l'; 365 criteria->urgent = 'l';
246 } else if (strcmp(value, "oldest") == 0) { 366 } else if (strcmp(effective_value, "oldest") == 0) {
247 criteria->urgent = 'o'; 367 criteria->urgent = 'o';
248 } else { 368 } else {
249 error = 369 error =
250 strdup("The value for 'urgent' must be 'latest' or 'oldest'"); 370 strdup("The value for 'urgent' must be 'latest' or 'oldest'");
251 } 371 }
252 } else if (strcmp(name, "workspace") == 0) { 372 break;
253 criteria->workspace = strdup(value); 373 case T_WORKSPACE:
254 } else { 374 criteria->workspace = strdup(effective_value);
255 const char *fmt = "Token '%s' is not recognized"; 375 break;
256 int len = strlen(fmt) + strlen(name) - 1; 376 case T_INVALID:
257 error = malloc(len); 377 break;
258 snprintf(error, len, fmt, name);
259 } 378 }
379 free(effective_value);
260 380
261 if (error) { 381 if (error) {
262 return false; 382 return false;