all repos — openbox @ 6593261f30d611ff3b71abdb9fd043851fdd2ca9

openbox fork - make it a bit more like ryudo

new least-intrusive focus stealing prevention
Dana Jansens danakj@orodu.net
commit

6593261f30d611ff3b71abdb9fd043851fdd2ca9

parent

074bd96696084ced565c4d1b67884a6381cc8d0e

6 files changed, 76 insertions(+), 30 deletions(-)

jump to
M openbox/client.copenbox/client.c

@@ -214,7 +214,7 @@ gboolean activate = FALSE;

ObAppSettings *settings; gboolean transient = FALSE; Rect place, *monitor; - Time map_time; + Time launch_time, map_time; grab_server(TRUE);

@@ -252,6 +252,8 @@ XFree(wmhint);

} ob_debug("Managing window: 0x%lx\n", window); + + map_time = event_get_server_time(); /* choose the events we want to receive on the CLIENT window */ attrib_set.event_mask = CLIENT_EVENTMASK;

@@ -300,7 +302,7 @@ /* now we have all of the window's information so we can set this up */

client_setup_decor_and_functions(self, FALSE); /* tell startup notification that this app started */ - map_time = sn_app_started(self->startup_id, self->class); + launch_time = sn_app_started(self->startup_id, self->class); /* do this after we have a frame.. it uses the frame to help determine the WM_STATE to apply. */

@@ -451,6 +453,13 @@

if (activate) { gboolean raise = FALSE; + /* This is focus stealing prevention */ + ob_debug_type(OB_DEBUG_FOCUS, + "Want to focus new window 0x%x at time %u " + "launched at %u (last user interaction time %u)\n", + self->window, map_time, launch_time, + event_last_user_time); + if (menu_frame_visible || moveresize_in_progress) { activate = FALSE; raise = TRUE;

@@ -464,8 +473,8 @@ /* if it's on another desktop */

else if (!(self->desktop == screen_desktop || self->desktop == DESKTOP_ALL) && /* the timestamp is from before you changed desktops */ - map_time && screen_desktop_user_time && - !event_time_after(map_time, screen_desktop_user_time)) + launch_time && screen_desktop_user_time && + !event_time_after(launch_time, screen_desktop_user_time)) { activate = FALSE; raise = TRUE;

@@ -477,11 +486,21 @@ /* If something is focused, and it's not our relative... */

else if (focus_client && client_search_focus_tree_full(self) == NULL && client_search_focus_group_full(self) == NULL) { - /* If its a transient (and parents aren't focused) and the time - is ambiguous (either the current focus target doesn't have - a timestamp, or they are the same (we probably inherited it - from them) */ - if (client_has_parent(self)) { + /* If the user is working in another window right now, then don't + steal focus */ + if (event_last_user_time && launch_time && + event_time_after(event_last_user_time, launch_time) && + event_last_user_time != launch_time && + event_time_after(event_last_user_time, + map_time - OB_EVENT_USER_TIME_DELAY)) + { + activate = FALSE; + ob_debug_type(OB_DEBUG_FOCUS, + "Not focusing the window because the user is " + "working in another window\n"); + } + /* If its a transient (and its parents aren't focused) */ + else if (client_has_parent(self)) { activate = FALSE; ob_debug_type(OB_DEBUG_FOCUS, "Not focusing the window because it is a "

@@ -510,6 +529,10 @@ }

} if (!activate) { + ob_debug_type(OB_DEBUG_FOCUS, + "Focus stealing prevention activated for %s at " + "time %u (last user interactioon time %u)\n", + self->title, map_time, event_last_user_time); /* if the client isn't focused, then hilite it so the user knows it is there */ client_hilite(self, TRUE);
M openbox/event.copenbox/event.c

@@ -97,8 +97,8 @@ static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);

static gboolean focus_delay_func(gpointer data); static void focus_delay_client_dest(ObClient *client, gpointer data); -/* The time for the current event being processed */ Time event_curtime = CurrentTime; +Time event_last_user_time = CurrentTime; static gboolean focus_left_screen = FALSE; /*! A list of ObSerialRanges which are to be ignored for mouse enter events */

@@ -235,6 +235,12 @@ /* if more event types are anticipated, get their timestamp

explicitly */ break; } + + /* watch that if we get an event earlier than the last specified user_time, + which can happen if the clock goes backwards, we erase the last + specified user_time */ + if (t && event_last_user_time && event_time_after(event_last_user_time, t)) + event_last_user_time = CurrentTime; event_curtime = t; }

@@ -1496,6 +1502,16 @@ }

else if (msgtype == prop_atoms.net_wm_icon_geometry) { client_update_icon_geometry(client); } + else if (msgtype == prop_atoms.net_wm_user_time) { + guint32 t; + if (PROP_GET32(client->window, net_wm_user_time, cardinal, &t) && + t && !event_time_after(t, e->xproperty.time) && + (!event_last_user_time || + event_time_after(t, event_last_user_time))) + { + event_last_user_time = t; + } + } #ifdef SYNC else if (msgtype == prop_atoms.net_wm_sync_request_counter) { client_update_sync_request_counter(client);

@@ -1934,3 +1950,15 @@ else

/* t2 is in the first half so t1 has to come after it */ return t1 >= t2 && t1 < (t2 + TIME_HALF); } + +Time event_get_server_time() +{ + /* Generate a timestamp */ + XEvent event; + + XChangeProperty(ob_display, screen_support_win, + prop_atoms.wm_class, prop_atoms.string, + 8, PropModeAppend, NULL, 0); + XWindowEvent(ob_display, screen_support_win, PropertyChangeMask, &event); + return event.xproperty.time; +}
M openbox/event.hopenbox/event.h

