#include "dock.h"
#include "config.h"
#include "mainloop.h"
+#include "startupnotify.h"
#include <glib.h>
}
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;
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;
}
}
-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;
l = g_slist_append(NULL, a);
- action_run(l, c, 0);
+ action_run(l, c, 0, time);
}
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);
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);
}
}
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)
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)
gint x;
gint y;
gint button;
+ Time time;
};
struct InteractiveAction {
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);
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! */
/* 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) {
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 */
}
}
-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)
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);
/* 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);
}
}
/* 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);
}
}
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;
}
}
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 */
/* 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] ==
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();
}
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)
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,
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;
}
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;
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;
}
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;
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;
/*! 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 */
}
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);
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
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;
}
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
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)
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);
}
}
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
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;
/* 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;
}
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*/
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:
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;
}
*/
#include "startupnotify.h"
+#include "gettext.h"
+
+extern gchar **environ;
#ifndef USE_LIBSN
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
#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);
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);
}
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;
}
}
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;
{
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:
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;
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;
}
}
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;
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
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