Internal heuristics for Wayland clients,
NET_WM_WINDOW_TYPE for XWayland clients.
+ *shaded* [yes|no]
+ Whether or not the client is rolled up.
+
+ *maximized* [both|horizontal|vertical|none]
+ Whether the client is maximized along both axes, the
+ horizontal axis only, the vertical axis only, or neither
+ axis (none).
+
+ *iconified* [yes|no]
+ Whether or not the client is iconified.
+
+ *focused* [yes|no]
+ Whether or not the client is focused.
+
+ *omnipresent* [yes|no]
+ Whether or not the client is visible on all desktops.
+
+ *desktop*
+ The desktop the client is currently on. This can be the
+ number or name of a desktop, or special relative values
+ "current", "other", "left", "right" or "last". The
+ "left" and "right" directions will not wrap.
+
+ *tiled* [up|right|down|left|center]
+ Whether the client is tiled (snapped) along the the
+ indicated screen edge.
+
+ *tiled_region*
+ Whether the client is tiled (snapped) to the indicated
+ region.
+
+ *decoration* [full|border|none]
+ Whether the client has full server-side decorations,
+ borders only, or no server-side decorations.
+
This argument is optional.
*then*
case ACTION_TYPE_UNMAXIMIZE:
if (!strcmp(argument, "direction")) {
enum view_axis axis = view_axis_parse(content);
- if (axis == VIEW_AXIS_NONE) {
+ if (axis == VIEW_AXIS_NONE || axis == VIEW_AXIS_INVALID) {
wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s' (%s)",
action_names[action->type], argument, content);
} else {
case ACTION_TYPE_SET_DECORATIONS:
if (!strcmp(argument, "decorations")) {
enum ssd_mode mode = ssd_mode_parse(content);
- action_arg_add_int(action, argument, mode);
+ if (mode != LAB_SSD_MODE_INVALID) {
+ action_arg_add_int(action, argument, mode);
+ } else {
+ wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s' (%s)",
+ action_names[action->type], argument, content);
+ }
goto cleanup;
}
if (!strcasecmp(argument, "forceSSD")) {
current_view_query->sandbox_engine = xstrdup(content);
} else if (!strcasecmp(nodename, "sandboxAppId")) {
current_view_query->sandbox_app_id = xstrdup(content);
+ } else if (!strcasecmp(nodename, "shaded")) {
+ current_view_query->shaded = parse_bool(content, -1);
+ } else if (!strcasecmp(nodename, "maximized")) {
+ current_view_query->maximized = view_axis_parse(content);
+ } else if (!strcasecmp(nodename, "iconified")) {
+ current_view_query->iconified = parse_bool(content, -1);
+ } else if (!strcasecmp(nodename, "focused")) {
+ current_view_query->focused = parse_bool(content, -1);
+ } else if (!strcasecmp(nodename, "omnipresent")) {
+ current_view_query->omnipresent = parse_bool(content, -1);
+ } else if (!strcasecmp(nodename, "tiled")) {
+ current_view_query->tiled = view_edge_parse(content);
+ } else if (!strcasecmp(nodename, "tiled_region")) {
+ current_view_query->tiled_region = xstrdup(content);
+ } else if (!strcasecmp(nodename, "desktop")) {
+ current_view_query->desktop = xstrdup(content);
+ } else if (!strcasecmp(nodename, "decoration")) {
+ current_view_query->decoration = ssd_mode_parse(content);
+ } else if (!strcasecmp(nodename, "monitor")) {
+ current_view_query->monitor = xstrdup(content);
}
}
#include "common/macros.h"
#include "common/match.h"
#include "common/mem.h"
+#include "common/parse-bool.h"
#include "common/scene-helpers.h"
#include "input/keyboard.h"
#include "labwc.h"
#include "ssd.h"
#include "view.h"
#include "window-rules.h"
+#include "wlr/util/log.h"
#include "workspaces.h"
#include "xwayland.h"
view_query_free(struct view_query *query)
{
wl_list_remove(&query->link);
- free(query->identifier);
- free(query->title);
- free(query->sandbox_engine);
- free(query->sandbox_app_id);
- free(query);
+ zfree(query->identifier);
+ zfree(query->title);
+ zfree(query->sandbox_engine);
+ zfree(query->sandbox_app_id);
+ zfree(query->tiled_region);
+ zfree(query->desktop);
+ zfree(query->monitor);
+ zfree(query);
+}
+
+static enum three_state
+bool_to_tristate(bool b)
+{
+ return b ? LAB_STATE_ENABLED : LAB_STATE_DISABLED;
+}
+
+static enum three_state
+match_tristate(enum three_state desired, bool actual, enum three_state old_match)
+{
+ switch (desired) {
+ case LAB_STATE_ENABLED:
+ return bool_to_tristate(actual);
+ case LAB_STATE_DISABLED:
+ return bool_to_tristate(!actual);
+ default:
+ return old_match;
+ }
}
bool
view_matches_query(struct view *view, struct view_query *query)
{
- bool match = true;
- bool empty = true;
+ enum three_state match = LAB_STATE_UNSPECIFIED;
- const char *identifier = view_get_string_prop(view, "app_id");
- if (match && query->identifier) {
- empty = false;
- match &= identifier && match_glob(query->identifier, identifier);
+ if (query->identifier) {
+ const char *identifier = view_get_string_prop(view, "app_id");
+ if (!(identifier && match_glob(query->identifier, identifier))) {
+ return false;
+ }
}
- const char *title = view_get_string_prop(view, "title");
- if (match && query->title) {
- empty = false;
- match &= title && match_glob(query->title, title);
+ if (query->title) {
+ const char *title = view_get_string_prop(view, "title");
+ if (!(title && match_glob(query->title, title))) {
+ return false;
+ }
}
- if (match && query->window_type >= 0) {
- empty = false;
- match &= view_contains_window_type(view, query->window_type);
+ if (query->window_type >= 0) {
+ if (!view_contains_window_type(view, query->window_type)) {
+ return false;
+ }
}
- if (match && query->sandbox_engine) {
+ if (query->sandbox_engine) {
const struct wlr_security_context_v1_state *security_context =
security_context_from_view(view);
- empty = false;
- match &= security_context && security_context->sandbox_engine
- && match_glob(query->sandbox_engine, security_context->sandbox_engine);
+ if (!(security_context && security_context->sandbox_engine &&
+ match_glob(query->sandbox_engine, security_context->sandbox_engine))) {
+ return false;
+ }
}
- if (match && query->sandbox_app_id) {
+ if (query->sandbox_app_id) {
const struct wlr_security_context_v1_state *security_context =
security_context_from_view(view);
- empty = false;
- match &= security_context && security_context->app_id
- && match_glob(query->sandbox_app_id, security_context->app_id);
+ if (!(security_context && security_context->app_id &&
+ match_glob(query->sandbox_app_id, security_context->app_id))) {
+ return false;
+ }
+ }
+
+ match = match_tristate(query->shaded, view->shaded, match);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+
+ if (query->maximized != VIEW_AXIS_INVALID) {
+ match = bool_to_tristate(view->maximized == query->maximized);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+ }
+
+ match = match_tristate(query->iconified, view->minimized, match);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+
+ match = match_tristate(query->focused, view->server->active_view == view, match);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+
+ match = match_tristate(query->omnipresent, view->visible_on_all_workspaces, match);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+
+ if (query->tiled != VIEW_EDGE_INVALID) {
+ match = bool_to_tristate(query->tiled == view->tiled);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+ }
+
+ if (query->tiled_region) {
+ match = bool_to_tristate(view->tiled_region &&
+ !strcasecmp(query->tiled_region, view->tiled_region->name));
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+ }
+
+ if (query->desktop) {
+ if (!strcasecmp(query->desktop, "other")) {
+ struct workspace *current = view->server->workspaces.current;
+ match = bool_to_tristate(strcasecmp(view->workspace->name, current->name));
+ } else {
+ // TODO: perhaps allow wrapping for "left" and "right" workspaces
+ struct workspace *target =
+ workspaces_find(view->server->workspaces.current,
+ query->desktop, false);
+ match = bool_to_tristate(target &&
+ !strcasecmp(view->workspace->name, target->name));
+ }
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+ }
+
+ enum ssd_mode decoration = view_get_ssd_mode(view);
+ if (query->decoration != LAB_SSD_MODE_INVALID) {
+ match = bool_to_tristate(query->decoration == decoration);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
}
- return !empty && match;
+ if (query->monitor) {
+ struct output *target = output_from_name(view->server, query->monitor);
+ match = bool_to_tristate(target == view->output);
+ if (match == LAB_STATE_DISABLED) {
+ return false;
+ }
+ }
+
+ return match == LAB_STATE_ENABLED;
}
static bool
view_axis_parse(const char *direction)
{
if (!direction) {
- return VIEW_AXIS_NONE;
+ return VIEW_AXIS_INVALID;
}
if (!strcasecmp(direction, "horizontal")) {
return VIEW_AXIS_HORIZONTAL;
return VIEW_AXIS_VERTICAL;
} else if (!strcasecmp(direction, "both")) {
return VIEW_AXIS_BOTH;
- } else {
+ } else if (!strcasecmp(direction, "none")) {
return VIEW_AXIS_NONE;
+ } else {
+ return VIEW_AXIS_INVALID;
}
}