diff options
author | Elijah Newren <newren@math.utah.edu> | 2004-06-24 15:47:05 +0000 |
---|---|---|
committer | Elijah Newren <newren@src.gnome.org> | 2004-06-24 15:47:05 +0000 |
commit | 28a54c6bb4f5e4157cec8e6a69736ceef07c3099 (patch) | |
tree | 139266d9301e6d83ab5689bc78a9237c3c711e0b | |
parent | ef1ecc812858e3a5c2460a2689118f11d43142a8 (diff) | |
download | metacity-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-- | ChangeLog | 42 | ||||
-rw-r--r-- | src/display.c | 14 | ||||
-rw-r--r-- | src/display.h | 1 | ||||
-rw-r--r-- | src/screen.c | 12 | ||||
-rw-r--r-- | src/stack.c | 26 | ||||
-rw-r--r-- | src/stack.h | 4 | ||||
-rw-r--r-- | src/window-props.c | 32 | ||||
-rw-r--r-- | src/window.c | 155 | ||||
-rw-r--r-- | src/window.h | 20 |
9 files changed, 256 insertions, 50 deletions
@@ -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 |