Add ForEach action which is like If but runs on all clients
[mikachu/openbox.git] / openbox / actions.c
index 023fab3..bf00c6c 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 
-   actions.h for the Openbox window manager
+   actions.c for the Openbox window manager
    Copyright (c) 2007        Dana Jansens
 
    This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
 #include "event.h"
 #include "config.h"
 #include "client.h"
+#include "focus.h"
 #include "openbox.h"
 #include "debug.h"
 
@@ -49,6 +50,9 @@ struct _ObActionsDefinition {
     } setup;
     ObActionsDataFreeFunc free;
     ObActionsRunFunc run;
+    ObActionsShutdownFunc shutdown;
+    gboolean modifies_focused_window;
+    gboolean can_stop;
 };
 
 struct _ObActionsAct {
@@ -79,7 +83,9 @@ void actions_shutdown(gboolean reconfig)
 
     /* free all the registered actions */
     while (registered) {
-        actions_definition_unref(registered->data);
+        ObActionsDefinition *d = registered->data;
+        if (d->shutdown) d->shutdown();
+        actions_definition_unref(d);
         registered = g_slist_delete_link(registered, registered);
     }
 }
@@ -99,11 +105,14 @@ ObActionsDefinition* do_register(const gchar *name,
             return NULL;
     }
 
-    def = g_new(ObActionsDefinition, 1);
+    def = g_slice_new0(ObActionsDefinition);
     def->ref = 1;
     def->name = g_strdup(name);
     def->free = free;
     def->run = run;
+    def->shutdown = NULL;
+    def->modifies_focused_window = TRUE;
+    def->can_stop = FALSE;
 
     registered = g_slist_prepend(registered, def);
     return def;
@@ -135,6 +144,54 @@ gboolean actions_register(const gchar *name,
     return def != NULL;
 }
 
+gboolean actions_set_shutdown(const gchar *name,
+                              ObActionsShutdownFunc shutdown)
+{
+    GSList *it;
+    ObActionsDefinition *def;
+
+    for (it = registered; it; it = g_slist_next(it)) {
+        def = it->data;
+        if (!g_ascii_strcasecmp(name, def->name)) {
+            def->shutdown = shutdown;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+gboolean actions_set_modifies_focused_window(const gchar *name,
+                                             gboolean modifies)
+{
+    GSList *it;
+    ObActionsDefinition *def;
+
+    for (it = registered; it; it = g_slist_next(it)) {
+        def = it->data;
+        if (!g_ascii_strcasecmp(name, def->name)) {
+            def->modifies_focused_window = modifies;
+            return TRUE;
+        }
+    }
+    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;
@@ -144,7 +201,7 @@ static void actions_definition_unref(ObActionsDefinition *def)
 {
     if (def && --def->ref == 0) {
         g_free(def->name);
-        g_free(def);
+        g_slice_free(ObActionsDefinition, def);
     }
 }
 
@@ -164,7 +221,7 @@ static ObActionsAct* actions_build_act_from_string(const gchar *name)
 
     /* if we found the action */
     if (def) {
-        act = g_new(ObActionsAct, 1);
+        act = g_slice_new(ObActionsAct);
         act->ref = 1;
         act->def = def;
         actions_definition_ref(act->def);
@@ -248,7 +305,7 @@ void actions_act_unref(ObActionsAct *act)
             act->def->free(act->options);
         /* unref the definition */
         actions_definition_unref(act->def);
-        g_free(act);
+        g_slice_free(ObActionsAct, act);
     }
 }
 
@@ -280,6 +337,7 @@ void actions_run_acts(GSList *acts,
                       struct _ObClient *client)
 {
     GSList *it;
+    gboolean update_user_time;
 
     /* Don't allow saving the initial state when running things from the
        menu */
@@ -289,6 +347,7 @@ void actions_run_acts(GSList *acts,
     if (x < 0 && y < 0)
         screen_pointer_pos(&x, &y);
 
+    update_user_time = FALSE;
     for (it = acts; it; it = g_slist_next(it)) {
         ObActionsData data;
         ObActionsAct *act = it->data;
@@ -315,17 +374,26 @@ void actions_run_acts(GSList *acts,
         /* 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();
+                }
+                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;
             }
         }
     }
+    if (update_user_time)
+        event_update_user_time();
 }
 
 gboolean actions_interactive_act_running(void)
@@ -363,13 +431,19 @@ static gboolean actions_interactive_begin_act(ObActionsAct *act, guint state)
 static void actions_interactive_end_act(void)
 {
     if (interactive_act) {
+        ObActionsAct *ia = interactive_act;
+
+        /* set this to NULL first so the i_post() function can't cause this to
+           get called again (if it decides it wants to cancel any ongoing
+           interactive action). */
+        interactive_act = NULL;
+
         ungrab_keyboard();
 
-        if (interactive_act->i_post)
-            interactive_act->i_post(interactive_act->options);
+        if (ia->i_post)
+            ia->i_post(ia->options);
 
-        actions_act_unref(interactive_act);
-        interactive_act = NULL;
+        actions_act_unref(ia);
     }
 }
 
@@ -378,6 +452,7 @@ gboolean actions_interactive_input_event(XEvent *e)
     gboolean used = FALSE;
     if (interactive_act) {
         if (!interactive_act->i_input(interactive_initial_state, e,
+                                      grab_input_context(),
                                       interactive_act->options, &used))
         {
             used = TRUE; /* if it cancelled the action then it has to of
@@ -419,7 +494,7 @@ void actions_client_move(ObActionsData *data, gboolean start)
                     ob_debug_type(OB_DEBUG_FOCUS,
                                   "Generating fake leave because we did a "
                                   "mouse-event action");
-                    event_enter_client(data->client);
+                    event_leave_client(data->client);
                 }
             }
         }