summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElijah Newren <newren@math.utah.edu>2004-06-24 15:47:05 +0000
committerElijah Newren <newren@src.gnome.org>2004-06-24 15:47:05 +0000
commit28a54c6bb4f5e4157cec8e6a69736ceef07c3099 (patch)
tree139266d9301e6d83ab5689bc78a9237c3c711e0b
parentef1ecc812858e3a5c2460a2689118f11d43142a8 (diff)
downloadmetacity-28a54c6bb4f5e4157cec8e6a69736ceef07c3099.tar.gz
Add support for _NET_WM_USER_TIME
2004-06-17 Elijah Newren <newren@math.utah.edu> Add support for _NET_WM_USER_TIME * src/display.c: (meta_display_open): Add _NET_WM_USER_TIME to atom_names[], (event_callback): Manually set _NET_WM_USER_TIME upon KeyPress (doesn't work since keyboard isn't grabbed) and ButtonPress (does work), this is just a fallback for applications that don't update this themselves. * src/display.h: (struct _MetaDisplay): Add atom_net_wm_user_time field * src/screen.c: (meta_screen_apply_startup_properties): Check for TIMESTAMP provided from startup sequence as well. * src/stack.c: s/meta_window_set_stack_position/meta_window_set_stack_position_no_sync/, (meta_window_set_stack_position): New function which calls the meta_window_set_stack_position_no_sync function followed immediately by calling meta_stack_sync_to_server. * src/window-props.c: (init_net_wm_user_time), (reload_net_wm_user_time): new functions, (reload_wm_hints): also load atom_net_wm_user_time * src/window.c: new XSERVER_TIME_IS_LATER macro (accounts for timestamp wraparound), (meta_window_new_with_attrs): add timestamp attributes, (window_takes_focus_on_map): use TIMESTAMP from startup notification and _NET_WM_USER_TIME to decide whether to focus new windows, (meta_window_show): if app doesn't take focus on map, place it just below the focused window in the stack (process_property_notify): check for changes to _NET_WM_USRE_TIME, (meta_window_stack_just_below): new function * src/window.h: (_MetaWindow struct): new fields for initial_timestamp, initial_timestamp_set, net_wm_user_time_set, and net_wm_user_time, (meta_window_stack_just_below): new function
-rw-r--r--ChangeLog42
-rw-r--r--src/display.c14
-rw-r--r--src/display.h1
-rw-r--r--src/screen.c12
-rw-r--r--src/stack.c26
-rw-r--r--src/stack.h4
-rw-r--r--src/window-props.c32
-rw-r--r--src/window.c155
-rw-r--r--src/window.h20
9 files changed, 256 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index 17346fee..cf0ddafc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2004-06-17 Elijah Newren <newren@math.utah.edu>
+
+ Add support for _NET_WM_USER_TIME
+
+ * src/display.c:
+ (meta_display_open): Add _NET_WM_USER_TIME to atom_names[],
+ (event_callback): Manually set _NET_WM_USER_TIME upon KeyPress
+ (doesn't work since keyboard isn't grabbed) and ButtonPress (does
+ work), this is just a fallback for applications that don't update
+ this themselves.
+
+ * src/display.h: (struct _MetaDisplay): Add atom_net_wm_user_time field
+
+ * src/screen.c: (meta_screen_apply_startup_properties): Check for
+ TIMESTAMP provided from startup sequence as well.
+
+ * src/stack.c:
+ s/meta_window_set_stack_position/meta_window_set_stack_position_no_sync/,
+ (meta_window_set_stack_position): New function which calls the
+ meta_window_set_stack_position_no_sync function followed immediately
+ by calling meta_stack_sync_to_server.
+
+ * src/window-props.c:
+ (init_net_wm_user_time), (reload_net_wm_user_time): new functions,
+ (reload_wm_hints): also load atom_net_wm_user_time
+
+ * src/window.c:
+ new XSERVER_TIME_IS_LATER macro (accounts for timestamp wraparound),
+ (meta_window_new_with_attrs): add timestamp attributes,
+ (window_takes_focus_on_map): use TIMESTAMP from startup
+ notification and _NET_WM_USER_TIME to decide whether to focus new
+ windows,
+ (meta_window_show): if app doesn't take focus on map, place it
+ just below the focused window in the stack
+ (process_property_notify): check for changes to _NET_WM_USRE_TIME,
+ (meta_window_stack_just_below): new function
+
+ * src/window.h:
+ (_MetaWindow struct): new fields for initial_timestamp,
+ initial_timestamp_set, net_wm_user_time_set, and net_wm_user_time,
+ (meta_window_stack_just_below): new function
+
2004-06-21 Anders Carlsson <andersca@gnome.org>
* src/common.h:
diff --git a/src/display.c b/src/display.c
index 50ff9583..fa574bfe 100644
--- a/src/display.c
+++ b/src/display.c
@@ -281,6 +281,7 @@ meta_display_open (const char *name)
"_NET_WM_ACTION_MINIMIZE",
"_NET_FRAME_EXTENTS",
"_NET_REQUEST_FRAME_EXTENTS",
+ "_NET_WM_USER_TIME",
};
Atom atoms[G_N_ELEMENTS(atom_names)];
@@ -427,6 +428,7 @@ meta_display_open (const char *name)
display->atom_net_wm_action_minimize = atoms[82];
display->atom_net_frame_extents = atoms[83];
display->atom_net_request_frame_extents = atoms[84];
+ display->atom_net_wm_user_time = atoms[85];
display->prop_hooks = NULL;
meta_display_init_window_prop_hooks (display);
@@ -1177,7 +1179,7 @@ event_callback (XEvent *event,
Window modified;
gboolean frame_was_receiver;
gboolean filter_out_event;
-
+
display = data;
if (dump_events)
@@ -1326,6 +1328,16 @@ event_callback (XEvent *event,
}
}
#endif /* HAVE_SHAPE */
+
+ if (window && ((event->type == KeyPress) || (event->type == ButtonPress)))
+ {
+ g_assert (CurrentTime != display->current_time);
+ meta_topic (META_DEBUG_WINDOW_STATE,
+ "Metacity set %s's net_wm_user_time to %d.\n",
+ window->desc, display->current_time);
+ window->net_wm_user_time_set = TRUE;
+ window->net_wm_user_time = display->current_time;
+ }
switch (event->type)
{
diff --git a/src/display.h b/src/display.h
index b49dcc1f..08255fe1 100644
--- a/src/display.h
+++ b/src/display.h
@@ -175,6 +175,7 @@ struct _MetaDisplay
Atom atom_net_wm_strut_partial;
Atom atom_net_frame_extents;
Atom atom_net_request_frame_extents;
+ Atom atom_net_wm_user_time;
/* This is the actual window from focus events,
* not the one we last set
diff --git a/src/screen.c b/src/screen.c
index 293734f5..bfc86895 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -2481,6 +2481,7 @@ meta_screen_apply_startup_properties (MetaScreen *screen,
if (sequence != NULL)
{
int space;
+ Time timestamp;
meta_topic (META_DEBUG_STARTUP,
"Found startup sequence for window %s ID \"%s\"\n",
@@ -2500,6 +2501,17 @@ meta_screen_apply_startup_properties (MetaScreen *screen,
}
}
+ if (!window->initial_timestamp_set)
+ {
+ timestamp = sn_startup_sequence_get_timestamp (sequence);
+ meta_topic (META_DEBUG_STARTUP,
+ "Setting initial window timestamp to %lu based on startup info\n",
+ timestamp);
+
+ window->initial_timestamp_set = TRUE;
+ window->initial_timestamp = timestamp;
+ }
+
return;
}
else
diff --git a/src/stack.c b/src/stack.c
index 50f37c34..eacc9ae0 100644
--- a/src/stack.c
+++ b/src/stack.c
@@ -47,6 +47,8 @@
#define WINDOW_IN_STACK(w) (w->stack_position >= 0)
static void meta_stack_sync_to_server (MetaStack *stack);
+static void meta_window_set_stack_position_no_sync (MetaWindow *window,
+ int position);
MetaStack*
meta_stack_new (MetaScreen *screen)
@@ -122,8 +124,8 @@ meta_stack_remove (MetaStack *stack,
/* Set window to top position, so removing it will not leave gaps
* in the set of positions
*/
- meta_window_set_stack_position (window,
- stack->n_positions - 1);
+ meta_window_set_stack_position_no_sync (window,
+ stack->n_positions - 1);
window->stack_position = -1;
stack->n_positions -= 1;
@@ -162,8 +164,8 @@ void
meta_stack_raise (MetaStack *stack,
MetaWindow *window)
{
- meta_window_set_stack_position (window,
- stack->n_positions - 1);
+ meta_window_set_stack_position_no_sync (window,
+ stack->n_positions - 1);
meta_stack_sync_to_server (stack);
}
@@ -172,7 +174,7 @@ void
meta_stack_lower (MetaStack *stack,
MetaWindow *window)
{
- meta_window_set_stack_position (window, 0);
+ meta_window_set_stack_position_no_sync (window, 0);
meta_stack_sync_to_server (stack);
}
@@ -669,7 +671,7 @@ ensure_above (MetaWindow *above,
if (above->stack_position < below->stack_position)
{
/* move above to below->stack_position bumping below down the stack */
- meta_window_set_stack_position (above, below->stack_position);
+ meta_window_set_stack_position_no_sync (above, below->stack_position);
g_assert (below->stack_position + 1 == above->stack_position);
}
meta_topic (META_DEBUG_STACK, "%s above at %d > %s below at %d\n",
@@ -1465,8 +1467,8 @@ meta_stack_windows_cmp (MetaStack *stack,
}
void
-meta_window_set_stack_position (MetaWindow *window,
- int position)
+meta_window_set_stack_position_no_sync (MetaWindow *window,
+ int position)
{
int low, high, delta;
GList *tmp;
@@ -1517,3 +1519,11 @@ meta_window_set_stack_position (MetaWindow *window,
"Window %s had stack_position set to %d\n",
window->desc, window->stack_position);
}
+
+void
+meta_window_set_stack_position (MetaWindow *window,
+ int position)
+{
+ meta_window_set_stack_position_no_sync (window, position);
+ meta_stack_sync_to_server (window->screen->stack);
+}
diff --git a/src/stack.h b/src/stack.h
index b0c21e56..0b8d05e2 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -141,7 +141,3 @@ void meta_window_set_stack_position (MetaWindow *window,
int position);
#endif
-
-
-
-
diff --git a/src/window-props.c b/src/window-props.c
index 6f9b4b67..2eed8b2e 100644
--- a/src/window-props.c
+++ b/src/window-props.c
@@ -171,6 +171,31 @@ reload_net_wm_pid (MetaWindow *window,
}
static void
+init_net_wm_user_time (MetaDisplay *display,
+ Atom property,
+ MetaPropValue *value)
+{
+ value->type = META_PROP_VALUE_CARDINAL;
+ value->atom = display->atom_net_wm_user_time;
+}
+
+static void
+reload_net_wm_user_time (MetaWindow *window,
+ MetaPropValue *value)
+{
+ if (value->type != META_PROP_VALUE_INVALID)
+ {
+ gulong cardinal = value->v.cardinal;
+
+ window->net_wm_user_time_set = TRUE;
+ window->net_wm_user_time = cardinal;
+ meta_topic (META_DEBUG_STARTUP,
+ "Window %s has _NET_WM_USER_TIME of %lu\n",
+ window->desc, window->net_wm_user_time);
+ }
+}
+
+static void
set_window_title (MetaWindow *window,
const char *title)
{
@@ -814,7 +839,7 @@ reload_wm_hints (MetaWindow *window,
-#define N_HOOKS 23
+#define N_HOOKS 24
void
meta_display_init_window_prop_hooks (MetaDisplay *display)
@@ -844,6 +869,11 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
hooks[i].reload_func = reload_net_wm_pid;
++i;
+ hooks[i].property = display->atom_net_wm_user_time;
+ hooks[i].init_func = init_net_wm_user_time;
+ hooks[i].reload_func = reload_net_wm_user_time;
+ ++i;
+
hooks[i].property = display->atom_net_wm_name;
hooks[i].init_func = init_net_wm_name;
hooks[i].reload_func = reload_net_wm_name;
diff --git a/src/window.c b/src/window.c
index addfd2fa..aa3c4d0e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -47,6 +47,14 @@
#include <X11/extensions/shape.h>
#endif
+/* Xserver time can wraparound, thus comparing two timestamps needs to take
+ * this into account. Here's a little macro to help out.
+ */
+#define XSERVER_TIME_IS_LATER(time1, time2) \
+ ( ((time1 >= time2) && (time1 - time2 < G_MAXULONG / 2)) || \
+ ((time1 < time2) && (time2 - time1 > G_MAXULONG / 2)) \
+ )
+
typedef enum
{
META_IS_CONFIGURE_REQUEST = 1 << 0,
@@ -216,7 +224,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
MetaWorkspace *space;
gulong existing_wm_state;
gulong event_mask;
-#define N_INITIAL_PROPS 12
+#define N_INITIAL_PROPS 13
Atom initial_props[N_INITIAL_PROPS];
int i;
gboolean has_shape;
@@ -446,6 +454,8 @@ meta_window_new_with_attrs (MetaDisplay *display,
window->all_keys_grabbed = FALSE;
window->withdrawn = FALSE;
window->initial_workspace_set = FALSE;
+ window->initial_timestamp_set = FALSE;
+ window->net_wm_user_time_set = FALSE;
window->calc_placement = FALSE;
window->shaken_loose = FALSE;
window->have_focus_click_grab = FALSE;
@@ -509,6 +519,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
window->layer = META_LAYER_LAST; /* invalid value */
window->stack_position = -1;
window->initial_workspace = 0; /* not used */
+ window->initial_timestamp = 0; /* not used */
meta_display_register_x_window (display, &window->xwindow, window);
@@ -536,6 +547,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
initial_props[i++] = XA_WM_NORMAL_HINTS;
initial_props[i++] = display->atom_wm_protocols;
initial_props[i++] = XA_WM_HINTS;
+ initial_props[i++] = display->atom_net_wm_user_time;
g_assert (N_INITIAL_PROPS == i);
meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS);
@@ -1555,6 +1567,8 @@ meta_window_queue_calc_showing (MetaWindow *window)
static gboolean
window_takes_focus_on_map (MetaWindow *window)
{
+ Time compare;
+
/* don't initially focus windows that are intended to not accept
* focus
*/
@@ -1572,41 +1586,80 @@ window_takes_focus_on_map (MetaWindow *window)
/* don't focus these */
break;
case META_WINDOW_NORMAL:
+ case META_WINDOW_DIALOG:
+ case META_WINDOW_MODAL_DIALOG:
- /* Always focus new windows */
- return TRUE;
+ meta_topic (META_DEBUG_STARTUP,
+ "COMPARISON:\n"
+ " net_wm_user_time_set : %d\n"
+ " net_wm_user_time : %lu\n"
+ " initial_timestamp_set: %d\n"
+ " initial_timestamp : %lu\n",
+ window->net_wm_user_time_set,
+ window->net_wm_user_time,
+ window->initial_timestamp_set,
+ window->initial_timestamp);
+ if (window->display->focus_window != NULL) {
+ meta_topic (META_DEBUG_STARTUP,
+ "COMPARISON (continued):\n"
+ " focus_window : %s\n"
+ " fw->net_wm_user_time : %lu\n",
+ window->display->focus_window->desc,
+ window->display->focus_window->net_wm_user_time);
+ }
- /* Old Windows-XP style rule for reference */
- /* Focus only if the current focus is on a desktop element
- * or nonexistent.
- *
- * (using display->focus_window is a bit of a race condition,
- * but I have no idea how to avoid it)
+ /* We expect the most common case for not focusing a new window
+ * to be when a hint to not focus it has been set. Since we can
+ * deal with that case rapidly, we use special case it--this is
+ * merely a preliminary optimization. :)
*/
- if (window->display->focus_window == NULL ||
- (window->display->focus_window &&
- (window->display->focus_window->type == META_WINDOW_DOCK ||
- window->display->focus_window->type == META_WINDOW_DESKTOP)))
- return TRUE;
- break;
- case META_WINDOW_DIALOG:
- case META_WINDOW_MODAL_DIALOG:
+ if ( ((window->net_wm_user_time_set == TRUE) &&
+ (window->net_wm_user_time == 0))
+ ||
+ ((window->initial_timestamp_set == TRUE) &&
+ (window->initial_timestamp == 0)))
+ {
+ meta_topic (META_DEBUG_STARTUP,
+ "window %s explicitly requested no focus\n",
+ window->desc);
+ return FALSE;
+ }
- /* Always focus */
- return TRUE;
+ if (!(window->net_wm_user_time_set) && !(window->initial_timestamp_set))
+ {
+ meta_topic (META_DEBUG_STARTUP,
+ "no information about window %s found\n",
+ window->desc);
+ return TRUE;
+ }
- /* Old Windows-XP style rule for reference */
- /* Focus only if the transient parent has focus */
- /* (using display->focus_window is a bit of a race condition,
- * but I have no idea how to avoid it)
+ /* To determine the "launch" time of an application,
+ * startup-notification can set the TIMESTAMP and the
+ * application (usually via its toolkit such as gtk or qt) can
+ * set the _NET_WM_USER_TIME. If both are set, then it means
+ * the user has interacted with the application since it
+ * launched, and _NET_WM_USER_TIME is the value that should be
+ * used in the comparison.
*/
- if (window->display->focus_window == NULL ||
- (window->display->focus_window &&
- meta_window_is_ancestor_of_transient (window->display->focus_window,
- window)) ||
- (window->display->focus_window->type == META_WINDOW_DOCK ||
- window->display->focus_window->type == META_WINDOW_DESKTOP))
- return TRUE;
+ compare = window->initial_timestamp_set ? window->initial_timestamp : 0;
+ compare = window->net_wm_user_time_set ? window->net_wm_user_time : compare;
+
+ if ((window->display->focus_window == NULL) ||
+ (XSERVER_TIME_IS_LATER (compare, window->display->focus_window->net_wm_user_time)))
+ {
+ meta_topic (META_DEBUG_STARTUP,
+ "new window %s with no intervening events\n",
+ window->desc);
+ return TRUE;
+ }
+ else
+ {
+ meta_topic (META_DEBUG_STARTUP,
+ "window %s focus prevented by other activity; %lu is before %lu\n",
+ window->desc, compare, window->display->focus_window->net_wm_user_time);
+ return FALSE;
+ }
+
break;
}
@@ -1618,13 +1671,20 @@ meta_window_show (MetaWindow *window)
{
gboolean did_placement;
gboolean did_show;
-
+ gboolean takes_focus_on_map;
+
meta_topic (META_DEBUG_WINDOW_STATE,
"Showing window %s, shaded: %d iconic: %d placed: %d\n",
window->desc, window->shaded, window->iconic, window->placed);
did_show = FALSE;
did_placement = FALSE;
+ takes_focus_on_map = window_takes_focus_on_map (window);
+
+ if ( (!takes_focus_on_map) && (window->display->focus_window != NULL) )
+ meta_window_stack_just_below (window,
+ window->display->focus_window);
+
if (!window->placed)
{
/* We have to recalc the placement here since other windows may
@@ -1721,7 +1781,7 @@ meta_window_show (MetaWindow *window)
}
}
- if (window_takes_focus_on_map (window))
+ if (takes_focus_on_map)
{
meta_window_focus (window,
meta_display_get_current_time (window->display));
@@ -4418,6 +4478,13 @@ process_property_notify (MetaWindow *window,
meta_window_reload_property (window,
window->display->atom_net_wm_sync_request_counter);
}
+ else if (event->atom == window->display->atom_net_wm_user_time)
+ {
+ meta_verbose ("Property notify on %s for _NET_WM_USER_TIME\n", window->desc);
+
+ meta_window_reload_property (window,
+ window->display->atom_net_wm_user_time);
+ }
return TRUE;
}
@@ -7056,3 +7123,27 @@ meta_window_update_layer (MetaWindow *window)
meta_stack_update_layer (window->screen->stack, window);
meta_stack_thaw (window->screen->stack);
}
+
+void
+meta_window_stack_just_below (MetaWindow *window,
+ MetaWindow *below_this_one)
+{
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (below_this_one != NULL);
+
+ if (window->stack_position > below_this_one->stack_position)
+ {
+ meta_topic (META_DEBUG_STACK,
+ "Setting stack position of window %s to %d (making it below window %s).\n",
+ window->desc,
+ below_this_one->stack_position - 1,
+ below_this_one->desc);
+ meta_window_set_stack_position (window, below_this_one->stack_position - 1);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_STACK,
+ "Window %s was already below window %s.\n",
+ window->desc, below_this_one->desc);
+ }
+}
diff --git a/src/window.h b/src/window.h
index 534b2524..ca794841 100644
--- a/src/window.h
+++ b/src/window.h
@@ -103,6 +103,9 @@ struct _MetaWindow
/* Initial workspace property */
int initial_workspace;
+ /* Initial timestamp property */
+ Time initial_timestamp;
+
/* Whether we're maximized */
guint maximized : 1;
guint maximize_after_placement : 1;
@@ -139,6 +142,12 @@ struct _MetaWindow
/* whether an initial workspace was explicitly set */
guint initial_workspace_set : 1;
+ /* whether an initial timestamp was explicitly set */
+ guint initial_timestamp_set : 1;
+
+ /* whether net_wm_user_time has been set yet */
+ guint net_wm_user_time_set : 1;
+
/* These are the flags from WM_PROTOCOLS */
guint take_focus : 1;
guint delete_window : 1;
@@ -259,6 +268,10 @@ struct _MetaWindow
* is withdrawing the window.
*/
int unmaps_pending;
+
+ /* set to the most recent user-interaction event timestamp that we
+ know about for this window */
+ Time net_wm_user_time;
/* The size we set the window to last (i.e. what we believe
* to be its actual size on the server). The x, y are
@@ -501,8 +514,7 @@ void meta_window_recalc_features (MetaWindow *window);
void meta_window_queue_update_icon (MetaWindow *window);
-#endif
-
-
-
+void meta_window_stack_just_below (MetaWindow *window,
+ MetaWindow *below_this_one);
+#endif