]> Dogcows Code - chaz/openbox/commitdiff
wow... this is a big commit...
authorDana Jansens <danakj@orodu.net>
Sun, 11 Mar 2007 04:44:15 +0000 (04:44 +0000)
committerDana Jansens <danakj@orodu.net>
Sun, 11 Mar 2007 04:44:15 +0000 (04:44 +0000)
all related to _NET_WM_USER_TIME and focus stealing prevention

a) add launcher startup notification. this means when you run something from
   the openbox menu or a key/mouse binding, that startup notification will go
   on in openbox and other applications like your panel or something
b) add the _NET_WM_USER_TIME property for windows
c) use the _NET_WM_USER_TIME data and startup notification to prevent focus
   stealing.
d) cookie party !! ! all are invited.
e) oh yeah, and pass around timestamps for a lot more things. like, when you
   run an action, send the timestamp for the event that is running the action.
   this is important for startup notification. this also affects menus.
f) yes.. cookies..

would it be a good idea to disable focus stealing prevention if a window takes
too long to load? i mean.. maybe after a certain length of time, a user can't be
expected to not do anything in any other windows, but would they still want the
new application to focus then? HMM. open question i guess..

16 files changed:
openbox/action.c
openbox/action.h
openbox/client.c
openbox/client.h
openbox/client_list_combined_menu.c
openbox/client_list_menu.c
openbox/event.c
openbox/focus.c
openbox/focus.h
openbox/keyboard.c
openbox/menu.h
openbox/menuframe.c
openbox/menuframe.h
openbox/mouse.c
openbox/startupnotify.c
openbox/startupnotify.h

index 8ad60931f9f40b2f709b00dcba7eb27455a17664..7d41d71262695866648e600b621443eece8f593d 100644 (file)
@@ -33,6 +33,7 @@
 #include "dock.h"
 #include "config.h"
 #include "mainloop.h"
+#include "startupnotify.h"
 
 #include <glib.h>
 
@@ -1005,7 +1006,7 @@ ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 }
 
 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
-                     guint state, guint button, gint x, gint y,
+                     guint state, guint button, gint x, gint y, Time time,
                      gboolean cancel, gboolean done)
 {
     GSList *it;
@@ -1048,6 +1049,8 @@ void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
 
             a->data.any.button = button;
 
+            a->data.any.time = time;
+
             if (a->data.any.interactive) {
                 a->data.inter.cancel = cancel;
                 a->data.inter.final = done;
@@ -1068,7 +1071,7 @@ void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
     }
 }
 
-void action_run_string(const gchar *name, struct _ObClient *c)
+void action_run_string(const gchar *name, struct _ObClient *c, Time time)
 {
     ObAction *a;
     GSList *l;
@@ -1078,7 +1081,7 @@ void action_run_string(const gchar *name, struct _ObClient *c)
 
     l = g_slist_append(NULL, a);
 
-    action_run(l, c, 0);
+    action_run(l, c, 0, time);
 }
 
 void action_execute(union ActionData *data)
@@ -1093,13 +1096,21 @@ void action_execute(union ActionData *data)
                           cmd, e->message);
                 g_error_free(e);
             } else {
-                if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
+                gchar **env, *program;
+                
+                program = g_path_get_basename(argv[0]);
+                env = sn_get_spawn_environment(program,
+                                               data->execute.any.time);
+                if (!g_spawn_async(NULL, argv, env, G_SPAWN_SEARCH_PATH |
                                    G_SPAWN_DO_NOT_REAP_CHILD,
                                    NULL, NULL, NULL, &e)) {
                     g_warning("failed to execute '%s': %s",
                               cmd, e->message);
                     g_error_free(e);
+                    sn_spawn_cancel();
                 }
+                g_strfreev(env);
+                g_free(program);
                 g_strfreev(argv);
             }
             g_free(cmd);
@@ -1119,7 +1130,8 @@ void action_activate(union ActionData *data)
            moving on us */
         event_halt_focus_delay();
 
-        client_activate(data->activate.any.c, data->activate.here, TRUE);
+        client_activate(data->activate.any.c, data->activate.here, TRUE,
+                        data->activate.any.time);
     }
 }
 
@@ -1594,7 +1606,8 @@ void action_cycle_windows(union ActionData *data)
 
     focus_cycle(data->cycle.forward, data->cycle.linear, data->any.interactive,
                 data->cycle.dialog,
-                data->cycle.inter.final, data->cycle.inter.cancel);
+                data->cycle.inter.final, data->cycle.inter.cancel,
+                data->cycle.inter.any.time);
 }
 
 void action_directional_focus(union ActionData *data)
@@ -1607,7 +1620,8 @@ void action_directional_focus(union ActionData *data)
                             data->any.interactive,
                             data->interdiraction.dialog,
                             data->interdiraction.inter.final,
