Pending:
* Drag and drop clipboard utility
* Find and apply the VTE get_text method to save at store session in the journal or think in other data to save.
Signed-off-by: Agustin Zubiaga <aguz@sugarlabs.org>
Signed-off-by: Daniel Francis <francis@sugarlabs.org>
Signed-off-by: Manuel Kaufmann <humitos@gmail.com>
---
terminal.py | 102 +++++++++++++++++++++++++++++++++--------------------------
1 file changed, 57 insertions(+), 45 deletions(-)
diff --git a/terminal.py b/terminal.py
index ee46fdc..6a5c0df 100644
a
|
b
|
import ConfigParser |
23 | 23 | import logging |
24 | 24 | from gettext import gettext as _ |
25 | 25 | |
26 | | import gtk |
27 | | import vte |
28 | | import pango |
29 | | |
30 | | from sugar.graphics.toolbutton import ToolButton |
31 | | from sugar.graphics.toolbarbox import ToolbarBox |
32 | | from sugar.graphics.toolbarbox import ToolbarButton |
33 | | from sugar.graphics.notebook import Notebook |
34 | | |
35 | | from sugar.activity.widgets import ActivityToolbarButton |
36 | | from sugar.activity.widgets import StopButton |
37 | | from sugar.activity import activity |
38 | | from sugar import env |
| 26 | from gi.repository import GLib |
| 27 | from gi.repository import Gtk |
| 28 | from gi.repository import Gdk |
| 29 | from gi.repository import Vte |
| 30 | from gi.repository import Pango |
| 31 | |
| 32 | from sugar3.graphics.toolbutton import ToolButton |
| 33 | from sugar3.graphics.toolbarbox import ToolbarBox |
| 34 | from sugar3.graphics.toolbarbox import ToolbarButton |
| 35 | from sugar3.graphics.notebook import Notebook |
| 36 | |
| 37 | from sugar3.activity.widgets import EditToolbar |
| 38 | from sugar3.activity.widgets import ActivityToolbarButton |
| 39 | from sugar3.activity.widgets import StopButton |
| 40 | from sugar3.activity import activity |
| 41 | from sugar3 import env |
39 | 42 | |
40 | 43 | MASKED_ENVIRONMENT = [ |
41 | 44 | 'DBUS_SESSION_BUS_ADDRESS', |
… |
… |
class TerminalActivity(activity.Activity): |
100 | 103 | toolbar_box.toolbar.insert(root_button, -1) |
101 | 104 | root_button.show() |
102 | 105 | |
103 | | separator = gtk.SeparatorToolItem() |
| 106 | separator = Gtk.SeparatorToolItem() |
104 | 107 | separator.props.draw = False |
105 | 108 | separator.set_expand(True) |
106 | 109 | toolbar_box.toolbar.insert(separator, -1) |
… |
… |
class TerminalActivity(activity.Activity): |
116 | 119 | self._update_accelerators(toolbar_box) |
117 | 120 | |
118 | 121 | self._notebook = Notebook() |
119 | | self._notebook.set_property("tab-pos", gtk.POS_TOP) |
| 122 | self._notebook.set_property("tab-pos", Gtk.PositionType.TOP) |
120 | 123 | self._notebook.set_scrollable(True) |
121 | 124 | self._notebook.show() |
122 | 125 | |
… |
… |
class TerminalActivity(activity.Activity): |
131 | 134 | # This code is copied from toolbutton.py |
132 | 135 | # to solve workaround bug described in OLPC #10930 |
133 | 136 | accel_group = self.get_data('sugar-accel-group') |
134 | | keyval, mask = gtk.accelerator_parse( |
| 137 | keyval, mask = Gtk.accelerator_parse( |
135 | 138 | child.props.accelerator) |
136 | 139 | # the accelerator needs to be set at the child, |
137 | | # so the gtk.AccelLabel |
| 140 | # so the Gtk.AccelLabel |
138 | 141 | # in the palette can pick it up. |
139 | | child.child.add_accelerator('clicked', accel_group, |
| 142 | child.get_child().add_accelerator('clicked', accel_group, |
140 | 143 | keyval, mask, |
141 | | gtk.ACCEL_LOCKED | gtk.ACCEL_VISIBLE) |
| 144 | Gtk.AccelFlags.LOCKED | Gtk.AccelFlags.VISIBLE) |
142 | 145 | |
143 | 146 | if isinstance(child, ToolbarButton): |
144 | 147 | if child.get_page() is not None: |
… |
… |
class TerminalActivity(activity.Activity): |
147 | 150 | self._update_accelerators(child) |
148 | 151 | |
149 | 152 | def _create_edit_toolbar(self): |
150 | | edit_toolbar = activity.EditToolbar() |
| 153 | edit_toolbar = EditToolbar() |
151 | 154 | edit_toolbar.undo.props.visible = False |
152 | 155 | edit_toolbar.redo.props.visible = False |
153 | 156 | edit_toolbar.separator.props.visible = False |
… |
… |
class TerminalActivity(activity.Activity): |
167 | 170 | vt.paste_clipboard() |
168 | 171 | |
169 | 172 | def _create_view_toolbar(self): # Zoom toolbar |
170 | | view_toolbar = gtk.Toolbar() |
| 173 | view_toolbar = Gtk.Toolbar() |
171 | 174 | |
172 | 175 | zoom_out_button = ToolButton('zoom-out') |
173 | 176 | zoom_out_button.set_tooltip(_('Zoom out')) |
… |
… |
class TerminalActivity(activity.Activity): |
208 | 211 | self.fullscreen() |
209 | 212 | |
210 | 213 | def _create_tab_toolbar(self): |
211 | | tab_toolbar = gtk.Toolbar() |
| 214 | tab_toolbar = Gtk.Toolbar() |
212 | 215 | new_tab_button = ToolButton('tab-add') |
213 | 216 | new_tab_button.set_tooltip(_("Open New Tab")) |
214 | 217 | new_tab_button.props.accelerator = '<Ctrl><Shift>T' |
… |
… |
class TerminalActivity(activity.Activity): |
297 | 300 | return True |
298 | 301 | |
299 | 302 | def _create_tab(self, tab_state): |
300 | | vt = vte.Terminal() |
| 303 | vt = Vte.Terminal() |
301 | 304 | vt.connect("child-exited", self.__tab_child_exited_cb) |
302 | 305 | vt.connect("window-title-changed", self.__tab_title_changed_cb) |
303 | 306 | |
304 | 307 | # FIXME have to resend motion events to parent, see #1402 |
305 | 308 | vt.connect('motion-notify-event', self.__motion_notify_cb) |
306 | 309 | |
307 | | vt.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_DROP, |
308 | | [('text/plain', 0, 0), ('STRING', 0, 1)], |
309 | | gtk.gdk.ACTION_DEFAULT | |
310 | | gtk.gdk.ACTION_COPY) |
311 | | vt.connect('drag_data_received', self.__drag_data_received_cb) |
| 310 | #vt.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.DROP, |
| 311 | # [('text/plain', 0, 0), ('STRING', 0, 1)], |
| 312 | # Gdk.DragAction.DEFAULT | |
| 313 | # Gdk.DragAction.COPY) |
| 314 | #vt.connect('drag_data_received', self.__drag_data_received_cb) |
312 | 315 | |
313 | 316 | self._configure_vt(vt) |
314 | 317 | |
315 | 318 | vt.show() |
316 | 319 | |
317 | | label = gtk.Label() |
| 320 | label = Gtk.Label() |
318 | 321 | |
319 | | scrollbar = gtk.VScrollbar(vt.get_adjustment()) |
| 322 | scrollbar = Gtk.VScrollbar.new(vt.get_vadjustment()) |
320 | 323 | scrollbar.show() |
321 | 324 | |
322 | | box = gtk.HBox() |
323 | | box.pack_start(vt) |
324 | | box.pack_start(scrollbar) |
| 325 | box = Gtk.HBox() |
| 326 | box.pack_start(vt, True, True, 0) |
| 327 | box.pack_start(scrollbar, False, True, 0) |
325 | 328 | |
326 | 329 | box.vt = vt |
327 | 330 | box.label = label |
… |
… |
class TerminalActivity(activity.Activity): |
364 | 367 | for l in tab_state['scrollback']: |
365 | 368 | vt.feed(l + '\r\n') |
366 | 369 | |
367 | | box.pid = vt.fork_command() |
368 | | |
| 370 | box.pid = vt.fork_command_full(Vte.PtyFlags.DEFAULT, |
| 371 | os.environ["HOME"], |
| 372 | ["/bin/bash"], |
| 373 | [], |
| 374 | GLib.SpawnFlags.DO_NOT_REAP_CHILD, |
| 375 | None, |
| 376 | None) |
369 | 377 | self._notebook.props.page = index |
370 | 378 | vt.grab_focus() |
371 | 379 | |
372 | 380 | return index |
373 | 381 | |
374 | 382 | def __motion_notify_cb(self, widget, event): |
375 | | self.canvas.parent.emit('motion-notify-event', event) |
| 383 | self.emit('motion-notify-event', event) |
376 | 384 | |
377 | 385 | def __become_root_cb(self, button): |
378 | 386 | vt = self._notebook.get_nth_page(self._notebook.get_current_page()).vt |
379 | 387 | vt.feed('\r\n') |
380 | | vt.fork_command("/bin/su", ('/bin/su', '-')) |
| 388 | vt.fork_command_full(Vte.PtyFlags.DEFAULT, |
| 389 | os.environ["HOME"], |
| 390 | ["/bin/su"], |
| 391 | [], |
| 392 | GLib.SpawnFlags.DO_NOT_REAP_CHILD, |
| 393 | None, |
| 394 | None) |
381 | 395 | |
382 | 396 | def __key_press_cb(self, window, event): |
383 | 397 | """Route some keypresses directly to the vte and then drop them. |
… |
… |
class TerminalActivity(activity.Activity): |
392 | 406 | vt = self._notebook.get_nth_page(current_page).vt |
393 | 407 | vt.event(event) |
394 | 408 | |
395 | | key_name = gtk.gdk.keyval_name(event.keyval) |
| 409 | key_name = Gdk.keyval_name(event.keyval) |
396 | 410 | |
397 | 411 | # Escape is used in Sugar to cancel fullscreen mode. |
398 | 412 | if key_name == 'Escape': |
399 | 413 | event_to_vt(event) |
400 | 414 | return True |
401 | 415 | |
402 | | elif event.get_state() & gtk.gdk.CONTROL_MASK: |
| 416 | elif event.get_state() & Gdk.ModifierType.CONTROL_MASK: |
403 | 417 | if key_name in ['z', 'q']: |
404 | 418 | event_to_vt(event) |
405 | 419 | return True |
… |
… |
class TerminalActivity(activity.Activity): |
415 | 429 | data = simplejson.loads(text) |
416 | 430 | fd.close() |
417 | 431 | |
418 | | data_file = file_path |
419 | | |
420 | 432 | # Clean out any existing tabs. |
421 | 433 | while self._notebook.get_n_pages(): |
422 | 434 | self._notebook.remove_page(0) |
… |
… |
class TerminalActivity(activity.Activity): |
496 | 508 | conf.add_section('terminal') |
497 | 509 | |
498 | 510 | font = self._get_conf(conf, 'font', 'Monospace') |
499 | | vt.set_font(pango.FontDescription(font)) |
| 511 | vt.set_font(Pango.FontDescription(font)) |
500 | 512 | |
501 | 513 | fg_color = self._get_conf(conf, 'fg_color', '#000000') |
502 | 514 | bg_color = self._get_conf(conf, 'bg_color', '#FFFFFF') |
503 | | vt.set_colors(gtk.gdk.color_parse(fg_color), |
504 | | gtk.gdk.color_parse(bg_color), []) |
| 515 | vt.set_colors(Gdk.color_parse(fg_color), |
| 516 | Gdk.color_parse(bg_color), []) |
505 | 517 | |
506 | 518 | blink = self._get_conf(conf, 'cursor_blink', False) |
507 | | vt.set_cursor_blinks(blink) |
| 519 | vt.set_cursor_blink_mode(blink) |
508 | 520 | |
509 | 521 | bell = self._get_conf(conf, 'bell', False) |
510 | 522 | vt.set_audible_bell(bell) |