QUERY_TARGET_IS_FOCUS_TARGET,
} QueryTarget;
+typedef enum {
+ MATCH_TYPE_NONE = 0,
+ MATCH_TYPE_PATTERN,
+ MATCH_TYPE_REGEX,
+ MATCH_TYPE_EXACT,
+} MatchType;
+
+typedef struct {
+ MatchType type;
+ union m {
+ GPatternSpec *pattern;
+ GRegex *regex;
+ gchar *exact;
+ } m;
+} TypedMatch;
+
typedef struct {
QueryTarget target;
gboolean shaded_on;
guint desktop_number;
guint screendesktop_number;
guint client_monitor;
- GPatternSpec *matchtitle;
- GRegex *regextitle;
- gchar *exacttitle;
+ TypedMatch title;
+ TypedMatch class;
+ TypedMatch name;
+ TypedMatch role;
+ TypedMatch type;
} Query;
typedef struct {
GArray* queries;
GSList *thenacts;
GSList *elseacts;
+ gboolean stop;
} Options;
static gpointer setup_func(xmlNodePtr node);
static void free_func(gpointer options);
-static gboolean run_func(ObActionsData *data, gpointer options);
+static gboolean run_func_if(ObActionsData *data, gpointer options);
+static gboolean run_func_stop(ObActionsData *data, gpointer options);
+static gboolean run_func_foreach(ObActionsData *data, gpointer options);
void action_if_startup(void)
{
- actions_register("If", setup_func, free_func, run_func);
+ actions_register("If", setup_func, free_func, run_func_if);
+ actions_register("Stop", NULL, NULL, run_func_stop);
+ actions_register("ForEach", setup_func, free_func, run_func_foreach);
+
+ actions_set_can_stop("Stop", TRUE);
}
static inline void set_bool(xmlNodePtr node,
}
}
+static void setup_typed_match(TypedMatch *tm, xmlNodePtr n)
+{
+ gchar *s;
+ if ((s = obt_xml_node_string(n))) {
+ gchar *type = NULL;
+ if (!obt_xml_attr_string(n, "type", &type) ||
+ !g_ascii_strcasecmp(type, "pattern"))
+ {
+ tm->type = MATCH_TYPE_PATTERN;
+ tm->m.pattern = g_pattern_spec_new(s);
+ } else if (type && !g_ascii_strcasecmp(type, "regex")) {
+ tm->type = MATCH_TYPE_REGEX;
+ tm->m.regex = g_regex_new(s, 0, 0, NULL);
+ } else if (type && !g_ascii_strcasecmp(type, "exact")) {
+ tm->type = MATCH_TYPE_EXACT;
+ tm->m.exact = g_strdup(s);
+ }
+ g_free(s);
+ g_free(type);
+ }
+}
+
+static void free_typed_match(TypedMatch *tm)
+{
+ switch (tm->type) {
+ case MATCH_TYPE_PATTERN:
+ g_pattern_spec_free(tm->m.pattern);
+ break;
+ case MATCH_TYPE_REGEX:
+ g_regex_unref(tm->m.regex);
+ break;
+ case MATCH_TYPE_EXACT:
+ g_free(tm->m.exact);
+ break;
+ case MATCH_TYPE_NONE:
+ break;
+ }
+}
+
+static gboolean check_typed_match(TypedMatch *tm, const gchar *s)
+{
+ switch (tm->type) {
+ case MATCH_TYPE_PATTERN:
+ return g_pattern_match_string(tm->m.pattern, s);
+ case MATCH_TYPE_REGEX:
+ return g_regex_match(tm->m.regex, s, 0, NULL);
+ case MATCH_TYPE_EXACT:
+ return !strcmp(tm->m.exact, s);
+ case MATCH_TYPE_NONE:
+ return TRUE;
+ }
+ g_assert_not_reached();
+}
+
static void setup_query(Options* o, xmlNodePtr node, QueryTarget target) {
Query *q = g_slice_new0(Query);
g_array_append_val(o->queries, q);
q->screendesktop_number = obt_xml_node_int(n);
}
if ((n = obt_xml_find_node(node, "title"))) {
- gchar *s, *type = NULL;
- if ((s = obt_xml_node_string(n))) {
- if (!obt_xml_attr_string(n, "type", &type) ||
- !g_ascii_strcasecmp(type, "pattern"))
- {
- q->matchtitle = g_pattern_spec_new(s);
- } else if (type && !g_ascii_strcasecmp(type, "regex")) {
- q->regextitle = g_regex_new(s, 0, 0, NULL);
- } else if (type && !g_ascii_strcasecmp(type, "exact")) {
- q->exacttitle = g_strdup(s);
- }
- g_free(s);
- }
+ setup_typed_match(&q->title, n);
+ }
+ if ((n = obt_xml_find_node(node, "class"))) {
+ setup_typed_match(&q->class, n);
+ }
+ if ((n = obt_xml_find_node(node, "name"))) {
+ setup_typed_match(&q->name, n);
+ }
+ if ((n = obt_xml_find_node(node, "role"))) {
+ setup_typed_match(&q->role, n);
+ }
+ if ((n = obt_xml_find_node(node, "type"))) {
+ setup_typed_match(&q->type, n);
}
if ((n = obt_xml_find_node(node, "monitor"))) {
q->client_monitor = obt_xml_node_int(n);
for (i = 0; i < o->queries->len; ++i) {
Query *q = g_array_index(o->queries, Query*, i);
- if (q->matchtitle)
- g_pattern_spec_free(q->matchtitle);
- if (q->regextitle)
- g_regex_unref(q->regextitle);
- if (q->exacttitle)
- g_free(q->exacttitle);
+ free_typed_match(&q->title);
+ free_typed_match(&q->class);
+ free_typed_match(&q->name);
+ free_typed_match(&q->role);
+ free_typed_match(&q->type);
g_slice_free(Query, q);
}
}
/* Always return FALSE because its not interactive */
-static gboolean run_func(ObActionsData *data, gpointer options)
+static gboolean run_func_if(ObActionsData *data, gpointer options)
{
Options *o = options;
ObClient *action_target = data->client;
if (q->screendesktop_number)
is_true &= screen_desktop == q->screendesktop_number - 1;
- if (q->matchtitle) {
- is_true &= g_pattern_match_string(q->matchtitle,
- query_target->original_title);
- }
- if (q->regextitle) {
- is_true &= g_regex_match(q->regextitle,
- query_target->original_title,
- 0,
- NULL);
- }
- if (q->exacttitle)
- is_true &= !strcmp(q->exacttitle, query_target->original_title);
+ is_true &= check_typed_match(&q->title, query_target->original_title);
+ is_true &= check_typed_match(&q->class, query_target->class);
+ is_true &= check_typed_match(&q->name, query_target->name);
+ is_true &= check_typed_match(&q->role, query_target->role);
+ is_true &= check_typed_match(&q->type,
+ client_type_to_string(query_target));
if (q->client_monitor)
is_true &= client_monitor(query_target) == q->client_monitor - 1;
return FALSE;
}
+
+static gboolean run_func_foreach(ObActionsData *data, gpointer options)
+{
+ GList *it;
+ Options *o = options;
+
+ o->stop = FALSE;
+
+ for (it = client_list; it; it = g_list_next(it)) {
+ data->client = it->data;
+ run_func_if(data, options);
+ if (o->stop) {
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean run_func_stop(ObActionsData *data, gpointer options)
+{
+ Options *o = options;
+
+ /* This stops the loop above so we don't invoke actions on any more
+ clients */
+ o->stop = TRUE;
+
+ /* TRUE causes actions_run_acts to not run further actions on the current
+ client */
+ return TRUE;
+}