[gnome-shell] [ShellApp] Add method to focus an app (all windows), make _activate do this
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] [ShellApp] Add method to focus an app (all windows), make _activate do this
- Date: Thu, 6 May 2010 15:19:51 +0000 (UTC)
commit 0d1ac8cb5be63e066598a0a3ff92f5dfebbc3f91
Author: Colin Walters <walters verbum org>
Date: Sat Apr 17 16:57:58 2010 -0400
[ShellApp] Add method to focus an app (all windows), make _activate do this
The design calls for raising all windows for a given app in
certain circumstances; implement this. The new _focus method
raises all windows for the app if it's running.
We further change the _activate method (which a lot of the shell
UI calls now) to invoke _focus for the running case, which means
that e.g. the application well will now raise all app windows.
https://bugzilla.gnome.org/show_bug.cgi?id=616051
src/shell-app.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++------
src/shell-app.h | 2 +
2 files changed, 145 insertions(+), 18 deletions(-)
---
diff --git a/src/shell-app.c b/src/shell-app.c
index 41d031d..6c78d23 100644
--- a/src/shell-app.c
+++ b/src/shell-app.c
@@ -6,6 +6,7 @@
#include "shell-app-private.h"
#include "shell-global.h"
#include "shell-enum-types.h"
+#include "display.h"
#include <string.h>
@@ -245,14 +246,153 @@ shell_app_is_transient (ShellApp *app)
return shell_app_info_is_transient (app->info);
}
+typedef struct {
+ MetaWorkspace *workspace;
+ GSList **transients;
+} CollectTransientsData;
+
+static gboolean
+collect_transients_on_workspace (MetaWindow *window,
+ gpointer datap)
+{
+ CollectTransientsData *data = datap;
+
+ if (data->workspace && meta_window_get_workspace (window) != data->workspace)
+ return TRUE;
+
+ *data->transients = g_slist_prepend (*data->transients, window);
+ return TRUE;
+}
+
+/* The basic idea here is that when we're targeting a window,
+ * if it has transients we want to pick the most recent one
+ * the user interacted with.
+ * This function makes raising GEdit with the file chooser
+ * open work correctly.
+ */
+static MetaWindow *
+find_most_recent_transient_on_same_workspace (MetaDisplay *display,
+ MetaWindow *reference)
+{
+ GSList *transients, *transients_sorted, *iter;
+ MetaWindow *result;
+ CollectTransientsData data;
+
+ transients = NULL;
+ data.workspace = meta_window_get_workspace (reference);
+ data.transients = &transients;
+
+ meta_window_foreach_transient (reference, collect_transients_on_workspace, &data);
+
+ transients_sorted = meta_display_sort_windows_by_stacking (display, transients);
+ /* Reverse this so we're top-to-bottom (yes, we should probably change the order
+ * returned from the sort_windows_by_stacking function)
+ */
+ transients_sorted = g_slist_reverse (transients_sorted);
+ g_slist_free (transients);
+ transients = NULL;
+
+ result = NULL;
+ for (iter = transients_sorted; iter; iter = iter->next)
+ {
+ MetaWindow *window = iter->data;
+ MetaWindowType wintype = meta_window_get_window_type (window);
+
+ /* Don't want to focus UTILITY types, like the Gimp toolbars */
+ if (wintype == META_WINDOW_NORMAL ||
+ wintype == META_WINDOW_DIALOG)
+ {
+ result = window;
+ break;
+ }
+ }
+ g_slist_free (transients_sorted);
+ return result;
+}
+
+/**
+ * shell_app_activate_window:
+ * @app: a #ShellApp
+ * @window: (allow-none): Window to be focused
+ * @timestamp: Event timestamp
+ *
+ * Bring all windows for the given app to the foreground,
+ * but ensure that @window is on top. If @window is %NULL,
+ * the window with the most recent user time for the app
+ * will be used.
+ *
+ * This function has no effect if @app is not currently running.
+ */
+void
+shell_app_activate_window (ShellApp *app,
+ MetaWindow *window,
+ guint32 timestamp)
+{
+ GSList *windows;
+
+ if (shell_app_get_state (app) != SHELL_APP_STATE_RUNNING)
+ return;
+
+ windows = shell_app_get_windows (app);
+ if (window == NULL && windows)
+ window = windows->data;
+
+ if (!g_slist_find (windows, window))
+ return;
+ else
+ {
+ GSList *iter;
+ ShellGlobal *global = shell_global_get ();
+ MetaScreen *screen = shell_global_get_screen (global);
+ MetaDisplay *display = meta_screen_get_display (screen);
+ MetaWorkspace *active = meta_screen_get_active_workspace (screen);
+ MetaWorkspace *workspace = meta_window_get_workspace (window);
+ guint32 last_user_timestamp = meta_display_get_last_user_time (display);
+ MetaWindow *most_recent_transient;
+
+ if (meta_display_xserver_time_is_before (display, timestamp, last_user_timestamp))
+ {
+ meta_window_set_demands_attention (window);
+ return;
+ }
+
+ /* Now raise all the other windows for the app that are on
+ * the same workspace, in reverse order to preserve the stacking.
+ */
+ for (iter = windows; iter; iter = iter->next)
+ {
+ MetaWindow *other_window = iter->data;
+
+ if (other_window != window)
+ meta_window_raise (other_window);
+ }
+
+ /* If we have a transient that the user's interacted with more recently than
+ * the window, pick that.
+ */
+ most_recent_transient = find_most_recent_transient_on_same_workspace (display, window);
+ if (most_recent_transient
+ && meta_display_xserver_time_is_before (display,
+ meta_window_get_user_time (window),
+ meta_window_get_user_time (most_recent_transient)))
+ window = most_recent_transient;
+
+ if (active != workspace)
+ meta_workspace_activate_with_focus (workspace, window, timestamp);
+ else
+ meta_window_activate (window, timestamp);
+ }
+}
+
/**
* shell_app_activate:
* @app: a #ShellApp
*
* Perform an appropriate default action for operating on this application,
* dependent on its current state. For example, if the application is not
- * currently running, launch it. If it is running, activate the most recently
- * used window.
+ * currently running, launch it. If it is running, activate the most
+ * recently used NORMAL window (or if that window has a transient, the most
+ * recently used transient for that window).
*/
void
shell_app_activate (ShellApp *app)
@@ -266,22 +406,7 @@ shell_app_activate (ShellApp *app)
case SHELL_APP_STATE_STARTING:
break;
case SHELL_APP_STATE_RUNNING:
- {
- GSList *windows = shell_app_get_windows (app);
- if (windows)
- {
- ShellGlobal *global = shell_global_get ();
- MetaScreen *screen = shell_global_get_screen (global);
- MetaWorkspace *active = meta_screen_get_active_workspace (screen);
- MetaWindow *window = windows->data;
- MetaWorkspace *workspace = meta_window_get_workspace (window);
-
- if (active != workspace)
- meta_workspace_activate_with_focus (workspace, window, shell_global_get_current_time (global));
- else
- meta_window_activate (window, shell_global_get_current_time (global));
- }
- }
+ shell_app_activate_window (app, NULL, shell_global_get_current_time (shell_global_get ()));
break;
}
}
diff --git a/src/shell-app.h b/src/shell-app.h
index 42e071e..de96915 100644
--- a/src/shell-app.h
+++ b/src/shell-app.h
@@ -41,6 +41,8 @@ char *shell_app_get_name (ShellApp *app);
char *shell_app_get_description (ShellApp *app);
gboolean shell_app_is_transient (ShellApp *app);
+void shell_app_activate_window (ShellApp *app, MetaWindow *window, guint32 timestamp);
+
void shell_app_activate (ShellApp *app);
void shell_app_open_new_window (ShellApp *app);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]