add the _NET_WM_USER_TIME property support. When focus_new is enabled, don't focus new windows if the user is doing something in another window since it launched. If we can tell when it launched, either from the _NET_WM_USER_TIME or from startup notification.
This commit is contained in:
parent
bd19fd06db
commit
9d6e390765
8 changed files with 66 additions and 15 deletions
|
@ -57,8 +57,10 @@ typedef struct
|
||||||
gpointer data;
|
gpointer data;
|
||||||
} Destructor;
|
} Destructor;
|
||||||
|
|
||||||
GList *client_list = NULL;
|
GList *client_list = NULL;
|
||||||
GSList *client_destructors = NULL;
|
|
||||||
|
static GSList *client_destructors = NULL;
|
||||||
|
static Time client_last_user_time = CurrentTime;
|
||||||
|
|
||||||
static void client_get_all(ObClient *self);
|
static void client_get_all(ObClient *self);
|
||||||
static void client_toggle_border(ObClient *self, gboolean show);
|
static void client_toggle_border(ObClient *self, gboolean show);
|
||||||
|
@ -298,7 +300,7 @@ void client_manage(Window window)
|
||||||
client_get_all(self);
|
client_get_all(self);
|
||||||
client_restore_session_state(self);
|
client_restore_session_state(self);
|
||||||
|
|
||||||
sn_app_started(self->startup_id, self->class);
|
self->user_time = sn_app_started(self->startup_id, self->class);
|
||||||
|
|
||||||
/* 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! */
|
||||||
|
@ -459,15 +461,26 @@ void client_manage(Window window)
|
||||||
clicking a window to activate is. so keep the new window out of the way
|
clicking a window to activate is. so keep the new window out of the way
|
||||||
but do focus it. */
|
but do focus it. */
|
||||||
if (activate) {
|
if (activate) {
|
||||||
/* if using focus_delay, stop the timer now so that focus doesn't go
|
/* This is focus stealing prevention, if a user_time has been set */
|
||||||
moving on us */
|
if (self->user_time == CurrentTime ||
|
||||||
event_halt_focus_delay();
|
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);
|
client_focus(self);
|
||||||
/* since focus can change the stacking orders, if we focus the window
|
/* since focus can change the stacking orders, if we focus the
|
||||||
then the standard raise it gets is not enough, we need to queue one
|
window then the standard raise it gets is not enough, we need
|
||||||
for after the focus change takes place */
|
to queue one for after the focus change takes place */
|
||||||
client_raise(self);
|
client_raise(self);
|
||||||
|
} else {
|
||||||
|
ob_debug("Focus stealing prevention activated for %s\n",
|
||||||
|
self->title);
|
||||||
|
/* if the client isn't focused, then hilite it so the user
|
||||||
|
knows it is there */
|
||||||
|
client_hilite(self, TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
||||||
|
@ -857,6 +870,7 @@ static void client_get_all(ObClient *self)
|
||||||
client_update_sm_client_id(self);
|
client_update_sm_client_id(self);
|
||||||
client_update_strut(self);
|
client_update_strut(self);
|
||||||
client_update_icons(self);
|
client_update_icons(self);
|
||||||
|
client_update_user_time(self, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_get_startup_id(ObClient *self)
|
static void client_get_startup_id(ObClient *self)
|
||||||
|
@ -1804,6 +1818,26 @@ void client_update_icons(ObClient *self)
|
||||||
frame_adjust_icon(self->frame);
|
frame_adjust_icon(self->frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void client_update_user_time(ObClient *self, gboolean new_event)
|
||||||
|
{
|
||||||
|
guint32 time;
|
||||||
|
|
||||||
|
if (PROP_GET32(self->window, net_wm_user_time, cardinal, &time)) {
|
||||||
|
self->user_time = time;
|
||||||
|
/* we set this every time, not just when it grows, because in practice
|
||||||
|
sometimes time goes backwards! (ntpdate.. yay....) so.. if it goes
|
||||||
|
backward we don't want all windows to stop focusing. we'll just
|
||||||
|
assume noone is setting times older than the last one, cuz that
|
||||||
|
would be pretty stupid anyways
|
||||||
|
However! This is called when a window is mapped to get its user time
|
||||||
|
but it's an old number, it's not changing it from new user
|
||||||
|
interaction, so in that case, don't change the last user time.
|
||||||
|
*/
|
||||||
|
if (new_event)
|
||||||
|
client_last_user_time = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void client_change_state(ObClient *self)
|
static void client_change_state(ObClient *self)
|
||||||
{
|
{
|
||||||
gulong state[2];
|
gulong state[2];
|
||||||
|
|
|
@ -269,6 +269,8 @@ struct _ObClient
|
||||||
ObClientIcon *icons;
|
ObClientIcon *icons;
|
||||||
/*! The number of icons in icons */
|
/*! The number of icons in icons */
|
||||||
guint nicons;
|
guint nicons;
|
||||||
|
|
||||||
|
guint32 user_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _ObAppSettings
|
struct _ObAppSettings
|
||||||
|
@ -530,6 +532,8 @@ void client_update_class(ObClient *self);
|
||||||
void client_update_strut(ObClient *self);
|
void client_update_strut(ObClient *self);
|
||||||
/*! Updates the window's icons */
|
/*! Updates the window's icons */
|
||||||
void client_update_icons(ObClient *self);
|
void client_update_icons(ObClient *self);
|
||||||
|
/*! Updates the window's user time */
|
||||||
|
void client_update_user_time(ObClient *self, gboolean new_event);
|
||||||
|
|
||||||
/*! Set up what decor should be shown on the window and what functions should
|
/*! Set up what decor should be shown on the window and what functions should
|
||||||
be allowed (ObClient::decorations and ObClient::functions).
|
be allowed (ObClient::decorations and ObClient::functions).
|
||||||
|
|
|
@ -1148,6 +1148,9 @@ static void event_handle_client(ObClient *client, XEvent *e)
|
||||||
else if (msgtype == prop_atoms.net_wm_icon) {
|
else if (msgtype == prop_atoms.net_wm_icon) {
|
||||||
client_update_icons(client);
|
client_update_icons(client);
|
||||||
}
|
}
|
||||||
|
else if (msgtype == prop_atoms.net_wm_user_time) {
|
||||||
|
client_update_user_time(client, TRUE);
|
||||||
|
}
|
||||||
else if (msgtype == prop_atoms.sm_client_id) {
|
else if (msgtype == prop_atoms.sm_client_id) {
|
||||||
client_update_sm_client_id(client);
|
client_update_sm_client_id(client);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ void prop_startup()
|
||||||
CREATE(net_wm_icon, "_NET_WM_ICON");
|
CREATE(net_wm_icon, "_NET_WM_ICON");
|
||||||
/* CREATE(net_wm_pid, "_NET_WM_PID"); */
|
/* CREATE(net_wm_pid, "_NET_WM_PID"); */
|
||||||
CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS");
|
CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS");
|
||||||
|
CREATE(net_wm_user_time, "_NET_WM_USER_TIME");
|
||||||
CREATE(net_frame_extents, "_NET_FRAME_EXTENTS");
|
CREATE(net_frame_extents, "_NET_FRAME_EXTENTS");
|
||||||
|
|
||||||
/* CREATE(net_wm_ping, "_NET_WM_PING"); */
|
/* CREATE(net_wm_ping, "_NET_WM_PING"); */
|
||||||
|
|
|
@ -92,6 +92,7 @@ typedef struct Atoms {
|
||||||
Atom net_wm_icon;
|
Atom net_wm_icon;
|
||||||
/* Atom net_wm_pid; */
|
/* Atom net_wm_pid; */
|
||||||
Atom net_wm_allowed_actions;
|
Atom net_wm_allowed_actions;
|
||||||
|
Atom net_wm_user_time;
|
||||||
Atom net_frame_extents;
|
Atom net_frame_extents;
|
||||||
|
|
||||||
/* application protocols */
|
/* application protocols */
|
||||||
|
|
|
@ -204,7 +204,7 @@ gboolean screen_annex()
|
||||||
window, screen_support_win);
|
window, screen_support_win);
|
||||||
|
|
||||||
/* set the _NET_SUPPORTED_ATOMS hint */
|
/* set the _NET_SUPPORTED_ATOMS hint */
|
||||||
num_support = 53;
|
num_support = 54;
|
||||||
i = 0;
|
i = 0;
|
||||||
supported = g_new(gulong, num_support);
|
supported = g_new(gulong, num_support);
|
||||||
supported[i++] = prop_atoms.net_current_desktop;
|
supported[i++] = prop_atoms.net_current_desktop;
|
||||||
|
@ -258,6 +258,7 @@ gboolean screen_annex()
|
||||||
supported[i++] = prop_atoms.net_wm_state_demands_attention;
|
supported[i++] = prop_atoms.net_wm_state_demands_attention;
|
||||||
supported[i++] = prop_atoms.net_moveresize_window;
|
supported[i++] = prop_atoms.net_moveresize_window;
|
||||||
supported[i++] = prop_atoms.net_wm_moveresize;
|
supported[i++] = prop_atoms.net_wm_moveresize;
|
||||||
|
supported[i++] = prop_atoms.net_wm_user_time;
|
||||||
supported[i++] = prop_atoms.net_frame_extents;
|
supported[i++] = prop_atoms.net_frame_extents;
|
||||||
supported[i++] = prop_atoms.ob_wm_state_undecorated;
|
supported[i++] = prop_atoms.ob_wm_state_undecorated;
|
||||||
g_assert(i == num_support);
|
g_assert(i == num_support);
|
||||||
|
|
|
@ -24,7 +24,10 @@
|
||||||
void sn_startup(gboolean reconfig) {}
|
void sn_startup(gboolean reconfig) {}
|
||||||
void sn_shutdown(gboolean reconfig) {}
|
void sn_shutdown(gboolean reconfig) {}
|
||||||
gboolean sn_app_starting() { return FALSE; }
|
gboolean sn_app_starting() { return FALSE; }
|
||||||
void sn_app_started(gchar *wmclass) {}
|
Time sn_app_started(const gchar *id, const gchar *wmclass)
|
||||||
|
{
|
||||||
|
return CurrentTime;
|
||||||
|
}
|
||||||
gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
|
gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -188,9 +191,10 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
|
||||||
screen_set_root_cursor();
|
screen_set_root_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sn_app_started(const gchar *id, const gchar *wmclass)
|
Time sn_app_started(const gchar *id, const gchar *wmclass)
|
||||||
{
|
{
|
||||||
GSList *it;
|
GSList *it;
|
||||||
|
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;
|
ObWaitData *d = it->data;
|
||||||
|
@ -201,9 +205,11 @@ void sn_app_started(const gchar *id, const gchar *wmclass)
|
||||||
(seqclass && wmclass && !strcmp(seqclass, wmclass)))
|
(seqclass && wmclass && !strcmp(seqclass, wmclass)))
|
||||||
{
|
{
|
||||||
sn_startup_sequence_complete(d->seq);
|
sn_startup_sequence_complete(d->seq);
|
||||||
|
t = sn_startup_sequence_get_timestamp(d->seq);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean sn_get_desktop(gchar *id, guint *desktop)
|
gboolean sn_get_desktop(gchar *id, guint *desktop)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define ob__startupnotify_h
|
#define ob__startupnotify_h
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
void sn_startup(gboolean reconfig);
|
void sn_startup(gboolean reconfig);
|
||||||
void sn_shutdown(gboolean reconfig);
|
void sn_shutdown(gboolean reconfig);
|
||||||
|
@ -27,7 +28,7 @@ void sn_shutdown(gboolean reconfig);
|
||||||
gboolean sn_app_starting();
|
gboolean sn_app_starting();
|
||||||
|
|
||||||
/*! Notify that an app has started */
|
/*! Notify that an app has started */
|
||||||
void sn_app_started(const gchar *id, const gchar *wmclass);
|
Time sn_app_started(const gchar *id, const gchar *wmclass);
|
||||||
|
|
||||||
/*! Get the desktop requested via the startup-notiication protocol if one
|
/*! Get the desktop requested via the startup-notiication protocol if one
|
||||||
was requested */
|
was requested */
|
||||||
|
|
Loading…
Reference in a new issue