@@ -24,8 +24,14 @@ #include <glib.h>

struct _ObClient; +/*! The amount of time before a window appears that is checked for user input + to determine if the user is working in another window */ +#define OB_EVENT_USER_TIME_DELAY (500) /* 0.5 seconds */ + /*! Time at which the last event with a timestamp occured. */ extern Time event_curtime; +/*! The last user-interaction time, as given by the clients */ +extern Time event_last_user_time; /*! The value of the mask for the NumLock modifier */ extern guint NumLockMask;

@@ -54,5 +60,7 @@

/*! Compare t1 and t2, taking into account wraparound. True if t1 comes at the same time or later than t2. */ gboolean event_time_after(Time t1, Time t2); + +Time event_get_server_time(); #endif
M openbox/prop.copenbox/prop.c

@@ -93,7 +93,7 @@ CREATE(net_wm_icon, "_NET_WM_ICON");

CREATE(net_wm_icon_geometry, "_NET_WM_ICON_GEOMETRY"); /* CREATE(net_wm_pid, "_NET_WM_PID"); */ CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS"); -/* CREATE(net_wm_user_time, "_NET_WM_USER_TIME"); */ + CREATE(net_wm_user_time, "_NET_WM_USER_TIME"); /* CREATE(net_wm_user_time_window, "_NET_WM_USER_TIME_WINDOW"); */ CREATE(kde_net_wm_frame_strut, "_KDE_NET_WM_FRAME_STRUT"); CREATE(net_frame_extents, "_NET_FRAME_EXTENTS");
M openbox/prop.hopenbox/prop.h

@@ -131,7 +131,7 @@ Atom net_wm_icon;

Atom net_wm_icon_geometry; /* Atom net_wm_pid; */ Atom net_wm_allowed_actions; -/* Atom net_wm_user_time; */ + Atom net_wm_user_time; /* Atom net_wm_user_time_window; */ Atom net_frame_extents;
M openbox/screen.copenbox/screen.c

@@ -107,22 +107,7 @@ if (xerror_occured)

current_wm_sn_owner = None; } - { - /* Generate a timestamp */ - XEvent event; - - XSelectInput(ob_display, screen_support_win, PropertyChangeMask); - - XChangeProperty(ob_display, screen_support_win, - prop_atoms.wm_class, prop_atoms.string, - 8, PropModeAppend, NULL, 0); - XWindowEvent(ob_display, screen_support_win, - PropertyChangeMask, &event); - - XSelectInput(ob_display, screen_support_win, NoEventMask); - - timestamp = event.xproperty.time; - } + timestamp = event_get_server_time(); XSetSelectionOwner(ob_display, wm_sn_atom, screen_support_win, timestamp);

@@ -172,12 +157,14 @@ gulong *supported;

/* create the netwm support window */ attrib.override_redirect = TRUE; + attrib.event_mask = PropertyChangeMask; screen_support_win = XCreateWindow(ob_display, RootWindow(ob_display, ob_screen), -100, -100, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, - CWOverrideRedirect, &attrib); + CWEventMask | CWOverrideRedirect, + &attrib); XMapWindow(ob_display, screen_support_win); XLowerWindow(ob_display, screen_support_win);

@@ -282,8 +269,8 @@ supported[i++] = prop_atoms.net_wm_state_below;

supported[i++] = prop_atoms.net_wm_state_demands_attention; supported[i++] = prop_atoms.net_moveresize_window; supported[i++] = prop_atoms.net_wm_moveresize; -/* supported[i++] = prop_atoms.net_wm_user_time; +/* supported[i++] = prop_atoms.net_wm_user_time_window; */ supported[i++] = prop_atoms.net_frame_extents;