-                            data->interdiraction.inter.cancel);
+                            data->interdiraction.inter.cancel,
+                            data->interdiraction.inter.any.time);
 }
 
 void action_movetoedge(union ActionData *data)
index 4c749fee0932eaf921d322cad578c8c36cdb4f95..639db0184352e6cdd5ae8dfa76aa851bdf1d809f 100644 (file)
@@ -48,6 +48,7 @@ struct AnyAction {
     gint x;
     gint y;
     gint button;
+    Time time;
 };
 
 struct InteractiveAction {
@@ -209,22 +210,22 @@ ObAction* action_copy(const ObAction *a);
          affects interactive actions, but should generally always be FALSE.
 */
 void action_run_list(GSList *acts, struct _ObClient *c, ObFrameContext context,
-                     guint state, guint button, gint x, gint y,
+                     guint state, guint button, gint x, gint y, Time time,
                      gboolean cancel, gboolean done);
 
-#define action_run_mouse(a, c, n, s, b, x, y) \
-    action_run_list(a, c, n, s, b, x, y, FALSE, FALSE)
+#define action_run_mouse(a, c, n, s, b, x, y, t) \
+    action_run_list(a, c, n, s, b, x, y, t, FALSE, FALSE)
 
-#define action_run_interactive(a, c, s, n, d) \
-    action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, -1, -1, n, d)
+#define action_run_interactive(a, c, s, t, n, d) \
+    action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, -1, -1, t, n, d)
 
-#define action_run_key(a, c, s, x, y) \
-    action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, x, y, FALSE, FALSE)
+#define action_run_key(a, c, s, x, y, t) \
+    action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, x, y, t, FALSE, FALSE)
 
-#define action_run(a, c, s) \
-    action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, -1, -1, FALSE, FALSE)
+#define action_run(a, c, s, t) \
+    action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, -1, -1, t, FALSE, FALSE)
 
-void action_run_string(const gchar *name, struct _ObClient *c);
+void action_run_string(const gchar *name, struct _ObClient *c, Time time);
 
 /* Execute */
 void action_execute(union ActionData *data);
index bfb9f790169f6e39eccd05e634f92d3de0b8544b..cbef506ef0a9e05de8e01958f12b37b769dfb136 100644 (file)
@@ -296,11 +296,15 @@ void client_manage(Window window)
     self->wmstate = NormalState;
     self->layer = -1;
     self->desktop = screen_num_desktops; /* always an invalid value */
+    self->user_time = ~0; /* maximum value, always newer than the real time */
 
     client_get_all(self);
     client_restore_session_state(self);
 
-    self->user_time = sn_app_started(self->startup_id, self->class);
+    {
+        Time t = sn_app_started(self->startup_id, self->class);
+        if (t) self->user_time = t;
+    }
 
     /* update the focus lists, do this before the call to change_state or
        it can end up in the list twice! */
@@ -327,7 +331,7 @@ void client_manage(Window window)
     /* get and set application level settings */
     settings = get_settings(self);
 
-    stacking_add(CLIENT_AS_WINDOW(self));
+    stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
     client_restore_session_stacking(self);
 
     if (settings) {
@@ -453,35 +457,55 @@ void client_manage(Window window)
     keyboard_grab_for_client(self, TRUE);
     mouse_grab_for_client(self, TRUE);
 
-    client_showhide(self);
-
-    /* use client_focus instead of client_activate cuz client_activate does
-       stuff like switch desktops etc and I'm not interested in all that when
-       a window maps since its not based on an action from the user like
-       clicking a window to activate is. so keep the new window out of the way
-       but do focus it. */
     if (activate) {
         /* This is focus stealing prevention, if a user_time has been set */
-        if (self->user_time == CurrentTime ||
-            self->user_time > client_last_user_time)
+        ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n",
+                 self->window, self->user_time, client_last_user_time);
+        if (!self->user_time || self->user_time >= client_last_user_time)
         {
-            /* if using focus_delay, stop the timer now so that focus doesn't
-               go moving on us */
-            event_halt_focus_delay();
-
-            client_focus(self);
             /* since focus can change the stacking orders, if we focus the
                window then the standard raise it gets is not enough, we need
                to queue one for after the focus change takes place */
             client_raise(self);
         } else {
-            ob_debug("Focus stealing prevention activated for %s\n",
-                     self->title);
+            ob_debug("Focus stealing prevention activated for %s with time %u "
+                     "(last time %u)\n",
+                     self->title, self->user_time, client_last_user_time);
             /* if the client isn't focused, then hilite it so the user
                knows it is there */
             client_hilite(self, TRUE);
+
+            /* don't focus it ! (focus stealing prevention) */
+            activate = FALSE;
         }
     }
