Skip to content

Instantly share code, notes, and snippets.

@joelwampler
Created January 11, 2015 05:24
Show Gist options
  • Save joelwampler/7abdb2afdbb4873796bd to your computer and use it in GitHub Desktop.
Save joelwampler/7abdb2afdbb4873796bd to your computer and use it in GitHub Desktop.
Patch for gnome-terminal 3.14.2 which reverts all commits related to removing the ability to set a custom title. See first comment below for more info.
diff --git a/help/C/gs-tabs.page b/help/C/gs-tabs.page
index ea4ea6b..67dbba1 100644
--- a/help/C/gs-tabs.page
+++ b/help/C/gs-tabs.page
@@ -5,6 +5,7 @@
<info>
<link type="guide" xref="index#getting-started"/>
+ <link type="seealso" xref="pref-title"/>
<revision pkgversion="3.8" date="2013-02-17" status="candidate"/>
<revision pkgversion="3.12" date="2014-03-07" status="candidate"/>
diff --git a/help/C/pref-custom-command.page b/help/C/pref-custom-command.page
index cc47037..0e752d9 100644
--- a/help/C/pref-custom-command.page
+++ b/help/C/pref-custom-command.page
@@ -44,9 +44,9 @@
<steps>
<item>
- <p>Select
- <guiseq><gui style="menu">Edit</gui><gui style="menuitem">Profile
- Preferences</gui><gui style="tab">Command</gui></guiseq>.</p>
+ <p>Select <guiseq><gui style="menu">Edit</gui>
+ <gui style="menuitem">Profile Preferences</gui>
+ <gui style="tab">Title and Command</gui></guiseq>.</p>
</item>
<item>
<p>Check <gui>Run a custom command instead of my shell</gui>.</p>
diff --git a/help/C/pref-custom-exit.page b/help/C/pref-custom-exit.page
index ff1d617..3927fc9 100644
--- a/help/C/pref-custom-exit.page
+++ b/help/C/pref-custom-exit.page
@@ -38,9 +38,10 @@
<steps>
<item>
- <p>Select
- <guiseq><gui style="menu">Edit</gui><gui style="menuitem">Profile
- Preferences</gui><gui style="tab">Command</gui></guiseq>.</p>
+ <p>Select <guiseq>
+ <gui style="menu">Edit</gui>
+ <gui style="menuitem">Profile Preferences</gui>
+ <gui style="tab">Title and Command</gui></guiseq>.</p>
</item>
<item>
<p>From the <gui>When command exits</gui> drop down list, select one of
diff --git a/help/C/pref-profiles.page b/help/C/pref-profiles.page
index 7dca41d..f8e755c 100644
--- a/help/C/pref-profiles.page
+++ b/help/C/pref-profiles.page
@@ -121,7 +121,7 @@
<link xref="pref-custom-exit"><cmd>exit</cmd> command</link>.
You can also set a
<link xref="pref-custom-command">custom shell</link> in the
- <gui style="tab">Command</gui> tab.</p>
+ <gui style="tab">Title and Command</gui> tab.</p>
</item>
<item>
<p>Set your preferred <link xref="app-colors">theme and colors</link>
diff --git a/help/C/pref-title.page b/help/C/pref-title.page
new file mode 100644
index 0000000..d29521f
--- /dev/null
+++ b/help/C/pref-title.page
@@ -0,0 +1,79 @@
+<page xmlns="http://projectmallard.org/1.0/"
+ type="task"
+ id="pref-title">
+
+ <info>
+ <revision version="0.1" date="2013-02-18" status="candidate"/>
+ <link type="guide" xref="index#preferences"/>
+ <link type="guide" xref="profile"/>
+
+ <credit type="author copyright">
+ <name>Sindhu S</name>
+ <email>sindhus@live.in</email>
+ <years>2013</years>
+ </credit>
+ <credit type="copyright editor">
+ <name>Ekaterina Gerasimova</name>
+ <email>kittykat3756@gmail.com</email>
+ <years>2013</years>
+ </credit>
+ <credit type="copyright editor">
+ <name>Michael Hill</name>
+ <email>mdhillca@gmail.com</email>
+ <years>2013</years>
+ </credit>
+
+ <include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude"/>
+
+ <desc>Allow commands to set the title for a <app>Terminal</app> tab or window.</desc>
+
+ </info>
+
+ <title><app>Terminal</app> title</title>
+
+ <p><app>Terminal</app> can allow commands to set the name of your
+ <app>Terminal</app> tab or window. This title will display at startup or on
+ opening a new tab.</p>
+
+ <steps>
+ <item>
+ <p>Select <guiseq><gui style="menu">Edit</gui>
+ <gui style="menuitem">Profile Preferences</gui>
+ <gui style="tab">Title and Command</gui></guiseq>.</p>
+ </item>
+ <item>
+ <p>Next to <gui>Initial title</gui>, enter the title that you wish
+ <app>Terminal</app> to display.</p>
+ </item>
+ <item>
+ <p>Select one of the following options:</p>
+ <terms>
+ <item>
+ <title><gui>Replace initial title</gui></title>
+ <p>Commands executed in <app>Terminal</app> are allowed to replace
+ the initial title.</p>
+ </item>
+ <item>
+ <title><gui>Append initial title</gui></title>
+ <p>The new title will consist of the title set by the currently
+ executing command, followed by the initial title.</p>
+ </item>
+ <item>
+ <title><gui>Prepend initial title</gui></title>
+ <p>The new title will consist of the initial title followed by the
+ title set by the currently executing command.</p>
+ </item>
+ <item>
+ <title><gui>Keep initial title</gui></title>
+ <p>The initial title which is set by the user will be retained.</p>
+ </item>
+ </terms>
+ <p>Your selection will be saved and applied immediately.</p>
+ </item>
+ <item>
+ <p>Click <gui style="button">Close</gui> to return to
+ <app>Terminal</app>.</p>
+ </item>
+ </steps>
+
+</page>
diff --git a/help/Makefile.am b/help/Makefile.am
index e96b060..f8e49e0 100644
--- a/help/Makefile.am
+++ b/help/Makefile.am
@@ -36,6 +36,7 @@ HELP_FILES = \
pref-scrolling.page \
pref-tab-window.page \
pref-theme.page \
+ pref-title.page \
profile.page \
prob-reset.page \
txt-copy-paste.page \
--- a/help/Makefile.in
+++ b/help/Makefile.in
@@ -328,6 +328,7 @@
pref-scrolling.page \
pref-tab-window.page \
pref-theme.page \
+ pref-title.page \
profile.page \
prob-reset.page \
txt-copy-paste.page \
diff --git a/src/migration.c b/src/migration.c
index 6cdd573..8898911 100644
--- a/src/migration.c
+++ b/src/migration.c
@@ -86,6 +86,8 @@ enum {
#define KEY_SCROLL_ON_KEYSTROKE "scroll_on_keystroke"
#define KEY_SCROLL_ON_OUTPUT "scroll_on_output"
#define KEY_SILENT_BELL "silent_bell"
+#define KEY_TITLE_MODE "title_mode"
+#define KEY_TITLE "title"
#define KEY_UPDATE_RECORDS "update_records"
#define KEY_USE_CUSTOM_COMMAND "use_custom_command"
#define KEY_USE_SYSTEM_FONT "use_system_font"
@@ -393,6 +395,11 @@ migrate_profile (TerminalSettingsList *list,
migrate_bool (client, path, KEY_BOLD_COLOR_SAME_AS_FG,
settings, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG_KEY,
FALSE);
+ migrate_genum (client, path, KEY_TITLE_MODE,
+ settings, TERMINAL_PROFILE_TITLE_MODE_KEY,
+ TERMINAL_TYPE_TITLE_MODE);
+ migrate_string (client, path, KEY_TITLE,
+ settings, TERMINAL_PROFILE_TITLE_KEY);
migrate_bool (client, path, KEY_ALLOW_BOLD,
settings, TERMINAL_PROFILE_ALLOW_BOLD_KEY,
FALSE);
@@ -534,6 +541,7 @@ migrate_accels (GSettings *global_settings,
{ "zoom_in", "zoom-in" },
{ "zoom_out", "zoom-out" },
{ "zoom_normal", "zoom-normal" },
+ { "set_window_title", "set-terminal-title" },
{ "reset", "reset" },
{ "reset_and_clear", "reset-and-clear" },
{ "prev_tab", "prev-tab" },
diff --git a/src/org.gnome.Terminal.gschema.xml b/src/org.gnome.Terminal.gschema.xml
index c7d0edb..7044931 100644
--- a/src/org.gnome.Terminal.gschema.xml
+++ b/src/org.gnome.Terminal.gschema.xml
@@ -24,6 +24,13 @@
-->
<schemalist gettext-domain="gnome-terminal">
+ <enum id='org.gnome.Terminal.TitleMode'>
+ <value nick='replace' value='0'/>
+ <value nick='before' value='1'/>
+ <value nick='after' value='2'/>
+ <value nick='ignore' value='3'/>
+ </enum>
+
<enum id='org.gnome.Terminal.NewTerminalMode'>
<value nick='window' value='0'/>
<value nick='tab' value='1'/>
@@ -116,6 +123,16 @@
<summary>Whether bold text should use the same color as normal text</summary>
<description>If true, boldface text will be rendered using the same color as normal text.</description>
</key>
+ <key name="title-mode" enum="org.gnome.Terminal.TitleMode">
+ <default>'replace'</default>
+ <summary>What to do with dynamic title</summary>
+ <description>If the application in the terminal sets the title (most typically people have their shell set up to do this), the dynamically-set title can erase the configured title, go before it, go after it, or replace it. The possible values are "replace", "before", "after", and "ignore".</description>
+ </key>
+ <key name="title" type="s">
+ <default l10n="messages" context="title">'Terminal'</default>
+ <summary>Title for terminal</summary>
+ <description>Title to display for the terminal window or tab. This title may be replaced by or combined with the title set by the application inside the terminal, depending on the title_mode setting.</description>
+ </key>
<key name="allow-bold" type="b">
<default>true</default>
<summary>Whether to allow bold text</summary>
@@ -363,6 +380,10 @@
<default>'disabled'</default>
<summary>Keyboard shortcut to toggle the visibility of the menubar</summary>
</key>
+ <key name="set-terminal-title" type="s">
+ <default>'disabled'</default>
+ <summary>Keyboard shortcut to set the terminal title</summary>
+ </key>
<key name="reset" type="s">
<default>'disabled'</default>
<summary>Keyboard shortcut to reset the terminal</summary>
diff --git a/src/profile-editor.c b/src/profile-editor.c
index 8e5732d..f121867 100644
--- a/src/profile-editor.c
+++ b/src/profile-editor.c
@@ -1041,6 +1041,17 @@ terminal_profile_edit (GSettings *profile,
"active",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET |
G_SETTINGS_BIND_INVERT_BOOLEAN);
+ g_settings_bind (profile, TERMINAL_PROFILE_TITLE_KEY,
+ gtk_builder_get_object (builder, "title-entry"), "text",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind_with_mapping (profile, TERMINAL_PROFILE_TITLE_MODE_KEY,
+ gtk_builder_get_object (builder,
+ "title-mode-combobox"),
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET,
+ (GSettingsBindGetMapping) string_to_enum,
+ (GSettingsBindSetMapping) enum_to_string,
+ terminal_title_mode_get_type, NULL);
g_settings_bind (profile, TERMINAL_PROFILE_UPDATE_RECORDS_KEY,
gtk_builder_get_object (builder,
"update-records-checkbutton"),
diff --git a/src/profile-preferences.ui b/src/profile-preferences.ui
index de901ee..3c77481 100644
--- a/src/profile-preferences.ui
+++ b/src/profile-preferences.ui
@@ -544,6 +544,138 @@
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
+ <object class="GtkVBox" id="vbox79">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label33">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Title</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment10108">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox93">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox137">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="title-entry-label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Initial _title:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">title-entry</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="title-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox138">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="title-mode-combobox-label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">When terminal commands set their o_wn titles:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">title-mode-combobox</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="title-mode-combobox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">model2</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkVBox" id="vbox80">
<property name="visible">True</property>
<property name="can_focus">False</property>
diff --git a/src/terminal-accels.c b/src/terminal-accels.c
index 8a036ce..afd9993 100644
--- a/src/terminal-accels.c
+++ b/src/terminal-accels.c
@@ -70,6 +70,7 @@
#define KEY_RESET_AND_CLEAR "reset-and-clear"
#define KEY_RESET "reset"
#define KEY_SAVE_CONTENTS "save-contents"
+#define KEY_SET_TERMINAL_TITLE "set-terminal-title"
#define KEY_TOGGLE_MENUBAR "toggle-menubar"
#define KEY_ZOOM_IN "zoom-in"
#define KEY_ZOOM_NORMAL "zoom-normal"
@@ -98,6 +99,7 @@
#define ACCEL_PATH_KEY_PREV_TAB ACCEL_PATH_ROOT "TabsPrevious"
#define ACCEL_PATH_KEY_RESET ACCEL_PATH_ROOT "TerminalReset"
#define ACCEL_PATH_KEY_RESET_AND_CLEAR ACCEL_PATH_ROOT "TerminalResetClear"
+#define ACCEL_PATH_KEY_SET_TERMINAL_TITLE ACCEL_PATH_ROOT "TerminalSetTitle"
#define ACCEL_PATH_KEY_SAVE_CONTENTS ACCEL_PATH_ROOT "FileSaveContents"
#define ACCEL_PATH_KEY_TOGGLE_MENUBAR ACCEL_PATH_ROOT "ViewMenubar"
#define ACCEL_PATH_KEY_ZOOM_IN ACCEL_PATH_ROOT "ViewZoomIn"
@@ -176,6 +178,7 @@ static KeyEntry view_entries[] = {
};
static KeyEntry terminal_entries[] = {
+ ENTRY (N_("Set Title"), KEY_SET_TERMINAL_TITLE, "set-title", NULL, NULL ),
ENTRY (N_("Reset"), KEY_RESET, "reset", "b", "false"),
ENTRY (N_("Reset and Clear"), KEY_RESET_AND_CLEAR, "reset", "b", "true" ),
};
diff --git a/src/terminal-app.c b/src/terminal-app.c
index 95302c5..7d5ce40 100644
--- a/src/terminal-app.c
+++ b/src/terminal-app.c
@@ -542,6 +542,7 @@ terminal_app_new_terminal (TerminalApp *app,
TerminalWindow *window,
GSettings *profile,
char **override_command,
+ const char *title,
const char *working_dir,
char **child_env,
double zoom)
@@ -551,7 +552,7 @@ terminal_app_new_terminal (TerminalApp *app,
g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL);
- screen = terminal_screen_new (profile, override_command,
+ screen = terminal_screen_new (profile, override_command, title,
working_dir, child_env, zoom);
terminal_window_add_screen (window, screen, -1);
diff --git a/src/terminal-app.h b/src/terminal-app.h
index 9502845..6da6036 100644
--- a/src/terminal-app.h
+++ b/src/terminal-app.h
@@ -75,6 +75,7 @@ TerminalScreen *terminal_app_new_terminal (TerminalApp *app,
TerminalWindow *window,
GSettings *profile,
char **override_command,
+ const char *title,
const char *working_dir,
char **child_env,
double zoom);
diff --git a/src/terminal-enums.h b/src/terminal-enums.h
index 6b85923..c85f529 100644
--- a/src/terminal-enums.h
+++ b/src/terminal-enums.h
@@ -31,6 +31,14 @@ typedef enum {
typedef enum
{
+ TERMINAL_TITLE_REPLACE,
+ TERMINAL_TITLE_BEFORE,
+ TERMINAL_TITLE_AFTER,
+ TERMINAL_TITLE_IGNORE
+} TerminalTitleMode;
+
+typedef enum
+{
TERMINAL_EXIT_CLOSE,
TERMINAL_EXIT_RESTART,
TERMINAL_EXIT_HOLD
diff --git a/src/terminal-gdbus.c b/src/terminal-gdbus.c
index 7b68a85..b801b9e 100644
--- a/src/terminal-gdbus.c
+++ b/src/terminal-gdbus.c
@@ -368,7 +368,7 @@ terminal_factory_impl_create_instance (TerminalFactory *factory,
TerminalObjectSkeleton *skeleton;
char *object_path;
GSettings *profile = NULL;
- const char *profile_uuid;
+ const char *profile_uuid, *title;
gboolean zoom_set = FALSE;
gdouble zoom = 1.0;
guint window_id;
@@ -456,10 +456,12 @@ terminal_factory_impl_create_instance (TerminalFactory *factory,
g_assert (window != NULL);
+ if (!g_variant_lookup (options, "title", "&s", &title))
+ title = NULL;
if (g_variant_lookup (options, "zoom", "d", &zoom))
zoom_set = TRUE;
- screen = terminal_screen_new (profile, NULL, NULL, NULL,
+ screen = terminal_screen_new (profile, NULL, title, NULL, NULL,
zoom_set ? zoom : 1.0);
terminal_window_add_screen (window, screen, -1);
terminal_window_switch_screen (window, screen);
diff --git a/src/terminal-schemas.h b/src/terminal-schemas.h
index 90cc5a0..1380fab 100644
--- a/src/terminal-schemas.h
+++ b/src/terminal-schemas.h
@@ -56,6 +56,8 @@ G_BEGIN_DECLS
#define TERMINAL_PROFILE_SCROLLBAR_POLICY_KEY "scrollbar-policy"
#define TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE_KEY "scroll-on-keystroke"
#define TERMINAL_PROFILE_SCROLL_ON_OUTPUT_KEY "scroll-on-output"
+#define TERMINAL_PROFILE_TITLE_MODE_KEY "title-mode"
+#define TERMINAL_PROFILE_TITLE_KEY "title"
#define TERMINAL_PROFILE_UPDATE_RECORDS_KEY "update-records"
#define TERMINAL_PROFILE_USE_CUSTOM_COMMAND_KEY "use-custom-command"
#define TERMINAL_PROFILE_USE_SKEY_KEY "use-skey"
diff --git a/src/terminal-screen.c b/src/terminal-screen.c
index ad78388..52871d7 100644
--- a/src/terminal-screen.c
+++ b/src/terminal-screen.c
@@ -77,11 +77,17 @@ struct _TerminalScreenPrivate
GSettings *profile; /* never NULL */
guint profile_changed_id;
guint profile_forgotten_id;
+ char *raw_title, *raw_icon_title;
+ char *cooked_title, *cooked_icon_title;
+ char *override_title;
+ gboolean icon_title_set;
char *initial_working_directory;
char **initial_env;
char **override_command;
gboolean shell;
int child_pid;
+ double font_scale;
+ gboolean user_title; /* title was manually set */
GSList *match_tags;
guint launch_child_source_id;
};
@@ -144,6 +150,11 @@ static void terminal_screen_icon_title_changed (VteTerminal *vte_terminal
static void update_color_scheme (TerminalScreen *screen);
+static gboolean terminal_screen_format_title (TerminalScreen *screen, const char *raw_title, char **old_cooked_title);
+
+static void terminal_screen_cook_title (TerminalScreen *screen);
+static void terminal_screen_cook_icon_title (TerminalScreen *screen);
+
static char* terminal_screen_check_match (TerminalScreen *screen,
GdkEvent *event,
int *flavor);
@@ -342,6 +353,9 @@ terminal_screen_init (TerminalScreen *screen)
gtk_target_table_free (targets, n_targets);
gtk_target_list_unref (target_list);
+ priv->override_title = NULL;
+ priv->user_title = FALSE;
+
g_signal_connect (screen, "window-title-changed",
G_CALLBACK (terminal_screen_window_title_changed),
screen);
@@ -592,6 +606,11 @@ terminal_screen_finalize (GObject *object)
terminal_screen_set_profile (screen, NULL);
+ g_free (priv->raw_title);
+ g_free (priv->cooked_title);
+ g_free (priv->override_title);
+ g_free (priv->raw_icon_title);
+ g_free (priv->cooked_icon_title);
g_free (priv->initial_working_directory);
g_strfreev (priv->override_command);
g_strfreev (priv->initial_env);
@@ -607,6 +626,7 @@ terminal_screen_finalize (GObject *object)
TerminalScreen *
terminal_screen_new (GSettings *profile,
char **override_command,
+ const char *title,
const char *working_dir,
char **child_env,
double zoom)
@@ -624,6 +644,9 @@ terminal_screen_new (GSettings *profile,
g_settings_get_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS_KEY),
g_settings_get_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS_KEY));
+ if (title)
+ terminal_screen_set_override_title (screen, title);
+
priv->initial_working_directory = g_strdup (working_dir);
if (override_command)
@@ -678,27 +701,173 @@ terminal_screen_exec (TerminalScreen *screen,
}
const char*
+terminal_screen_get_raw_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->raw_title)
+ return priv->raw_title;
+
+ return "";
+}
+
+const char*
terminal_screen_get_title (TerminalScreen *screen)
{
- return vte_terminal_get_window_title (VTE_TERMINAL (screen));
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->cooked_title == NULL)
+ terminal_screen_cook_title (screen);
+
+ /* cooked_title may still be NULL */
+ if (priv->cooked_title != NULL)
+ return priv->cooked_title;
+ else
+ return "";
}
const char*
terminal_screen_get_icon_title (TerminalScreen *screen)
{
- return vte_terminal_get_icon_title (VTE_TERMINAL (screen));
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->cooked_icon_title == NULL)
+ terminal_screen_cook_icon_title (screen);
+
+ /* cooked_icon_title may still be NULL */
+ if (priv->cooked_icon_title != NULL)
+ return priv->cooked_icon_title;
+ else
+ return "";
}
gboolean
terminal_screen_get_icon_title_set (TerminalScreen *screen)
{
- return vte_terminal_get_icon_title (VTE_TERMINAL (screen)) != NULL;
+ return screen->priv->icon_title_set;
+}
+
+/* Supported format specifiers:
+ * %S = static title
+ * %D = dynamic title
+ * %A = dynamic title, falling back to static title if empty
+ * %- = separator, if not at start or end of string (excluding whitespace)
+ */
+static const char *
+terminal_screen_get_title_format (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ static const char *formats[] = {
+ "%A" /* TERMINAL_TITLE_REPLACE */,
+ "%D%-%S" /* TERMINAL_TITLE_BEFORE */,
+ "%S%-%D" /* TERMINAL_TITLE_AFTER */,
+ "%S" /* TERMINAL_TITLE_IGNORE */
+ };
+
+ return formats[g_settings_get_enum (priv->profile, TERMINAL_PROFILE_TITLE_MODE_KEY)];
+}
+
+/**
+ * terminal_screen_format_title::
+ * @screen:
+ * @raw_title: main ingredient
+ * @titleptr <inout>: pointer of the current title string
+ *
+ * Format title according @format, and stores it in <literal>*titleptr</literal>.
+ * Always ensures that *titleptr will be non-NULL.
+ *
+ * Returns: %TRUE iff the title changed
+ */
+static gboolean
+terminal_screen_format_title (TerminalScreen *screen,
+ const char *raw_title,
+ char **titleptr)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ const char *format, *arg;
+ const char *static_title = NULL;
+ GString *title;
+ gboolean add_sep = FALSE;
+
+ g_assert (titleptr);
+
+ /* use --title argument if one was supplied, otherwise ask the profile */
+ if (priv->override_title)
+ static_title = priv->override_title;
+ else
+ g_settings_get (priv->profile, TERMINAL_PROFILE_TITLE_KEY, "&s", &static_title);
+
+ title = g_string_sized_new (128);
+
+ format = terminal_screen_get_title_format (screen);
+ for (arg = format; *arg; arg += 2)
+ {
+ const char *text_to_append = NULL;
+
+ g_assert (arg[0] == '%');
+
+ switch (arg[1])
+ {
+ case 'A':
+ text_to_append = raw_title ? raw_title : static_title;
+ break;
+ case 'D':
+ text_to_append = raw_title;
+ break;
+ case 'S':
+ text_to_append = static_title;
+ break;
+ case '-':
+ text_to_append = NULL;
+ add_sep = TRUE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (!text_to_append || !text_to_append[0])
+ continue;
+
+ if (add_sep && title->len > 0)
+ g_string_append (title, " - ");
+
+ g_string_append (title, text_to_append);
+ add_sep = FALSE;
+ }
+
+ if (*titleptr == NULL || strcmp (title->str, *titleptr) != 0)
+ {
+ g_free (*titleptr);
+ *titleptr = g_string_free (title, FALSE);
+ return TRUE;
+ }
+
+ g_string_free (title, TRUE);
+ return FALSE;
+}
+
+static void
+terminal_screen_cook_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (terminal_screen_format_title (screen, priv->raw_title, &priv->cooked_title))
+ g_object_notify (G_OBJECT (screen), "title");
+}
+
+static void
+terminal_screen_cook_icon_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (terminal_screen_format_title (screen, priv->raw_icon_title, &priv->cooked_icon_title))
+ g_object_notify (G_OBJECT (screen), "icon-title");
}
static void
terminal_screen_profile_changed_cb (GSettings *profile,
const char *prop_name,
- TerminalScreen *screen)
+ TerminalScreen *screen)
{
TerminalScreenPrivate *priv = screen->priv;
GObject *object = G_OBJECT (screen);
@@ -738,6 +907,14 @@ terminal_screen_profile_changed_cb (GSettings *profile,
vte_terminal_set_cjk_ambiguous_width (vte_terminal, (int) width);
}
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_TITLE_MODE_KEY) ||
+ prop_name == I_(TERMINAL_PROFILE_TITLE_KEY))
+ {
+ terminal_screen_cook_title (screen);
+ terminal_screen_cook_icon_title (screen);
+ }
+
if (gtk_widget_get_realized (GTK_WIDGET (screen)) &&
(!prop_name ||
prop_name == I_(TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY) ||
@@ -1495,6 +1672,85 @@ terminal_screen_button_press (GtkWidget *widget,
return FALSE;
}
+static void
+terminal_screen_set_dynamic_title (TerminalScreen *screen,
+ const char *title,
+ gboolean userset)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ g_assert (TERMINAL_IS_SCREEN (screen));
+
+ if ((priv->user_title && !userset) ||
+ (priv->raw_title && title &&
+ strcmp (priv->raw_title, title) == 0))
+ return;
+
+ g_free (priv->raw_title);
+ priv->raw_title = g_strdup (title);
+ terminal_screen_cook_title (screen);
+}
+
+static void
+terminal_screen_set_dynamic_icon_title (TerminalScreen *screen,
+ const char *icon_title,
+ gboolean userset)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ GObject *object = G_OBJECT (screen);
+
+ g_assert (TERMINAL_IS_SCREEN (screen));
+
+ if ((priv->user_title && !userset) ||
+ (priv->icon_title_set &&
+ priv->raw_icon_title &&
+ icon_title &&
+ strcmp (priv->raw_icon_title, icon_title) == 0))
+ return;
+
+ g_object_freeze_notify (object);
+
+ g_free (priv->raw_icon_title);
+ priv->raw_icon_title = g_strdup (icon_title);
+ priv->icon_title_set = TRUE;
+
+ g_object_notify (object, "icon-title-set");
+ terminal_screen_cook_icon_title (screen);
+
+ g_object_thaw_notify (object);
+}
+
+void
+terminal_screen_set_override_title (TerminalScreen *screen,
+ const char *title)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ char *old_title;
+
+ old_title = priv->override_title;
+ priv->override_title = g_strdup (title);
+ g_free (old_title);
+
+ terminal_screen_set_dynamic_title (screen, title, FALSE);
+ terminal_screen_set_dynamic_icon_title (screen, title, FALSE);
+}
+
+const char*
+terminal_screen_get_dynamic_title (TerminalScreen *screen)
+{
+ g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
+
+ return screen->priv->raw_title;
+}
+
+const char*
+terminal_screen_get_dynamic_icon_title (TerminalScreen *screen)
+{
+ g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
+
+ return screen->priv->raw_icon_title;
+}
+
/**
* terminal_screen_get_current_dir:
* @screen:
@@ -1525,15 +1781,18 @@ static void
terminal_screen_window_title_changed (VteTerminal *vte_terminal,
TerminalScreen *screen)
{
- g_object_notify (G_OBJECT (screen), "title");
+ terminal_screen_set_dynamic_title (screen,
+ vte_terminal_get_window_title (vte_terminal),
+ FALSE);
}
static void
terminal_screen_icon_title_changed (VteTerminal *vte_terminal,
TerminalScreen *screen)
{
- g_object_notify (G_OBJECT (screen), "icon-title");
- g_object_notify (G_OBJECT (screen), "icon-title-set");
+ terminal_screen_set_dynamic_icon_title (screen,
+ vte_terminal_get_icon_title (vte_terminal),
+ FALSE);
}
static void
@@ -1595,6 +1854,24 @@ terminal_screen_child_exited (VteTerminal *terminal,
}
}
+void
+terminal_screen_set_user_title (TerminalScreen *screen,
+ const char *text)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ /* The user set the title to nothing, let's understand that as a
+ request to revert to dynamically setting the title again. */
+ if (!text || !text[0])
+ priv->user_title = FALSE;
+ else
+ {
+ priv->user_title = TRUE;
+ terminal_screen_set_dynamic_title (screen, text, TRUE);
+ terminal_screen_set_dynamic_icon_title (screen, text, TRUE);
+ }
+}
+
static void
terminal_screen_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
diff --git a/src/terminal-screen.h b/src/terminal-screen.h
index 96f0a0d..871ecff 100644
--- a/src/terminal-screen.h
+++ b/src/terminal-screen.h
@@ -76,6 +76,7 @@ const char *terminal_screen_get_uuid (TerminalScreen *screen);
TerminalScreen *terminal_screen_new (GSettings *profile,
char **override_command,
+ const char *title,
const char *working_dir,
char **child_env,
double zoom);
@@ -100,10 +101,20 @@ void terminal_screen_set_initial_environment (TerminalScreen *screen,
char **argv);
char ** terminal_screen_get_initial_environment (TerminalScreen *screen);
+const char* terminal_screen_get_raw_title (TerminalScreen *screen);
const char* terminal_screen_get_title (TerminalScreen *screen);
const char* terminal_screen_get_icon_title (TerminalScreen *screen);
gboolean terminal_screen_get_icon_title_set (TerminalScreen *screen);
+void terminal_screen_set_user_title (TerminalScreen *screen,
+ const char *text);
+
+void terminal_screen_set_override_title (TerminalScreen *screen,
+ const char *title);
+
+const char *terminal_screen_get_dynamic_title (TerminalScreen *screen);
+const char *terminal_screen_get_dynamic_icon_title (TerminalScreen *screen);
+
char *terminal_screen_get_current_dir (TerminalScreen *screen);
void terminal_screen_get_size (TerminalScreen *screen,
diff --git a/src/terminal-tab-label.c b/src/terminal-tab-label.c
index e060a45..e8bdc08 100644
--- a/src/terminal-tab-label.c
+++ b/src/terminal-tab-label.c
@@ -75,9 +75,8 @@ sync_tab_label (TerminalScreen *screen,
title = terminal_screen_get_title (screen);
hbox = gtk_widget_get_parent (label);
- gtk_label_set_text (GTK_LABEL (label),
- title && title[0] ? title : _("Terminal"));
-
+ gtk_label_set_text (GTK_LABEL (label), title);
+
gtk_widget_set_tooltip_text (hbox, title);
}
@@ -203,23 +202,6 @@ terminal_tab_label_constructed (GObject *object)
}
static void
-terminal_tab_label_dispose (GObject *object)
-{
- TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (object);
- TerminalTabLabelPrivate *priv = tab_label->priv;
-
- if (priv->screen != NULL) {
- g_signal_handlers_disconnect_by_func (priv->screen,
- G_CALLBACK (sync_tab_label),
- priv->label);
- g_object_unref (priv->screen);
- priv->screen = NULL;
- }
-
- G_OBJECT_CLASS (terminal_tab_label_parent_class)->dispose (object);
-}
-
-static void
terminal_tab_label_finalize (GObject *object)
{
// TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (object);
@@ -256,7 +238,7 @@ terminal_tab_label_set_property (GObject *object,
switch (prop_id) {
case PROP_SCREEN:
- priv->screen = g_value_dup_object (value);
+ priv->screen = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -271,7 +253,6 @@ terminal_tab_label_class_init (TerminalTabLabelClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gobject_class->constructed = terminal_tab_label_constructed;
- gobject_class->dispose = terminal_tab_label_dispose;
gobject_class->finalize = terminal_tab_label_finalize;
gobject_class->get_property = terminal_tab_label_get_property;
gobject_class->set_property = terminal_tab_label_set_property;
diff --git a/src/terminal-tabs-menu.c b/src/terminal-tabs-menu.c
index fb2b966..ed5fc7b 100644
--- a/src/terminal-tabs-menu.c
+++ b/src/terminal-tabs-menu.c
@@ -176,9 +176,7 @@ sync_tab_title (TerminalScreen *screen,
title = terminal_screen_get_title (screen);
- g_object_set (action,
- "label", title && title[0] ? title : _("Terminal"),
- NULL);
+ g_object_set (action, "label", title, NULL);
}
static void
diff --git a/src/terminal-window.c b/src/terminal-window.c
index ce85744..1241580 100644
--- a/src/terminal-window.c
+++ b/src/terminal-window.c
@@ -183,6 +183,8 @@ static void view_zoom_out_callback (GtkAction *action,
TerminalWindow *window);
static void view_zoom_normal_callback (GtkAction *action,
TerminalWindow *window);
+static void terminal_set_title_callback (GtkAction *action,
+ TerminalWindow *window);
static void terminal_add_encoding_callback (GtkAction *action,
TerminalWindow *window);
static void terminal_reset_callback (GtkAction *action,
@@ -408,7 +410,7 @@ action_new_terminal_cb (GSimpleAction *action,
new_working_directory = terminal_screen_get_current_dir (priv->active_screen);
terminal_app_new_terminal (app, window, profile,
- NULL,
+ NULL, NULL,
new_working_directory,
terminal_screen_get_initial_environment (priv->active_screen),
1.0);
@@ -726,6 +728,94 @@ action_move_tab_cb (GSimpleAction *action,
}
static void
+terminal_set_title_dialog_response_cb (GtkWidget *dialog,
+ int response,
+ TerminalScreen *screen)
+{
+ if (response == GTK_RESPONSE_OK)
+ {
+ GtkEntry *entry;
+ const char *text;
+
+ entry = GTK_ENTRY (g_object_get_data (G_OBJECT (dialog), "title-entry"));
+ text = gtk_entry_get_text (entry);
+ terminal_screen_set_user_title (screen, text);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static const char *
+terminal_screen_get_user_title (TerminalScreen *screen)
+{
+ return terminal_screen_get_raw_title (screen);
+}
+
+static void
+action_set_title_cb (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ TerminalWindow *window = user_data;
+ TerminalWindowPrivate *priv = window->priv;
+ GtkWidget *dialog, *message_area, *hbox, *label, *entry;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ /* FIXME: hook the screen up so this dialogue closes if the terminal screen closes */
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_OTHER,
+ GTK_BUTTONS_OK_CANCEL,
+ "%s", "");
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Set Title"));
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_window_set_role (GTK_WINDOW (dialog), "gnome-terminal-change-title");
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ /* Alternative button order was set automatically by GtkMessageDialog */
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (terminal_set_title_dialog_response_cb), priv->active_screen);
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (terminal_util_dialog_response_on_delete), NULL);
+
+ message_area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog));
+ gtk_container_foreach (GTK_CONTAINER (message_area), (GtkCallback) gtk_widget_hide, NULL);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (message_area), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new_with_mnemonic (_("_Title:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ entry = gtk_entry_new ();
+ gtk_entry_set_width_chars (GTK_ENTRY (entry), 32);
+ gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+ gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+ gtk_widget_show_all (hbox);
+
+ gtk_widget_grab_focus (entry);
+ gtk_entry_set_text (GTK_ENTRY (entry), terminal_screen_get_user_title (priv->active_screen));
+ gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+ g_object_set_data (G_OBJECT (dialog), "title-entry", entry);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+terminal_set_title_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "set-title"),
+ NULL);
+}
+
+static void
action_zoom_cb (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
@@ -2345,6 +2435,7 @@ terminal_window_init (TerminalWindow *window)
{ "reset", action_reset_cb, "b", NULL, NULL },
{ "switch-tab", action_switch_tab_cb, "i", NULL, NULL },
{ "move-tab", action_move_tab_cb, "i", NULL, NULL },
+ { "set-title", action_set_title_cb, NULL, NULL, NULL },
{ "zoom", action_zoom_cb, "i", NULL, NULL },
{ "detach-tab", action_detach_tab_cb, NULL, NULL, NULL },
{ "find", action_find_cb, "s", NULL, NULL },
@@ -2449,6 +2540,9 @@ terminal_window_init (TerminalWindow *window)
/* Terminal menu */
{ "TerminalProfiles", NULL, N_("Change _Profile") },
+ { "TerminalSetTitle", NULL, N_("_Set Title…"), NULL,
+ NULL,
+ G_CALLBACK (terminal_set_title_callback) },
{ "TerminalSetEncoding", NULL, N_("Set _Character Encoding") },
{ "TerminalReset", NULL, N_("_Reset"), NULL,
NULL,
@@ -2922,14 +3016,11 @@ sync_screen_title (TerminalScreen *screen,
TerminalWindow *window)
{
TerminalWindowPrivate *priv = window->priv;
- const char *title;
if (screen != priv->active_screen)
return;
- title = terminal_screen_get_title (screen);
- gtk_window_set_title (GTK_WINDOW (window),
- title && title[0] ? title : _("Terminal"));
+ gtk_window_set_title (GTK_WINDOW (window), terminal_screen_get_title (screen));
}
static void
diff --git a/src/terminal.xml b/src/terminal.xml
index d280f79..e07e9c2 100644
--- a/src/terminal.xml
+++ b/src/terminal.xml
@@ -46,6 +46,7 @@
</menu>
<menu action="Terminal">
<menu action="TerminalProfiles" />
+ <menuitem action="TerminalSetTitle" />
<menu action="TerminalSetEncoding" >
<placeholder name="EncodingsPH" />
<separator />
@@ -104,6 +105,8 @@
<menuitem action="TabsMoveLeft"/>
<menuitem action="TabsMoveRight"/>
<separator />
+ <menuitem action="TerminalSetTitle" />
+ <separator />
<menuitem action="FileCloseTab"/>
</popup>
</ui>
@joelwampler
Copy link
Author

Removing this feature severely affected the way I use Terminal, and futzing with the dynamic title feature isn't doing what I need. According to the defect someone filed, the feature is gone for good: https://bugzilla.gnome.org/show_bug.cgi?id=720693

This patch works against the source archive gnome-terminal-3.14.2.tar.xz found here: https://download.gnome.org/sources/gnome-terminal/3.14/

My goal was to download and rebuild the Fedora 21 RPM, adding this patch, and while I don't understand the gnome-terminal source well enough to know for sure if I've caused any issues, so far it seems to be working fine.

Here is a quick HOW-TO to patch the source RPM on Fedora 21:
  • Prepare your system to build RPMs
sudo yum install -y rpmdevtools
rpmdev-setuptree
  • Grab the source RPM for gnome-terminal and install it (note: no sudo here so installs in your own home dir):
yumdownloader --source gnome-terminal
rpm -ivh gnome-terminal-3.14.2-1.fc21.src.rpm
  • Add the above patch to the ~/rpmbuild/SOURCES directory
  • Add the patch to ~/rpmbuild/SPEC/gnome-terminal.spec using something like this in the appropriate sections:
Patch1: 0002-Restore-set-title-gnome-3-14.patch
# under %prep...
%patch1 -p1
  • Update the release number so you can update your currently installed version:
Release: 2%{?dist}
  • rpmbuild -bb gnome-terminal.spec
  • sudo rpm -Fvh ~/rpmbuild/RPMS/x86_64/*.rpm

You might need to install some additional packages the first time you build, but it should tell you which ones.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment