Add ForEach action which is like If but runs on all clients
authorMikael Magnusson <mikachu@gmail.com>
Sun, 18 Aug 2013 22:03:51 +0000 (00:03 +0200)
committerMikael Magnusson <mikachu@gmail.com>
Mon, 19 Aug 2013 19:35:44 +0000 (21:35 +0200)
Also adds a Stop action that lets you stop running, in case you only
want to run actions on the first match.

openbox/actions.c
openbox/actions.h
openbox/actions/if.c

index ac849a9..bf00c6c 100644 (file)
@@ -52,6 +52,7 @@ struct _ObActionsDefinition {
     ObActionsRunFunc run;
     ObActionsShutdownFunc shutdown;
     gboolean modifies_focused_window;
     ObActionsRunFunc run;
     ObActionsShutdownFunc shutdown;
     gboolean modifies_focused_window;
+    gboolean can_stop;
 };
 
 struct _ObActionsAct {
 };
 
 struct _ObActionsAct {
@@ -111,6 +112,7 @@ ObActionsDefinition* do_register(const gchar *name,
     def->run = run;
     def->shutdown = NULL;
     def->modifies_focused_window = TRUE;
     def->run = run;
     def->shutdown = NULL;
     def->modifies_focused_window = TRUE;
+    def->can_stop = FALSE;
 
     registered = g_slist_prepend(registered, def);
     return def;
 
     registered = g_slist_prepend(registered, def);
     return def;
@@ -174,6 +176,22 @@ gboolean actions_set_modifies_focused_window(const gchar *name,
     return FALSE;
 }
 
     return FALSE;
 }
 
+gboolean actions_set_can_stop(const gchar *name,
+                              gboolean can_stop)
+{
+    GSList *it;
+    ObActionsDefinition *def;
+
+    for (it = registered; it; it = g_slist_next(it)) {
+        def = it->data;
+        if (!g_ascii_strcasecmp(name, def->name)) {
+            def->can_stop = can_stop;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
 static void actions_definition_ref(ObActionsDefinition *def)
 {
     ++def->ref;
 static void actions_definition_ref(ObActionsDefinition *def)
 {
     ++def->ref;
@@ -356,16 +374,18 @@ void actions_run_acts(GSList *acts,
         /* fire the action's run function with this data */
         if (ok) {
             if (!act->def->run(&data, act->options)) {
         /* fire the action's run function with this data */
         if (ok) {
             if (!act->def->run(&data, act->options)) {
-                if (actions_act_is_interactive(act))
+                if (actions_act_is_interactive(act)) {
                     actions_interactive_end_act();
                     actions_interactive_end_act();
+                }
                 if (client && client == focus_client &&
                     act->def->modifies_focused_window)
                 {
                     update_user_time = TRUE;
                 }
             } else {
                 if (client && client == focus_client &&
                     act->def->modifies_focused_window)
                 {
                     update_user_time = TRUE;
                 }
             } else {
-                /* make sure its interactive if it returned TRUE */
-                g_assert(act->i_input);
+                /* make sure its interactive or allowed to stop
+                   if it returned TRUE */
+                g_assert(act->i_input || act->def->can_stop);
 
                 /* no actions are run after the interactive one */
                 break;
 
                 /* no actions are run after the interactive one */
                 break;
index f413ad8..f8e1ba8 100644 (file)
@@ -84,6 +84,8 @@ gboolean actions_set_shutdown(const gchar *name,
                               ObActionsShutdownFunc shutdown);
 gboolean actions_set_modifies_focused_window(const gchar *name,
                                              gboolean modifies);
                               ObActionsShutdownFunc shutdown);
 gboolean actions_set_modifies_focused_window(const gchar *name,
                                              gboolean modifies);
+gboolean actions_set_can_stop(const gchar *name,
+                              gboolean modifies);
 
 ObActionsAct* actions_parse(xmlNodePtr node);
 ObActionsAct* actions_parse_string(const gchar *name);
 
 ObActionsAct* actions_parse(xmlNodePtr node);
 ObActionsAct* actions_parse_string(const gchar *name);
index 8a31c9a..1802c6a 100644 (file)
@@ -64,15 +64,22 @@ typedef struct {
     GArray* queries;
     GSList *thenacts;
     GSList *elseacts;
     GArray* queries;
     GSList *thenacts;
     GSList *elseacts;
+    gboolean stop;
 } Options;
 
 static gpointer setup_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 } 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)
 {
 
 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 inline void set_bool(xmlNodePtr node,
@@ -228,7 +235,7 @@ static void free_func(gpointer options)
 }
 
 /* Always return FALSE because its not interactive */
 }
 
 /* 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;
 {
     Options *o = options;
     ObClient *action_target = data->client;
@@ -351,3 +358,34 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     return FALSE;
 }
 
     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;
+}