Let the If action match window titles with GRegex
[dana/openbox.git] / openbox / actions / if.c
index 833bdd3..7087d6a 100644 (file)
@@ -19,6 +19,19 @@ typedef struct {
     gboolean iconic_off;
     gboolean focused;
     gboolean unfocused;
+    gboolean urgent_on;
+    gboolean urgent_off;
+    gboolean decor_off;
+    gboolean decor_on;
+    gboolean omnipresent_on;
+    gboolean omnipresent_off;
+    gboolean desktop_current;
+    gboolean desktop_other;
+    guint    desktop_number;
+    guint    screendesktop_number;
+    GPatternSpec *matchtitle;
+    GRegex *regextitle;
+    gchar  *plaintitle;
     GSList *thenacts;
     GSList *elseacts;
 } Options;
@@ -29,71 +42,90 @@ static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_if_startup(void)
 {
-    actions_register("If", setup_func, free_func, run_func, NULL, NULL);
+    actions_register("If", setup_func, free_func, run_func);
 }
 
-static gpointer setup_func(xmlNodePtr node)
+static inline set_bool(xmlNodePtr node,
+                       const char *name,
+                       gboolean *on,
+                       gboolean *off)
 {
     xmlNodePtr n;
-    Options *o;
-
-    o = g_new0(Options, 1);
 
-    if ((n = obt_parse_find_node(node, "shaded"))) {
-        if (obt_parse_node_bool(n))
-            o->shaded_on = TRUE;
-        else
-            o->shaded_off = TRUE;
-    }
-    if ((n = obt_parse_find_node(node, "maximized"))) {
-        if (obt_parse_node_bool(n))
-            o->maxfull_on = TRUE;
+    if ((n = obt_xml_find_node(node, name))) {
+        if (obt_xml_node_bool(n))
+            *on = TRUE;
         else
-            o->maxfull_off = TRUE;
+            *off = TRUE;
     }
-    if ((n = obt_parse_find_node(node, "maximizedhorizontal"))) {
-        if (obt_parse_node_bool(n))
-            o->maxhorz_on = TRUE;
-        else
-            o->maxhorz_off = TRUE;
-    }
-    if ((n = obt_parse_find_node(node, "maximizedvertical"))) {
-        if (obt_parse_node_bool(n))
-            o->maxvert_on = TRUE;
-        else
-            o->maxvert_off = TRUE;
+}
+
+static gpointer setup_func(xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o;
+
+    o = g_slice_new0(Options);
+
+    set_bool(node, "shaded", &o->shaded_on, &o->shaded_off);
+    set_bool(node, "maximized", &o->maxfull_on, &o->maxfull_off);
+    set_bool(node, "maximizedhorizontal", &o->maxhorz_on, &o->maxhorz_off);
+    set_bool(node, "maximizedvertical", &o->maxvert_on, &o->maxvert_off);
+    set_bool(node, "iconified", &o->iconic_on, &o->iconic_off);
+    set_bool(node, "focused", &o->focused, &o->unfocused);
+    set_bool(node, "urgent", &o->urgent_on, &o->urgent_off);
+    set_bool(node, "undecorated", &o->decor_off, &o->decor_on);
+    set_bool(node, "omnipresent", &o->omnipresent_on, &o->omnipresent_off);
+
+    if ((n = obt_xml_find_node(node, "desktop"))) {
+        gchar *s;
+        if ((s = obt_xml_node_string(n))) {
+            if (!g_ascii_strcasecmp(s, "current"))
+                o->desktop_current = TRUE;
+            if (!g_ascii_strcasecmp(s, "other"))
+                o->desktop_other = TRUE;
+            else
+                o->desktop_number = atoi(s);
+            g_free(s);
+        }
     }
-    if ((n = obt_parse_find_node(node, "iconified"))) {
-        if (obt_parse_node_bool(n))
-            o->iconic_on = TRUE;
-        else
-            o->iconic_off = TRUE;
+    if ((n = obt_xml_find_node(node, "activedesktop"))) {
+        o->screendesktop_number = obt_xml_node_int(n);
     }
-    if ((n = obt_parse_find_node(node, "focused"))) {
-        if (obt_parse_node_bool(n))
-            o->focused = TRUE;
-        else
-            o->unfocused = TRUE;
+    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"))
+            {
+                o->matchtitle = g_pattern_spec_new(s);
+            } else if (type && !g_ascii_strcasecmp(type, "regex")) {
+                o->regextitle = g_regex_new(s, 0, 0, NULL);
+            } else if (type && !g_ascii_strcasecmp(type, "plain")) {
+                o->plaintitle = g_strdup(s);
+            }
+            g_free(s);
+        }
     }
 
-    if ((n = obt_parse_find_node(node, "then"))) {
+    if ((n = obt_xml_find_node(node, "then"))) {
         xmlNodePtr m;
 
-        m = obt_parse_find_node(n->children, "action");
+        m = obt_xml_find_node(n->children, "action");
         while (m) {
             ObActionsAct *action = actions_parse(m);
             if (action) o->thenacts = g_slist_append(o->thenacts, action);
-            m = obt_parse_find_node(m->next, "action");
+            m = obt_xml_find_node(m->next, "action");
         }
     }
-    if ((n = obt_parse_find_node(node, "else"))) {
+    if ((n = obt_xml_find_node(node, "else"))) {
         xmlNodePtr m;
 
-        m = obt_parse_find_node(n->children, "action");
+        m = obt_xml_find_node(n->children, "action");
         while (m) {
             ObActionsAct *action = actions_parse(m);
             if (action) o->elseacts = g_slist_append(o->elseacts, action);
-            m = obt_parse_find_node(m->next, "action");
+            m = obt_xml_find_node(m->next, "action");
         }
     }
 
@@ -112,8 +144,14 @@ static void free_func(gpointer options)
         actions_act_unref(o->elseacts->data);
         o->elseacts = g_slist_delete_link(o->elseacts, o->elseacts);
     }
-
-    g_free(o);
+    if (o->matchtitle)
+        g_pattern_spec_free(o->matchtitle);
+    if (o->regextitle)
+        g_regex_unref(o->regextitle);
+    if (o->plaintitle)
+        g_free(o->plaintitle);
+
+    g_slice_free(Options, o);
 }
 
 /* Always return FALSE because its not interactive */
@@ -123,18 +161,38 @@ static gboolean run_func(ObActionsData *data, gpointer options)
     GSList *acts;
     ObClient *c = data->client;
 
-    if ((!o->shaded_on || (c && c->shaded)) &&
-        (!o->shaded_off || (c && !c->shaded)) &&
-        (!o->iconic_on || (c && c->iconic)) &&
-        (!o->iconic_off || (c && !c->iconic)) &&
-        (!o->maxhorz_on || (c && c->max_horz)) &&
-        (!o->maxhorz_off || (c && !c->max_horz)) &&
-        (!o->maxvert_on || (c && c->max_vert)) &&
-        (!o->maxvert_off || (c && !c->max_vert)) &&
-        (!o->maxfull_on || (c && c->max_vert && c->max_horz)) &&
-        (!o->maxfull_off || (c && !(c->max_vert && c->max_horz))) &&
-        (!o->focused || (c && (c == focus_client))) &&
-        (!o->unfocused || (c && !(c == focus_client))))
+    if (c &&
+        (!o->shaded_on   ||  c->shaded) &&
+        (!o->shaded_off  || !c->shaded) &&
+        (!o->iconic_on   ||  c->iconic) &&
+        (!o->iconic_off  || !c->iconic) &&
+        (!o->maxhorz_on  ||  c->max_horz) &&
+        (!o->maxhorz_off || !c->max_horz) &&
+        (!o->maxvert_on  ||  c->max_vert) &&
+        (!o->maxvert_off || !c->max_vert) &&
+        (!o->maxfull_on  ||  (c->max_vert && c->max_horz)) &&
+        (!o->maxfull_off || !(c->max_vert && c->max_horz)) &&
+        (!o->focused     ||  (c == focus_client)) &&
+        (!o->unfocused   || !(c == focus_client)) &&
+        (!o->urgent_on   ||  (c->urgent || c->demands_attention)) &&
+        (!o->urgent_off  || !(c->urgent || c->demands_attention)) &&
+        (!o->decor_off   ||  (c->undecorated || !(c->decorations & OB_FRAME_DECOR_TITLEBAR))) &&
+        (!o->decor_on    ||  (!c->undecorated && (c->decorations & OB_FRAME_DECOR_TITLEBAR))) &&
+        (!o->omnipresent_on  || (c->desktop == DESKTOP_ALL)) &&
+        (!o->omnipresent_off || (c->desktop != DESKTOP_ALL)) &&
+        (!o->desktop_current || ((c->desktop == screen_desktop) ||
+                                 (c->desktop == DESKTOP_ALL))) &&
+        (!o->desktop_other   || ((c->desktop != screen_desktop) &&
+                                 (c->desktop != DESKTOP_ALL))) &&
+        (!o->desktop_number  || ((c->desktop == o->desktop_number - 1) ||
+                                 (c->desktop == DESKTOP_ALL))) &&
+        (!o->screendesktop_number || screen_desktop == o->screendesktop_number - 1) &&
+        (!o->matchtitle ||
+         (g_pattern_match_string(o->matchtitle, c->original_title))) &&
+        (!o->regextitle ||
+         (g_regex_match(o->regextitle, c->original_title, 0, NULL))) &&
+        (!o->plaintitle ||
+         (!strcmp(o->plaintitle, c->original_title))))
     {
         acts = o->thenacts;
     }