+    else {
+        /* This may look rather odd. Well it's because new windows are added
+           to the stacking order non-intrusively. If we're not going to focus
+           the new window or hilite it, then we raise it to the top. This will
+           take affect for things that don't get focused like splash screens.
+           Also if you don't have focus_new enabled, then it's going to get
+           raised to the top. Legacy begets legacy I guess?
+        */
+        client_raise(self);
+    }
+
+    /* this has to happen before we try focus the window, but we want it to
+       happen after the client's stacking has been determined or it looks bad
+    */
+    client_showhide(self);
+
+    /* use client_focus instead of client_activate cuz client_activate does
+       stuff like switch desktops etc and I'm not interested in all that when
+       a window maps since its not based on an action from the user like
+       clicking a window to activate it. so keep the new window out of the way
+       but do focus it. */
+    if (activate) {
+        /* if using focus_delay, stop the timer now so that focus doesn't
+           go moving on us */
+        event_halt_focus_delay();
+        client_focus(self);
+    }
 
     /* client_activate does this but we aret using it so we have to do it
        here as well */
@@ -2926,46 +2950,52 @@ void client_unfocus(ObClient *self)
     }
 }
 
-void client_activate(ObClient *self, gboolean here, gboolean user)
+void client_activate(ObClient *self, gboolean here, gboolean user,
+                     Time timestamp)
 {
     /* XXX do some stuff here if user is false to determine if we really want
-       to activate it or not (a parent or group member is currently active) */
-
-    if (client_normal(self) && screen_showing_desktop)
-        screen_show_desktop(FALSE);
-    if (self->iconic)
-        client_iconify(self, FALSE, here);
-    if (self->desktop != DESKTOP_ALL &&
-        self->desktop != screen_desktop) {
-        if (here)
-            client_set_desktop(self, screen_desktop, FALSE);
-        else
-            screen_set_desktop(self->desktop);
-    } else if (!self->frame->visible)
-        /* if its not visible for other reasons, then don't mess
-           with it */
-        return;
-    if (self->shaded)
-        client_shade(self, FALSE);
+       to activate it or not (a parent or group member is currently
+       active)?
+    */
+    if (!user)
+        client_hilite(self, TRUE);
+    else {
+        if (client_normal(self) && screen_showing_desktop)
+            screen_show_desktop(FALSE);
+        if (self->iconic)
+            client_iconify(self, FALSE, here);
+        if (self->desktop != DESKTOP_ALL &&
+            self->desktop != screen_desktop) {
+            if (here)
+                client_set_desktop(self, screen_desktop, FALSE);
+            else
+                screen_set_desktop(self->desktop);
+        } else if (!self->frame->visible)
+            /* if its not visible for other reasons, then don't mess
+               with it */
+            return;
+        if (self->shaded)
+            client_shade(self, FALSE);
 
-    client_focus(self);
+        client_focus(self);
 
-    /* we do this an action here. this is rather important. this is because
-       we want the results from the focus change to take place BEFORE we go
-       about raising the window. when a fullscreen window loses focus, we need
-       this or else the raise wont be able to raise above the to-lose-focus
-       fullscreen window. */
-    client_raise(self);
+        /* we do this an action here. this is rather important. this is because
+           we want the results from the focus change to take place BEFORE we go
+           about raising the window. when a fullscreen window loses focus, we
+           need this or else the raise wont be able to raise above the
+           to-lose-focus fullscreen window. */
+        client_raise(self);
+    }
 }
 
 void client_raise(ObClient *self)
 {
-    action_run_string("Raise", self);
+    action_run_string("Raise", self, CurrentTime);
 }
 
 void client_lower(ObClient *self)
 {
-    action_run_string("Lower", self);
+    action_run_string("Lower", self, CurrentTime);
 }
 
 gboolean client_focused(ObClient *self)
index cb6eed53e7ae4d9e5b7ab02308f724f1f2071e13..04849b632e89fbb3b08593e6287c0076e702e0d2 100644 (file)
@@ -484,8 +484,10 @@ void client_unfocus(ObClient *self);
               otherwise, the desktop is changed to where the client lives.
   @param user If true, then a user action is what requested the activation;
               otherwise, it means an application requested it on its own
+  @param timestamp The time at which the activate was requested.
 */
-void client_activate(ObClient *self, gboolean here, gboolean user);
+void client_activate(ObClient *self, gboolean here, gboolean user,
+                     Time timestamp);
 
 /*! Calculates the stacking layer for the client window */
 void client_calc_layer(ObClient *self);
index bc8081b5fda2061cbcee0d7dde99482efa145124..c18c9c201d35216414d538181a3aec321932b5d7 100644 (file)
@@ -84,13 +84,14 @@ static void self_update(ObMenuFrame *frame, gpointer data)
 
 /* executes it using the client in the actions, since we set that
    when we make the actions! */
