ObAppSettings *settings;
gboolean transient = FALSE;
Rect place, *monitor;
- Time map_time;
+ Time launch_time, map_time;
grab_server(TRUE);
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;
attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
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. */
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;
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;
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 "
}
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);
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 */
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;
}
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);
/* 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;
+}
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;
comes at the same time or later than t2. */
gboolean event_time_after(Time t1, Time t2);
+Time event_get_server_time();
+
#endif
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");
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;
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);
/* 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);
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;