summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Persch <chpe@src.gnome.org>2021-08-03 19:16:19 +0200
committerChristian Persch <chpe@src.gnome.org>2021-08-03 19:16:19 +0200
commit76220dc83ab3be42def2d57a8d9240412a45db5f (patch)
tree41d8cfb6a29e8d213d00b8a6485daa0b23ca9cd2
parent3b5150e92c43dc7528499eaa6dcbcd95fd818e34 (diff)
downloadgnome-terminal-wip/intent.tar.gz
WIP: intentwip/intent
-rw-r--r--data/org.gnome.Terminal.desktop.in1
-rw-r--r--src/org.gnome.Terminal.xml14
-rw-r--r--src/server.cc4
-rw-r--r--src/terminal-app.cc103
-rw-r--r--src/terminal-app.hh3
-rw-r--r--src/terminal-defines.hh3
-rw-r--r--src/terminal-gdbus.cc249
-rw-r--r--src/terminal-gdbus.hh32
-rw-r--r--src/terminal-screen.cc63
-rw-r--r--src/terminal-screen.hh11
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);