-static void menu_execute(ObMenuEntry *self, guint state, gpointer data)
+static void menu_execute(ObMenuEntry *self, guint state, gpointer data,
+                         Time time)
 {
     ObAction *a;
 
     if (self->data.normal.actions) {
         a = self->data.normal.actions->data;
-        action_run(self->data.normal.actions, a->data.any.c, state);
+        action_run(self->data.normal.actions, a->data.any.c, state, time);
     }
 }
 
index 569269a37a9c7f33e527a52dd8ba32fde49d6a49..d703babdf334621d3e0308a964fa7a8b14e6c19e 100644 (file)
@@ -102,13 +102,14 @@ static void desk_menu_update(ObMenuFrame *frame, gpointer data)
 
 /* executes it using the client in the actions, since we set that
    when we make the actions! */
-static void desk_menu_execute(ObMenuEntry *self, guint state, gpointer data)
+static void desk_menu_execute(ObMenuEntry *self, guint state, gpointer data,
+                              Time time)
 {
     ObAction *a;
 
     if (self->data.normal.actions) {
         a = self->data.normal.actions->data;
-        action_run(self->data.normal.actions, a->data.any.c, state);
+        action_run(self->data.normal.actions, a->data.any.c, state, time);
     }
 }
 
index 9faf9403e6f4a6d328e6f056377eb9cebb8636f1..1988f108ab45f108eed34c3d269cd3df7556cf23 100644 (file)
@@ -895,13 +895,17 @@ static void event_handle_client(ObClient *client, XEvent *e)
             switch (e->xconfigurerequest.detail) {
             case Below:
             case BottomIf:
-                client_lower(client);
+                /* Apps are so rude. And this is totally disconnected from
+                   activation/focus. Bleh. */
+                /*client_lower(client);*/
                 break;
 
             case Above:
             case TopIf:
             default:
-                client_raise(client);
+                /* Apps are so rude. And this is totally disconnected from
+                   activation/focus. Bleh. */
+                /*client_raise(client);*/
                 break;
             }
         }
@@ -940,7 +944,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                                        it can happen now when the window is on
                                        another desktop, but we still don't
                                        want it! */
-        client_activate(client, FALSE, TRUE);
+        client_activate(client, FALSE, TRUE, CurrentTime);
         break;
     case ClientMessage:
         /* validate cuz we query stuff off the client here */
@@ -1002,7 +1006,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
             /* XXX make use of data.l[1] and [2] ! */
             client_activate(client, FALSE,
                             (e->xclient.data.l[0] == 0 ||
-                             e->xclient.data.l[0] == 2));
+                             e->xclient.data.l[0] == 2),
+                            e->xclient.data.l[1]);
         } else if (msgtype == prop_atoms.net_wm_moveresize) {
             ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
             if ((Atom)e->xclient.data.l[2] ==
@@ -1242,7 +1247,8 @@ static void event_handle_menu(XEvent *ev)
         if (menu_can_hide) {
             if ((e = menu_entry_frame_under(ev->xbutton.x_root,
                                             ev->xbutton.y_root)))
-                menu_entry_frame_execute(e, ev->xbutton.state);
+                menu_entry_frame_execute(e, ev->xbutton.state,
+                                         ev->xbutton.time);
             else
                 menu_frame_hide_all();
         }
@@ -1272,7 +1278,8 @@ static void event_handle_menu(XEvent *ev)
         else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
             ObMenuFrame *f;
             if ((f = find_active_menu()))
-                menu_entry_frame_execute(f->selected, ev->xkey.state);
+                menu_entry_frame_execute(f->selected, ev->xkey.state,
+                                         ev->xkey.time);
         } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
             ObMenuFrame *f;
             if ((f = find_active_or_last_menu()) && f->parent)
index e21e8b5ba8233809efd5a0d51c7b18df5c95ec34..2d6804bc2576654edfcb5a976119e3eb0ca265b9 100644 (file)
@@ -56,9 +56,11 @@ static ObIconPopup *focus_cycle_popup;
 
 static void focus_cycle_destructor(ObClient *client, gpointer data)
 {
-    /* end cycling if the target disappears */
+    /* end cycling if the target disappears. CurrentTime is fine, time won't
+       be used
+    */
     if (focus_cycle_target == client)
-        focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
+        focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, CurrentTime);
 }
 
 static Window createWindow(Window parent, gulong mask,
@@ -185,9 +187,11 @@ void focus_set_client(ObClient *client)
         XSync(ob_display, FALSE);
     }
 
-    /* in the middle of cycling..? kill it. */
+    /* in the middle of cycling..? kill it. CurrentTime is fine, time won't
+       be used.
+    */
     if (focus_cycle_target)
