1/* 2 * notebook.vala - This file is part of the Geany MultiTerm plugin 3 * 4 * Copyright (c) 2012 Matthew Brush <matt@geany.org>. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 * MA 02110-1301, USA. 20 */ 21 22using Gtk; 23using Gdk; 24using Pango; 25using Vte; 26 27namespace MultiTerm 28{ 29 public class Notebook : Gtk.Notebook 30 { 31 private Button add_button; 32 public Config cfg; 33 private ContextMenu? context_menu; 34 35 private void on_tab_label_close_clicked(int tab_num) 36 { 37 if (this.get_n_pages() > 1) 38 this.remove_terminal(tab_num); 39 } 40 41 private void on_show_tabs_activate(bool show_tabs) 42 { 43 this.show_tabs = show_tabs; 44 cfg.show_tabs = show_tabs; 45 } 46 47 private bool on_next_tab_activate() 48 { 49 int n_tabs = this.get_n_pages(); 50 int current = this.get_current_page(); 51 52 if (current < (n_tabs - 1)) 53 { 54 current++; 55 this.set_current_page(current); 56 } 57 58 return (current < (n_tabs - 1)) ? true : false; 59 } 60 61 private bool on_previous_tab_activate() 62 { 63 int current = this.get_current_page(); 64 65 if (current > 0) 66 { 67 current--; 68 this.set_current_page(current); 69 } 70 71 return (current > 0) ? true : false; 72 } 73 74 private void on_new_shell_activate(ShellConfig cfg) 75 { 76 add_terminal(cfg); 77 } 78 79 private void on_new_window_activate() 80 { 81 Pid pid; 82 string[] args = { cfg.external_terminal, null }; 83 84 try 85 { 86 if (Process.spawn_async(null, args, null, SpawnFlags.SEARCH_PATH, null, out pid)) 87 debug("Started external terminal '%s' with pid of '%d'", args[0], pid); 88 } 89 catch (SpawnError err) 90 { 91 warning(_("Unable to launch external terminal: %s").printf(err.message)); 92 } 93 } 94 95 private void on_move_to_location(string location) 96 { 97 Container frame = this.get_parent() as Container; 98 Container parent = frame.get_parent() as Container; 99 Gtk.Notebook new_nb; 100 101 parent.remove(frame); 102 103 if (location == "msgwin") 104 { 105 new_nb = this.get_data<Notebook>("msgwin_notebook"); 106 new_nb.append_page(frame, this.get_data<Label>("label")); 107 } 108 else 109 { 110 new_nb = this.get_data<Notebook>("sidebar_notebook"); 111 new_nb.append_page(frame, this.get_data<Label>("label")); 112 } 113 114 new_nb.set_current_page(new_nb.page_num(frame)); 115 cfg.location = location; 116 } 117 118 private void on_add_button_style_set() 119 { 120 int w, h; 121 Gtk.icon_size_lookup_for_settings(add_button.get_settings(), 122 IconSize.MENU, 123 out w, out h); 124 add_button.set_size_request(w+2, h+2); 125 } 126 127 private void on_add_button_clicked() 128 { 129 foreach (ShellConfig sh in cfg.shell_configs) 130 { 131 if (sh.section.strip() == "shell=default") 132 { 133 add_terminal(sh); 134 return; 135 } 136 } 137 warning(_("Unable to locate default shell in configuration file")); 138 } 139 140 private bool on_terminal_right_click_event(EventButton event) 141 { 142 if (context_menu == null) 143 { 144 context_menu = new ContextMenu(cfg); 145 context_menu.show_tabs_activate.connect(on_show_tabs_activate); 146 context_menu.next_tab_activate.connect(on_next_tab_activate); 147 context_menu.previous_tab_activate.connect(on_previous_tab_activate); 148 context_menu.new_shell_activate.connect(on_new_shell_activate); 149 context_menu.new_window_activate.connect(on_new_window_activate); 150 context_menu.move_to_location_activate.connect(on_move_to_location); 151 } 152 context_menu.popup(null, null, null, event.button, event.time); 153 return true; 154 } 155 156 public Terminal add_terminal(ShellConfig cfg) 157 { 158 TabLabel label = new TabLabel(cfg.name); 159 Terminal term = new Terminal(cfg); 160 161 label.show_all(); 162 label.close_clicked.connect(on_tab_label_close_clicked); 163 label.set_data<Terminal>("terminal", term); 164 165 term.set_data<TabLabel>("label", label); 166 term.show_all(); 167 term.right_click_event.connect(on_terminal_right_click_event); 168 169 this.append_page(term, label); 170 this.set_tab_reorderable(term, true); 171 /* TODO: this is deprecated, try and figure out alternative 172 * from GtkNotebook docs. */ 173 this.set_tab_label_packing(term, true, true, PackType.END); 174 this.scrollable = true; 175 176 return term; 177 } 178 179 public void remove_terminal(int tab_num) 180 { 181 this.remove_page(tab_num); 182 } 183 184 public class Notebook(string config_filename) 185 { 186 Gtk.Image img; 187 RcStyle style; 188 189 cfg = new Config(config_filename); 190 191 style = new RcStyle(); 192 style.xthickness = 0; 193 style.ythickness = 0; 194 195 img = new Gtk.Image.from_stock(Gtk.Stock.ADD, Gtk.IconSize.MENU); 196 197 add_button = new Button(); 198 add_button.modify_style(style); 199 add_button.relief = ReliefStyle.NONE; 200 add_button.focus_on_click = false; 201 add_button.set_border_width(2); 202 add_button.set_tooltip_text(_("New terminal")); 203 add_button.add(img); 204 add_button.clicked.connect(on_add_button_clicked); 205 add_button.show_all(); 206 add_button.style_set.connect(on_add_button_style_set); 207 208 /* TODO: make this button show a list to select which shell 209 * to open */ 210 //this.set_action_widget(add_button, PackType.END); 211 212 this.show_tabs = cfg.show_tabs; 213 214 foreach (ShellConfig sh in cfg.shell_configs) 215 { 216 Terminal term = add_terminal(sh); 217 term.right_click_event.connect(on_terminal_right_click_event); 218 } 219 } 220 } 221} 222