diff options
| author | mbkma <[email protected]> | 2026-02-01 08:12:15 +0100 |
|---|---|---|
| committer | Victor Kareh <[email protected]> | 2026-03-16 10:20:49 -0400 |
| commit | 3092e0048390ed6373436ee2447256f65256c153 (patch) | |
| tree | 054c285dc72167930899b8ea8f50991fe8d1c08a | |
| parent | 40a129a26d9006e51dd63ddcde6cd2e210d30b92 (diff) | |
| download | mate-terminal-application.tar.bz2 mate-terminal-application.tar.xz | |
port to GtkApplicationapplication
| -rw-r--r-- | src/terminal-app.c | 338 | ||||
| -rw-r--r-- | src/terminal-app.h | 12 | ||||
| -rw-r--r-- | src/terminal-encoding.c | 2 | ||||
| -rw-r--r-- | src/terminal-window.c | 51 | ||||
| -rw-r--r-- | src/terminal-window.h | 4 | ||||
| -rw-r--r-- | src/terminal.c | 538 |
6 files changed, 286 insertions, 659 deletions
diff --git a/src/terminal-app.c b/src/terminal-app.c index 831f42f..5dcb99e 100644 --- a/src/terminal-app.c +++ b/src/terminal-app.c @@ -70,22 +70,18 @@ * */ -GSettings *settings_global; - struct _TerminalAppClass { - GObjectClass parent_class; + GtkApplicationClass parent_class; - void (* quit) (TerminalApp *app); void (* profile_list_changed) (TerminalApp *app); void (* encoding_list_changed) (TerminalApp *app); }; struct _TerminalApp { - GObject parent_instance; + GtkApplication parent_instance; - GList *windows; GtkWidget *new_profile_dialog; GtkWidget *manage_profiles_dialog; GtkWidget *manage_profiles_list; @@ -94,6 +90,7 @@ struct _TerminalApp GtkWidget *manage_profiles_delete_button; GtkWidget *manage_profiles_default_menu; + GSettings *settings_global; GSettings *settings_font; GHashTable *profiles; @@ -120,7 +117,6 @@ enum enum { - QUIT, PROFILE_LIST_CHANGED, ENCODING_LIST_CHANGED, LAST_SIGNAL @@ -140,8 +136,6 @@ enum SOURCE_SESSION = 1 }; -static TerminalApp *global_app = NULL; - #define MONOSPACE_FONT_SCHEMA "org.mate.interface" #define MONOSPACE_FONT_KEY "monospace-font-name" #define DEFAULT_MONOSPACE_FONT ("Monospace 10") @@ -157,6 +151,9 @@ static TerminalApp *global_app = NULL; #define ENCODING_LIST_KEY "active-encodings" +/* Define the type - inherits from GtkApplication */ +G_DEFINE_TYPE (TerminalApp, terminal_app, GTK_TYPE_APPLICATION) + /* two following functions were copied from libmate-desktop to get rid * of dependency on it * @@ -323,16 +320,6 @@ profiles_lookup_by_visible_name_foreach (gpointer key, info->result = value; } -static void -terminal_window_destroyed (TerminalWindow *window, - TerminalApp *app) -{ - app->windows = g_list_remove (app->windows, window); - - if (app->windows == NULL) - g_signal_emit (app, signals[QUIT], 0); -} - static TerminalProfile * terminal_app_create_profile (TerminalApp *app, const char *name) @@ -361,7 +348,7 @@ terminal_app_create_profile (TerminalApp *app, } static void -terminal_app_delete_profile (TerminalProfile *profile) +terminal_app_delete_profile (TerminalApp *app, TerminalProfile *profile) { const char *profile_name; char *profile_dir; @@ -370,7 +357,7 @@ terminal_app_delete_profile (TerminalProfile *profile) profile_name = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME); profile_dir = g_strconcat (CONF_PROFILE_PREFIX, profile_name, "/", NULL); - gsettings_remove_all_from_strv (settings_global, PROFILE_LIST_KEY, profile_name); + gsettings_remove_all_from_strv (app->settings_global, PROFILE_LIST_KEY, profile_name); /* And remove the profile directory */ DConfClient *client = dconf_client_new (); @@ -400,6 +387,7 @@ terminal_app_profile_cell_data_func (GtkTreeViewColumn *tree_column, g_object_get_property (G_OBJECT (profile), "visible-name", &value); g_object_set_property (G_OBJECT (cell), "text", &value); g_value_unset (&value); + g_object_unref (profile); } static int @@ -548,7 +536,7 @@ profile_combo_box_changed_cb (GtkWidget *widget, if (!profile) return; - g_settings_set_string (settings_global, DEFAULT_PROFILE_KEY, + g_settings_set_string (app->settings_global, DEFAULT_PROFILE_KEY, terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME)); /* Even though the GSettings change notification does this, it happens too late. @@ -629,12 +617,16 @@ profile_list_delete_confirm_response_cb (GtkWidget *dialog, int response) { TerminalProfile *profile; + TerminalApp *app; profile = TERMINAL_PROFILE (g_object_get_data (G_OBJECT (dialog), "profile")); g_assert (profile != NULL); if (response == GTK_RESPONSE_ACCEPT) - terminal_app_delete_profile (profile); + { + app = terminal_app_get (); + terminal_app_delete_profile (app, profile); + } gtk_widget_destroy (dialog); } @@ -682,7 +674,7 @@ profile_list_delete_button_clicked_cb (GtkWidget *button, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, - _("Delete profile ā%sā?"), + _("Delete profile \"%s\"?"), terminal_profile_get_property_string (selected_profile, TERMINAL_PROFILE_VISIBLE_NAME)); mate_dialog_add_button (GTK_DIALOG (dialog), @@ -1145,7 +1137,7 @@ new_profile_response_cb (GtkWidget *new_profile_dialog, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, - _("You already have a profile called ā%sā. Do you want to create another profile with the same name?"), name); + _("You already have a profile called \"%s\". Do you want to create another profile with the same name?"), name); /* Alternative button order was set automatically by GtkMessageDialog */ retval = gtk_dialog_run (GTK_DIALOG (confirm_dialog)); gtk_widget_destroy (confirm_dialog); @@ -1163,7 +1155,7 @@ new_profile_response_cb (GtkWidget *new_profile_dialog, new_profile /* adopts the refcount */); /* And now save the new profile name to GSettings */ - gsettings_append_strv (settings_global, + gsettings_append_strv (app->settings_global, PROFILE_LIST_KEY, new_profile_name); @@ -1389,18 +1381,19 @@ static void terminal_app_client_quit_cb (EggSMClient *client, TerminalApp *app) { - g_signal_emit (app, signals[QUIT], 0); + g_application_quit (G_APPLICATION (app)); } #endif /* HAVE_SMCLIENT */ -/* Class implementation */ - -G_DEFINE_TYPE (TerminalApp, terminal_app, G_TYPE_OBJECT) +/* GtkApplication vfuncs */ static void -terminal_app_init (TerminalApp *app) +terminal_app_startup (GApplication *application) { - global_app = app; + TerminalApp *app = TERMINAL_APP (application); + + /* Chain up */ + G_APPLICATION_CLASS (terminal_app_parent_class)->startup (application); gtk_window_set_default_icon_name (MATE_TERMINAL_ICON_NAME); @@ -1412,20 +1405,20 @@ terminal_app_init (TerminalApp *app) app->encodings = terminal_encodings_get_builtins (); - settings_global = g_settings_new (CONF_GLOBAL_SCHEMA); + app->settings_global = g_settings_new (CONF_GLOBAL_SCHEMA); app->settings_font = g_settings_new (MONOSPACE_FONT_SCHEMA); - g_signal_connect (settings_global, + g_signal_connect (app->settings_global, "changed::" PROFILE_LIST_KEY, G_CALLBACK(terminal_app_profile_list_notify_cb), app); - g_signal_connect (settings_global, + g_signal_connect (app->settings_global, "changed::" DEFAULT_PROFILE_KEY, G_CALLBACK(terminal_app_default_profile_notify_cb), app); - g_signal_connect (settings_global, + g_signal_connect (app->settings_global, "changed::" ENCODING_LIST_KEY, G_CALLBACK(terminal_app_encoding_list_notify_cb), app); @@ -1435,33 +1428,33 @@ terminal_app_init (TerminalApp *app) G_CALLBACK(terminal_app_system_font_notify_cb), app); - g_signal_connect (settings_global, + g_signal_connect (app->settings_global, "changed::" ENABLE_MNEMONICS_KEY, G_CALLBACK(terminal_app_enable_mnemonics_notify_cb), app); - g_signal_connect (settings_global, + g_signal_connect (app->settings_global, "changed::" ENABLE_MENU_BAR_ACCEL_KEY, G_CALLBACK(terminal_app_enable_menu_accels_notify_cb), app); /* Load the settings */ - terminal_app_profile_list_notify_cb (settings_global, + terminal_app_profile_list_notify_cb (app->settings_global, PROFILE_LIST_KEY, app); - terminal_app_default_profile_notify_cb (settings_global, + terminal_app_default_profile_notify_cb (app->settings_global, DEFAULT_PROFILE_KEY, app); - terminal_app_encoding_list_notify_cb (settings_global, + terminal_app_encoding_list_notify_cb (app->settings_global, ENCODING_LIST_KEY, app); terminal_app_system_font_notify_cb (app->settings_font, MONOSPACE_FONT_KEY, app); - terminal_app_enable_menu_accels_notify_cb (settings_global, + terminal_app_enable_menu_accels_notify_cb (app->settings_global, ENABLE_MENU_BAR_ACCEL_KEY, app); - terminal_app_enable_mnemonics_notify_cb (settings_global, + terminal_app_enable_mnemonics_notify_cb (app->settings_global, ENABLE_MNEMONICS_KEY, app); @@ -1491,9 +1484,93 @@ terminal_app_init (TerminalApp *app) } static void -terminal_app_finalize (GObject *object) +terminal_app_activate (GApplication *application) { - TerminalApp *app = TERMINAL_APP (object); + TerminalApp *app = TERMINAL_APP (application); + GList *windows; + + /* If we have windows, just present the first one */ + windows = gtk_application_get_windows (GTK_APPLICATION (app)); + if (windows != NULL) + { + gtk_window_present (GTK_WINDOW (windows->data)); + return; + } + + /* Otherwise create a new window with default profile */ + TerminalWindow *window; + TerminalProfile *profile; + + window = terminal_app_new_window (app, gdk_screen_get_default ()); + profile = terminal_app_get_profile_for_new_term (app); + + terminal_app_new_terminal (app, window, profile, + NULL, NULL, NULL, NULL, 1.0); + + gtk_window_present (GTK_WINDOW (window)); +} + +static int +terminal_app_command_line (GApplication *application, + GApplicationCommandLine *command_line) +{ + TerminalApp *app = TERMINAL_APP (application); + TerminalOptions *options = NULL; + GError *error = NULL; + int argc; + char **argv; + const char *working_directory; + const char *startup_id; + gboolean allow_resume; + + argv = g_application_command_line_get_arguments (command_line, &argc); + working_directory = g_application_command_line_get_cwd (command_line); + startup_id = g_application_command_line_getenv (command_line, "DESKTOP_STARTUP_ID"); + + /* Determine if we're resuming from session */ + allow_resume = g_application_command_line_get_is_remote (command_line) == FALSE; + + options = terminal_options_parse (working_directory, + NULL, /* display_name - get from environment */ + startup_id, + NULL, /* envv - we get it from command line */ + TRUE, /* remote args */ + TRUE, /* do_not_use_factory */ + &argc, &argv, + &error, + NULL); + + if (options == NULL) + { + g_application_command_line_printerr (command_line, + _("Failed to parse arguments: %s\n"), + error->message); + g_error_free (error); + g_strfreev (argv); + return EXIT_FAILURE; + } + + if (!terminal_app_handle_options (app, options, allow_resume, &error)) + { + g_application_command_line_printerr (command_line, + "Error handling options: %s\n", + error->message); + g_error_free (error); + terminal_options_free (options); + g_strfreev (argv); + return EXIT_FAILURE; + } + + terminal_options_free (options); + g_strfreev (argv); + + return EXIT_SUCCESS; +} + +static void +terminal_app_shutdown (GApplication *application) +{ + TerminalApp *app = TERMINAL_APP (application); #ifdef HAVE_SMCLIENT EggSMClient *sm_client; @@ -1503,41 +1580,56 @@ terminal_app_finalize (GObject *object) 0, 0, NULL, NULL, app); #endif /* HAVE_SMCLIENT */ - g_signal_handlers_disconnect_by_func (settings_global, + g_signal_handlers_disconnect_by_func (app->settings_global, G_CALLBACK(terminal_app_profile_list_notify_cb), app); - g_signal_handlers_disconnect_by_func (settings_global, + g_signal_handlers_disconnect_by_func (app->settings_global, G_CALLBACK(terminal_app_default_profile_notify_cb), app); - g_signal_handlers_disconnect_by_func (settings_global, + g_signal_handlers_disconnect_by_func (app->settings_global, G_CALLBACK(terminal_app_encoding_list_notify_cb), app); g_signal_handlers_disconnect_by_func (app->settings_font, G_CALLBACK(terminal_app_system_font_notify_cb), app); - g_signal_handlers_disconnect_by_func (settings_global, + g_signal_handlers_disconnect_by_func (app->settings_global, G_CALLBACK(terminal_app_enable_menu_accels_notify_cb), app); - g_signal_handlers_disconnect_by_func (settings_global, + g_signal_handlers_disconnect_by_func (app->settings_global, G_CALLBACK(terminal_app_enable_mnemonics_notify_cb), app); - g_object_unref (settings_global); - g_object_unref (app->settings_font); + g_clear_object (&app->settings_global); + g_clear_object (&app->settings_font); g_free (app->default_profile_id); + app->default_profile_id = NULL; g_hash_table_destroy (app->profiles); + app->profiles = NULL; g_hash_table_destroy (app->encodings); + app->encodings = NULL; - pango_font_description_free (app->system_font_desc); + if (app->system_font_desc) + { + pango_font_description_free (app->system_font_desc); + app->system_font_desc = NULL; + } terminal_accels_shutdown (); - G_OBJECT_CLASS (terminal_app_parent_class)->finalize (object); + /* Chain up */ + G_APPLICATION_CLASS (terminal_app_parent_class)->shutdown (application); +} - global_app = NULL; +/* GObject vfuncs */ + +static void +terminal_app_finalize (GObject *object) +{ + /* Most cleanup is done in shutdown */ + G_OBJECT_CLASS (terminal_app_parent_class)->finalize (object); } static void @@ -1583,11 +1675,11 @@ terminal_app_set_property (GObject *object, { case PROP_ENABLE_MENU_BAR_ACCEL: app->enable_menu_accels = g_value_get_boolean (value); - g_settings_set_boolean (settings_global, ENABLE_MENU_BAR_ACCEL_KEY, app->enable_menu_accels); + g_settings_set_boolean (app->settings_global, ENABLE_MENU_BAR_ACCEL_KEY, app->enable_menu_accels); break; case PROP_ENABLE_MNEMONICS: app->enable_mnemonics = g_value_get_boolean (value); - g_settings_set_boolean (settings_global, ENABLE_MNEMONICS_KEY, app->enable_mnemonics); + g_settings_set_boolean (app->settings_global, ENABLE_MNEMONICS_KEY, app->enable_mnemonics); break; case PROP_DEFAULT_PROFILE: case PROP_SYSTEM_FONT: @@ -1598,31 +1690,65 @@ terminal_app_set_property (GObject *object, } } -static void -terminal_app_real_quit (TerminalApp *app) +static gboolean +terminal_app_local_command_line (GApplication *application, + char ***arguments, + int *exit_status) { - gtk_main_quit(); + char **argv = *arguments; + + /* Parse locally with strict option checking before any D-Bus contact. + * For --help* and --version this calls exit() in the local process. + * For unknown options it returns NULL so we can report the error locally. */ + { + char **args = g_strdupv (argv); + int argc; + GError *error = NULL; + TerminalOptions *options; + + for (argc = 0; args[argc] != NULL; argc++) + ; + + options = terminal_options_parse (NULL, NULL, NULL, NULL, + FALSE, FALSE, + &argc, &args, + &error, +#ifdef HAVE_SMCLIENT + gtk_get_option_group (FALSE), + egg_sm_client_get_option_group (), +#endif /* HAVE_SMCLIENT */ + NULL); + g_strfreev (args); + + if (options == NULL) + { + g_printerr (_("Failed to parse arguments: %s\n"), error->message); + g_error_free (error); + *exit_status = EXIT_FAILURE; + return TRUE; + } + + terminal_options_free (options); + } + + return FALSE; } static void terminal_app_class_init (TerminalAppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GApplicationClass *application_class = G_APPLICATION_CLASS (klass); object_class->finalize = terminal_app_finalize; object_class->get_property = terminal_app_get_property; object_class->set_property = terminal_app_set_property; - klass->quit = terminal_app_real_quit; - - signals[QUIT] = - g_signal_new (I_("quit"), - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (TerminalAppClass, quit), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + application_class->local_command_line = terminal_app_local_command_line; + application_class->startup = terminal_app_startup; + application_class->activate = terminal_app_activate; + application_class->command_line = terminal_app_command_line; + application_class->shutdown = terminal_app_shutdown; signals[PROFILE_LIST_CHANGED] = g_signal_new (I_("profile-list-changed"), @@ -1671,28 +1797,32 @@ terminal_app_class_init (TerminalAppClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } +static void +terminal_app_init (TerminalApp *app) +{ + /* Initialization is done in startup vfunc */ +} + /* Public API */ TerminalApp* terminal_app_get (void) { - if (global_app == NULL) - { - g_object_new (TERMINAL_TYPE_APP, NULL); - g_assert (global_app != NULL); - } + GApplication *app; - return global_app; + app = g_application_get_default (); + if (app != NULL && TERMINAL_IS_APP (app)) + return TERMINAL_APP (app); + + return NULL; } -void -terminal_app_shutdown (void) +GSettings* +terminal_app_get_global_settings (TerminalApp *app) { - if (global_app == NULL) - return; + g_return_val_if_fail (TERMINAL_IS_APP (app), NULL); - g_object_unref (global_app); - g_assert (global_app == NULL); + return app->settings_global; } /** @@ -1881,9 +2011,7 @@ terminal_app_new_window (TerminalApp *app, window = terminal_window_new (); - app->windows = g_list_append (app->windows, window); - g_signal_connect (window, "destroy", - G_CALLBACK (terminal_window_destroyed), app); + gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (window)); if (screen) gtk_window_set_screen (GTK_WINDOW (window), screen); @@ -1948,26 +2076,38 @@ terminal_app_get_current_window (TerminalApp *app, GdkScreen *from_screen, int workspace) { - GList *res = NULL; + GList *windows; + GList *res; TerminalWindow *ret = NULL; - if (app->windows == NULL) - return NULL; + windows = gtk_application_get_windows (GTK_APPLICATION (app)); + if (windows == NULL) + return NULL; - res = g_list_last (app->windows); + res = g_list_last (windows); g_assert (from_screen != NULL); while (res) { int win_workspace; + + if (!TERMINAL_IS_WINDOW (res->data)) + { + res = g_list_previous (res); + continue; + } + if (gtk_window_get_screen(GTK_WINDOW(res->data)) != from_screen) - continue; + { + res = g_list_previous (res); + continue; + } - win_workspace = terminal_app_get_workspace_for_window(res->data); + win_workspace = terminal_app_get_workspace_for_window(TERMINAL_WINDOW(res->data)); - /* Same workspace or if the window is set to show up on all workspaces */ - if (win_workspace == workspace || win_workspace == -1) + /* Same workspace, or no specific workspace requested, or window is on all workspaces */ + if (workspace == -1 || win_workspace == workspace || win_workspace == -1) ret = terminal_window_get_latest_focused (ret, TERMINAL_WINDOW(res->data)); res = g_list_previous (res); @@ -2111,6 +2251,7 @@ void terminal_app_save_config (TerminalApp *app, GKeyFile *key_file) { + GList *windows; GList *lw; guint n = 0; GPtrArray *window_names_array; @@ -2122,13 +2263,18 @@ terminal_app_save_config (TerminalApp *app, g_key_file_set_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_VERSION, TERMINAL_CONFIG_VERSION); g_key_file_set_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_COMPAT_VERSION, TERMINAL_CONFIG_COMPAT_VERSION); - window_names_array = g_ptr_array_sized_new (g_list_length (app->windows) + 1); + windows = gtk_application_get_windows (GTK_APPLICATION (app)); + window_names_array = g_ptr_array_sized_new (g_list_length (windows) + 1); - for (lw = app->windows; lw != NULL; lw = lw->next) + for (lw = windows; lw != NULL; lw = lw->next) { - TerminalWindow *window = TERMINAL_WINDOW (lw->data); + TerminalWindow *window; char *group; + if (!TERMINAL_IS_WINDOW (lw->data)) + continue; + + window = TERMINAL_WINDOW (lw->data); group = g_strdup_printf ("Window%u", n++); g_ptr_array_add (window_names_array, group); diff --git a/src/terminal-app.h b/src/terminal-app.h index ebb78c1..98b15fa 100644 --- a/src/terminal-app.h +++ b/src/terminal-app.h @@ -73,7 +73,10 @@ G_BEGIN_DECLS #define TERMINAL_APP_ENABLE_MNEMONICS "enable-mnemonics" #define TERMINAL_APP_SYSTEM_FONT "system-font" -/* TerminalApp */ +/* Application ID for GtkApplication */ +#define TERMINAL_APPLICATION_ID "org.mate.Terminal" + +/* TerminalApp - now inherits from GtkApplication */ #define TERMINAL_TYPE_APP (terminal_app_get_type ()) #define TERMINAL_APP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_APP, TerminalApp)) @@ -84,14 +87,15 @@ G_BEGIN_DECLS typedef struct _TerminalAppClass TerminalAppClass; typedef struct _TerminalApp TerminalApp; - -extern GSettings *settings_global; +typedef struct _TerminalAppPrivate TerminalAppPrivate; GType terminal_app_get_type (void); +/* Get the application instance - now uses g_application_get_default() internally */ TerminalApp* terminal_app_get (void); -void terminal_app_shutdown (void); +/* Get GSettings for global settings */ +GSettings* terminal_app_get_global_settings (TerminalApp *app); gboolean terminal_app_handle_options (TerminalApp *app, TerminalOptions *options, diff --git a/src/terminal-encoding.c b/src/terminal-encoding.c index a470c99..c132985 100644 --- a/src/terminal-encoding.c +++ b/src/terminal-encoding.c @@ -302,7 +302,7 @@ update_active_encodings_gsettings (void) strings = g_array_append_val (strings, id_string); } - g_settings_set_strv (settings_global, "active-encodings", (const gchar **) strings->data); + g_settings_set_strv (terminal_app_get_global_settings (terminal_app_get ()), "active-encodings", (const gchar **) strings->data); g_array_free (strings, TRUE); g_slist_foreach (list, (GFunc) terminal_encoding_unref, NULL); diff --git a/src/terminal-window.c b/src/terminal-window.c index 75e5fd8..f12f1c5 100644 --- a/src/terminal-window.c +++ b/src/terminal-window.c @@ -45,8 +45,6 @@ #include "skey-popup.h" #endif -static gboolean detach_tab = FALSE; - struct _TerminalWindowPrivate { GtkActionGroup *action_group; @@ -162,10 +160,10 @@ static gboolean terminal_window_focus_in_event (GtkWidget *widget, static gboolean notebook_button_press_cb (GtkWidget *notebook, GdkEventButton *event, - GSettings *settings); + gpointer user_data); static gboolean window_key_press_cb (GtkWidget *notebook, GdkEventKey *event, - GSettings *settings); + gpointer user_data); static gboolean notebook_popup_menu_cb (GtkWidget *notebook, TerminalWindow *window); static void notebook_page_selected_callback (GtkWidget *notebook, @@ -269,7 +267,7 @@ sync_screen_icon_title (TerminalScreen *screen, GParamSpec *psepc, TerminalWindow *window); -G_DEFINE_TYPE_WITH_PRIVATE (TerminalWindow, terminal_window, GTK_TYPE_WINDOW) +G_DEFINE_TYPE_WITH_PRIVATE (TerminalWindow, terminal_window, GTK_TYPE_APPLICATION_WINDOW) /* Menubar mnemonics & accel settings handling */ @@ -2294,9 +2292,9 @@ terminal_window_init (TerminalWindow *window) gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE); gtk_notebook_set_group_name (GTK_NOTEBOOK (priv->notebook), I_("mate-terminal-window")); g_signal_connect (priv->notebook, "button-press-event", - G_CALLBACK (notebook_button_press_cb), settings_global); + G_CALLBACK (notebook_button_press_cb), NULL); g_signal_connect (window, "key-press-event", - G_CALLBACK (window_key_press_cb), settings_global); + G_CALLBACK (window_key_press_cb), NULL); g_signal_connect (priv->notebook, "popup-menu", G_CALLBACK (notebook_popup_menu_cb), window); g_signal_connect_after (priv->notebook, "switch-page", @@ -2483,14 +2481,6 @@ terminal_window_finalize (GObject *object) g_object_unref (priv->ui_manager); - if (priv->confirm_close_dialog) - gtk_dialog_response (GTK_DIALOG (priv->confirm_close_dialog), - GTK_RESPONSE_DELETE_EVENT); - - if (priv->search_find_dialog) - gtk_dialog_response (GTK_DIALOG (priv->search_find_dialog), - GTK_RESPONSE_DELETE_EVENT); - g_free (priv->icon); G_OBJECT_CLASS (terminal_window_parent_class)->finalize (object); @@ -2727,9 +2717,10 @@ terminal_window_add_screen (TerminalWindow *window, TRUE); } -void -terminal_window_remove_screen (TerminalWindow *window, - TerminalScreen *screen) +static void +remove_screen_internal (TerminalWindow *window, + TerminalScreen *screen, + gboolean detach) { TerminalWindowPrivate *priv = window->priv; TerminalScreenContainer *screen_container; @@ -2739,18 +2730,22 @@ terminal_window_remove_screen (TerminalWindow *window, update_tab_visibility (window, -1); screen_container = terminal_screen_container_get_from_screen (screen); - if (detach_tab) - { + if (detach) gtk_notebook_detach_tab (GTK_NOTEBOOK (priv->notebook), GTK_WIDGET (screen_container)); - detach_tab = FALSE; - } else gtk_container_remove (GTK_CONTAINER (priv->notebook), GTK_WIDGET (screen_container)); } void +terminal_window_remove_screen (TerminalWindow *window, + TerminalScreen *screen) +{ + remove_screen_internal (window, screen, FALSE); +} + +void terminal_window_move_screen (TerminalWindow *source_window, TerminalWindow *dest_window, TerminalScreen *screen, @@ -2775,9 +2770,7 @@ terminal_window_move_screen (TerminalWindow *source_window, g_object_ref_sink (screen_container); g_object_ref_sink (screen); - detach_tab = TRUE; - - terminal_window_remove_screen (source_window, screen); + remove_screen_internal (source_window, screen, TRUE); /* Now we can safely remove the screen from the container and let the container die */ gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (GTK_WIDGET (screen))), GTK_WIDGET (screen)); @@ -3034,11 +3027,12 @@ terminal_window_get_active (TerminalWindow *window) static gboolean notebook_button_press_cb (GtkWidget *widget, GdkEventButton *event, - GSettings *settings) + gpointer user_data) { TerminalWindow *window = TERMINAL_WINDOW (gtk_widget_get_toplevel (widget)); TerminalWindowPrivate *priv = window->priv; GtkNotebook *notebook = GTK_NOTEBOOK (widget); + GSettings *settings = terminal_app_get_global_settings (terminal_app_get ()); GtkWidget *tab; GtkWidget *menu; GtkAction *action; @@ -3122,8 +3116,9 @@ notebook_button_press_cb (GtkWidget *widget, static gboolean window_key_press_cb (GtkWidget *widget, GdkEventKey *event, - GSettings *settings) + gpointer user_data) { + GSettings *settings = terminal_app_get_global_settings (terminal_app_get ()); if (g_settings_get_boolean (settings, "ctrl-tab-switch-tabs") && event->state & GDK_CONTROL_MASK) { @@ -3732,7 +3727,7 @@ confirm_close_window_or_tab (TerminalWindow *window, int n_tabs; char *confirm_msg; - if (!g_settings_get_boolean (settings_global, "confirm-window-close")) + if (!g_settings_get_boolean (terminal_app_get_global_settings (terminal_app_get ()), "confirm-window-close")) return FALSE; if (screen) diff --git a/src/terminal-window.h b/src/terminal-window.h index 86b8e28..c66acd4 100644 --- a/src/terminal-window.h +++ b/src/terminal-window.h @@ -39,14 +39,14 @@ typedef struct _TerminalWindowPrivate TerminalWindowPrivate; struct _TerminalWindow { - GtkWindow parent_instance; + GtkApplicationWindow parent_instance; TerminalWindowPrivate *priv; }; struct _TerminalWindowClass { - GtkWindowClass parent_class; + GtkApplicationWindowClass parent_class; }; diff --git a/src/terminal.c b/src/terminal.c index 7909fdf..c9a044b 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -38,431 +38,15 @@ #include "eggsmclient.h" #endif /* HAVE_SMCLIENT */ -#include "terminal-accels.h" #include "terminal-app.h" #include "terminal-debug.h" #include "terminal-intl.h" -#include "terminal-options.h" -#include "terminal-util.h" - -#define TERMINAL_FACTORY_SERVICE_NAME_PREFIX "org.mate.Terminal.Display" -#define TERMINAL_FACTORY_SERVICE_PATH "/org/mate/Terminal/Factory" -#define TERMINAL_FACTORY_INTERFACE_NAME "org.mate.Terminal.Factory" - -static char * -ay_to_string (GVariant *variant, - GError **error) -{ - gsize len; - const char *data; - - data = g_variant_get_fixed_array (variant, &len, sizeof (char)); - if (len == 0) - return NULL; - - /* Make sure there are no embedded NULs */ - if (memchr (data, '\0', len) != NULL) - { - g_set_error_literal (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "String is shorter than claimed"); - return NULL; - } - - return g_strndup (data, len); -} - -static char ** -ay_to_strv (GVariant *variant, - int *argc) -{ - GPtrArray *argv; - const char *data, *nullbyte; - gsize data_len; - gssize len; - - data = g_variant_get_fixed_array (variant, &data_len, sizeof (char)); - if (data_len == 0 || data_len > G_MAXSSIZE) - { - if (argc != NULL) - *argc = 0; - return NULL; - } - - argv = g_ptr_array_new (); - - len = data_len; - do - { - gssize string_len; - - nullbyte = memchr (data, '\0', len); - - string_len = nullbyte ? (gssize) (nullbyte - data) : len; - g_ptr_array_add (argv, g_strndup (data, string_len)); - - len -= string_len + 1; - data += string_len + 1; - } - while (len > 0); - - if (argc) - *argc = argv->len; - - /* NULL terminate */ - g_ptr_array_add (argv, NULL); - return (char **) g_ptr_array_free (argv, FALSE); -} - -static GVariant * -string_to_ay (const char *string) -{ - gsize len; - char *data; - - len = strlen (string); - data = g_strndup (string, len); - - return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, len, TRUE, g_free, data); -} - -typedef struct -{ - char *factory_name; - TerminalOptions *options; - int exit_code; - char **argv; - int argc; -} OwnData; - -static void -method_call_cb (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - if (g_strcmp0 (method_name, "HandleArguments") == 0) - { - 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@ayi@ay)", - &v_wd, &v_display, &v_sid, &v_envv, &initial_workspace, &v_argv); - - working_directory = ay_to_string (v_wd, &error); - if (error) - goto out; - display_name = ay_to_string (v_display, &error); - if (error) - goto out; - startup_id = ay_to_string (v_sid, &error); - if (error) - goto out; - envv = ay_to_strv (v_envv, NULL); - argv = ay_to_strv (v_argv, &argc); - - _terminal_debug_print (TERMINAL_DEBUG_FACTORY, - "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)", - initial_workspace); - - options = terminal_options_parse (working_directory, - display_name, - startup_id, - envv, - TRUE, - TRUE, - &argc, &argv, - &error, - NULL); - - if (options != NULL) - { - options->initial_workspace = initial_workspace; - - terminal_app_handle_options (terminal_app_get (), options, FALSE /* no resume */, &error); - terminal_options_free (options); - } - -out: - g_variant_unref (v_wd); - g_free (working_directory); - g_variant_unref (v_display); - g_free (display_name); - g_variant_unref (v_sid); - g_free (startup_id); - g_variant_unref (v_envv); - g_strfreev (envv); - g_variant_unref (v_argv); - g_strfreev (argv); - - if (error == NULL) - { - g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); - } - else - { - g_dbus_method_invocation_return_gerror (invocation, error); - g_error_free (error); - } - } -} - -static void -bus_acquired_cb (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - static const char dbus_introspection_xml[] = - "<node name='/org/mate/Terminal'>" - "<interface name='org.mate.Terminal.Factory'>" - "<method name='HandleArguments'>" - "<arg type='ay' name='working_directory' direction='in' />" - "<arg type='ay' name='display_name' direction='in' />" - "<arg type='ay' name='startup_id' direction='in' />" - "<arg type='ay' name='environment' direction='in' />" - "<arg type='i' name='workspace' direction='in' />" - "<arg type='ay' name='arguments' direction='in' />" - "</method>" - "</interface>" - "</node>"; - - static const GDBusInterfaceVTable interface_vtable = - { - method_call_cb, - NULL, - NULL, - { 0 } - }; - - OwnData *data = (OwnData *) user_data; - GDBusNodeInfo *introspection_data; - guint registration_id; - GError *error = NULL; - - _terminal_debug_print (TERMINAL_DEBUG_FACTORY, - "Bus %s acquired\n", name); - - introspection_data = g_dbus_node_info_new_for_xml (dbus_introspection_xml, NULL); - g_assert (introspection_data != NULL); - - registration_id = g_dbus_connection_register_object (connection, - TERMINAL_FACTORY_SERVICE_PATH, - introspection_data->interfaces[0], - &interface_vtable, - NULL, NULL, - &error); - g_dbus_node_info_unref (introspection_data); - - if (registration_id == 0) - { - g_printerr ("Failed to register object: %s\n", error->message); - g_error_free (error); - data->exit_code = EXIT_FAILURE; - gtk_main_quit (); - } -} - -static void -name_acquired_cb (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - OwnData *data = (OwnData *) user_data; - GError *error = NULL; - - _terminal_debug_print (TERMINAL_DEBUG_FACTORY, - "Acquired the name %s on the session bus\n", name); - - if (data->options == NULL) - { - /* Name re-acquired!? */ - g_assert_not_reached (); - } - - if (!terminal_app_handle_options (terminal_app_get (), data->options, TRUE /* do resume */, &error)) - { - g_printerr ("Failed to handle options: %s\n", error->message); - g_error_free (error); - data->exit_code = EXIT_FAILURE; - gtk_main_quit (); - } - - terminal_options_free (data->options); - data->options = NULL; -} - -static void -name_lost_cb (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - OwnData *data = (OwnData *) user_data; - GError *error = NULL; - char **envv; - int i; - GVariantBuilder builder; - GVariant *value; - GString *string; - char *s; - gsize len; - - _terminal_debug_print (TERMINAL_DEBUG_FACTORY, - "Lost the name %s on the session bus\n", name); - - /* Couldn't get the connection? No way to continue! */ - if (connection == NULL) - { - data->exit_code = EXIT_FAILURE; - gtk_main_quit (); - return; - } - - if (data->options == NULL) - { - /* Already handled */ - data->exit_code = EXIT_SUCCESS; - gtk_main_quit (); - return; - } - - _terminal_debug_print (TERMINAL_DEBUG_FACTORY, - "Forwarding arguments to existing instance\n"); - - 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)); - - string = g_string_new (NULL); - envv = g_get_environ (); - for (i = 0; envv[i]; ++i) - { - if (i > 0) - g_string_append_c (string, '\0'); - - g_string_append (string, envv[i]); - } - g_strfreev (envv); - - len = string->len; - s = g_string_free (string, FALSE); - 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) - { - if (i > 0) - g_string_append_c (string, '\0'); - g_string_append (string, data->argv[i]); - } - - len = string->len; - s = g_string_free (string, FALSE); - g_variant_builder_add (&builder, "@ay", - g_variant_new_from_data (G_VARIANT_TYPE ("ay"), s, len, TRUE, g_free, s)); - - value = g_dbus_connection_call_sync (connection, - data->factory_name, - TERMINAL_FACTORY_SERVICE_PATH, - TERMINAL_FACTORY_INTERFACE_NAME, - "HandleArguments", - g_variant_builder_end (&builder), - G_VARIANT_TYPE ("()"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - if (value == NULL) - { - g_printerr ("Failed to forward arguments: %s\n", error->message); - g_error_free (error); - data->exit_code = EXIT_FAILURE; - gtk_main_quit (); - } - else - { - g_variant_unref (value); - data->exit_code = EXIT_SUCCESS; - } - - terminal_options_free (data->options); - data->options = NULL; - - gtk_main_quit (); -} - -static char * -get_factory_name_for_display (const char *display_name) -{ - GString *name; - const char *p; - - name = g_string_sized_new (strlen (TERMINAL_FACTORY_SERVICE_NAME_PREFIX) + strlen (display_name) + 1 /* NUL */); - g_string_append (name, TERMINAL_FACTORY_SERVICE_NAME_PREFIX); - - for (p = display_name; *p; ++p) - { - if (g_ascii_isalnum (*p)) - g_string_append_c (name, *p); - else - g_string_append_c (name, '_'); - } - - _terminal_debug_print (TERMINAL_DEBUG_FACTORY, - "Factory name is \"%s\"\n", name->str); - - 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; - - window = gdk_get_default_root_window(); - - atom = gdk_atom_intern_static_string ("_NET_CURRENT_DESKTOP"); - cardinal_atom = gdk_atom_intern_static_string ("CARDINAL"); - - if (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) { - int i; - char **argv_copy; - int argc_copy; - const char *startup_id, *home_dir; - TerminalOptions *options; - GError *error = NULL; - char *working_directory; - int ret = EXIT_SUCCESS; + TerminalApp *app; + int ret; setlocale (LC_ALL, ""); @@ -472,120 +56,18 @@ main (int argc, char **argv) _terminal_debug_init (); - /* Make a NULL-terminated copy since we may need it later */ - argv_copy = g_new (char *, argc + 1); - for (i = 0; i < argc; ++i) - argv_copy [i] = argv [i]; - argv_copy [i] = NULL; - argc_copy = argc; - - startup_id = g_getenv ("DESKTOP_STARTUP_ID"); - - working_directory = g_get_current_dir (); - - /* Now change directory to $HOME so we don't prevent unmounting, e.g. if the - * factory is started by caja-open-terminal. See bug #565328. - * On failure back to /. - */ - home_dir = g_get_home_dir (); - if (home_dir == NULL || chdir (home_dir) < 0) - if (chdir ("/") < 0) - g_warning ("Could not change working directory."); - - options = terminal_options_parse (working_directory, - NULL, - startup_id, - NULL, - FALSE, - FALSE, - &argc, &argv, - &error, -#ifdef HAVE_SMCLIENT - gtk_get_option_group (TRUE), - egg_sm_client_get_option_group (), -#endif /* HAVE_SMCLIENT */ - NULL); - g_free (working_directory); - - if (options == NULL) - { - g_printerr (_("Failed to parse arguments: %s\n"), error->message); - g_error_free (error); - exit (EXIT_FAILURE); - } - g_set_application_name (_("Terminal")); - /* Unset the these env variables, so they doesn't end up - * in the factory's env and thus in the terminals' envs. - */ - g_unsetenv ("DESKTOP_STARTUP_ID"); - g_unsetenv ("GIO_LAUNCHED_DESKTOP_FILE_PID"); - g_unsetenv ("GIO_LAUNCHED_DESKTOP_FILE"); - - if (options->startup_id == NULL) - { - options->startup_id = g_strdup_printf ("_TIME%" G_GINT64_FORMAT, - g_get_monotonic_time () / 1000); - } - - gdk_init (&argc, &argv); - const char *display_name = gdk_display_get_name (gdk_display_get_default ()); - options->display_name = g_strdup (display_name); - - if (options->use_factory) - { - OwnData *data; - guint owner_id; - - data = g_new (OwnData, 1); - data->factory_name = get_factory_name_for_display (display_name); - data->options = options; - data->exit_code = -1; - 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, - bus_acquired_cb, - name_acquired_cb, - name_lost_cb, - data, NULL); - - gtk_main (); - - ret = data->exit_code; - g_bus_unown_name (owner_id); - - g_free (data->factory_name); - g_free (data); - - } - else - { - gtk_init(&argc, &argv); - terminal_app_handle_options (terminal_app_get (), options, TRUE /* allow resume */, &error); - terminal_options_free (options); - - if (error == NULL) - { - gtk_main (); - } - else - { - g_printerr ("Error handling options: %s\n", error->message); - g_error_free (error); - ret = EXIT_FAILURE; - } - } + /* Create the GtkApplication */ + app = g_object_new (TERMINAL_TYPE_APP, + "application-id", TERMINAL_APPLICATION_ID, + "flags", G_APPLICATION_HANDLES_COMMAND_LINE, + NULL); - terminal_app_shutdown (); + /* Run the application */ + ret = g_application_run (G_APPLICATION (app), argc, argv); - g_free (argv_copy); + g_object_unref (app); return ret; } |