-        focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
+        focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, CurrentTime);
 
     old = focus_client;
     focus_client = client;
@@ -547,7 +551,7 @@ static gboolean valid_focus_target(ObClient *ft)
 }
 
 void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
-                 gboolean dialog, gboolean done, gboolean cancel)
+                 gboolean dialog, gboolean done, gboolean cancel, Time time)
 {
     static ObClient *first = NULL;
     static ObClient *t = NULL;
@@ -608,7 +612,7 @@ void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
 
 done_cycle:
     if (done && focus_cycle_target)
-        client_activate(focus_cycle_target, FALSE, TRUE);
+        client_activate(focus_cycle_target, FALSE, TRUE, time);
 
     t = NULL;
     first = NULL;
@@ -625,7 +629,8 @@ done_cycle:
 }
 
 void focus_directional_cycle(ObDirection dir, gboolean interactive,
-                             gboolean dialog, gboolean done, gboolean cancel)
+                             gboolean dialog, gboolean done, gboolean cancel,
+                             Time time)
 {
     static ObClient *first = NULL;
     ObClient *ft = NULL;
@@ -670,7 +675,7 @@ void focus_directional_cycle(ObDirection dir, gboolean interactive,
 
 done_cycle:
     if (done && focus_cycle_target)
-        client_activate(focus_cycle_target, FALSE, TRUE);
+        client_activate(focus_cycle_target, FALSE, TRUE, time);
 
     first = NULL;
     focus_cycle_target = NULL;
index ce2c4d05eb6ebfebcf25004a3fc94ccaf29262dd..1c95faa046272848b19dd39591cc6b2291cf9191 100644 (file)
@@ -60,9 +60,10 @@ void focus_fallback(ObFocusFallbackType type);
 
 /*! Cycle focus amongst windows. */
 void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
-                 gboolean dialog, gboolean done, gboolean cancel);
+                 gboolean dialog, gboolean done, gboolean cancel, Time time);
 void focus_directional_cycle(ObDirection dir, gboolean interactive,
-                             gboolean dialog, gboolean done, gboolean cancel);
+                             gboolean dialog, gboolean done, gboolean cancel,
+                             Time time);
 void focus_cycle_draw_indicator();
 
 /*! Add a new client into the focus order */
index f8872938f0cf1a64ed34925400615bf00c1876bf..b95b0805b00083cbb9a6ed57cea46cdf11b9f6c4 100644 (file)
@@ -184,9 +184,9 @@ gboolean keyboard_interactive_grab(guint state, ObClient *client,
 }
 
 void keyboard_interactive_end(ObInteractiveState *s,
-                              guint state, gboolean cancel)
+                              guint state, gboolean cancel, Time time)
 {
-    action_run_interactive(s->actions, s->client, state, cancel, TRUE);
+    action_run_interactive(s->actions, s->client, state, time, cancel, TRUE);
 
     g_slist_free(s->actions);
     g_free(s);
@@ -236,7 +236,7 @@ gboolean keyboard_process_interactive_grab(const XEvent *e, ObClient **client)
                 cancel = done = TRUE;
         }
         if (done) {
-            keyboard_interactive_end(s, e->xkey.state, cancel);
+            keyboard_interactive_end(s, e->xkey.state, cancel, e->xkey.time);
 
             handled = TRUE;
         } else
@@ -280,7 +280,8 @@ void keyboard_event(ObClient *client, const XEvent *e)
                 keyboard_reset_chains();
 
                 action_run_key(p->actions, client, e->xkey.state,
-                               e->xkey.x_root, e->xkey.y_root);
+                               e->xkey.x_root, e->xkey.y_root,
+                               e->xkey.time);
             }
             break;
         }
index 781280ca48eea0b2b2e980c03a0810185e690541..829c751a1e103ce5ac3eaeeb09f685d0a16681e1 100644 (file)
@@ -39,7 +39,7 @@ typedef struct _ObSeparatorMenuEntry ObSeparatorMenuEntry;
 
 typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data);
 typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry,
-                                  guint state, gpointer data);
+                                  guint state, gpointer data, Time time);
 typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data);
 
 struct _ObMenu
index 743f4204ca7ea7fa00cac7d1586b59697b09dfad..108864679e88319a7a949dcadab8d767809f9a7a 100644 (file)
@@ -803,7 +803,7 @@ void menu_entry_frame_show_submenu(ObMenuEntryFrame *self)
     menu_frame_show(f, self->frame);
 }
 
-void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state)
+void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state, Time time)
 {
     if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
         self->entry->data.normal.enabled)
@@ -821,9 +821,9 @@ void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state)
             menu_frame_hide_all();
 
         if (func)
