diff --git a/data/io.elementary.code.gschema.xml b/data/io.elementary.code.gschema.xml
index bcbb4e40e7..e5ce805a54 100644
--- a/data/io.elementary.code.gschema.xml
+++ b/data/io.elementary.code.gschema.xml
@@ -47,6 +47,11 @@
Symbol outline visibility
Whether or not the symbol outline is visible
+
+ ''
+ Last opened path
+ Last opened path in the terminal
+
diff --git a/data/io.elementary.code.plugins.terminal.gschema.xml b/data/io.elementary.code.plugins.terminal.gschema.xml
deleted file mode 100644
index d668bbc1df..0000000000
--- a/data/io.elementary.code.plugins.terminal.gschema.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- ''
- Last opened path
- Last opened path in the terminal plugin
-
-
-
diff --git a/data/meson.build b/data/meson.build
index 7bc7e26c70..662a676fce 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -25,7 +25,6 @@ install_data([
install_data(
'io.elementary.code.gschema.xml',
'io.elementary.code.plugins.spell.gschema.xml',
- 'io.elementary.code.plugins.terminal.gschema.xml',
install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'glib-2.0', 'schemas')
)
diff --git a/meson.build b/meson.build
index 5ecfaa0641..d42c22ce46 100644
--- a/meson.build
+++ b/meson.build
@@ -38,6 +38,7 @@ git_dep = dependency('libgit2-glib-1.0')
fontconfig_dep = dependency('fontconfig')
pangofc_dep = dependency('pangoft2')
posix_dep = meson.get_compiler('vala').find_library('posix')
+vte_dep = dependency('vte-2.91')
code_resources = gnome.compile_resources(
'code-resources', 'data/' + meson.project_name() + '.gresource.xml',
@@ -62,7 +63,8 @@ dependencies = [
fontconfig_dep,
pangofc_dep,
posix_dep,
- vala_dep
+ vala_dep,
+ vte_dep
]
subdir('data')
diff --git a/plugins/meson.build b/plugins/meson.build
index 96d0e62a1d..aa8891eb76 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -8,6 +8,5 @@ subdir('markdown-actions')
subdir('pastebin')
subdir('preserve-indent')
subdir('spell')
-subdir('terminal')
subdir('vim-emulation')
subdir('word-completion')
diff --git a/plugins/terminal/meson.build b/plugins/terminal/meson.build
deleted file mode 100644
index 0b2852aa9a..0000000000
--- a/plugins/terminal/meson.build
+++ /dev/null
@@ -1,35 +0,0 @@
-module_name = 'terminal'
-
-module_files = [
- 'terminal.vala'
-]
-
-vte_dep = dependency('vte-2.91')
-
-module_deps = [
- codecore_dep,
- vte_dep
-]
-
-shared_module(
- module_name,
- module_files,
- dependencies: module_deps,
- install: true,
- install_dir: join_paths(pluginsdir, module_name)
-)
-
-custom_target(module_name + '.plugin_merge',
- input: module_name + '.plugin',
- output: module_name + '.plugin',
- command : [msgfmt,
- '--desktop',
- '--keyword=Description',
- '--keyword=Name',
- '-d' + join_paths(meson.source_root (), 'po', 'plugins'),
- '--template=@INPUT@',
- '-o@OUTPUT@',
- ],
- install : true,
- install_dir: join_paths(pluginsdir, module_name),
-)
diff --git a/plugins/terminal/terminal.plugin b/plugins/terminal/terminal.plugin
deleted file mode 100644
index 92be33a8de..0000000000
--- a/plugins/terminal/terminal.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Plugin]
-Module=terminal
-Loader=C
-IAge=2
-Name=Terminal
-Description=A terminal in your code editor
-Icon=utilities-terminal
-Authors=Mario Guerriero
-Copyright=Copyright © 2012 Code and Euclide Developers
-Website=https://github.com/elementary/code
diff --git a/plugins/terminal/terminal.vala b/plugins/terminal/terminal.vala
deleted file mode 100644
index 13caa54857..0000000000
--- a/plugins/terminal/terminal.vala
+++ /dev/null
@@ -1,373 +0,0 @@
-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
-/***
- BEGIN LICENSE
-
- Copyright (C) 2011-2013 Mario Guerriero
- This program is free software: you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License version 3, as published
- by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranties of
- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program. If not, see
-
- END LICENSE
-***/
-
-public class Scratch.Plugins.Terminal : Peas.ExtensionBase, Peas.Activatable {
- const double MIN_SCALE = 0.2;
- const double MAX_SCALE = 5.0;
-
- MainWindow window = null;
-
- private GLib.Settings settings;
-
- Gtk.Notebook? bottombar = null;
- Scratch.Widgets.HeaderBar? toolbar = null;
- Gtk.ToggleToolButton? tool_button = null;
-
- Vte.Terminal terminal;
- Gtk.Grid grid;
-
- GLib.Pid child_pid;
-
- private const string SETTINGS_SCHEMA = "io.elementary.terminal.settings";
- private const string LEGACY_SETTINGS_SCHEMA = "org.pantheon.terminal.settings";
-
- private string font_name = "";
-
- Scratch.Services.Interface plugins;
- public Object object { owned get; construct; }
-
- public void update_state () {
- }
-
- public void activate () {
-
- plugins = (Scratch.Services.Interface) object;
-
- plugins.hook_window.connect ((w) => {
- if (window != null)
- return;
-
- window = w;
- window.key_press_event.connect (on_window_key_press_event);
- window.destroy.connect (save_last_working_directory);
-
- });
-
- plugins.hook_notebook_bottom.connect ((n) => {
- if (bottombar == null) {
- this.bottombar = n;
- this.bottombar.switch_page.connect ((page, page_num) => {
- if (tool_button.active != (grid == page) && bottombar.page_num (grid) > -1)
- tool_button.active = (grid == page);
- });
- }
- });
-
- plugins.hook_toolbar.connect ((n) => {
- if (toolbar == null) {
- this.toolbar = n;
- on_hook_toolbar (this.toolbar);
- }
- });
-
- on_hook_notebook ();
- }
-
- public void deactivate () {
- if (terminal != null)
- grid.destroy ();
-
- if (tool_button != null)
- tool_button.destroy ();
-
- window.key_press_event.disconnect (on_window_key_press_event);
- window.destroy.disconnect (save_last_working_directory);
- }
-
- void save_last_working_directory () {
- settings.set_string ("last-opened-path", get_shell_location ());
- }
-
- bool on_window_key_press_event (Gdk.EventKey event) {
- /* t toggles focus between terminal and document */
- if (event.keyval == Gdk.Key.t
- && Gdk.ModifierType.MOD1_MASK in event.state
- && Gdk.ModifierType.CONTROL_MASK in event.state) {
-
- if (terminal.has_focus && window.get_current_document () != null) {
- window.get_current_document ().focus ();
- debug ("Move focus: EDITOR.");
- return true;
-
- } else if (window.get_current_document () != null &&
- window.get_current_document ().source_view.has_focus) {
-
- terminal.grab_focus ();
- debug ("Move focus: TERMINAL.");
- return true;
-
- }
- }
-
- if (terminal.has_focus) {
- /* Action any terminal hotkeys */
- return terminal.key_press_event (event);
- }
-
- return false;
- }
-
- void on_terminal_child_exited () {
- if (get_shell_location () == "") {
- // Terminal has no shell - close
- tool_button.active = false;
- }
- }
-
- bool on_terminal_key_press_event (Gdk.EventKey event) {
- var mods = (event.state & Gtk.accelerator_get_default_mod_mask ());
- bool control_pressed = ((mods & Gdk.ModifierType.CONTROL_MASK) != 0);
- bool other_mod_pressed = (((mods & ~Gdk.ModifierType.SHIFT_MASK) & ~Gdk.ModifierType.CONTROL_MASK) != 0);
- bool only_control_pressed = control_pressed && !other_mod_pressed; /* Shift can be pressed */
-
- if (only_control_pressed) {
- switch (event.keyval) {
- case Gdk.Key.plus:
- case Gdk.Key.KP_Add:
- case Gdk.Key.equal:
- increment_size ();
- return true;
-
- case Gdk.Key.minus:
- case Gdk.Key.KP_Subtract:
- decrement_size ();
- return true;
-
- case Gdk.Key.@0:
- case Gdk.Key.KP_0:
- set_default_font_size ();
- return true;
-
- default:
- break;
- }
- }
-
- return false;
- }
-
- void on_hook_toolbar (Scratch.Widgets.HeaderBar toolbar) {
- var icon = new Gtk.Image.from_icon_name ("utilities-terminal", Gtk.IconSize.LARGE_TOOLBAR);
- tool_button = new Gtk.ToggleToolButton ();
- tool_button.set_icon_widget (icon);
- tool_button.set_active (false);
- tool_button.tooltip_text = _("Show Terminal");
- tool_button.toggled.connect (() => {
- if (this.tool_button.active) {
- tool_button.tooltip_text = _("Hide Terminal");
- if (get_shell_location () == "") {
- // Terminal has no shell or was destroyed - recreate
- if (grid != null) {
- grid.destroy ();
- }
-
- on_hook_notebook ();
- }
-
- bottombar.set_current_page (bottombar.append_page (grid, new Gtk.Label (_("Terminal"))));
- terminal.grab_focus ();
- } else {
- tool_button.tooltip_text = _("Show Terminal");
- bottombar.remove_page (bottombar.page_num (grid));
- var document = window.get_current_document ();
- if (document != null) {
- document.focus ();
- }
- }
- });
-
- tool_button.show_all ();
-
- toolbar.pack_end (tool_button);
- }
-
- public string get_shell_location () {
- int pid = (!) (this.child_pid);
- try {
- return GLib.FileUtils.read_link ("/proc/%d/cwd".printf (pid));
- } catch (GLib.FileError error) {
- warning ("An error occurred while fetching the current dir of shell: %s", error.message);
- return "";
- }
- }
-
- void on_hook_notebook () {
- this.settings = new GLib.Settings (Constants.PROJECT_NAME + ".plugins.terminal");
- this.terminal = new Vte.Terminal ();
- this.terminal.scrollback_lines = -1;
-
- // Set font, allow-bold, audible-bell, background, foreground, and palette of pantheon-terminal
- var schema_source = SettingsSchemaSource.get_default ();
- var terminal_schema = schema_source.lookup (SETTINGS_SCHEMA, true);
- if (terminal_schema != null) {
- update_terminal_settings (SETTINGS_SCHEMA);
- } else {
- var legacy_terminal_schema = schema_source.lookup (LEGACY_SETTINGS_SCHEMA, true);
- if (legacy_terminal_schema != null) {
- update_terminal_settings (LEGACY_SETTINGS_SCHEMA);
- }
- }
-
- terminal.key_press_event.connect (on_terminal_key_press_event);
- terminal.child_exited.connect (on_terminal_child_exited);
-
- // Set terminal font
- if (font_name == "") {
- var system_settings = new GLib.Settings ("org.gnome.desktop.interface");
- font_name = system_settings.get_string ("monospace-font-name");
- }
-
- var fd = Pango.FontDescription.from_string (font_name);
- this.terminal.set_font (fd);
-
- // Popup menu
- var menu = new Gtk.Menu ();
-
- // COPY
- Gtk.MenuItem copy = new Gtk.MenuItem.with_label (_("Copy"));
- copy.activate.connect (() => {
- terminal.copy_clipboard ();
- });
- menu.append (copy);
-
- // PASTE
- Gtk.MenuItem paste = new Gtk.MenuItem.with_label (_("Paste"));
- paste.activate.connect (() => {
- terminal.paste_clipboard ();
- });
- menu.append (paste);
-
- menu.show_all ();
-
- this.terminal.button_press_event.connect ((event) => {
- if (event.button == 3) {
- menu.select_first (false);
- menu.popup_at_pointer (event);
- }
- return false;
- });
-
- try {
- var last_path_setting = settings.get_string ("last-opened-path");
- //FIXME Replace with the async method once the .vapi is fixed upstream.
- terminal.spawn_sync (
- Vte.PtyFlags.DEFAULT,
- last_path_setting == "" ? "~/" : last_path_setting,
- { Vte.get_user_shell () },
- null,
- GLib.SpawnFlags.SEARCH_PATH,
- null,
- out child_pid
- );
- } catch (GLib.Error e) {
- warning (e.message);
- }
-
- grid = new Gtk.Grid ();
- var sb = new Gtk.Scrollbar (Gtk.Orientation.VERTICAL, terminal.vadjustment);
- grid.attach (terminal, 0, 0, 1, 1);
- grid.attach (sb, 1, 0, 1, 1);
-
- // Make the terminal occupy the whole GUI
- terminal.vexpand = true;
- terminal.hexpand = true;
-
- grid.show_all ();
- }
-
- private void update_terminal_settings (string settings_schema) {
- var pantheon_terminal_settings = new GLib.Settings (settings_schema);
-
- font_name = pantheon_terminal_settings.get_string ("font");
-
- bool audible_bell_setting = pantheon_terminal_settings.get_boolean ("audible-bell");
- this.terminal.set_audible_bell (audible_bell_setting);
-
- string cursor_shape_setting = pantheon_terminal_settings.get_string ("cursor-shape");
-
- switch (cursor_shape_setting) {
- case "Block":
- this.terminal.cursor_shape = Vte.CursorShape.BLOCK;
- break;
- case "I-Beam":
- this.terminal.cursor_shape = Vte.CursorShape.IBEAM;
- break;
- case "Underline":
- this.terminal.cursor_shape = Vte.CursorShape.UNDERLINE;
- break;
- }
-
- string background_setting = pantheon_terminal_settings.get_string ("background");
- Gdk.RGBA background_color = Gdk.RGBA ();
- background_color.parse (background_setting);
-
- string foreground_setting = pantheon_terminal_settings.get_string ("foreground");
- Gdk.RGBA foreground_color = Gdk.RGBA ();
- foreground_color.parse (foreground_setting);
-
- string palette_setting = pantheon_terminal_settings.get_string ("palette");
-
- string[] hex_palette = {"#000000", "#FF6C60", "#A8FF60", "#FFFFCC", "#96CBFE",
- "#FF73FE", "#C6C5FE", "#EEEEEE", "#000000", "#FF6C60",
- "#A8FF60", "#FFFFB6", "#96CBFE", "#FF73FE", "#C6C5FE",
- "#EEEEEE"};
-
- string current_string = "";
- int current_color = 0;
- for (var i = 0; i < palette_setting.length; i++) {
- if (palette_setting[i] == ':') {
- hex_palette[current_color] = current_string;
- current_string = "";
- current_color++;
- } else {
- current_string += palette_setting[i].to_string ();
- }
- }
-
- Gdk.RGBA[] palette = new Gdk.RGBA[16];
-
- for (int i = 0; i < hex_palette.length; i++) {
- Gdk.RGBA new_color = Gdk.RGBA ();
- new_color.parse (hex_palette[i]);
- palette[i] = new_color;
- }
-
- this.terminal.set_colors (foreground_color, background_color, palette);
- }
-
- public void increment_size () {
- terminal.font_scale = (terminal.font_scale + 0.1).clamp (MIN_SCALE, MAX_SCALE);
- }
-
- public void decrement_size () {
- terminal.font_scale = (terminal.font_scale - 0.1).clamp (MIN_SCALE, MAX_SCALE);
- }
-
- public void set_default_font_size () {
- terminal.font_scale = 1.0;
- }
-}
-
-[ModuleInit]
-public void peas_register_types (GLib.TypeModule module) {
- var objmodule = module as Peas.ObjectModule;
- objmodule.register_extension_type (typeof (Peas.Activatable),
- typeof (Scratch.Plugins.Terminal));
-}
diff --git a/src/MainWindow.vala b/src/MainWindow.vala
index 2c0f378308..f89552e452 100644
--- a/src/MainWindow.vala
+++ b/src/MainWindow.vala
@@ -33,6 +33,7 @@ namespace Scratch {
private Gtk.Revealer search_revealer;
public Scratch.Widgets.SearchBar search_bar;
private Code.WelcomeView welcome_view;
+ private Code.Terminal terminal;
private FolderManager.FileView folder_manager_view;
private Scratch.Services.DocumentManager document_manager;
@@ -40,7 +41,6 @@ namespace Scratch {
private Scratch.Services.PluginsManager plugins;
// Widgets for Plugins
- public Gtk.Notebook bottombar;
public Code.Sidebar sidebar;
private Granite.Dialog? preferences_dialog = null;
@@ -89,6 +89,7 @@ namespace Scratch {
public const string ACTION_TOGGLE_COMMENT = "action_toggle_comment";
public const string ACTION_TOGGLE_SIDEBAR = "action_toggle_sidebar";
public const string ACTION_TOGGLE_OUTLINE = "action_toggle_outline";
+ public const string ACTION_TOGGLE_TERMINAL = "action-toggle-terminal";
public const string ACTION_NEXT_TAB = "action_next_tab";
public const string ACTION_PREVIOUS_TAB = "action_previous_tab";
public const string ACTION_CLEAR_LINES = "action_clear_lines";
@@ -132,6 +133,7 @@ namespace Scratch {
{ ACTION_ZOOM_OUT, action_zoom_out},
{ ACTION_TOGGLE_COMMENT, action_toggle_comment },
{ ACTION_TOGGLE_SIDEBAR, action_toggle_sidebar, null, "true" },
+ { ACTION_TOGGLE_TERMINAL, action_toggle_terminal, null, "false"},
{ ACTION_TOGGLE_OUTLINE, action_toggle_outline, null, "false" },
{ ACTION_NEXT_TAB, action_next_tab },
{ ACTION_PREVIOUS_TAB, action_previous_tab },
@@ -182,6 +184,7 @@ namespace Scratch {
action_accelerators.set (ACTION_TOGGLE_COMMENT, "slash");
action_accelerators.set (ACTION_TOGGLE_SIDEBAR, "F9"); // GNOME
action_accelerators.set (ACTION_TOGGLE_SIDEBAR, "backslash"); // Atom
+ action_accelerators.set (ACTION_TOGGLE_TERMINAL, "t");
action_accelerators.set (ACTION_TOGGLE_OUTLINE, "backslash");
action_accelerators.set (ACTION_NEXT_TAB, "Tab");
action_accelerators.set (ACTION_PREVIOUS_TAB, "Tab");
@@ -403,12 +406,10 @@ namespace Scratch {
folder_manager_view.restore_saved_state ();
- bottombar = new Gtk.Notebook ();
- bottombar.no_show_all = true;
- bottombar.page_removed.connect (() => { on_plugin_toggled (bottombar); });
- bottombar.page_added.connect (() => {
- on_plugin_toggled (bottombar);
- });
+ terminal = new Code.Terminal () {
+ no_show_all = true,
+ visible = false
+ };
var view_grid = new Gtk.Grid () {
orientation = Gtk.Orientation.VERTICAL
@@ -432,7 +433,7 @@ namespace Scratch {
vp = new Gtk.Paned (Gtk.Orientation.VERTICAL);
vp.position = (height - 150);
vp.pack1 (content_stack, true, false);
- vp.pack2 (bottombar, false, false);
+ vp.pack2 (terminal, false, false);
var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
box.add (toolbar);
@@ -462,7 +463,6 @@ namespace Scratch {
plugins.hook_window (this);
plugins.hook_toolbar (toolbar);
plugins.hook_share_menu (toolbar.share_menu);
- plugins.hook_notebook_bottom (bottombar);
};
plugins.extension_added.connect (() => {
@@ -581,13 +581,6 @@ namespace Scratch {
return false;
}
- private void on_plugin_toggled (Gtk.Notebook notebook) {
- var pages = notebook.get_n_pages ();
- notebook.set_show_tabs (pages > 1);
- notebook.no_show_all = (pages == 0);
- notebook.visible = (pages > 0);
- }
-
protected override bool delete_event (Gdk.EventAny event) {
handle_quit ();
return !check_unsaved_changes ();
@@ -607,11 +600,6 @@ namespace Scratch {
Utils.action_from_group (ACTION_REVERT, actions).set_enabled (val);
search_bar.sensitive = val;
toolbar.share_app_menu.sensitive = val;
-
- // PlugIns
- if (val) {
- on_plugin_toggled (bottombar);
- }
}
// Get current document
@@ -713,16 +701,19 @@ namespace Scratch {
}
public void set_default_zoom () {
+ terminal.set_default_font_size ();
Scratch.settings.set_string ("font", get_current_font () + " " + get_default_font_size ().to_string ());
}
// Ctrl + scroll
public void action_zoom_in () {
+ terminal.increment_size ();
zooming (Gdk.ScrollDirection.UP);
}
// Ctrl + scroll
public void action_zoom_out () {
+ terminal.decrement_size ();
zooming (Gdk.ScrollDirection.DOWN);
}
@@ -1110,6 +1101,21 @@ namespace Scratch {
sidebar.visible = action.get_state ().get_boolean ();
}
+ private void action_toggle_terminal () {
+ var terminal_action = Utils.action_from_group (ACTION_TOGGLE_TERMINAL, actions);
+ terminal_action.set_state (!terminal_action.get_state ().get_boolean ());
+
+ terminal.visible = terminal_action.get_state ().get_boolean ();
+
+ if (terminal_action.get_state ().get_boolean ()) {
+ terminal.no_show_all = false;
+ terminal.show_all ();
+ terminal.grab_focus ();
+ } else if (get_current_document () != null) {
+ get_current_document ().focus ();
+ }
+ }
+
private void action_toggle_outline (SimpleAction action) {
action.set_state (!action.get_state ().get_boolean ());
document_view.outline_visible = action.get_state ().get_boolean ();
diff --git a/src/Services/PluginManager.vala b/src/Services/PluginManager.vala
index dbe1c08843..4287bc1a73 100644
--- a/src/Services/PluginManager.vala
+++ b/src/Services/PluginManager.vala
@@ -28,7 +28,6 @@ namespace Scratch.Services {
public signal void hook_share_menu (Gtk.Menu menu);
public signal void hook_toolbar (Scratch.Widgets.HeaderBar toolbar);
public signal void hook_notebook_sidebar (Gtk.Notebook notebook);
- public signal void hook_notebook_bottom (Gtk.Notebook notebook);
public signal void hook_document (Scratch.Services.Document doc);
public signal void hook_preferences_dialog (Scratch.Dialogs.Preferences dialog);
@@ -132,9 +131,7 @@ namespace Scratch.Services {
this.hook_toolbar.connect ((t) => {
plugin_iface.hook_toolbar (t);
});
- this.hook_notebook_bottom.connect ((n) => {
- plugin_iface.hook_notebook_bottom (n);
- });
+
this.hook_document.connect ((d) => {
plugin_iface.hook_document (d);
});
diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala
index 444663efb9..c7d94ae021 100644
--- a/src/Widgets/HeaderBar.vala
+++ b/src/Widgets/HeaderBar.vala
@@ -189,6 +189,15 @@ namespace Scratch.Widgets {
image = new Gtk.Image.from_icon_name ("panel-left-symbolic", Gtk.IconSize.MENU)
};
+ var terminal_button = new Gtk.ToggleButton () {
+ action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_TERMINAL,
+ image = new Gtk.Image.from_icon_name ("panel-bottom-symbolic", Gtk.IconSize.MENU)
+ };
+ terminal_button.tooltip_markup = Granite.markup_accel_tooltip (
+ app_instance.get_accels_for_action (terminal_button.action_name),
+ _("Show Terminal")
+ );
+
outline_button = new Gtk.ToggleButton () {
action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_OUTLINE,
image = new Gtk.Image.from_icon_name ("panel-right-symbolic", Gtk.IconSize.MENU)
@@ -203,6 +212,7 @@ namespace Scratch.Widgets {
};
panels_box.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED);
panels_box.add (sidebar_button);
+ panels_box.add (terminal_button);
panels_box.add (outline_button);
var preferences_menuitem = new Gtk.ModelButton ();
@@ -248,6 +258,20 @@ namespace Scratch.Widgets {
show_all ();
+ terminal_button.toggled.connect (() => {
+ if (terminal_button.active) {
+ terminal_button.tooltip_markup = Granite.markup_accel_tooltip (
+ app_instance.get_accels_for_action (terminal_button.action_name),
+ _("Hide Terminal")
+ );
+ } else {
+ terminal_button.tooltip_markup = Granite.markup_accel_tooltip (
+ app_instance.get_accels_for_action (terminal_button.action_name),
+ _("Show Terminal")
+ );
+ }
+ });
+
share_menu.insert.connect (on_share_menu_changed);
share_menu.remove.connect (on_share_menu_changed);
diff --git a/src/Widgets/Terminal.vala b/src/Widgets/Terminal.vala
new file mode 100644
index 0000000000..5f0baad88d
--- /dev/null
+++ b/src/Widgets/Terminal.vala
@@ -0,0 +1,177 @@
+/*
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ * SPDX-FileCopyrightText: 2022 elementary, Inc. (https://elementary.io)
+ * 2011-2013 Mario Guerriero
+ */
+
+public class Code.Terminal : Gtk.Box {
+ private const double MAX_SCALE = 5.0;
+ private const double MIN_SCALE = 0.2;
+ private const string LEGACY_SETTINGS_SCHEMA = "org.pantheon.terminal.settings";
+ private const string SETTINGS_SCHEMA = "io.elementary.terminal.settings";
+
+ private GLib.Pid child_pid;
+ private Vte.Terminal terminal;
+
+ construct {
+ terminal = new Vte.Terminal () {
+ hexpand = true,
+ vexpand = true,
+ scrollback_lines = -1
+ };
+
+ // Set font, allow-bold, audible-bell, background, foreground, and palette of pantheon-terminal
+ var schema_source = SettingsSchemaSource.get_default ();
+ var terminal_schema = schema_source.lookup (SETTINGS_SCHEMA, true);
+ if (terminal_schema != null) {
+ update_terminal_settings (SETTINGS_SCHEMA);
+ } else {
+ var legacy_terminal_schema = schema_source.lookup (LEGACY_SETTINGS_SCHEMA, true);
+ if (legacy_terminal_schema != null) {
+ update_terminal_settings (LEGACY_SETTINGS_SCHEMA);
+ }
+ }
+
+ terminal.child_exited.connect (() => {
+ GLib.Application.get_default ().activate_action (Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_TOGGLE_TERMINAL, null);
+ });
+
+ var copy = new Gtk.MenuItem.with_label (_("Copy"));
+ copy.activate.connect (() => {
+ terminal.copy_clipboard ();
+ });
+
+ var paste = new Gtk.MenuItem.with_label (_("Paste"));
+ paste.activate.connect (() => {
+ terminal.paste_clipboard ();
+ });
+
+ var menu = new Gtk.Menu ();
+ menu.append (copy);
+ menu.append (paste);
+ menu.show_all ();
+
+ terminal.button_press_event.connect ((event) => {
+ if (event.button == 3) {
+ menu.select_first (false);
+ menu.popup_at_pointer (event);
+ }
+ return false;
+ });
+
+ var settings = new Settings (Constants.PROJECT_NAME + ".saved-state");
+ try {
+ var last_path_setting = settings.get_string ("last-opened-path");
+ //FIXME Replace with the async method once the .vapi is fixed upstream.
+ terminal.spawn_sync (
+ Vte.PtyFlags.DEFAULT,
+ last_path_setting == "" ? "~/" : last_path_setting,
+ { Vte.get_user_shell () },
+ null,
+ GLib.SpawnFlags.SEARCH_PATH,
+ null,
+ out child_pid
+ );
+ } catch (GLib.Error e) {
+ warning (e.message);
+ }
+
+ var scrolled_window = new Gtk.ScrolledWindow (null, terminal.get_vadjustment ());
+ scrolled_window.add (terminal);
+
+ add (scrolled_window);
+
+ destroy.connect (() => {
+ settings.set_string ("last-opened-path", get_shell_location ());
+ });
+ }
+
+ private string get_shell_location () {
+ int pid = (!) (this.child_pid);
+ try {
+ return GLib.FileUtils.read_link ("/proc/%d/cwd".printf (pid));
+ } catch (GLib.FileError error) {
+ warning ("An error occurred while fetching the current dir of shell: %s", error.message);
+ return "";
+ }
+ }
+
+ private void update_terminal_settings (string settings_schema) {
+ var pantheon_terminal_settings = new GLib.Settings (settings_schema);
+
+ var font_name = pantheon_terminal_settings.get_string ("font");
+ if (font_name == "") {
+ var system_settings = new GLib.Settings ("org.gnome.desktop.interface");
+ font_name = system_settings.get_string ("monospace-font-name");
+ }
+
+ var fd = Pango.FontDescription.from_string (font_name);
+ terminal.set_font (fd);
+
+ bool audible_bell_setting = pantheon_terminal_settings.get_boolean ("audible-bell");
+ this.terminal.set_audible_bell (audible_bell_setting);
+
+ string cursor_shape_setting = pantheon_terminal_settings.get_string ("cursor-shape");
+
+ switch (cursor_shape_setting) {
+ case "Block":
+ this.terminal.cursor_shape = Vte.CursorShape.BLOCK;
+ break;
+ case "I-Beam":
+ this.terminal.cursor_shape = Vte.CursorShape.IBEAM;
+ break;
+ case "Underline":
+ this.terminal.cursor_shape = Vte.CursorShape.UNDERLINE;
+ break;
+ }
+
+ string background_setting = pantheon_terminal_settings.get_string ("background");
+ Gdk.RGBA background_color = Gdk.RGBA ();
+ background_color.parse (background_setting);
+
+ string foreground_setting = pantheon_terminal_settings.get_string ("foreground");
+ Gdk.RGBA foreground_color = Gdk.RGBA ();
+ foreground_color.parse (foreground_setting);
+
+ string palette_setting = pantheon_terminal_settings.get_string ("palette");
+
+ string[] hex_palette = {"#000000", "#FF6C60", "#A8FF60", "#FFFFCC", "#96CBFE",
+ "#FF73FE", "#C6C5FE", "#EEEEEE", "#000000", "#FF6C60",
+ "#A8FF60", "#FFFFB6", "#96CBFE", "#FF73FE", "#C6C5FE",
+ "#EEEEEE"};
+
+ string current_string = "";
+ int current_color = 0;
+ for (var i = 0; i < palette_setting.length; i++) {
+ if (palette_setting[i] == ':') {
+ hex_palette[current_color] = current_string;
+ current_string = "";
+ current_color++;
+ } else {
+ current_string += palette_setting[i].to_string ();
+ }
+ }
+
+ Gdk.RGBA[] palette = new Gdk.RGBA[16];
+
+ for (int i = 0; i < hex_palette.length; i++) {
+ Gdk.RGBA new_color = Gdk.RGBA ();
+ new_color.parse (hex_palette[i]);
+ palette[i] = new_color;
+ }
+
+ this.terminal.set_colors (foreground_color, background_color, palette);
+ }
+
+ public void increment_size () {
+ terminal.font_scale = (terminal.font_scale + 0.1).clamp (MIN_SCALE, MAX_SCALE);
+ }
+
+ public void decrement_size () {
+ terminal.font_scale = (terminal.font_scale - 0.1).clamp (MIN_SCALE, MAX_SCALE);
+ }
+
+ public void set_default_font_size () {
+ terminal.font_scale = 1.0;
+ }
+}
diff --git a/src/meson.build b/src/meson.build
index 952db68485..2535e6fd96 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -45,6 +45,7 @@ code_files = files(
'Widgets/PaneSwitcher.vala',
'Widgets/SearchBar.vala',
'Widgets/SourceView.vala',
+ 'Widgets/Terminal.vala',
'Widgets/WelcomeView.vala',
'SymbolPane/SymbolOutline.vala',
'SymbolPane/Vala/ValaComparisonHelper.vala',