diff options
author | Christian Persch <chpe@src.gnome.org> | 2021-08-03 19:16:19 +0200 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2021-08-03 19:16:19 +0200 |
commit | 76220dc83ab3be42def2d57a8d9240412a45db5f (patch) | |
tree | 41d8cfb6a29e8d213d00b8a6485daa0b23ca9cd2 | |
parent | 3b5150e92c43dc7528499eaa6dcbcd95fd818e34 (diff) | |
download | gnome-terminal-wip/intent.tar.gz |
WIP: intentwip/intent
-rw-r--r-- | data/org.gnome.Terminal.desktop.in | 1 | ||||
-rw-r--r-- | src/org.gnome.Terminal.xml | 14 | ||||
-rw-r--r-- | src/server.cc | 4 | ||||
-rw-r--r-- | src/terminal-app.cc | 103 | ||||
-rw-r--r-- | src/terminal-app.hh | 3 | ||||
-rw-r--r-- | src/terminal-defines.hh | 3 | ||||
-rw-r--r-- | src/terminal-gdbus.cc | 249 | ||||
-rw-r--r-- | src/terminal-gdbus.hh | 32 | ||||
-rw-r--r-- | src/terminal-screen.cc | 63 | ||||
-rw-r--r-- | src/terminal-screen.hh | 11 |
10 files changed, 425 insertions, 58 deletions
diff --git a/data/org.gnome.Terminal.desktop.in b/data/org.gnome.Terminal.desktop.in index 915c077f..072e2e71 100644 --- a/data/org.gnome.Terminal.desktop.in +++ b/data/org.gnome.Terminal.desktop.in @@ -11,6 +11,7 @@ StartupNotify=true StartupWMClass=Gnome-terminal X-GNOME-SingleWindow=false Actions=new-window;preferences; +Implements=org.freedesktop.Terminal1; [Desktop Action new-window] Name=New Window diff --git a/src/org.gnome.Terminal.xml b/src/org.gnome.Terminal.xml index a6ada0e5..59c8a6f4 100644 --- a/src/org.gnome.Terminal.xml +++ b/src/org.gnome.Terminal.xml @@ -2,7 +2,7 @@ <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Introspection 0.1//EN" "http://www.freedesktop.org/software/dbus/introspection.dtd"> <!-- - Copyright © 2011 Christian Persch + Copyright © 2011, 2021 Christian Persch This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -40,4 +40,16 @@ <arg type="i" name="exit_code" direction="in" /> </signal> </interface> + + <interface name="org.freedesktop.Terminal1"> + <annotation name="org.gtk.GDBus.C.Name" value="Intent" /> + <method name="LaunchCommand"> + <arg type="aay" name="argv" direction="in" /> + <arg type="ay" name="cwd" direction="in" /> + <arg type="ay" name="desktop_entry" direction="in" /> + <arg type="aay" name="envv" direction="in" /> + <arg type="a{sv}" name="options" direction="in" /> + <arg type="a{sv}" name="platform_data" direction="in" /> + </method> + </interface> </node> diff --git a/src/server.cc b/src/server.cc index 358d62ae..94c6462a 100644 --- a/src/server.cc +++ b/src/server.cc @@ -43,6 +43,7 @@ #include "terminal-libgsystem.hh" static char *app_id = nullptr; +static gboolean no_intent = false; #define INACTIVITY_TIMEOUT (100 /* ms */) @@ -67,6 +68,7 @@ option_app_id_cb (const gchar *option_name, static const GOptionEntry options[] = { { "app-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (void*)option_app_id_cb, "Application ID", "ID" }, + { "no-intent", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, (void*)&no_intent, nullptr, nullptr }, { nullptr } }; @@ -163,7 +165,7 @@ init_server (int argc, } /* Now we can create the app */ - GApplication *app = terminal_app_new (app_id); + auto const app = terminal_app_new(app_id, !no_intent); g_free (app_id); app_id = nullptr; diff --git a/src/terminal-app.cc b/src/terminal-app.cc index a06485cf..84317e8e 100644 --- a/src/terminal-app.cc +++ b/src/terminal-app.cc @@ -95,7 +95,9 @@ struct _TerminalApp { GtkApplication parent_instance; - GDBusObjectManagerServer *object_manager; + GDBusObjectManagerServer *org_gnome_object_manager; + TerminalIntent* terminal_intent; + bool implement_intent; TerminalSettingsList *profiles_list; @@ -136,6 +138,11 @@ enum LAST_SIGNAL }; +enum { + PROP_0, + PROP_IMPLEMENT_INTENT, +}; + static guint signals[LAST_SIGNAL]; /* Debugging helper */ @@ -928,8 +935,6 @@ terminal_app_dbus_register (GApplication *application, GError **error) { TerminalApp *app = TERMINAL_APP (application); - gs_unref_object TerminalObjectSkeleton *object = nullptr; - gs_unref_object TerminalFactory *factory = nullptr; if (!G_APPLICATION_CLASS (terminal_app_parent_class)->dbus_register (application, connection, @@ -953,15 +958,30 @@ terminal_app_dbus_register (GApplication *application, } #endif /* ENABLE_SEARCH_PROVIDER */ - object = terminal_object_skeleton_new (TERMINAL_FACTORY_OBJECT_PATH); - factory = terminal_factory_impl_new (); - terminal_object_skeleton_set_factory (object, factory); + if (app->implement_intent) { + app->terminal_intent = terminal_intent_impl_new(); + if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(app->terminal_intent), + connection, + TERMINAL_INTENT_OBJECT_PATH, + error)) + return false; + } + + gs_unref_object TerminalObjectSkeleton* object = nullptr; + gs_unref_object TerminalFactory* factory = nullptr; + object = terminal_object_skeleton_new(TERMINAL_FACTORY_OBJECT_PATH); + factory = terminal_factory_impl_new(); + terminal_object_skeleton_set_factory(object, factory); - app->object_manager = g_dbus_object_manager_server_new (TERMINAL_OBJECT_PATH_PREFIX); - g_dbus_object_manager_server_export (app->object_manager, G_DBUS_OBJECT_SKELETON (object)); + app->org_gnome_object_manager = + g_dbus_object_manager_server_new(TERMINAL_OBJECT_PATH_PREFIX); - /* And export the object */ - g_dbus_object_manager_server_set_connection (app->object_manager, connection); + g_dbus_object_manager_server_export(app->org_gnome_object_manager, + G_DBUS_OBJECT_SKELETON(object)); + + /* And export the objects */ + g_dbus_object_manager_server_set_connection(app->org_gnome_object_manager, + connection); return TRUE; } @@ -972,10 +992,17 @@ terminal_app_dbus_unregister (GApplication *application, { TerminalApp *app = TERMINAL_APP (application); - if (app->object_manager) { - g_dbus_object_manager_server_unexport (app->object_manager, TERMINAL_FACTORY_OBJECT_PATH); - g_object_unref (app->object_manager); - app->object_manager = nullptr; + if (app->org_gnome_object_manager) { + g_dbus_object_manager_server_unexport(app->org_gnome_object_manager, + TERMINAL_FACTORY_OBJECT_PATH); + g_object_unref(app->org_gnome_object_manager); + app->org_gnome_object_manager = nullptr; + } + + if (app->terminal_intent) { + g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(app->terminal_intent)); + g_object_unref(app->terminal_intent); + app->terminal_intent = nullptr; } #ifdef ENABLE_SEARCH_PROVIDER @@ -992,12 +1019,32 @@ terminal_app_dbus_unregister (GApplication *application, } static void +terminal_app_set_property(GObject* object, + guint prop_id, + GValue const* value, + GParamSpec* pspec) +{ + auto const app = TERMINAL_APP(object); + + switch (prop_id) + { + case PROP_IMPLEMENT_INTENT: + app->implement_intent = g_value_get_boolean(value) != false; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void terminal_app_class_init (TerminalAppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GApplicationClass *g_application_class = G_APPLICATION_CLASS (klass); object_class->finalize = terminal_app_finalize; + object_class->set_property = terminal_app_set_property; g_application_class->activate = terminal_app_activate; g_application_class->startup = terminal_app_startup; @@ -1012,18 +1059,32 @@ terminal_app_class_init (TerminalAppClass *klass) nullptr, nullptr, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); + + g_object_class_install_property + (object_class, + PROP_IMPLEMENT_INTENT, + g_param_spec_boolean("implement-intent", nullptr, nullptr, + false, + GParamFlags(G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB))); + } /* Public API */ GApplication * -terminal_app_new (const char *app_id) +terminal_app_new (const char *app_id, + gboolean implement_intent) { const GApplicationFlags flags = G_APPLICATION_IS_SERVICE; return reinterpret_cast<GApplication*> (g_object_new (TERMINAL_TYPE_APP, "application-id", app_id ? app_id : TERMINAL_APPLICATION_ID, + "implement-intent", implement_intent, "flags", flags, nullptr)); } @@ -1060,8 +1121,8 @@ terminal_app_get_receiver_impl_by_object_path (TerminalApp *app, const char *object_path) { gs_unref_object GDBusObject *skeleton = - g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (app->object_manager), - object_path); + g_dbus_object_manager_get_object(G_DBUS_OBJECT_MANAGER(app->org_gnome_object_manager), + object_path); if (skeleton == nullptr || !TERMINAL_IS_OBJECT_SKELETON (skeleton)) return nullptr; @@ -1107,7 +1168,7 @@ terminal_app_register_screen (TerminalApp *app, terminal_object_skeleton_set_receiver (skeleton, TERMINAL_RECEIVER (impl)); g_object_unref (impl); - g_dbus_object_manager_server_export (app->object_manager, + g_dbus_object_manager_server_export (app->org_gnome_object_manager, G_DBUS_OBJECT_SKELETON (skeleton)); } @@ -1129,7 +1190,7 @@ terminal_app_unregister_screen (TerminalApp *app, if (impl != nullptr) terminal_receiver_impl_unset_screen (impl); - g_dbus_object_manager_server_unexport (app->object_manager, object_path); + g_dbus_object_manager_server_unexport (app->org_gnome_object_manager, object_path); } GdkAtom * @@ -1316,8 +1377,8 @@ terminal_app_get_system_font (TerminalApp *app) GDBusObjectManagerServer * terminal_app_get_object_manager (TerminalApp *app) { - g_warn_if_fail (app->object_manager != nullptr); - return app->object_manager; + g_warn_if_fail (app->org_gnome_object_manager != nullptr); + return app->org_gnome_object_manager; } gboolean diff --git a/src/terminal-app.hh b/src/terminal-app.hh index b86aea5d..cf614a87 100644 --- a/src/terminal-app.hh +++ b/src/terminal-app.hh @@ -46,7 +46,8 @@ typedef struct _TerminalApp TerminalApp; GType terminal_app_get_type (void); -GApplication *terminal_app_new (const char *app_id); +GApplication *terminal_app_new (const char *app_id, + gboolean implement_intent); #define terminal_app_get (TerminalApp *) g_application_get_default diff --git a/src/terminal-defines.hh b/src/terminal-defines.hh index b9ffba25..db6a06cb 100644 --- a/src/terminal-defines.hh +++ b/src/terminal-defines.hh @@ -40,6 +40,9 @@ enum { #define TERMINAL_SEARCH_PROVIDER_PATH TERMINAL_OBJECT_PATH_PREFIX "/SearchProvider" +#define TERMINAL_INTENT_OBJECT_PATH "/org/freedesktop/intent/Terminal1" +#define TERMINAL_INTENT_INTERFACE_NAME "org.freedesktop.Terminal1" + #define TERMINAL_ENV_SERVICE_NAME "GNOME_TERMINAL_SERVICE" #define TERMINAL_ENV_SCREEN "GNOME_TERMINAL_SCREEN" diff --git a/src/terminal-gdbus.cc b/src/terminal-gdbus.cc index 66bff6aa..9d382f6e 100644 --- a/src/terminal-gdbus.cc +++ b/src/terminal-gdbus.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2011, 2012 Christian Persch + * Copyright © 2011, 2012, 2021 Christian Persch * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include <gio/gio.h> #include <gio/gunixfdlist.h> +#include <glib/gi18n.h> #include "terminal-app.hh" #include "terminal-debug.hh" @@ -30,6 +31,10 @@ #include "terminal-window.hh" #include "terminal-libgsystem.hh" +#ifdef GDK_WINDOWING_X11 +#include <gdk/gdkx.h> +#endif + /* ------------------------------------------------------------------------- */ #define TERMINAL_RECEIVER_IMPL_GET_PRIVATE(impl)(G_TYPE_INSTANCE_GET_PRIVATE ((impl), TERMINAL_TYPE_RECEIVER_IMPL, TerminalReceiverImplPrivate)) @@ -85,14 +90,14 @@ terminal_receiver_impl_set_screen (TerminalReceiverImpl *impl, /* Class implementation */ typedef struct { - TerminalReceiver *receiver; - GDBusMethodInvocation *invocation; + void* object; + GDBusMethodInvocation* invocation; } ExecData; static void exec_data_free (ExecData *data) { - g_object_unref (data->receiver); + g_object_unref (data->object); g_object_unref (data->invocation); g_free (data); } @@ -107,7 +112,8 @@ exec_cb (TerminalScreen *screen, /* unused, may be %nullptr */ if (error) { g_dbus_method_invocation_return_gerror (data->invocation, error); } else { - terminal_receiver_complete_exec (data->receiver, data->invocation, nullptr /* outfdlist */); + terminal_receiver_complete_exec(TERMINAL_RECEIVER(data->object), + data->invocation, nullptr /* outfdlist */); } } @@ -207,7 +213,7 @@ terminal_receiver_impl_exec (TerminalReceiver *receiver, exec_argv = (char **) g_variant_get_bytestring_array (arguments, &exec_argc); ExecData *exec_data = g_new (ExecData, 1); - exec_data->receiver = (TerminalReceiver*)g_object_ref (receiver); + exec_data->object = g_object_ref(receiver); /* We want to transfer the ownership of @invocation to ExecData here, but * we have to temporarily ref it so that in the error case below (where * terminal_screen_exec() frees the exec data via the supplied callback, @@ -565,3 +571,234 @@ terminal_factory_impl_new (void) return reinterpret_cast<TerminalFactory*> (g_object_new (TERMINAL_TYPE_FACTORY_IMPL, nullptr)); } + +/* --------------------------------------------------------------------------- + * org.freedesktop.Terminal1 intent implementation + * --------------------------------------------------------------------------- + */ + +static void +exec_intent_cb(TerminalScreen *screen, /* unused, may be %nullptr */ + GError *error, /* set on error, %nullptr on success */ + ExecData *data) +{ + /* Note: these calls transfer the ref */ + g_object_ref(data->invocation); + if (error) { + g_dbus_method_invocation_return_gerror(data->invocation, error); + } else { + terminal_intent_complete_launch_command(TERMINAL_INTENT(data->object), + data->invocation); + } +} + +static gboolean +terminal_intent_impl_launch_command(TerminalIntent* intent, + GDBusMethodInvocation* invocation, + char const* const* argv, + char const* cwd, + char const* desktop_entry, + char const* const* envv, + GVariant* options, + GVariant* platform_data) +{ + TerminalApp *app = terminal_app_get (); + + if (!terminal_util_check_envv(envv)) { + /* Transfers ownership of @invocation */ + g_dbus_method_invocation_return_error_literal(invocation, + G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Invalid envv array passed"); + return true; + } + + /* Try to get some info from the passed desktop entry */ + gs_free char* desktop_cwd = nullptr; + gs_free char* desktop_icon = nullptr; + gs_free char* desktop_title = nullptr; + gs_free char* desktop_wm_class = nullptr; + gs_free char* desktop_profile_uuid = nullptr; + + if (desktop_entry[0]) { + gs_free char* desktop_entry_utf8 = g_utf8_make_valid(desktop_entry, -1); + gs_unref_key_file GKeyFile* key_file = g_key_file_new(); + + gs_free_error GError* err = nullptr; + if (!g_key_file_load_from_file(key_file, + desktop_entry, + GKeyFileFlags(G_KEY_FILE_NONE), + &err)) { + /* Transfers ownership of @invocation */ + g_dbus_method_invocation_return_error(invocation, + G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Failed to load desktop entry \"%s\": %s", + desktop_entry_utf8, err->message); + return true; + } + + gs_free char* version = g_key_file_get_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_VERSION, + nullptr); + gs_free char* type = g_key_file_get_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_TYPE, + nullptr); + auto const is_terminal = g_key_file_get_boolean(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_TERMINAL, + nullptr); + if (!version || + !g_str_equal(version, "1.0") || + !type || + !g_str_equal(type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) || + !is_terminal) { + /* Transfers ownership of @invocation */ + g_dbus_method_invocation_return_error(invocation, + G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "\"%s\" is not a valid desktop file of a terminal application", + desktop_entry_utf8); + return true; + } + + + desktop_cwd = g_key_file_get_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_PATH, + nullptr); + + desktop_icon = g_key_file_get_locale_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_ICON, + nullptr, // default locale + nullptr); + + desktop_title = g_key_file_get_locale_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_NAME, + nullptr, // default locale + nullptr); + if (!desktop_title || !desktop_title[0]) { + g_clear_pointer(&desktop_title, GDestroyNotify(g_free)); + desktop_title = g_key_file_get_locale_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME, + nullptr, // default locale + nullptr); + } + + desktop_wm_class = g_key_file_get_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS, + nullptr); + + desktop_profile_uuid = g_key_file_get_string(key_file, + G_KEY_FILE_DESKTOP_GROUP, + "X-GNOME-Profile-UUID", + nullptr); + } + + auto option_keep = gboolean{false}; + (void)g_variant_lookup(options, "keep-terminal-open", "b", &option_keep); + + char const* option_profile_uuid = nullptr; + (void)g_variant_lookup(options, "x-gnome-profile", "&s", &option_profile_uuid); + + GError* err = nullptr; + gs_unref_object GSettings* profile = + terminal_profiles_list_ref_profile_by_uuid(terminal_app_get_profiles_list (app), + option_profile_uuid ? option_profile_uuid : desktop_profile_uuid, /* nullptr if default */ + &err); + if (profile == nullptr) { + g_dbus_method_invocation_take_error(invocation, err); + return true; + } + + /* Now open new window and terminal */ + auto window = terminal_window_new(G_APPLICATION(app)); + + char const* startup_id = nullptr; + if (g_variant_lookup(platform_data, "desktop-startup-id", "&s", &startup_id)) + gtk_window_set_startup_id(GTK_WINDOW(window), startup_id); + + if (desktop_wm_class) { +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) + gtk_window_set_wmclass(GTK_WINDOW(window), desktop_wm_class, desktop_wm_class); +#endif + } + + auto const zoom = 1.0; + + auto const screen = terminal_screen_new(profile, + desktop_title ? desktop_title : _("Terminal"), + zoom); + + if (option_keep) + terminal_screen_set_exit_action(screen, TERMINAL_EXIT_HOLD); + + terminal_window_add_screen(window, screen, -1); + + gtk_window_present(GTK_WINDOW(window)); + + auto exec_data = g_new(ExecData, 1); + exec_data->object = g_object_ref(intent); + /* We want to transfer the ownership of @invocation to ExecData here, but + * we have to temporarily ref it so that in the error case below (where + * terminal_screen_exec() frees the exec data via the supplied callback, + * the g_dbus_method_invocation_take_error() calll still can take ownership + * of the invocation's ref passed to this function (terminal_receiver_impl_exec()). + */ + exec_data->invocation = (GDBusMethodInvocation*)g_object_ref (invocation); + + if (!terminal_screen_exec(screen, + argv, + envv, + false /* shell */, + cwd[0] ? cwd : desktop_cwd ? desktop_cwd : nullptr, + nullptr, nullptr, + TerminalScreenExecCallback(exec_intent_cb), + exec_data /* adopted */, + GDestroyNotify(exec_data_free), + nullptr /* cancellable */, + &err)) { + /* Transfers ownership of @invocation */ + g_dbus_method_invocation_take_error(invocation, err); + } + + /* Now we can remove that extra ref again. */ + g_object_unref (invocation); + + return true; +} + +static void +terminal_intent_impl_iface_init (TerminalIntentIface *iface) +{ + iface->handle_launch_command = terminal_intent_impl_launch_command; +} + +G_DEFINE_TYPE_WITH_CODE (TerminalIntentImpl, terminal_intent_impl, TERMINAL_TYPE_INTENT_SKELETON, + G_IMPLEMENT_INTERFACE (TERMINAL_TYPE_INTENT, terminal_intent_impl_iface_init)) + +static void +terminal_intent_impl_init (TerminalIntentImpl *impl) +{ +} + +static void +terminal_intent_impl_class_init (TerminalIntentImplClass *klass) +{ +} + +/** + * terminal_intent_impl_new: + * + * Returns: (transfer full): a new #TerminalIntentImpl + */ +TerminalIntent * +terminal_intent_impl_new (void) +{ + return reinterpret_cast<TerminalIntent*> + (g_object_new (TERMINAL_TYPE_INTENT_IMPL, nullptr)); +} diff --git a/src/terminal-gdbus.hh b/src/terminal-gdbus.hh index 38c24bc4..baa6a9b7 100644 --- a/src/terminal-gdbus.hh +++ b/src/terminal-gdbus.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Christian Persch + * Copyright © 2011, 2021 Christian Persch * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,8 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef TERMINAL_RECEIVER_IMPL_H -#define TERMINAL_RECEIVER_IMPL_H +#pragma once #include <glib-object.h> @@ -85,6 +84,29 @@ GType terminal_factory_impl_get_type (void); TerminalFactory *terminal_factory_impl_new (void); -G_END_DECLS +/* ------------------------------------------------------------------------- */ + +#define TERMINAL_TYPE_INTENT_IMPL (terminal_intent_impl_get_type ()) +#define TERMINAL_INTENT_IMPL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_INTENT_IMPL, TerminalIntentImpl)) +#define TERMINAL_INTENT_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_INTENT_IMPL, TerminalIntentImplClass)) +#define TERMINAL_IS_INTENT_IMPL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_INTENT_IMPL)) +#define TERMINAL_IS_INTENT_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_INTENT_IMPL)) +#define TERMINAL_INTENT_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_INTENT_IMPL, TerminalIntentImplClass)) + +typedef struct _TerminalIntentImpl TerminalIntentImpl; +typedef struct _TerminalIntentImplClass TerminalIntentImplClass; + +struct _TerminalIntentImplClass { + TerminalIntentSkeletonClass parent_class; +}; -#endif /* !TERMINAL_RECEIVER_IMPL_H */ +struct _TerminalIntentImpl +{ + TerminalIntentSkeleton parent_instance; +}; + +GType terminal_intent_impl_get_type (void); + +TerminalIntent *terminal_intent_impl_new (void); + +G_END_DECLS diff --git a/src/terminal-screen.cc b/src/terminal-screen.cc index 382ac296..6036a89e 100644 --- a/src/terminal-screen.cc +++ b/src/terminal-screen.cc @@ -108,6 +108,9 @@ struct _TerminalScreenPrivate gboolean exec_on_realize; guint idle_exec_source; ExecData *exec_data; + + bool exit_action_set; + TerminalExitAction exit_action; }; enum @@ -176,12 +179,12 @@ static void terminal_screen_show_info_bar (TerminalScreen *screen, static char**terminal_screen_get_child_environment (TerminalScreen *screen, - char **initial_envv, + char const* const* initial_envv, char **path, char **shell); static gboolean terminal_screen_get_child_command (TerminalScreen *screen, - char **exec_argv, + char const* const* exec_argv, const char *path_env, const char *shell_env, gboolean shell, @@ -236,9 +239,9 @@ fake_dup3 (int fd, int fd2, int flags) #endif /* !__linux__ */ static char* -strv_to_string (char **strv) +strv_to_string (char const* const* strv) { - return strv ? g_strjoinv (" ", strv) : g_strdup ("(null)"); + return strv ? g_strjoinv (" ", (char**)strv) : g_strdup ("(null)"); } static char* @@ -896,10 +899,10 @@ terminal_screen_reexec (TerminalScreen *screen, gboolean terminal_screen_exec (TerminalScreen *screen, - char **argv, - char **initial_envv, + char const* const* argv, + char const* const* initial_envv, gboolean as_shell, - const char *cwd, + char const* cwd, GUnixFDList *fd_list, GVariant *fd_array, TerminalScreenExecCallback callback, @@ -919,7 +922,7 @@ terminal_screen_exec (TerminalScreen *screen, "[screen %p] exec: argv:[%s] envv:%p(%u) as-shell:%s cwd:%s\n", screen, (argv_str = strv_to_string(argv)), - initial_envv, initial_envv ? g_strv_length (initial_envv) : 0, + initial_envv, initial_envv ? g_strv_length((char**)initial_envv) : 0, as_shell ? "true":"false", cwd); } @@ -944,7 +947,7 @@ terminal_screen_exec (TerminalScreen *screen, gs_free char *path = nullptr; gs_free char *shell = nullptr; - gs_strfreev char **envv = terminal_screen_get_child_environment (screen, + gs_strfreev char **envv = terminal_screen_get_child_environment(screen, initial_envv, &path, &shell); @@ -997,7 +1000,7 @@ terminal_screen_exec (TerminalScreen *screen, data->fd_map = nullptr; } - data->argv = g_strdupv (argv); + data->argv = g_strdupv ((char**)argv); data->exec_argv = g_strdupv (exec_argv); data->cwd = g_strdup (cwd); data->envv = g_strdupv (envv); @@ -1348,7 +1351,7 @@ should_preserve_cwd (TerminalPreserveWorkingDirectory preserve_cwd, static gboolean terminal_screen_get_child_command (TerminalScreen *screen, - char **argv, + char const* const* argv, const char *path_env, const char *shell_env, gboolean as_shell, @@ -1371,7 +1374,7 @@ terminal_screen_get_child_command (TerminalScreen *screen, if (argv) { - exec_argv = g_strdupv (argv); + exec_argv = g_strdupv((char**)argv); /* argv and cwd come from the command line client, so it must always be used */ *preserve_cwd_p = TRUE; @@ -1432,10 +1435,10 @@ terminal_screen_get_child_command (TerminalScreen *screen, } static char** -terminal_screen_get_child_environment (TerminalScreen *screen, - char **initial_envv, - char **path, - char **shell) +terminal_screen_get_child_environment(TerminalScreen *screen, + char const* const* initial_envv, + char **path, + char **shell) { TerminalApp *app = terminal_app_get (); char **env; @@ -1449,11 +1452,11 @@ terminal_screen_get_child_environment (TerminalScreen *screen, env_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); if (initial_envv) - env = initial_envv; + env = (char**)initial_envv; else { env = current_environ = g_get_environ (); /* Remove this variable which we set in server.c:main() */ - env = g_environ_unsetenv (env, "G_ENABLE_DIAGNOSTIC"); + env = g_environ_unsetenv(env, "G_ENABLE_DIAGNOSTIC"); } for (i = 0; env[i]; ++i) @@ -1871,7 +1874,12 @@ terminal_screen_child_exited (VteTerminal *terminal, priv->child_pid = -1; - action = TerminalExitAction(g_settings_get_enum (priv->profile, TERMINAL_PROFILE_EXIT_ACTION_KEY)); + if (priv->exit_action_set) + action = priv->exit_action; + else + action = TerminalExitAction(g_settings_get_enum (priv->profile, TERMINAL_PROFILE_EXIT_ACTION_KEY)); + + auto const can_relaunch = !priv->exit_action_set; switch (action) { @@ -1885,8 +1893,12 @@ terminal_screen_child_exited (VteTerminal *terminal, GtkWidget *info_bar; info_bar = terminal_info_bar_new (GTK_MESSAGE_INFO, - _("_Relaunch"), RESPONSE_RELAUNCH, nullptr); + if (can_relaunch) + gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), + _("_Relaunch"), + RESPONSE_RELAUNCH); + if (WIFEXITED (status)) { terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar), _("The child process exited normally with status %d."), WEXITSTATUS (status)); @@ -2332,3 +2344,14 @@ terminal_screen_get_uuid (TerminalScreen *screen) return screen->priv->uuid; } + +void +terminal_screen_set_exit_action(TerminalScreen* screen, + TerminalExitAction action) +{ + g_return_if_fail(TERMINAL_IS_SCREEN(screen)); + + auto const priv = screen->priv; + priv->exit_action = action; + priv->exit_action_set = true; +} diff --git a/src/terminal-screen.hh b/src/terminal-screen.hh index df59b1a5..16ef8f6f 100644 --- a/src/terminal-screen.hh +++ b/src/terminal-screen.hh @@ -24,6 +24,8 @@ #include <vte/vte.h> +#include "terminal-enums.hh" + G_BEGIN_DECLS typedef enum { @@ -84,10 +86,10 @@ typedef void (* TerminalScreenExecCallback) (TerminalScreen *screen, gpointer user_data); gboolean terminal_screen_exec (TerminalScreen *screen, - char **argv, - char **envv, + char const* const* argv, + char const* const* envv, gboolean as_shell, - const char *cwd, + char const* cwd, GUnixFDList *fd_list, GVariant *fd_array, TerminalScreenExecCallback callback, @@ -126,6 +128,9 @@ void terminal_screen_get_cell_size (TerminalScreen *screen, void _terminal_screen_update_scrollbar (TerminalScreen *screen); +void terminal_screen_set_exit_action(TerminalScreen* screen, + TerminalExitAction action); + void terminal_screen_save_config (TerminalScreen *screen, GKeyFile *key_file, const char *group); |