Merge lp:~niclasl/pantheon-terminal/fix-1218681 into lp:~elementary-apps/pantheon-terminal/trunk
- fix-1218681
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | David Gomes |
Approved revision: | 545 |
Merged at revision: | 544 |
Proposed branch: | lp:~niclasl/pantheon-terminal/fix-1218681 |
Merge into: | lp:~elementary-apps/pantheon-terminal/trunk |
Diff against target: |
172 lines (+74/-10) 1 file modified
src/PantheonTerminalWindow.vala (+74/-10) |
To merge this branch: | bzr merge lp:~niclasl/pantheon-terminal/fix-1218681 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Gomes (community) | Needs Fixing | ||
Niclas Lockner (community) | Approve | ||
Julián Unrrein (community) | Needs Fixing | ||
Review via email: mp+184483@code.launchpad.net |
Commit message
Implemented support for restoring tabs.
Fixes bug #1218681.
Description of the change
DynamicNotebook: Fixed support for restoring closed tabs #1218681.
David Gomes (davidgomes) wrote : | # |
>tab.restore_data = t.get_shell_
If you have two tabs in the same location won't that mess it up? Shouldn't restore_data be an unique ID? I'm never sure what restore_data is for.
In any case, remove the trailing whitespace you added.
Niclas Lockner (niclasl) wrote : | # |
I'm not by my computer at the moment, but if I remember it correctly, the tab is only added to the ClosedTabs object in the DynamicNotebook object if it has a unique restore_data. At the moment, two closed tabs with the same location leads to only one of the tabs being added to the list of restorable tabs. This is the intended behavior, right?
And it seems that restore_data is intended to be whatever helps restoring the tab. I looked at how it was done in Files, and I think it also used the tab's current location.
Have you had time to speak to voldyman about the signals?
Julien Spautz (julien-spautz) wrote : | # |
As Niclas said, the restore_data has to be unique.
There is no real limitation as to what you put into restore_data. In most cases a file path or URL/URI is the easiest thing to do, but it could also be some sort of ID.
See the original blueprint: https:/
I haven't tested this branch, but I assume restoring a tab will only restore the location without the content, i.e. previously entered commands. I think it would be better to restore the content too. For this, you could store the terminal widgets in a hashmap, mapped to some ID, which you'll assign to restore_data.
I hope that clears things up a little.
Niclas Lockner (niclasl) wrote : | # |
I agree that saving the actual terminal and not only the directory would be more useful, but if I'm going to save the TerminalWidget object when a tab is closed, shouldn't there be a maximum number of stored objects, e.g. 10 last closed? If not, then hidden terminal widgets and bash processes would keep accumulating while the window is kept open. If it is limited, the same limit would need to be added to DynamicNotebook so that it doesn't store unlimited number of tabs.
The problem with the tab that gets added to the first window's trash bin even though it was closed in the second window seems to be related to DynamicNotebook as well. When the tab is moved from window A to window B, the signal handlers that the notebook in window A added to the tab are kept alongside the new handlers added by the notebook in window B. When the tab is closed, the connected signals from both window A and B are activated and therefore the tab ends up in window A's trash bin.
So how should I proceed with this? It looks like this cannot be fixed (in a nice way) without also touching DynamicNotebook.
Julien Spautz (julien-spautz) wrote : | # |
The tab ending up in the wrong window is a granite bug that you cannot fix here.
I'm not sure if the maximum amount of closed tabs should be hardcoded or be allowed to vary across apps, that needs some discussion, but there should definitely be a limit.
I don't know Terminal's code very well, but is there a way to store the content of a terminal widget more efficiently? Assuming we don't allow closing tabs with background processes, it would be sufficient to save the text only, which might be a more viable solution, if storing the terminal widgets themselves takes up too much memory.
Niclas Lockner (niclasl) wrote : | # |
I'll file a separate bug report for granite then.
I cannot find anything in the API that suggests that it's possible to insert a text to a Vte.Terminal object, which makes sense I guess. And even though it would be possible, the terminal widget is not completely restored anyway since the command history probably wont be restored (it is the bash process that holds that information, right?)
Niclas Lockner (niclasl) wrote : | # |
Okay, so my plan to solve this is as follows.
I create my own branch of Granite, where I
* solve the signal issue
* implement an upper limit (changeable with a setter) of the number of restorable tabs
* implement a new signal on the tab that gets activated when DynamicNotebook removes the tab from the set of restorable tabs (due to the limit being exceeded, or "Clear All" being pressed)
In this pantheon-terminal branch, I will
* store closed terminal widgets in a hashmap, as Julien suggests.
* let restored tabs reuse the existing terminal widget
* connect a callback to the "tab no longer restorable" signal that removes the terminal widget from the hashmap.
The Granite branch is just so that I have something to work with in pantheon-terminal, but if you like the changes you can use them as you like.
Does this sound good?
Julián Unrrein (junrrein) wrote : | # |
Hi Niclas,
Your plan sounds perfectly reasonable, you can go with it.
However, the Granite branch will need to get merged for your Terminal branch to get merged too.
David Gomes (davidgomes) wrote : | # |
Remove the extra trailing whitepsace you added.
David Gomes (davidgomes) : | # |
- 521. By Launchpad Translations on behalf of elementary-apps
-
Launchpad automatic translations update.
- 522. By Cody Garver
-
Silence C compilation warnings.
- 523. By David Gomes
-
Got rid of all the using statements.
- 524. By Rui Gomes
-
Minor fixes to the INSTALL file.
- 525. By Jeremy Wootten
-
Fixed bug #1208140, moved -d to -w, steps necessary taken to fix #1033456 in Files.
- 526. By Cody Garver
-
Release 0.2.4
- 527. By Sergey "Shnatsel" Davidoff
-
Use proper NoDisplay value to stop "Open Terminal Here" from showing up in Slingshot and other application launchers.
- 528. By Cody Garver
-
Release 0.2.4.1
- 529. By Launchpad Translations on behalf of elementary-apps
-
Launchpad automatic translations update.
- 530. By Launchpad Translations on behalf of elementary-apps
-
Launchpad automatic translations update.
- 531. By Niclas Lockner
-
Removed unused code
- 532. By Akshay Shekher
-
License fixes
- 533. By Launchpad Translations on behalf of elementary-apps
-
Launchpad automatic translations update.
David Gomes (davidgomes) : | # |
- 534. By Niclas Lockner
-
Made compatible with DynamicNotebook's new API.
- 535. By David Gomes
-
Granite version bump.
- 536. By David Gomes
-
Fixed typo.
- 537. By Niclas Lockner
-
Small-scale refactorization.
Simplified tab closing and window state saving, as well as the visibility of the tab bar code.
Silenced runtime errors and compiler warnings.
Fixed shell processes not being killed as well as follow-last-tab behavior not working correctly. - 538. By Jeremy Wootten
-
Changed "Open Terminal Here" to simply "Terminal".
- 539. By Niclas Lockner
-
Implemented support for restoring tabs
Niclas Lockner (niclasl) wrote : | # |
This is now ready to be reviewed again
- 540. By Niclas Lockner
-
Remove removed tab from the terminals list
Niclas Lockner (niclasl) wrote : | # |
I just noticed the missing space after create_tab. I'll fix that later today.
- 541. By Niclas Lockner
-
Code-style fix
- 542. By Niclas Lockner
-
Code-style fix
Niclas Lockner (niclasl) wrote : | # |
Code-style fixed
- 543. By Niclas Lockner
-
Catch Ctrl+D
- 544. By Niclas Lockner
-
Catch both Ctrl + d and D
David Gomes (davidgomes) wrote : | # |
There seems to be a bug. Say I have two tabs open and I close the second one with Ctrl+Shift+W or Ctrl+D, the first tab isn't focused. I think it's a problem with your branch because it doesn't happen with trunk.
- 545. By Niclas Lockner
-
Let the new terminal grab the focus after the old one is closed
David Gomes (davidgomes) wrote : | # |
Diff lines 46-47. Maybe you should just call action_close_tab () there?
Preview Diff
1 | === modified file 'src/PantheonTerminalWindow.vala' |
2 | --- src/PantheonTerminalWindow.vala 2013-12-26 21:48:07 +0000 |
3 | +++ src/PantheonTerminalWindow.vala 2014-01-21 20:49:25 +0000 |
4 | @@ -29,6 +29,8 @@ |
5 | private Gtk.Clipboard clipboard; |
6 | |
7 | private GLib.List <TerminalWidget> terminals = new GLib.List <TerminalWidget> (); |
8 | + private HashTable<string, TerminalWidget> restorable_terminals; |
9 | + private int restorable_counter = 0; |
10 | |
11 | public TerminalWidget current_terminal = null; |
12 | private bool is_fullscreen = false; |
13 | @@ -139,6 +141,9 @@ |
14 | open_tabs (); |
15 | |
16 | set_size_request (app.minimum_width, app.minimum_height); |
17 | + |
18 | + destroy.connect (on_destroy); |
19 | + restorable_terminals = new HashTable<string, TerminalWidget> (str_hash, str_equal); |
20 | } |
21 | |
22 | private void setup_ui () { |
23 | @@ -161,11 +166,14 @@ |
24 | notebook.tab_switched.connect (on_switch_page); |
25 | notebook.tab_moved.connect (on_tab_moved); |
26 | notebook.tab_reordered.connect (on_tab_reordered); |
27 | + notebook.tab_restored.connect (on_tab_restored); |
28 | notebook.tab_duplicated.connect (on_tab_duplicated); |
29 | notebook.close_tab_requested.connect (on_close_tab_requested); |
30 | notebook.new_tab_requested.connect (on_new_tab_requested); |
31 | notebook.allow_new_window = true; |
32 | notebook.allow_duplication = true; |
33 | + notebook.allow_restoring = true; |
34 | + notebook.max_restorable_tabs = 5; |
35 | notebook.group_name = "pantheon-terminal"; |
36 | notebook.can_focus = false; |
37 | add (notebook); |
38 | @@ -218,6 +226,17 @@ |
39 | } |
40 | |
41 | break; |
42 | + case Gdk.Key.@D: |
43 | + case Gdk.Key.@d: |
44 | + if ((e.state & Gdk.ModifierType.CONTROL_MASK) != 0) { |
45 | + if (!current_terminal.has_foreground_process ()) { |
46 | + current_terminal.tab.close (); |
47 | + current_terminal.grab_focus (); |
48 | + return true; |
49 | + } |
50 | + } |
51 | + |
52 | + break; |
53 | } |
54 | |
55 | return false; |
56 | @@ -291,7 +310,14 @@ |
57 | } |
58 | } |
59 | |
60 | - t.kill_ps (); |
61 | + if (!t.child_has_exited) { |
62 | + if (notebook.n_tabs >= 2) { |
63 | + make_restorable (tab); |
64 | + } else { |
65 | + t.kill_ps (); |
66 | + } |
67 | + } |
68 | + |
69 | if (notebook.n_tabs - 1 == 0) { |
70 | update_saved_window_state (); |
71 | reset_saved_tabs (); |
72 | @@ -304,6 +330,16 @@ |
73 | current_terminal.grab_focus (); |
74 | } |
75 | |
76 | + private void on_tab_restored (string label, string restore_key, GLib.Icon? icon) { |
77 | + TerminalWidget term = restorable_terminals.get (restore_key); |
78 | + var tab = create_tab (label, icon, term); |
79 | + |
80 | + restorable_terminals.remove (restore_key); |
81 | + notebook.insert_tab (tab, -1); |
82 | + notebook.current = tab; |
83 | + term.grab_focus (); |
84 | + } |
85 | + |
86 | private void on_tab_moved (Granite.Widgets.Tab tab, int x, int y) { |
87 | var new_window = app.new_window_with_coords (x, y, false); |
88 | var terminal = (tab.page as Gtk.Grid).get_child_at (0, 0) as TerminalWidget; |
89 | @@ -407,10 +443,6 @@ |
90 | /* Set up terminal */ |
91 | var t = new TerminalWidget (this); |
92 | t.scrollback_lines = settings.scrollback_lines; |
93 | - var g = new Gtk.Grid (); |
94 | - var sb = new Gtk.Scrollbar (Gtk.Orientation.VERTICAL, t.vadjustment); |
95 | - g.attach (t, 0, 0, 1, 1); |
96 | - g.attach (sb, 1, 0, 1, 1); |
97 | |
98 | /* Make the terminal occupy the whole GUI */ |
99 | t.vexpand = true; |
100 | @@ -426,14 +458,11 @@ |
101 | t.run_program (program); |
102 | } |
103 | |
104 | - var tab = new Granite.Widgets.Tab (_("Terminal"), null, g); |
105 | - |
106 | - t.tab = tab; |
107 | - tab.ellipsize_mode = Pango.EllipsizeMode.START; |
108 | + var tab = create_tab (_("Terminal"), null, t); |
109 | |
110 | t.child_exited.connect (() => { |
111 | if (!t.killed) { |
112 | - tab.close (); |
113 | + t.tab.close (); |
114 | } |
115 | }); |
116 | |
117 | @@ -450,6 +479,34 @@ |
118 | t.grab_focus (); |
119 | } |
120 | |
121 | + private Granite.Widgets.Tab create_tab (string label, GLib.Icon? icon, TerminalWidget term) { |
122 | + var g = new Gtk.Grid (); |
123 | + var sb = new Gtk.Scrollbar (Gtk.Orientation.VERTICAL, term.vadjustment); |
124 | + g.attach (term, 0, 0, 1, 1); |
125 | + g.attach (sb, 1, 0, 1, 1); |
126 | + var tab = new Granite.Widgets.Tab (label, icon, g); |
127 | + term.tab = tab; |
128 | + tab.ellipsize_mode = Pango.EllipsizeMode.START; |
129 | + |
130 | + return tab; |
131 | + } |
132 | + |
133 | + private void make_restorable (Granite.Widgets.Tab tab) { |
134 | + var restore_key = "%d".printf (restorable_counter++); |
135 | + var page = tab.page as Gtk.Grid; |
136 | + var term = page.get_child_at (0, 0) as TerminalWidget; |
137 | + |
138 | + terminals.remove (term); |
139 | + page.remove (term); |
140 | + restorable_terminals.insert (restore_key, term); |
141 | + tab.restore_data = restore_key; |
142 | + tab.dropped_callback = (() => { |
143 | + unowned TerminalWidget t = restorable_terminals.get (tab.restore_data); |
144 | + t.kill_ps (); |
145 | + restorable_terminals.remove (tab.restore_data); |
146 | + }); |
147 | + } |
148 | + |
149 | public void run_program_term (string program) { |
150 | new_tab ("", program); |
151 | } |
152 | @@ -494,6 +551,12 @@ |
153 | return false; |
154 | } |
155 | |
156 | + private void on_destroy () { |
157 | + foreach (unowned TerminalWidget t in restorable_terminals.get_values ()) { |
158 | + t.kill_ps (); |
159 | + } |
160 | + } |
161 | + |
162 | void action_quit () { |
163 | |
164 | } |
165 | @@ -516,6 +579,7 @@ |
166 | |
167 | void action_close_tab () { |
168 | current_terminal.tab.close (); |
169 | + current_terminal.grab_focus (); |
170 | } |
171 | |
172 | void action_new_window () { |
Code style:
Newline after diff line 29.
Testing:
1) Have at least two tabs opened in a Terminal window.
2) Drag one of them to form a new window.
3) Open at least one other tab in this new window (so that the dragged tab isn't the only one).
4) Close the dragged tab.
The closed dragged tab goes to the trash bin in the original window, instead of the new one as it should be.
Note that the new window may close itself when closing the dragged tab (this is known to happen in trunk).