diff --git a/src/display.c b/src/display.c index 4ff003275..b2accdc92 100644 --- a/src/display.c +++ b/src/display.c @@ -274,7 +274,8 @@ meta_display_open (const char *name) "_METACITY_SENTINEL", "_NET_WM_STRUT_PARTIAL", "_NET_WM_ACTION_FULLSCREEN", - "_NET_WM_ACTION_MINIMIZE" + "_NET_WM_ACTION_MINIMIZE", + "_NET_WM_USER_TIME" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -419,6 +420,7 @@ meta_display_open (const char *name) display->atom_net_wm_strut_partial = atoms[80]; display->atom_net_wm_action_fullscreen = atoms[81]; display->atom_net_wm_action_minimize = atoms[82]; + display->atom_net_wm_user_time = atoms[83]; display->prop_hooks = NULL; meta_display_init_window_prop_hooks (display); @@ -1168,7 +1170,8 @@ event_callback (XEvent *event, Window modified; gboolean frame_was_receiver; gboolean filter_out_event; - + Time event_time; + display = data; if (dump_events) @@ -1321,7 +1324,15 @@ event_callback (XEvent *event, meta_compositor_process_event (display->compositor, event, window); - + + if (window && + (event->type == KeyPress || + event->type == ButtonPress) && + (CurrentTime != + (event_time = event_get_time (display, event)))) { + window->net_wm_user_time = event_time; + } + switch (event->type) { case KeyPress: @@ -1867,9 +1878,10 @@ event_callback (XEvent *event, { MetaGroup *group; MetaScreen *screen; - - if (window && !frame_was_receiver) + + if (window && !frame_was_receiver) { meta_window_property_notify (window, event); + } group = meta_display_lookup_group (display, event->xproperty.window); diff --git a/src/display.h b/src/display.h index fc7e631c0..5d2fcc712 100644 --- a/src/display.h +++ b/src/display.h @@ -172,6 +172,7 @@ struct _MetaDisplay Atom atom_gnome_panel_action_run_dialog; Atom atom_metacity_sentinel; Atom atom_net_wm_strut_partial; + 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 2af481fff..825fc114d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -82,7 +82,7 @@ set_wm_check_hint (MetaScreen *screen) static int set_supported_hint (MetaScreen *screen) { -#define N_SUPPORTED 68 +#define N_SUPPORTED 69 Atom atoms[N_SUPPORTED]; atoms[0] = screen->display->atom_net_wm_name; @@ -153,6 +153,7 @@ set_supported_hint (MetaScreen *screen) atoms[65] = screen->display->atom_net_wm_strut_partial; atoms[66] = screen->display->atom_net_wm_action_fullscreen; atoms[67] = screen->display->atom_net_wm_action_minimize; + atoms[68] = screen->display->atom_net_wm_user_time; XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom_net_supported, diff --git a/src/window-props.c b/src/window-props.c index 3dae259a6..5c57ef707 100644 --- a/src/window-props.c +++ b/src/window-props.c @@ -170,6 +170,33 @@ 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 = (int) value->v.cardinal; + + if (cardinal <= 0) + meta_warning (_("Application set a bogus _NET_WM_USER_TIME %ld\n"), + cardinal); + else + { + window->net_wm_user_time = cardinal; + } + } +} + static void set_window_title (MetaWindow *window, const char *title) @@ -814,7 +841,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 +871,16 @@ 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_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 7cfaf5e47..a35b501b6 100644 --- a/src/window.c +++ b/src/window.c @@ -582,6 +582,17 @@ meta_window_new_with_attrs (MetaDisplay *display, meta_display_grab_window_buttons (window->display, window->xwindow); meta_display_grab_focus_window_button (window->display, window); + if (window->type == META_WINDOW_DESKTOP || + window->type == META_WINDOW_DOCK) + { + /* Change the default, but don't enforce this if the user + * focuses the dock/desktop and unsticks it using key shortcuts. + * Need to set this before adding to the workspaces so the MRU + * lists will be updated. + */ + window->on_all_workspaces = TRUE; + } + /* For the workspace, first honor hints, * if that fails put transients with parents, * otherwise put window on active space @@ -595,8 +606,11 @@ meta_window_new_with_attrs (MetaDisplay *display, "Window %s is initially on all spaces\n", window->desc); - meta_workspace_add_window (window->screen->active_workspace, window); + /* need to set on_all_workspaces first so that it will be + * added to all the MRU lists + */ window->on_all_workspaces = TRUE; + meta_workspace_add_window (window->screen->active_workspace, window); } else { @@ -636,6 +650,8 @@ meta_window_new_with_attrs (MetaDisplay *display, tmp_list = parent->workspaces; while (tmp_list != NULL) { + /* this will implicitly add to the appropriate MRU lists + */ meta_workspace_add_window (tmp_list->data, window); tmp_list = tmp_list->next; @@ -654,16 +670,6 @@ meta_window_new_with_attrs (MetaDisplay *display, meta_workspace_add_window (space, window); } - if (window->type == META_WINDOW_DESKTOP || - window->type == META_WINDOW_DOCK) - { - /* Change the default, but don't enforce this if - * the user focuses the dock/desktop and unsticks it - * using key shortcuts - */ - window->on_all_workspaces = TRUE; - } - /* for the various on_all_workspaces = TRUE possible above */ meta_window_set_current_workspace_hint (window); @@ -4317,6 +4323,20 @@ process_property_notify (MetaWindow *window, meta_window_reload_property (window, window->display->atom_metacity_update_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); + } + 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; } diff --git a/src/window.h b/src/window.h index 5523af13a..ee8356249 100644 --- a/src/window.h +++ b/src/window.h @@ -242,6 +242,11 @@ struct _MetaWindow /* if TRUE we have a grab on the focus click buttons */ guint have_focus_click_grab : 1; + + /* set to the most recent user-interaction event timestamp that we + * know about for this window + */ + Time net_wm_user_time; #ifdef HAVE_XSYNC /* XSync update counter */ diff --git a/src/workspace.c b/src/workspace.c index e8a820df5..415b04713 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -112,11 +112,30 @@ meta_workspace_add_window (MetaWorkspace *workspace, { g_return_if_fail (!meta_workspace_contains_window (workspace, window)); + /* If the window is on all workspaces, we want to add it to all mru + * lists, otherwise just add it to this workspaces mru list + */ + if (window->on_all_workspaces) + { + if (g_list_length (window->workspaces) == 0) + { + GList* tmp = window->screen->workspaces; + while (tmp) + { + MetaWorkspace* work = (MetaWorkspace*) tmp->data; + if (!g_list_find (work->mru_list, window)) + work->mru_list = g_list_append (work->mru_list, window); + + tmp = tmp->next; + } + } + } + else if (!g_list_find (workspace->mru_list, window)) + workspace->mru_list = g_list_prepend (workspace->mru_list, window); + workspace->windows = g_list_prepend (workspace->windows, window); window->workspaces = g_list_prepend (window->workspaces, workspace); - workspace->mru_list = g_list_append (workspace->mru_list, window); - meta_window_set_current_workspace_hint (window); meta_window_queue_calc_showing (window); @@ -142,7 +161,27 @@ meta_workspace_remove_window (MetaWorkspace *workspace, workspace->windows = g_list_remove (workspace->windows, window); window->workspaces = g_list_remove (window->workspaces, workspace); - workspace->mru_list = g_list_remove (workspace->mru_list, window); + + /* If the window is on all workspaces, we don't want to remove it + * from the MRU list unless this causes it to be removed from all + * workspaces + */ + if (window->on_all_workspaces) + { + if (g_list_length (window->workspaces) == 0) + { + GList* tmp = window->screen->workspaces; + while (tmp) + { + MetaWorkspace* work = (MetaWorkspace*) tmp->data; + work->mru_list = g_list_remove (work->mru_list, window); + + tmp = tmp->next; + } + } + } + else + workspace->mru_list = g_list_remove (workspace->mru_list, window); meta_window_set_current_workspace_hint (window);