-            func(entry, state, data);
+            func(entry, state, data, time);
         else
-            action_run(acts, client, state);
+            action_run(acts, client, state, time);
     }
 }
 
index 5f0d80846299d7000fc2b028c57930e2081cfe74..1d7cb542a168050dc5baeea85eeec96f9fbd0d55 100644 (file)
@@ -121,6 +121,6 @@ ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y);
 
 void menu_entry_frame_show_submenu(ObMenuEntryFrame *self);
 
-void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state);
+void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state, Time time);
 
 #endif
index 18f35d3cd6e335d5478b6503b68d716c42c94011..81eccfb8385b5bf9146c9eca42da2adc044be0b3 100644 (file)
@@ -155,7 +155,7 @@ void mouse_unbind_all()
 
 static gboolean fire_binding(ObMouseAction a, ObFrameContext context,
                              ObClient *c, guint state,
-                             guint button, gint x, gint y)
+                             guint button, gint x, gint y, Time time)
 {
     GSList *it;
     ObMouseBinding *b;
@@ -168,7 +168,7 @@ static gboolean fire_binding(ObMouseAction a, ObFrameContext context,
     /* if not bound, then nothing to do! */
     if (it == NULL) return FALSE;
 
-    action_run_mouse(b->actions[a], c, context, state, button, x, y);
+    action_run_mouse(b->actions[a], c, context, state, button, x, y, time);
     return TRUE;
 }
 
@@ -196,7 +196,8 @@ void mouse_event(ObClient *client, XEvent *e)
         fire_binding(OB_MOUSE_ACTION_PRESS, context,
                      client, e->xbutton.state,
                      e->xbutton.button,
-                     e->xbutton.x_root, e->xbutton.y_root);
+                     e->xbutton.x_root, e->xbutton.y_root,
+                     e->xbutton.time);
 
         if (CLIENT_CONTEXT(context, client)) {
             /* Replay the event, so it goes to the client*/
@@ -249,19 +250,22 @@ void mouse_event(ObClient *client, XEvent *e)
         fire_binding(OB_MOUSE_ACTION_RELEASE, context,
                      client, e->xbutton.state,
                      e->xbutton.button,
-                     e->xbutton.x_root, e->xbutton.y_root);
+                     e->xbutton.x_root, e->xbutton.y_root,
+                     e->xbutton.time);
         if (click)
             fire_binding(OB_MOUSE_ACTION_CLICK, context,
                          client, e->xbutton.state,
                          e->xbutton.button,
                          e->xbutton.x_root,
-                         e->xbutton.y_root);
+                         e->xbutton.y_root,
+                         e->xbutton.time);
         if (dclick)
             fire_binding(OB_MOUSE_ACTION_DOUBLE_CLICK, context,
                          client, e->xbutton.state,
                          e->xbutton.button,
                          e->xbutton.x_root,
-                         e->xbutton.y_root);
+                         e->xbutton.y_root,
+                         e->xbutton.time);
         break;
 
     case MotionNotify:
@@ -284,7 +288,7 @@ void mouse_event(ObClient *client, XEvent *e)
                     break;
 
                 fire_binding(OB_MOUSE_ACTION_MOTION, context,
-                             client, state, button, px, py);
+                             client, state, button, px, py, e->xmotion.time);
                 button = 0;
                 state = 0;
             }
index 1e5c45a8dc4a21860a84de93686b72e90d399936..1114d28fefa87c39fa3cda99d2ba85c3e85b11d5 100644 (file)
@@ -18,6 +18,9 @@
 */
 
 #include "startupnotify.h"
+#include "gettext.h"
+
+extern gchar **environ;
 
 #ifndef USE_LIBSN
 
@@ -29,6 +32,11 @@ Time sn_app_started(const gchar *id, const gchar *wmclass)
     return CurrentTime;
 }
 gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
+gchar **sn_get_spawn_environment(char *program, Time time)
+{
+    return g_strdupv(environ);
+}
+void sn_spawn_cancel() {}
 
 #else
 
@@ -39,18 +47,12 @@ gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
 #define SN_API_NOT_YET_FROZEN
 #include <libsn/sn.h>
 
-typedef struct {
-    SnStartupSequence *seq;
-    gboolean feedback;
-} ObWaitData;
-
 static SnDisplay *sn_display;
 static SnMonitorContext *sn_context;
-static GSList *sn_waits; /* list of ObWaitDatas */
+static SnLauncherContext *sn_launcher;
+static GSList *sn_waits; /* list of SnStartupSequences we're waiting on */
 
-static ObWaitData* wait_data_new(SnStartupSequence *seq);
-static void wait_data_free(ObWaitData *d);
-static ObWaitData* wait_find(const gchar *id);
+static SnStartupSequence* sequence_find(const gchar *id);
 
 static void sn_handler(const XEvent *e, gpointer data);
 static void sn_event_func(SnMonitorEvent *event, gpointer data);
