From 71204c2db80348c92b42c5cca08fc8c1166ab40d Mon Sep 17 00:00:00 2001 From: Martin Wimpress Date: Mon, 24 Feb 2014 14:44:24 +0000 Subject: [PATCH] Opening new terminal in a tab now works. The new intended behaviour is desbribed in https://bugzilla.gnome.org/show_bug.cgi?id=83203#c57 Fixes #45. --- src/terminal-app.c | 95 +++++++++++++++++++++++++++++++++--------- src/terminal-app.h | 4 +- src/terminal-options.c | 12 ++++-- src/terminal-options.h | 2 + src/terminal-window.c | 45 ++++++++++++++++++++ src/terminal-window.h | 3 ++ src/terminal.c | 46 +++++++++++++++++--- 7 files changed, 178 insertions(+), 29 deletions(-) diff --git a/src/terminal-app.c b/src/terminal-app.c index caf3533..71d14ee 100644 --- a/src/terminal-app.c +++ b/src/terminal-app.c @@ -219,6 +219,29 @@ terminal_app_get_screen_by_display_name (const char *display_name, return screen; } +static int +terminal_app_get_workspace_for_window (TerminalWindow *window) +{ + int ret = -1; + guchar *data = NULL; + GdkAtom atom; + GdkAtom cardinal_atom; + + atom = gdk_atom_intern_static_string ("_NET_WM_DESKTOP"); + cardinal_atom = gdk_atom_intern_static_string ("CARDINAL"); + + gdk_property_get (gtk_widget_get_window(GTK_WIDGET(window)), + atom, cardinal_atom, 0, 8, FALSE, + NULL, NULL, NULL, &data); + + if (data) + ret = *(int *)data; + + g_free (data); + return ret; +} + + /* Menubar mnemonics settings handling */ static int @@ -1688,32 +1711,38 @@ terminal_app_handle_options (TerminalApp *app, for (lw = options->initial_windows; lw != NULL; lw = lw->next) { InitialWindow *iw = lw->data; - TerminalWindow *window; + TerminalWindow *window = NULL; GList *lt; g_assert (iw->tabs); - /* Create & setup new window */ - window = terminal_app_new_window (app, gdk_screen); + if ( lw == options->initial_windows && ((InitialTab *)iw->tabs->data)->attach_window ) + window = terminal_app_get_current_window(app, gdk_screen, options->initial_workspace); - /* Restored windows shouldn't demand attention; see bug #586308. */ - if (iw->source_tag == SOURCE_SESSION) - terminal_window_set_is_restored (window); + if (!window) + { + /* Create & setup new window */ + window = terminal_app_new_window (app, gdk_screen); - if (options->startup_id != NULL) - gtk_window_set_startup_id (GTK_WINDOW (window), options->startup_id); + /* Restored windows shouldn't demand attention; see bug #586308. */ + if (iw->source_tag == SOURCE_SESSION) + terminal_window_set_is_restored (window); - /* Overwrite the default, unique window role set in terminal_window_init */ - if (iw->role) - gtk_window_set_role (GTK_WINDOW (window), iw->role); + if (options->startup_id != NULL) + gtk_window_set_startup_id (GTK_WINDOW (window), options->startup_id); - if (iw->force_menubar_state) - terminal_window_set_menubar_visible (window, iw->menubar_state); + /* Overwrite the default, unique window role set in terminal_window_init */ + if (iw->role) + gtk_window_set_role (GTK_WINDOW (window), iw->role); - if (iw->start_fullscreen) - gtk_window_fullscreen (GTK_WINDOW (window)); - if (iw->start_maximized) - gtk_window_maximize (GTK_WINDOW (window)); + if (iw->force_menubar_state) + terminal_window_set_menubar_visible (window, iw->menubar_state); + + if (iw->start_fullscreen) + gtk_window_fullscreen (GTK_WINDOW (window)); + if (iw->start_maximized) + gtk_window_maximize (GTK_WINDOW (window)); + } /* Now add the tabs */ for (lt = iw->tabs; lt != NULL; lt = lt->next) @@ -1842,13 +1871,41 @@ terminal_app_edit_encodings (TerminalApp *app, terminal_encoding_dialog_show (transient_parent); } +/* +* Get the window in the given screen and workspace. If nothing is found, +* a NULL is returned. +*/ TerminalWindow * -terminal_app_get_current_window (TerminalApp *app) +terminal_app_get_current_window (TerminalApp *app, + GdkScreen *from_screen, + int workspace) { + GList *res = NULL; + TerminalWindow *ret = NULL; + if (app->windows == NULL) return NULL; - return g_list_last (app->windows)->data; + res = g_list_last (app->windows); + + g_assert (from_screen != NULL); + + while (res) + { + int win_workspace; + if (gtk_window_get_screen(GTK_WINDOW(res->data)) != from_screen) + continue; + + win_workspace = terminal_app_get_workspace_for_window(res->data); + + /* Same workspace or if the window is set to show up on all workspaces */ + if (win_workspace == workspace || win_workspace == -1) + ret = terminal_window_get_latest_focused (ret, TERMINAL_WINDOW(res->data)); + + res = g_list_previous (res); + } + + return ret; } /** diff --git a/src/terminal-app.h b/src/terminal-app.h index 39c2ad1..70a0665 100644 --- a/src/terminal-app.h +++ b/src/terminal-app.h @@ -115,7 +115,9 @@ TerminalScreen *terminal_app_new_terminal (TerminalApp *app, char **child_env, double zoom); -TerminalWindow *terminal_app_get_current_window (TerminalApp *app); +TerminalWindow *terminal_app_get_current_window (TerminalApp *app, + GdkScreen *screen, + int curr_workspace); void terminal_app_manage_profiles (TerminalApp *app, GtkWindow *transient_parent); diff --git a/src/terminal-options.c b/src/terminal-options.c index 6881b67..ce41055 100644 --- a/src/terminal-options.c +++ b/src/terminal-options.c @@ -51,6 +51,7 @@ initial_tab_new (const char *profile, it->zoom = 1.0; it->zoom_set = FALSE; it->active = FALSE; + it->attach_window = FALSE; return it; } @@ -305,18 +306,22 @@ option_tab_callback (const gchar *option_name, { TerminalOptions *options = data; gboolean is_profile_id; + InitialWindow *iw; + InitialTab *it; is_profile_id = g_str_has_suffix (option_name, "-with-profile-internal-id"); if (options->initial_windows) { - InitialWindow *iw; - iw = g_list_last (options->initial_windows)->data; iw->tabs = g_list_append (iw->tabs, initial_tab_new (value, is_profile_id)); } else - add_new_window (options, value, is_profile_id); + { + iw = add_new_window (options, value, is_profile_id); + it = g_list_last(iw->tabs)->data; + it->attach_window = TRUE; + } return TRUE; } @@ -707,6 +712,7 @@ terminal_options_parse (const char *working_directory, options->default_maximize = FALSE; options->execute = FALSE; options->use_factory = TRUE; + options->initial_workspace = -1; options->env = g_strdupv (env); options->startup_id = g_strdup (startup_id && startup_id[0] ? startup_id : NULL); diff --git a/src/terminal-options.h b/src/terminal-options.h index cbada18..20f9a3f 100644 --- a/src/terminal-options.h +++ b/src/terminal-options.h @@ -53,6 +53,7 @@ typedef struct char *config_file; gboolean load_config; gboolean save_config; + int initial_workspace; } TerminalOptions; typedef struct @@ -65,6 +66,7 @@ typedef struct double zoom; guint zoom_set : 1; guint active : 1; + guint attach_window : 1; } InitialTab; typedef struct diff --git a/src/terminal-window.c b/src/terminal-window.c index 43333bf..d15a90c 100644 --- a/src/terminal-window.c +++ b/src/terminal-window.c @@ -97,6 +97,7 @@ struct _TerminalWindowPrivate /* Workaround until gtk+ bug #535557 is fixed */ guint icon_title_set : 1; + time_t focus_time; }; #define PROFILE_DATA_KEY "GT::Profile" @@ -139,6 +140,9 @@ static gboolean terminal_window_state_event (GtkWidget *widget, static gboolean terminal_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data); +static gboolean terminal_window_focus_in_event (GtkWidget *widget, + GdkEventFocus *event, + gpointer data); static gboolean notebook_button_press_cb (GtkWidget *notebook, GdkEventButton *event, @@ -2136,6 +2140,10 @@ terminal_window_init (TerminalWindow *window) g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK(terminal_window_delete_event), NULL); + g_signal_connect (G_OBJECT (window), "focus_in_event", + G_CALLBACK(terminal_window_focus_in_event), + NULL); + #ifdef MATE_ENABLE_DEBUG _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_GEOMETRY) { @@ -2383,6 +2391,20 @@ terminal_window_delete_event (GtkWidget *widget, return confirm_close_window_or_tab (TERMINAL_WINDOW (widget), NULL); } +static gboolean +terminal_window_focus_in_event (GtkWidget *widget, + GdkEventFocus *event, + gpointer data) +{ + TerminalWindow *window = TERMINAL_WINDOW (widget); + TerminalWindowPrivate *priv = window->priv; + + if (event->in) + priv->focus_time = time(NULL); + + return FALSE; +} + static void terminal_window_show (GtkWidget *widget) { @@ -4264,3 +4286,26 @@ terminal_window_save_state (TerminalWindow *window, g_key_file_set_string_list (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_TABS, (const char * const *) tab_names, len); g_strfreev (tab_names); } + + +TerminalWindow * +terminal_window_get_latest_focused (TerminalWindow *window1, + TerminalWindow *window2) +{ + TerminalWindowPrivate *priv1 = NULL; + TerminalWindowPrivate *priv2 = NULL; + + if (!window1) + return window2; + + if (!window2) + return window1; + + priv1 = window1->priv; + priv2 = window2->priv; + + if (priv2->focus_time > priv1->focus_time) + return window2; + + return window1; +} diff --git a/src/terminal-window.h b/src/terminal-window.h index d00f825..0e7b464 100644 --- a/src/terminal-window.h +++ b/src/terminal-window.h @@ -101,6 +101,9 @@ void terminal_window_save_state (TerminalWindow *window, GKeyFile *key_file, const char *group); +TerminalWindow *terminal_window_get_latest_focused (TerminalWindow *window1, + TerminalWindow *window2); + G_END_DECLS #endif /* TERMINAL_WINDOW_H */ diff --git a/src/terminal.c b/src/terminal.c index 22c7813..4bb7de3 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -155,12 +155,13 @@ method_call_cb (GDBusConnection *connection, TerminalOptions *options = NULL; GVariant *v_wd, *v_display, *v_sid, *v_envv, *v_argv; char *working_directory = NULL, *display_name = NULL, *startup_id = NULL; + int initial_workspace = -1; char **envv = NULL, **argv = NULL; int argc; GError *error = NULL; - g_variant_get (parameters, "(@ay@ay@ay@ay@ay)", - &v_wd, &v_display, &v_sid, &v_envv, &v_argv); + g_variant_get (parameters, "(@ay@ay@ay@ayi@ay)", + &v_wd, &v_display, &v_sid, &v_envv, &initial_workspace, &v_argv); working_directory = ay_to_string (v_wd, &error); if (error) @@ -175,10 +176,12 @@ method_call_cb (GDBusConnection *connection, argv = ay_to_strv (v_argv, &argc); _terminal_debug_print (TERMINAL_DEBUG_FACTORY, - "Factory invoked with working-dir='%s' display='%s' startup-id='%s'\n", + "Factory invoked with working-dir='%s' display='%s' startup-id='%s'" + "workspace='%d'\n", working_directory ? working_directory : "(null)", display_name ? display_name : "(null)", - startup_id ? startup_id : "(null)"); + startup_id ? startup_id : "(null)", + initial_workspace); options = terminal_options_parse (working_directory, display_name, @@ -190,6 +193,8 @@ method_call_cb (GDBusConnection *connection, &error, NULL); + options->initial_workspace = initial_workspace; + if (options != NULL) { terminal_app_handle_options (terminal_app_get (), options, FALSE /* no resume */, &error); @@ -233,6 +238,7 @@ bus_acquired_cb (GDBusConnection *connection, "" "" "" + "" "" "" "" @@ -340,8 +346,8 @@ name_lost_cb (GDBusConnection *connection, _terminal_debug_print (TERMINAL_DEBUG_FACTORY, "Forwarding arguments to existing instance\n"); - g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ayayayayay)")); - + g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ayayayayiay)")); + g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->default_working_dir)); g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->display_name)); g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->startup_id)); @@ -368,6 +374,8 @@ name_lost_cb (GDBusConnection *connection, g_variant_builder_add (&builder, "@ay", g_variant_new_from_data (G_VARIANT_TYPE ("ay"), s, len, TRUE, g_free, s)); + g_variant_builder_add (&builder, "@i", g_variant_new_int32 (data->options->initial_workspace)); + string = g_string_new (NULL); for (i = 0; i < data->argc; ++i) @@ -510,6 +518,29 @@ get_factory_name_for_display (const char *display_name) return g_string_free (name, FALSE); } +static int +get_initial_workspace (void) +{ + int ret = -1; + GdkWindow *window; + guchar *data = NULL; + GdkAtom atom; + GdkAtom cardinal_atom; + + g_type_init (); + + window = gdk_get_default_root_window(); + + atom = gdk_atom_intern_static_string ("_NET_CURRENT_DESKTOP"); + cardinal_atom = gdk_atom_intern_static_string ("CARDINAL"); + + gdk_property_get (window, atom, cardinal_atom, 0, 8, FALSE, NULL, NULL, NULL, &data); + + ret = *(int *)data; + g_free (data); + return ret; +} + int main (int argc, char **argv) { @@ -610,6 +641,9 @@ main (int argc, char **argv) data->argv = argv_copy; data->argc = argc_copy; + gtk_init(&argc, &argv); + options->initial_workspace = get_initial_workspace (); + owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, data->factory_name, G_BUS_NAME_OWNER_FLAGS_NONE,