Merge lp:~jeremywootten/pantheon-files/drag-tab-to-new-window into lp:~elementary-apps/pantheon-files/trunk

Proposed by Jeremy Wootten
Status: Merged
Approved by: Danielle Foré
Approved revision: 1970
Merged at revision: 2121
Proposed branch: lp:~jeremywootten/pantheon-files/drag-tab-to-new-window
Merge into: lp:~elementary-apps/pantheon-files/trunk
Diff against target: 371 lines (+162/-51)
4 files modified
src/Application.vala (+81/-26)
src/QuicklistHandler.vala (+1/-1)
src/View/Sidebar.vala (+1/-1)
src/View/Window.vala (+79/-23)
To merge this branch: bzr merge lp:~jeremywootten/pantheon-files/drag-tab-to-new-window
Reviewer Review Type Date Requested Status
Danielle Foré ux Approve
Review via email: mp+291111@code.launchpad.net

Commit message

Form new windows by dragging tabs; limit rate and number of new windows.

Description of the change

This branch addresses some issues around window creation.

1) Implement forming new windows by dragging tabs out of the window. The window is created where dropped.
2) A limit is put on the rate of window creation using the keyboard (Ctrl-N).
3) Only one function in Application is now allowed to create windows.

To post a comment you must log in.
Revision history for this message
Danielle Foré (danrabbit) wrote :

I think your idea about hiding the sidebar on new windows makes sense, but you've introduced an issue where if you close that first window it's impossible to get the sidebar back. Even killing everything and resetting the dconf key, I can't get the sidebar back. We should probably enforce that if you close the "main window" the sidebar will show on one of the other windows.

If I hold down Ctrl N, after the 3rd window everything crashes

review: Needs Fixing
Revision history for this message
Danielle Foré (danrabbit) wrote :

The expander is super ugly :/

Revision history for this message
Jeremy Wootten (jeremywootten) wrote :

Expander now removed. Instead the sidebar is allowed to shrink to zero width and is hidden or revealed just by changing the position of the paned (mouse) or by pressing F9 (keyboard). The shortcut only affects the currently focused window and does not change the "show-sidebar" setting.

The visible sidebar width (paned position not the sidebar allocated width) is saved when the first window is closed.

On reopening the visible width of the sidebar is restored to the larger of the minimum sidebar width (default = 96) or the saved width, unless the "show-sidebar" setting is false.

1970. By Jeremy Wootten

Implement drag tab to new window

Revision history for this message
Jeremy Wootten (jeremywootten) wrote :

As requested, the branch has been pruned to contain only the drag to new tab feature. A new branch will be created based on this one, to implement the auto-tiling and sidebar in new window management.

Revision history for this message
Danielle Foré (danrabbit) wrote :

I can confirm that this branch solves the two issues now attached to it.