@@ -62,6 +64,7 @@ void sn_startup(gboolean reconfig)
     sn_display = sn_display_new(ob_display, NULL, NULL);
     sn_context = sn_monitor_context_new(sn_display, ob_screen,
                                         sn_event_func, NULL, NULL);
+    sn_launcher = sn_launcher_context_new(sn_display, ob_screen);
 
     ob_main_loop_x_add(ob_main_loop, sn_handler, NULL, NULL);
 }
@@ -75,45 +78,26 @@ void sn_shutdown(gboolean reconfig)
     ob_main_loop_x_remove(ob_main_loop, sn_handler);
 
     for (it = sn_waits; it; it = g_slist_next(it))
-        wait_data_free(it->data);
+        sn_startup_sequence_unref((SnStartupSequence*)it->data);
     g_slist_free(sn_waits);
     sn_waits = NULL;
 
     screen_set_root_cursor();
 
+    sn_launcher_context_unref(sn_launcher);
     sn_monitor_context_unref(sn_context);
     sn_display_unref(sn_display);
 }
 
-static ObWaitData* wait_data_new(SnStartupSequence *seq)
-{
-    ObWaitData *d = g_new(ObWaitData, 1);
-    d->seq = seq;
-    d->feedback = TRUE;
-
-    sn_startup_sequence_ref(d->seq);
-
-    return d;
-}
-
-static void wait_data_free(ObWaitData *d)
-{
-    if (d) {
-        sn_startup_sequence_unref(d->seq);
-
-        g_free(d);
-    }
-}
-
-static ObWaitData* wait_find(const gchar *id)
+static SnStartupSequence* sequence_find(const gchar *id)
 {
-    ObWaitData *ret = NULL;
+    SnStartupSequence*ret = NULL;
     GSList *it;
 
     for (it = sn_waits; it; it = g_slist_next(it)) {
-        ObWaitData *d = it->data;
-        if (!strcmp(id, sn_startup_sequence_get_id(d->seq))) {
-            ret = d;
+        SnStartupSequence *seq = it->data;
+        if (!strcmp(id, sn_startup_sequence_get_id(seq))) {
+            ret = seq;
             break;
         }
     }
@@ -122,31 +106,17 @@ static ObWaitData* wait_find(const gchar *id)
 
 gboolean sn_app_starting()
 {
-    GSList *it;
-
-    for (it = sn_waits; it; it = g_slist_next(it)) {
-        ObWaitData *d = it->data;
-        if (d->feedback)
-            return TRUE;
-    }
-    return FALSE;
+    return sn_waits != NULL;
 }
 
 static gboolean sn_wait_timeout(gpointer data)
 {
-    ObWaitData *d = data;
-    d->feedback = FALSE;
+    SnStartupSequence *seq = data;
+    sn_waits = g_slist_remove(sn_waits, seq);
     screen_set_root_cursor();
     return FALSE; /* don't repeat */
 }
 
-static void sn_wait_destroy(gpointer data)
-{
-    ObWaitData *d = data;
-    sn_waits = g_slist_remove(sn_waits, d);
-    wait_data_free(d);
-}
-
 static void sn_handler(const XEvent *e, gpointer data)
 {
     XEvent ec;
@@ -158,18 +128,19 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
 {
     SnStartupSequence *seq;
     gboolean change = FALSE;
-    ObWaitData *d;
 
     if (!(seq = sn_monitor_event_get_startup_sequence(ev)))
         return;
 
     switch (sn_monitor_event_get_type(ev)) {
     case SN_MONITOR_EVENT_INITIATED:
-        d = wait_data_new(seq);
-        sn_waits = g_slist_prepend(sn_waits, d);
-        /* 15 second timeout for apps to start */
-        ob_main_loop_timeout_add(ob_main_loop, 15 * G_USEC_PER_SEC,
-                                 sn_wait_timeout, d, sn_wait_destroy);
+        sn_startup_sequence_ref(seq);
+        sn_waits = g_slist_prepend(sn_waits, seq);
+        /* 30 second timeout for apps to start if the launcher doesn't
+           have a timeout */
+        ob_main_loop_timeout_add(ob_main_loop, 30 * G_USEC_PER_SEC,
+                                 sn_wait_timeout, seq,
+                                 (GDestroyNotify)sn_startup_sequence_unref);
         change = TRUE;
         break;
     case SN_MONITOR_EVENT_CHANGED:
@@ -178,10 +149,10 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
         break;
     case SN_MONITOR_EVENT_COMPLETED:
     case SN_MONITOR_EVENT_CANCELED:
-        if ((d = wait_find(sn_startup_sequence_get_id(seq)))) {
-            d->feedback = FALSE;
+        if ((seq = sequence_find(sn_startup_sequence_get_id(seq)))) {
+            sn_waits = g_slist_remove(sn_waits, seq);
             ob_main_loop_timeout_remove_data(ob_main_loop, sn_wait_timeout,
-                                             d, FALSE);
+                                             seq, FALSE);
             change = TRUE;
         }
         break;
@@ -197,15 +168,15 @@ Time sn_app_started(const gchar *id, const gchar *wmclass)
     Time t = CurrentTime;
 
     for (it = sn_waits; it; it = g_slist_next(it)) {
-        ObWaitData *d = it->data;
+        SnStartupSequence *seq = it->data;
         const gchar *seqid, *seqclass;
-        seqid = sn_startup_sequence_get_id(d->seq);
-        seqclass = sn_startup_sequence_get_wmclass(d->seq);
+        seqid = sn_startup_sequence_get_id(seq);
+        seqclass = sn_startup_sequence_get_wmclass(seq);
         if ((seqid && id && !strcmp(seqid, id)) ||
             (seqclass && wmclass && !strcmp(seqclass, wmclass)))
         {
-            sn_startup_sequence_complete(d->seq);
-            t = sn_startup_sequence_get_timestamp(d->seq);
+            sn_startup_sequence_complete(seq);
+            t = sn_startup_sequence_get_timestamp(seq);
             break;
         }
     }
@@ -214,10 +185,10 @@ Time sn_app_started(const gchar *id, const gchar *wmclass)
 
 gboolean sn_get_desktop(gchar *id, guint *desktop)
 {
-    ObWaitData *d;
+    SnStartupSequence *seq;
 
-    if (id && (d = wait_find(id))) {
-        gint desk = sn_startup_sequence_get_workspace(d->seq);
+    if (id && (seq = sequence_find(id))) {
+        gint desk = sn_startup_sequence_get_workspace(seq);
         if (desk != -1) {
             *desktop = desk;
             return TRUE;
@@ -226,4 +197,53 @@ gboolean sn_get_desktop(gchar *id, guint *desktop)
     return FALSE;
 }
 
+static gboolean sn_launch_wait_timeout(gpointer data)
+{
+    SnLauncherContext *sn = data;
+    sn_launcher_context_complete(sn);
+    return FALSE; /* don't repeat */
+}
+
+gchar **sn_get_spawn_environment(char *program, Time time)
+{
+    gchar **env, *desc;
+    guint len;
+    const char *id;
+
+    desc = g_strdup_printf(_("Running %s\n"), program);
+
+    if (sn_launcher_context_get_initiated(sn_launcher)) {
+        sn_launcher_context_unref(sn_launcher);
+        sn_launcher = sn_launcher_context_new(sn_display, ob_screen);
+    }
+
+    sn_launcher_context_set_name(sn_launcher, program);
+    sn_launcher_context_set_description(sn_launcher, desc);
+    sn_launcher_context_set_icon_name(sn_launcher, program);
+    sn_launcher_context_set_binary_name(sn_launcher, program);
+    sn_launcher_context_initiate(sn_launcher, "openbox", program, time);
+    id = sn_launcher_context_get_startup_id(sn_launcher);
+
+    /* 30 second timeout for apps to start */
+    sn_launcher_context_ref(sn_launcher);
+    ob_main_loop_timeout_add(ob_main_loop, 30 * G_USEC_PER_SEC,
+                             sn_launch_wait_timeout, sn_launcher,
+                             (GDestroyNotify)sn_launcher_context_unref);
+
+    env = g_strdupv(environ);
+    len = g_strv_length(env); /* includes last null */
+    env = g_renew(gchar*, env, ++len); /* add one spot */
+    env[len-2] = g_strdup_printf("DESKTOP_STARTUP_ID=%s", id);
+    env[len-1] = NULL;
+
+    g_free(desc);
+
+    return env;
+}
+
+void sn_spawn_cancel()
+{
+    sn_launcher_context_complete(sn_launcher);
+}
+
 #endif
index cf23835476c09268a7b90192d80f0667e20068c3..533ff9c6fc701c3292cd023f47a2778d770b5f20 100644 (file)
@@ -34,4 +34,12 @@ Time sn_app_started(const gchar *id, const gchar *wmclass);
   was requested */
 gboolean sn_get_desktop(gchar *id, guint *desktop);
 
+/* Get the environment to run the program in, with startup notification */
+gchar **sn_get_spawn_environment(char *program, Time time);
+
+/* Tell startup notification we're not actually running the program we
+   told it we were
+*/
+void sn_spawn_cancel();
+
 #endif
This page took 0.054816 seconds and 4 git commands to generate.