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',