review: Approve (ux)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Application.vala'
--- src/Application.vala 2015-08-17 08:55:18 +0000
+++ src/Application.vala 2016-04-21 11:55:35 +0000
@@ -31,6 +31,7 @@
31 private Gtk.RecentManager recent;31 private Gtk.RecentManager recent;
3232
33 private const int MARLIN_ACCEL_MAP_SAVE_DELAY = 15;33 private const int MARLIN_ACCEL_MAP_SAVE_DELAY = 15;
34 private const uint MAX_WINDOWS = 25;
3435
35 public int window_count { get; private set; }36 public int window_count { get; private set; }
3637
@@ -109,7 +110,7 @@
109#endif110#endif
110111
111 window_count = 0;112 window_count = 0;
112 this.window_added.connect (() => {window_count++;});113 this.window_added.connect_after (() => {window_count++;});
113 this.window_removed.connect (() => {window_count--;});114 this.window_removed.connect (() => {window_count--;});
114 }115 }
115116
@@ -273,38 +274,78 @@
273 open_tabs (files);274 open_tabs (files);
274 else {275 else {
275 /* Open windows at each requested location. */276 /* Open windows at each requested location. */
276 foreach (var file in files)277 foreach (var file in files) {
277 open_window (file);278 create_window (file);
278 }279 }
279 }280 }
280281 }
281 public void create_window (File location = File.new_for_path (Environment.get_home_dir ()),282
282 Gdk.Screen screen = Gdk.Screen.get_default (),283 /* All window creation should be done via this function */
283 Marlin.ViewMode viewmode = Marlin.ViewMode.PREFERRED) {284 public Marlin.View.Window? create_window (File location = File.new_for_path (Environment.get_home_dir ()),
284285 Marlin.ViewMode viewmode = Marlin.ViewMode.PREFERRED,
285 open_window (location, screen, viewmode);286 int x = -1, int y = -1) {
286 }287
287288 if (this.get_windows ().length () >= MAX_WINDOWS) {
288 private void open_window (File? location, Gdk.Screen screen = Gdk.Screen.get_default (), Marlin.ViewMode viewmode = Marlin.ViewMode.PREFERRED) {289 return null;
289 (add_view_window (screen)).add_tab (location, viewmode);290 }
290 }291
291292 Marlin.View.Window win;
292 private Marlin.View.Window add_view_window (Gdk.Screen screen) {293 Gdk.Rectangle? new_win_rect = null;
293 var window = new Marlin.View.Window (this, screen);294 Gdk.Screen screen = Gdk.Screen.get_default ();
294 this.add_window (window as Gtk.Window);295 var aw = this.get_active_window ();
295 plugins.interface_loaded (window as Gtk.Widget);296 if (aw != null) {
296 return window;297 /* This is not the first window - determine size and position of new window */
298 int w, h;
299 aw.get_size (out w, out h);
300 /* Calculate difference between the visible width of the window and the width returned by Gtk+,
301 * which might include client side decorations (shadow) in some versions (bug 756618).
302 * Assumes top_menu stretches full visible width. */
303 var tm_aw = ((Marlin.View.Window)aw).top_menu.get_allocated_width ();
304 int shadow_width = (w - tm_aw) / 2;
305 shadow_width -= 10; //Allow a small gap between adjacent windows
306 screen = aw.get_screen ();
307 if (x <= 0 || y <= 0) {
308 /* Place holder for auto-tiling code. If missing then new window will be placed
309 * at the default position (centre of screen) */
310 } else { /* New window is a dropped tab */
311 /* Move new window so that centre of upper edge just inside the window is at mouse
312 * cursor position. This makes it easier for used to readjust window position with mouse if required.
313 */
314 x -= (shadow_width + w / 2);
315 y -= (shadow_width + 6);
316 new_win_rect = {x, y, w, h};
317 }
318 }
319
320 /* New window will not size or show itself if new_win_rect is not null */
321 win = new Marlin.View.Window (this, screen, new_win_rect == null);
322 this.add_window (win as Gtk.Window);
323 plugins.interface_loaded (win as Gtk.Widget);
324
325 if (!win.is_first_window) { /* First window will restore tabs itself */
326 win.add_tab (location, viewmode);
327 }
328
329 if (new_win_rect != null) {
330 move_resize_window (win, new_win_rect);
331 win.show ();
332 }
333
334 return win;
297 }335 }
298336
299 private void open_tabs (File[]? files, Gdk.Screen screen = Gdk.Screen.get_default ()) {337 private void open_tabs (File[]? files, Gdk.Screen screen = Gdk.Screen.get_default ()) {
300 Marlin.View.Window window = null;338 Marlin.View.Window window = null;
301339
302 /* Get the first window, if any, else create a new window */340 /* Get the first window, if any, else create a new window */
303 if (windows_exist ())341 if (windows_exist ()) {
304 window = (this.get_windows ()).data as Marlin.View.Window;342 window = (this.get_windows ()).data as Marlin.View.Window;
305 else343 } else {
306 window = add_view_window (screen);344 window = create_window ();
307345 if (window == null) { /* Maximum number of windows reached */
346 return;
347 }
348 }
308 if (files == null) {349 if (files == null) {
309 /* Restore session if settings allow */350 /* Restore session if settings allow */
310 if (!Preferences.settings.get_boolean ("restore-tabs") || window.restore_tabs () < 1) {351 if (!Preferences.settings.get_boolean ("restore-tabs") || window.restore_tabs () < 1) {
@@ -323,4 +364,18 @@
323 unowned List<weak Gtk.Window> windows = this.get_windows ();364 unowned List<weak Gtk.Window> windows = this.get_windows ();
324 return (windows != null && windows.data != null);365 return (windows != null && windows.data != null);
325 }366 }
367
368 private void move_resize_window (Gtk.Window win, Gdk.Rectangle? rect) {
369 if (rect == null) {
370 return;
371 }
372
373 if (rect.x > 0 && rect.y > 0) {
374 win.move (rect.x, rect.y);
375 }
376 if (rect.width > 0 && rect.height > 0) {
377 win.resize (rect.width, rect.height);
378 }
379 win.show ();
380 }
326}381}
327382
=== modified file 'src/QuicklistHandler.vala'
--- src/QuicklistHandler.vala 2015-05-03 06:44:42 +0000
+++ src/QuicklistHandler.vala 2016-04-21 11:55:35 +0000
@@ -104,7 +104,7 @@
104 menuitem.property_set ("label", bookmark.label);104 menuitem.property_set ("label", bookmark.label);
105 menuitem.item_activated.connect (() => {105 menuitem.item_activated.connect (() => {
106 var location = bookmark.get_location ();106 var location = bookmark.get_location ();
107 Marlin.Application.get ().create_window (location, Gdk.Screen.get_default ());107 Marlin.Application.get ().create_window (location);
108 });108 });
109109
110 ql.child_add_position (menuitem, index);110 ql.child_add_position (menuitem, index);
111111
=== modified file 'src/View/Sidebar.vala'
--- src/View/Sidebar.vala 2016-04-17 21:21:55 +0000
+++ src/View/Sidebar.vala 2016-04-21 11:55:35 +0000
@@ -1214,7 +1214,7 @@
1214 var location = mount.get_default_location ();1214 var location = mount.get_default_location ();
1215 if (flags == Marlin.OpenFlag.NEW_WINDOW) {1215 if (flags == Marlin.OpenFlag.NEW_WINDOW) {
1216 var app = Marlin.Application.get ();1216 var app = Marlin.Application.get ();
1217 app.create_window (location, window.get_screen ());1217 app.create_window (location);
1218 } else if (flags == Marlin.OpenFlag.NEW_TAB) {1218 } else if (flags == Marlin.OpenFlag.NEW_TAB) {
1219 window.add_tab (location, Marlin.ViewMode.CURRENT);1219 window.add_tab (location, Marlin.ViewMode.CURRENT);
1220 } else {1220 } else {
12211221
=== modified file 'src/View/Window.vala'
--- src/View/Window.vala 2016-04-12 08:47:09 +0000
+++ src/View/Window.vala 2016-04-21 11:55:35 +0000
@@ -57,6 +57,7 @@
57 public Chrome.ViewSwitcher view_switcher;57 public Chrome.ViewSwitcher view_switcher;
58 public Gtk.InfoBar info_bar;58 public Gtk.InfoBar info_bar;
59 public Granite.Widgets.DynamicNotebook tabs;59 public Granite.Widgets.DynamicNotebook tabs;
60 private Gtk.Paned lside_pane;
60 public Marlin.Places.Sidebar sidebar;61 public Marlin.Places.Sidebar sidebar;
61 public ViewContainer? current_tab = null;62 public ViewContainer? current_tab = null;
62 public uint window_number;63 public uint window_number;
@@ -86,7 +87,8 @@
86 action_edit_path ();87 action_edit_path ();
87 }88 }
8889
89 public Window (Marlin.Application app, Gdk.Screen myscreen) {90 public Window (Marlin.Application app, Gdk.Screen myscreen, bool show_window = true) {
91
90 /* Capture application window_count and active_window before they can change */92 /* Capture application window_count and active_window before they can change */
91 window_number = app.window_count;93 window_number = app.window_count;
92 application = app;94 application = app;
@@ -107,12 +109,23 @@
107109
108 connect_signals ();110 connect_signals ();
109 make_bindings ();111 make_bindings ();
110 show ();112
113 if (show_window) { /* otherwise Application will size and show window */
114 if (Preferences.settings.get_boolean("maximized")) {
115 maximize();
116 } else {
117 resize (Preferences.settings.get_int("window-width"),
118 Preferences.settings.get_int("window-height"));
119 }
120 show ();
121 }
111 }122 }
112123
113 private void build_window () {124 private void build_window () {
114 var lside_pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL);125 lside_pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL);
115 lside_pane.show ();126 lside_pane.show ();
127 /* Only show side bar in first window - (to be confirmed) */
128
116 lside_pane.pack1 (sidebar, false, false);129 lside_pane.pack1 (sidebar, false, false);
117 lside_pane.pack2 (tabs, true, false);130 lside_pane.pack2 (tabs, true, false);
118131
@@ -131,20 +144,30 @@
131 }144 }
132145
133 /** Apply preferences */146 /** Apply preferences */
134 lside_pane.position = Preferences.settings.get_int ("sidebar-width");
135 get_action ("show_sidebar").set_state (Preferences.settings.get_boolean ("show-sidebar"));
136 get_action ("show_hidden").set_state (Preferences.settings.get_boolean ("show-hiddenfiles"));147 get_action ("show_hidden").set_state (Preferences.settings.get_boolean ("show-hiddenfiles"));
137148
138 set_default_size (Preferences.settings.get_int("window-width"),149 var show_sidebar_pref = Preferences.settings.get_boolean ("show-sidebar");
139 Preferences.settings.get_int("window-height"));150 get_action ("show_sidebar").set_state (show_sidebar_pref);
151 show_sidebar (true);
140152
141 if (Preferences.settings.get_boolean("maximized"))153 if (is_first_window) {
142 maximize();154 window_position = Gtk.WindowPosition.CENTER;
155 } else { /* Allow new window created by tab dragging to be positioned where dropped */
156 window_position = Gtk.WindowPosition.NONE;
157 }
143 }158 }
144159
145 private void construct_sidebar () {160 private void construct_sidebar () {
146 sidebar = new Marlin.Places.Sidebar (this);161 sidebar = new Marlin.Places.Sidebar (this);
147 sidebar.show ();162 }
163
164 public void show_sidebar (bool show = true) {
165 var show_sidebar = (get_action ("show_sidebar")).state.get_boolean ();
166 if (show && show_sidebar) {
167 lside_pane.position = Preferences.settings.get_int ("sidebar-width");
168 } else {
169 lside_pane.position = 0;
170 }
148 }171 }
149172
150 private void construct_notebook () {173 private void construct_notebook () {
@@ -152,6 +175,8 @@
152 tabs.show_tabs = true;175 tabs.show_tabs = true;
153 tabs.allow_restoring = true;176 tabs.allow_restoring = true;
154 tabs.allow_duplication = true;177 tabs.allow_duplication = true;
178 tabs.allow_new_window = true;
179
155 this.configure_event.connect_after ((e) => {180 this.configure_event.connect_after ((e) => {
156 tabs.set_size_request (e.width / 2, -1);181 tabs.set_size_request (e.width / 2, -1);
157 return false;182 return false;
@@ -296,6 +321,16 @@
296 add_tab (File.new_for_uri (((tab.page as ViewContainer).uri)));321 add_tab (File.new_for_uri (((tab.page as ViewContainer).uri)));
297 });322 });
298323
324 tabs.tab_moved.connect ((tab, x, y) => {
325 var vc = tab.page as ViewContainer;
326 ((Marlin.Application) application).create_window (vc.location, real_mode (vc.view_mode), x, y);
327 /* A crash occurs if the original tab is removed while processing the signal */
328 GLib.Idle.add (() => {
329 remove_tab (vc);
330 return false;
331 });
332 });
333
299 sidebar.request_focus.connect (() => {334 sidebar.request_focus.connect (() => {
300 return !current_tab.locked_focus && !top_menu.locked_focus;335 return !current_tab.locked_focus && !top_menu.locked_focus;
301 });336 });
@@ -306,11 +341,12 @@
306 }341 }
307342
308 private void make_bindings () {343 private void make_bindings () {
309 /*Preference bindings */344 if (is_first_window) {
310 Preferences.settings.bind("show-sidebar", sidebar, "visible", SettingsBindFlags.DEFAULT);345 /*Preference bindings */
346 Preferences.settings.bind("show-sidebar", sidebar, "visible", SettingsBindFlags.GET);
347 Preferences.settings.bind("sidebar-width", lside_pane, "position", SettingsBindFlags.DEFAULT);
311348
312 /* keyboard shortcuts bindings */349 /* keyboard shortcuts bindings */
313 if (is_first_window) {
314 unowned Gtk.BindingSet binding_set = Gtk.BindingSet.by_class (get_class ());350 unowned Gtk.BindingSet binding_set = Gtk.BindingSet.by_class (get_class ());
315 Gtk.BindingEntry.add_signal (binding_set, Gdk.keyval_from_name ("BackSpace"), 0, "go_up", 0);351 Gtk.BindingEntry.add_signal (binding_set, Gdk.keyval_from_name ("BackSpace"), 0, "go_up", 0);
316 Gtk.BindingEntry.add_signal (binding_set, Gdk.keyval_from_name ("XF86Back"), 0, "go_back", 0);352 Gtk.BindingEntry.add_signal (binding_set, Gdk.keyval_from_name ("XF86Back"), 0, "go_back", 0);
@@ -444,8 +480,10 @@
444 tab.close ();480 tab.close ();
445 }481 }
446482
447 public void add_window(File location, Marlin.ViewMode mode){483 public void add_window (File location = File.new_for_path (Environment.get_home_dir ()),
448 ((Marlin.Application) application).create_window (location, screen, real_mode (mode));484 Marlin.ViewMode mode = Marlin.ViewMode.PREFERRED,
485 int x = -1, int y = -1) {
486 ((Marlin.Application) application).create_window (location, real_mode (mode), x, y);
449 }487 }
450488
451 private void undo_actions_set_insensitive () {489 private void undo_actions_set_insensitive () {
@@ -491,8 +529,19 @@
491 }529 }
492 }530 }
493531
532 private bool adding_window = false;
494 private void action_new_window (GLib.SimpleAction action, GLib.Variant? param) {533 private void action_new_window (GLib.SimpleAction action, GLib.Variant? param) {
495 (application as Marlin.Application).create_window ();534 /* Limit rate of adding new windows using the keyboard */
535 if (adding_window) {
536 return;
537 } else {
538 adding_window = true;
539 add_window ();
540 GLib.Timeout.add (500, () => {
541 adding_window = false;
542 return false;
543 });
544 }
496 }545 }
497546
498 private void action_quit (GLib.SimpleAction action, GLib.Variant? param) {547 private void action_quit (GLib.SimpleAction action, GLib.Variant? param) {
@@ -680,7 +729,10 @@
680 private void change_state_show_sidebar (GLib.SimpleAction action) {729 private void change_state_show_sidebar (GLib.SimpleAction action) {
681 bool state = !action.state.get_boolean ();730 bool state = !action.state.get_boolean ();
682 action.set_state (new GLib.Variant.boolean (state));731 action.set_state (new GLib.Variant.boolean (state));
683 Preferences.settings.set_boolean ("show-sidebar", state);732 if (!state) {
733 Preferences.settings.set_int ("sidebar-width", lside_pane.position);
734 }
735 show_sidebar (state);
684 }736 }
685737
686 private void connect_to_server () {738 private void connect_to_server () {
@@ -789,11 +841,7 @@
789 }841 }
790842
791 private void save_geometries () {843 private void save_geometries () {
792 Gtk.Allocation sidebar_alloc;844 save_sidebar_width ();
793 sidebar.get_allocation (out sidebar_alloc);
794
795 if (sidebar_alloc.width > 1)
796 Preferences.settings.set_int("sidebar-width", sidebar_alloc.width);
797845
798 bool is_maximized = (bool) get_window().get_state() & Gdk.WindowState.MAXIMIZED;846 bool is_maximized = (bool) get_window().get_state() & Gdk.WindowState.MAXIMIZED;
799847
@@ -807,6 +855,14 @@
807 Preferences.settings.set_boolean("maximized", is_maximized);855 Preferences.settings.set_boolean("maximized", is_maximized);
808 }856 }
809857
858 private void save_sidebar_width () {
859 var sw = lside_pane.get_position ();
860 var mw = Preferences.settings.get_int("minimum-sidebar-width");
861
862 sw = int.max (sw, mw);
863 Preferences.settings.set_int("sidebar-width", sw);
864 }
865
810 private void save_tabs () {866 private void save_tabs () {
811 VariantBuilder vb = new VariantBuilder (new VariantType ("a(uss)"));867 VariantBuilder vb = new VariantBuilder (new VariantType ("a(uss)"));
812868

Subscribers

People subscribed via source and target branches

to all changes: