wow... this is a big commit...
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..
This commit is contained in:
parent
9d6e390765
commit
19b480058e
16 changed files with 264 additions and 169 deletions
|
@ -33,6 +33,7 @@
|
||||||
#include "dock.h"
|
#include "dock.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "mainloop.h"
|
#include "mainloop.h"
|
||||||
|
#include "startupnotify.h"
|
||||||
|
|
||||||
#include <glib.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,
|
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)
|
gboolean cancel, gboolean done)
|
||||||
{
|
{
|
||||||
GSList *it;
|
GSList *it;
|
||||||
|
@ -1048,6 +1049,8 @@ void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
|
||||||
|
|
||||||
a->data.any.button = button;
|
a->data.any.button = button;
|
||||||
|
|
||||||
|
a->data.any.time = time;
|
||||||
|
|
||||||
if (a->data.any.interactive) {
|
if (a->data.any.interactive) {
|
||||||
a->data.inter.cancel = cancel;
|
a->data.inter.cancel = cancel;
|
||||||
a->data.inter.final = done;
|
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;
|
ObAction *a;
|
||||||
GSList *l;
|
GSList *l;
|
||||||
|
@ -1078,7 +1081,7 @@ void action_run_string(const gchar *name, struct _ObClient *c)
|
||||||
|
|
||||||
l = g_slist_append(NULL, a);
|
l = g_slist_append(NULL, a);
|
||||||
|
|
||||||
action_run(l, c, 0);
|
action_run(l, c, 0, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_execute(union ActionData *data)
|
void action_execute(union ActionData *data)
|
||||||
|
@ -1093,13 +1096,21 @@ void action_execute(union ActionData *data)
|
||||||
cmd, e->message);
|
cmd, e->message);
|
||||||
g_error_free(e);
|
g_error_free(e);
|
||||||
} else {
|
} 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,
|
G_SPAWN_DO_NOT_REAP_CHILD,
|
||||||
NULL, NULL, NULL, &e)) {
|
NULL, NULL, NULL, &e)) {
|
||||||
g_warning("failed to execute '%s': %s",
|
g_warning("failed to execute '%s': %s",
|
||||||
cmd, e->message);
|
cmd, e->message);
|
||||||
g_error_free(e);
|
g_error_free(e);
|
||||||
|
sn_spawn_cancel();
|
||||||
}
|
}
|
||||||
|
g_strfreev(env);
|
||||||
|
g_free(program);
|
||||||
g_strfreev(argv);
|
g_strfreev(argv);
|
||||||
}
|
}
|
||||||
g_free(cmd);
|
g_free(cmd);
|
||||||
|
@ -1119,7 +1130,8 @@ void action_activate(union ActionData *data)
|
||||||
moving on us */
|
moving on us */
|
||||||
event_halt_focus_delay();
|
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,
|
focus_cycle(data->cycle.forward, data->cycle.linear, data->any.interactive,
|
||||||
data->cycle.dialog,
|
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)
|
void action_directional_focus(union ActionData *data)
|
||||||
|
@ -1607,7 +1620,8 @@ void action_directional_focus(union ActionData *data)
|
||||||
data->any.interactive,
|
data->any.interactive,
|
||||||
data->interdiraction.dialog,
|
data->interdiraction.dialog,
|
||||||
data->interdiraction.inter.final,
|
data->interdiraction.inter.final,
|
||||||
data->interdiraction.inter.cancel);
|
data->interdiraction.inter.cancel,
|
||||||
|
data->interdiraction.inter.any.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_movetoedge(union ActionData *data)
|
void action_movetoedge(union ActionData *data)
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct AnyAction {
|
||||||
gint x;
|
gint x;
|
||||||
gint y;
|
gint y;
|
||||||
gint button;
|
gint button;
|
||||||
|
Time time;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InteractiveAction {
|
struct InteractiveAction {
|
||||||
|
@ -209,22 +210,22 @@ ObAction* action_copy(const ObAction *a);
|
||||||
affects interactive actions, but should generally always be FALSE.
|
affects interactive actions, but should generally always be FALSE.
|
||||||
*/
|
*/
|
||||||
void action_run_list(GSList *acts, struct _ObClient *c, ObFrameContext context,
|
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);
|
gboolean cancel, gboolean done);
|
||||||
|
|
||||||
#define action_run_mouse(a, c, n, s, b, x, y) \
|
#define action_run_mouse(a, c, n, s, b, x, y, t) \
|
||||||
action_run_list(a, c, n, s, b, x, y, FALSE, FALSE)
|
action_run_list(a, c, n, s, b, x, y, t, FALSE, FALSE)
|
||||||
|
|
||||||
#define action_run_interactive(a, c, s, 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, 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) \
|
#define action_run_key(a, c, s, x, y, t) \
|
||||||
action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, x, y, FALSE, FALSE)
|
action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, x, y, t, FALSE, FALSE)
|
||||||
|
|
||||||
#define action_run(a, c, s) \
|
#define action_run(a, c, s, t) \
|
||||||
action_run_list(a, c, OB_FRAME_CONTEXT_NONE, s, 0, -1, -1, FALSE, FALSE)
|
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 */
|
/* Execute */
|
||||||
void action_execute(union ActionData *data);
|
void action_execute(union ActionData *data);
|
||||||
|
|
122
openbox/client.c
122
openbox/client.c
|
@ -296,11 +296,15 @@ void client_manage(Window window)
|
||||||
self->wmstate = NormalState;
|
self->wmstate = NormalState;
|
||||||
self->layer = -1;
|
self->layer = -1;
|
||||||
self->desktop = screen_num_desktops; /* always an invalid value */
|
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_get_all(self);
|
||||||
client_restore_session_state(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
|
/* update the focus lists, do this before the call to change_state or
|
||||||
it can end up in the list twice! */
|
it can end up in the list twice! */
|
||||||
|
@ -327,7 +331,7 @@ void client_manage(Window window)
|
||||||
/* get and set application level settings */
|
/* get and set application level settings */
|
||||||
settings = get_settings(self);
|
settings = get_settings(self);
|
||||||
|
|
||||||
stacking_add(CLIENT_AS_WINDOW(self));
|
stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
|
||||||
client_restore_session_stacking(self);
|
client_restore_session_stacking(self);
|
||||||
|
|
||||||
if (settings) {
|
if (settings) {
|
||||||
|
@ -453,35 +457,55 @@ void client_manage(Window window)
|
||||||
keyboard_grab_for_client(self, TRUE);
|
keyboard_grab_for_client(self, TRUE);
|
||||||
mouse_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) {
|
if (activate) {
|
||||||
/* This is focus stealing prevention, if a user_time has been set */
|
/* This is focus stealing prevention, if a user_time has been set */
|
||||||
if (self->user_time == CurrentTime ||
|
ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n",
|
||||||
self->user_time > client_last_user_time)
|
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
|
/* since focus can change the stacking orders, if we focus the
|
||||||
window then the standard raise it gets is not enough, we need
|
window then the standard raise it gets is not enough, we need
|
||||||
to queue one for after the focus change takes place */
|
to queue one for after the focus change takes place */
|
||||||
client_raise(self);
|
client_raise(self);
|
||||||
} else {
|
} else {
|
||||||
ob_debug("Focus stealing prevention activated for %s\n",
|
ob_debug("Focus stealing prevention activated for %s with time %u "
|
||||||
self->title);
|
"(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
|
/* if the client isn't focused, then hilite it so the user
|
||||||
knows it is there */
|
knows it is there */
|
||||||
client_hilite(self, TRUE);
|
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
|
/* client_activate does this but we aret using it so we have to do it
|
||||||
here as well */
|
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
|
/* 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) */
|
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);
|
||||||
|
|
||||||
if (client_normal(self) && screen_showing_desktop)
|
client_focus(self);
|
||||||
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);
|
/* 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
|
||||||
/* we do this an action here. this is rather important. this is because
|
about raising the window. when a fullscreen window loses focus, we
|
||||||
we want the results from the focus change to take place BEFORE we go
|
need this or else the raise wont be able to raise above the
|
||||||
about raising the window. when a fullscreen window loses focus, we need
|
to-lose-focus fullscreen window. */
|
||||||
this or else the raise wont be able to raise above the to-lose-focus
|
client_raise(self);
|
||||||
fullscreen window. */
|
}
|
||||||
client_raise(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_raise(ObClient *self)
|
void client_raise(ObClient *self)
|
||||||
{
|
{
|
||||||
action_run_string("Raise", self);
|
action_run_string("Raise", self, CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_lower(ObClient *self)
|
void client_lower(ObClient *self)
|
||||||
{
|
{
|
||||||
action_run_string("Lower", self);
|
action_run_string("Lower", self, CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean client_focused(ObClient *self)
|
gboolean client_focused(ObClient *self)
|
||||||
|
|
|
@ -484,8 +484,10 @@ void client_unfocus(ObClient *self);
|
||||||
otherwise, the desktop is changed to where the client lives.
|
otherwise, the desktop is changed to where the client lives.
|
||||||
@param user If true, then a user action is what requested the activation;
|
@param user If true, then a user action is what requested the activation;
|
||||||
otherwise, it means an application requested it on its own
|
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 */
|
/*! Calculates the stacking layer for the client window */
|
||||||
void client_calc_layer(ObClient *self);
|
void client_calc_layer(ObClient *self);
|
||||||
|
|
|
@ -84,13 +84,14 @@ static void self_update(ObMenuFrame *frame, gpointer data)
|
||||||
|
|
||||||
/* executes it using the client in the actions, since we set that
|
/* executes it using the client in the actions, since we set that
|
||||||
when we make the actions! */
|
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;
|
ObAction *a;
|
||||||
|
|
||||||
if (self->data.normal.actions) {
|
if (self->data.normal.actions) {
|
||||||
a = self->data.normal.actions->data;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
/* executes it using the client in the actions, since we set that
|
||||||
when we make the actions! */
|
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;
|
ObAction *a;
|
||||||
|
|
||||||
if (self->data.normal.actions) {
|
if (self->data.normal.actions) {
|
||||||
a = self->data.normal.actions->data;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -895,13 +895,17 @@ static void event_handle_client(ObClient *client, XEvent *e)
|
||||||
switch (e->xconfigurerequest.detail) {
|
switch (e->xconfigurerequest.detail) {
|
||||||
case Below:
|
case Below:
|
||||||
case BottomIf:
|
case BottomIf:
|
||||||
client_lower(client);
|
/* Apps are so rude. And this is totally disconnected from
|
||||||
|
activation/focus. Bleh. */
|
||||||
|
/*client_lower(client);*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Above:
|
case Above:
|
||||||
case TopIf:
|
case TopIf:
|
||||||
default:
|
default:
|
||||||
client_raise(client);
|
/* Apps are so rude. And this is totally disconnected from
|
||||||
|
activation/focus. Bleh. */
|
||||||
|
/*client_raise(client);*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -940,7 +944,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
|
||||||
it can happen now when the window is on
|
it can happen now when the window is on
|
||||||
another desktop, but we still don't
|
another desktop, but we still don't
|
||||||
want it! */
|
want it! */
|
||||||
client_activate(client, FALSE, TRUE);
|
client_activate(client, FALSE, TRUE, CurrentTime);
|
||||||
break;
|
break;
|
||||||
case ClientMessage:
|
case ClientMessage:
|
||||||
/* validate cuz we query stuff off the client here */
|
/* 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] ! */
|
/* XXX make use of data.l[1] and [2] ! */
|
||||||
client_activate(client, FALSE,
|
client_activate(client, FALSE,
|
||||||
(e->xclient.data.l[0] == 0 ||
|
(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) {
|
} else if (msgtype == prop_atoms.net_wm_moveresize) {
|
||||||
ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
|
ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
|
||||||
if ((Atom)e->xclient.data.l[2] ==
|
if ((Atom)e->xclient.data.l[2] ==
|
||||||
|
@ -1242,7 +1247,8 @@ static void event_handle_menu(XEvent *ev)
|
||||||
if (menu_can_hide) {
|
if (menu_can_hide) {
|
||||||
if ((e = menu_entry_frame_under(ev->xbutton.x_root,
|
if ((e = menu_entry_frame_under(ev->xbutton.x_root,
|
||||||
ev->xbutton.y_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
|
else
|
||||||
menu_frame_hide_all();
|
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)) {
|
else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
|
||||||
ObMenuFrame *f;
|
ObMenuFrame *f;
|
||||||
if ((f = find_active_menu()))
|
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)) {
|
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
|
||||||
ObMenuFrame *f;
|
ObMenuFrame *f;
|
||||||
if ((f = find_active_or_last_menu()) && f->parent)
|
if ((f = find_active_or_last_menu()) && f->parent)
|
||||||
|
|
|
@ -56,9 +56,11 @@ static ObIconPopup *focus_cycle_popup;
|
||||||
|
|
||||||
static void focus_cycle_destructor(ObClient *client, gpointer data)
|
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)
|
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,
|
static Window createWindow(Window parent, gulong mask,
|
||||||
|
@ -185,9 +187,11 @@ void focus_set_client(ObClient *client)
|
||||||
XSync(ob_display, FALSE);
|
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)
|
if (focus_cycle_target)
|
||||||
focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
|
focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, CurrentTime);
|
||||||
|
|
||||||
old = focus_client;
|
old = focus_client;
|
||||||
focus_client = client;
|
focus_client = client;
|
||||||
|
@ -547,7 +551,7 @@ static gboolean valid_focus_target(ObClient *ft)
|
||||||
}
|
}
|
||||||
|
|
||||||
void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
|
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 *first = NULL;
|
||||||
static ObClient *t = NULL;
|
static ObClient *t = NULL;
|
||||||
|
@ -608,7 +612,7 @@ void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
|
||||||
|
|
||||||
done_cycle:
|
done_cycle:
|
||||||
if (done && focus_cycle_target)
|
if (done && focus_cycle_target)
|
||||||
client_activate(focus_cycle_target, FALSE, TRUE);
|
client_activate(focus_cycle_target, FALSE, TRUE, time);
|
||||||
|
|
||||||
t = NULL;
|
t = NULL;
|
||||||
first = NULL;
|
first = NULL;
|
||||||
|
@ -625,7 +629,8 @@ done_cycle:
|
||||||
}
|
}
|
||||||
|
|
||||||
void focus_directional_cycle(ObDirection dir, gboolean interactive,
|
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;
|
static ObClient *first = NULL;
|
||||||
ObClient *ft = NULL;
|
ObClient *ft = NULL;
|
||||||
|
@ -670,7 +675,7 @@ void focus_directional_cycle(ObDirection dir, gboolean interactive,
|
||||||
|
|
||||||
done_cycle:
|
done_cycle:
|
||||||
if (done && focus_cycle_target)
|
if (done && focus_cycle_target)
|
||||||
client_activate(focus_cycle_target, FALSE, TRUE);
|
client_activate(focus_cycle_target, FALSE, TRUE, time);
|
||||||
|
|
||||||
first = NULL;
|
first = NULL;
|
||||||
focus_cycle_target = NULL;
|
focus_cycle_target = NULL;
|
||||||
|
|
|
@ -60,9 +60,10 @@ void focus_fallback(ObFocusFallbackType type);
|
||||||
|
|
||||||
/*! Cycle focus amongst windows. */
|
/*! Cycle focus amongst windows. */
|
||||||
void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
|
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,
|
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();
|
void focus_cycle_draw_indicator();
|
||||||
|
|
||||||
/*! Add a new client into the focus order */
|
/*! Add a new client into the focus order */
|
||||||
|
|
|
@ -184,9 +184,9 @@ gboolean keyboard_interactive_grab(guint state, ObClient *client,
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyboard_interactive_end(ObInteractiveState *s,
|
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_slist_free(s->actions);
|
||||||
g_free(s);
|
g_free(s);
|
||||||
|
@ -236,7 +236,7 @@ gboolean keyboard_process_interactive_grab(const XEvent *e, ObClient **client)
|
||||||
cancel = done = TRUE;
|
cancel = done = TRUE;
|
||||||
}
|
}
|
||||||
if (done) {
|
if (done) {
|
||||||
keyboard_interactive_end(s, e->xkey.state, cancel);
|
keyboard_interactive_end(s, e->xkey.state, cancel, e->xkey.time);
|
||||||
|
|
||||||
handled = TRUE;
|
handled = TRUE;
|
||||||
} else
|
} else
|
||||||
|
@ -280,7 +280,8 @@ void keyboard_event(ObClient *client, const XEvent *e)
|
||||||
keyboard_reset_chains();
|
keyboard_reset_chains();
|
||||||
|
|
||||||
action_run_key(p->actions, client, e->xkey.state,
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ typedef struct _ObSeparatorMenuEntry ObSeparatorMenuEntry;
|
||||||
|
|
||||||
typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data);
|
typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data);
|
||||||
typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry,
|
typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry,
|
||||||
guint state, gpointer data);
|
guint state, gpointer data, Time time);
|
||||||
typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data);
|
typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data);
|
||||||
|
|
||||||
struct _ObMenu
|
struct _ObMenu
|
||||||
|
|
|
@ -803,7 +803,7 @@ void menu_entry_frame_show_submenu(ObMenuEntryFrame *self)
|
||||||
menu_frame_show(f, self->frame);
|
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 &&
|
if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
|
||||||
self->entry->data.normal.enabled)
|
self->entry->data.normal.enabled)
|
||||||
|
@ -821,9 +821,9 @@ void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state)
|
||||||
menu_frame_hide_all();
|
menu_frame_hide_all();
|
||||||
|
|
||||||
if (func)
|
if (func)
|
||||||
func(entry, state, data);
|
func(entry, state, data, time);
|
||||||
else
|
else
|
||||||
action_run(acts, client, state);
|
action_run(acts, client, state, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_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
|
#endif
|
||||||
|
|
|
@ -155,7 +155,7 @@ void mouse_unbind_all()
|
||||||
|
|
||||||
static gboolean fire_binding(ObMouseAction a, ObFrameContext context,
|
static gboolean fire_binding(ObMouseAction a, ObFrameContext context,
|
||||||
ObClient *c, guint state,
|
ObClient *c, guint state,
|
||||||
guint button, gint x, gint y)
|
guint button, gint x, gint y, Time time)
|
||||||
{
|
{
|
||||||
GSList *it;
|
GSList *it;
|
||||||
ObMouseBinding *b;
|
ObMouseBinding *b;
|
||||||
|
@ -168,7 +168,7 @@ static gboolean fire_binding(ObMouseAction a, ObFrameContext context,
|
||||||
/* if not bound, then nothing to do! */
|
/* if not bound, then nothing to do! */
|
||||||
if (it == NULL) return FALSE;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,8 @@ void mouse_event(ObClient *client, XEvent *e)
|
||||||
fire_binding(OB_MOUSE_ACTION_PRESS, context,
|
fire_binding(OB_MOUSE_ACTION_PRESS, context,
|
||||||
client, e->xbutton.state,
|
client, e->xbutton.state,
|
||||||
e->xbutton.button,
|
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)) {
|
if (CLIENT_CONTEXT(context, client)) {
|
||||||
/* Replay the event, so it goes to the 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,
|
fire_binding(OB_MOUSE_ACTION_RELEASE, context,
|
||||||
client, e->xbutton.state,
|
client, e->xbutton.state,
|
||||||
e->xbutton.button,
|
e->xbutton.button,
|
||||||
e->xbutton.x_root, e->xbutton.y_root);
|
e->xbutton.x_root, e->xbutton.y_root,
|
||||||
|
e->xbutton.time);
|
||||||
if (click)
|
if (click)
|
||||||
fire_binding(OB_MOUSE_ACTION_CLICK, context,
|
fire_binding(OB_MOUSE_ACTION_CLICK, context,
|
||||||
client, e->xbutton.state,
|
client, e->xbutton.state,
|
||||||
e->xbutton.button,
|
e->xbutton.button,
|
||||||
e->xbutton.x_root,
|
e->xbutton.x_root,
|
||||||
e->xbutton.y_root);
|
e->xbutton.y_root,
|
||||||
|
e->xbutton.time);
|
||||||
if (dclick)
|
if (dclick)
|
||||||
fire_binding(OB_MOUSE_ACTION_DOUBLE_CLICK, context,
|
fire_binding(OB_MOUSE_ACTION_DOUBLE_CLICK, context,
|
||||||
client, e->xbutton.state,
|
client, e->xbutton.state,
|
||||||
e->xbutton.button,
|
e->xbutton.button,
|
||||||
e->xbutton.x_root,
|
e->xbutton.x_root,
|
||||||
e->xbutton.y_root);
|
e->xbutton.y_root,
|
||||||
|
e->xbutton.time);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MotionNotify:
|
case MotionNotify:
|
||||||
|
@ -284,7 +288,7 @@ void mouse_event(ObClient *client, XEvent *e)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
fire_binding(OB_MOUSE_ACTION_MOTION, context,
|
fire_binding(OB_MOUSE_ACTION_MOTION, context,
|
||||||
client, state, button, px, py);
|
client, state, button, px, py, e->xmotion.time);
|
||||||
button = 0;
|
button = 0;
|
||||||
state = 0;
|
state = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "startupnotify.h"
|
#include "startupnotify.h"
|
||||||
|
#include "gettext.h"
|
||||||
|
|
||||||
|
extern gchar **environ;
|
||||||
|
|
||||||
#ifndef USE_LIBSN
|
#ifndef USE_LIBSN
|
||||||
|
|
||||||
|
@ -29,6 +32,11 @@ Time sn_app_started(const gchar *id, const gchar *wmclass)
|
||||||
return CurrentTime;
|
return CurrentTime;
|
||||||
}
|
}
|
||||||
gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
|
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
|
#else
|
||||||
|
|
||||||
|
@ -39,18 +47,12 @@ gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
|
||||||
#define SN_API_NOT_YET_FROZEN
|
#define SN_API_NOT_YET_FROZEN
|
||||||
#include <libsn/sn.h>
|
#include <libsn/sn.h>
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SnStartupSequence *seq;
|
|
||||||
gboolean feedback;
|
|
||||||
} ObWaitData;
|
|
||||||
|
|
||||||
static SnDisplay *sn_display;
|
static SnDisplay *sn_display;
|
||||||
static SnMonitorContext *sn_context;
|
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 SnStartupSequence* sequence_find(const gchar *id);
|
||||||
static void wait_data_free(ObWaitData *d);
|
|
||||||
static ObWaitData* wait_find(const gchar *id);
|
|
||||||
|
|
||||||
static void sn_handler(const XEvent *e, gpointer data);
|
static void sn_handler(const XEvent *e, gpointer data);
|
||||||
static void sn_event_func(SnMonitorEvent *event, 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_display = sn_display_new(ob_display, NULL, NULL);
|
||||||
sn_context = sn_monitor_context_new(sn_display, ob_screen,
|
sn_context = sn_monitor_context_new(sn_display, ob_screen,
|
||||||
sn_event_func, NULL, NULL);
|
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_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);
|
ob_main_loop_x_remove(ob_main_loop, sn_handler);
|
||||||
|
|
||||||
for (it = sn_waits; it; it = g_slist_next(it))
|
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);
|
g_slist_free(sn_waits);
|
||||||
sn_waits = NULL;
|
sn_waits = NULL;
|
||||||
|
|
||||||
screen_set_root_cursor();
|
screen_set_root_cursor();
|
||||||
|
|
||||||
|
sn_launcher_context_unref(sn_launcher);
|
||||||
sn_monitor_context_unref(sn_context);
|
sn_monitor_context_unref(sn_context);
|
||||||
sn_display_unref(sn_display);
|
sn_display_unref(sn_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ObWaitData* wait_data_new(SnStartupSequence *seq)
|
static SnStartupSequence* sequence_find(const gchar *id)
|
||||||
{
|
{
|
||||||
ObWaitData *d = g_new(ObWaitData, 1);
|
SnStartupSequence*ret = NULL;
|
||||||
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)
|
|
||||||
{
|
|
||||||
ObWaitData *ret = NULL;
|
|
||||||
GSList *it;
|
GSList *it;
|
||||||
|
|
||||||
for (it = sn_waits; it; it = g_slist_next(it)) {
|
for (it = sn_waits; it; it = g_slist_next(it)) {
|
||||||
ObWaitData *d = it->data;
|
SnStartupSequence *seq = it->data;
|
||||||
if (!strcmp(id, sn_startup_sequence_get_id(d->seq))) {
|
if (!strcmp(id, sn_startup_sequence_get_id(seq))) {
|
||||||
ret = d;
|
ret = seq;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,31 +106,17 @@ static ObWaitData* wait_find(const gchar *id)
|
||||||
|
|
||||||
gboolean sn_app_starting()
|
gboolean sn_app_starting()
|
||||||
{
|
{
|
||||||
GSList *it;
|
return sn_waits != NULL;
|
||||||
|
|
||||||
for (it = sn_waits; it; it = g_slist_next(it)) {
|
|
||||||
ObWaitData *d = it->data;
|
|
||||||
if (d->feedback)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean sn_wait_timeout(gpointer data)
|
static gboolean sn_wait_timeout(gpointer data)
|
||||||
{
|
{
|
||||||
ObWaitData *d = data;
|
SnStartupSequence *seq = data;
|
||||||
d->feedback = FALSE;
|
sn_waits = g_slist_remove(sn_waits, seq);
|
||||||
screen_set_root_cursor();
|
screen_set_root_cursor();
|
||||||
return FALSE; /* don't repeat */
|
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)
|
static void sn_handler(const XEvent *e, gpointer data)
|
||||||
{
|
{
|
||||||
XEvent ec;
|
XEvent ec;
|
||||||
|
@ -158,18 +128,19 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
|
||||||
{
|
{
|
||||||
SnStartupSequence *seq;
|
SnStartupSequence *seq;
|
||||||
gboolean change = FALSE;
|
gboolean change = FALSE;
|
||||||
ObWaitData *d;
|
|
||||||
|
|
||||||
if (!(seq = sn_monitor_event_get_startup_sequence(ev)))
|
if (!(seq = sn_monitor_event_get_startup_sequence(ev)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (sn_monitor_event_get_type(ev)) {
|
switch (sn_monitor_event_get_type(ev)) {
|
||||||
case SN_MONITOR_EVENT_INITIATED:
|
case SN_MONITOR_EVENT_INITIATED:
|
||||||
d = wait_data_new(seq);
|
sn_startup_sequence_ref(seq);
|
||||||
sn_waits = g_slist_prepend(sn_waits, d);
|
sn_waits = g_slist_prepend(sn_waits, seq);
|
||||||
/* 15 second timeout for apps to start */
|
/* 30 second timeout for apps to start if the launcher doesn't
|
||||||
ob_main_loop_timeout_add(ob_main_loop, 15 * G_USEC_PER_SEC,
|
have a timeout */
|
||||||
sn_wait_timeout, d, sn_wait_destroy);
|
ob_main_loop_timeout_add(ob_main_loop, 30 * G_USEC_PER_SEC,
|
||||||
|
sn_wait_timeout, seq,
|
||||||
|
(GDestroyNotify)sn_startup_sequence_unref);
|
||||||
change = TRUE;
|
change = TRUE;
|
||||||
break;
|
break;
|
||||||
case SN_MONITOR_EVENT_CHANGED:
|
case SN_MONITOR_EVENT_CHANGED:
|
||||||
|
@ -178,10 +149,10 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
|
||||||
break;
|
break;
|
||||||
case SN_MONITOR_EVENT_COMPLETED:
|
case SN_MONITOR_EVENT_COMPLETED:
|
||||||
case SN_MONITOR_EVENT_CANCELED:
|
case SN_MONITOR_EVENT_CANCELED:
|
||||||
if ((d = wait_find(sn_startup_sequence_get_id(seq)))) {
|
if ((seq = sequence_find(sn_startup_sequence_get_id(seq)))) {
|
||||||
d->feedback = FALSE;
|
sn_waits = g_slist_remove(sn_waits, seq);
|
||||||
ob_main_loop_timeout_remove_data(ob_main_loop, sn_wait_timeout,
|
ob_main_loop_timeout_remove_data(ob_main_loop, sn_wait_timeout,
|
||||||
d, FALSE);
|
seq, FALSE);
|
||||||
change = TRUE;
|
change = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -197,15 +168,15 @@ Time sn_app_started(const gchar *id, const gchar *wmclass)
|
||||||
Time t = CurrentTime;
|
Time t = CurrentTime;
|
||||||
|
|
||||||
for (it = sn_waits; it; it = g_slist_next(it)) {
|
for (it = sn_waits; it; it = g_slist_next(it)) {
|
||||||
ObWaitData *d = it->data;
|
SnStartupSequence *seq = it->data;
|
||||||
const gchar *seqid, *seqclass;
|
const gchar *seqid, *seqclass;
|
||||||
seqid = sn_startup_sequence_get_id(d->seq);
|
seqid = sn_startup_sequence_get_id(seq);
|
||||||
seqclass = sn_startup_sequence_get_wmclass(d->seq);
|
seqclass = sn_startup_sequence_get_wmclass(seq);
|
||||||
if ((seqid && id && !strcmp(seqid, id)) ||
|
if ((seqid && id && !strcmp(seqid, id)) ||
|
||||||
(seqclass && wmclass && !strcmp(seqclass, wmclass)))
|
(seqclass && wmclass && !strcmp(seqclass, wmclass)))
|
||||||
{
|
{
|
||||||
sn_startup_sequence_complete(d->seq);
|
sn_startup_sequence_complete(seq);
|
||||||
t = sn_startup_sequence_get_timestamp(d->seq);
|
t = sn_startup_sequence_get_timestamp(seq);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,10 +185,10 @@ Time sn_app_started(const gchar *id, const gchar *wmclass)
|
||||||
|
|
||||||
gboolean sn_get_desktop(gchar *id, guint *desktop)
|
gboolean sn_get_desktop(gchar *id, guint *desktop)
|
||||||
{
|
{
|
||||||
ObWaitData *d;
|
SnStartupSequence *seq;
|
||||||
|
|
||||||
if (id && (d = wait_find(id))) {
|
if (id && (seq = sequence_find(id))) {
|
||||||
gint desk = sn_startup_sequence_get_workspace(d->seq);
|
gint desk = sn_startup_sequence_get_workspace(seq);
|
||||||
if (desk != -1) {
|
if (desk != -1) {
|
||||||
*desktop = desk;
|
*desktop = desk;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -226,4 +197,53 @@ gboolean sn_get_desktop(gchar *id, guint *desktop)
|
||||||
return FALSE;
|
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
|
#endif
|
||||||
|
|
|
@ -34,4 +34,12 @@ Time sn_app_started(const gchar *id, const gchar *wmclass);
|
||||||
was requested */
|
was requested */
|
||||||
gboolean sn_get_desktop(gchar *id, guint *desktop);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue