Skip to content

Commit 66d4299

Browse files
authored
Restore Last Window Tabs on Startup (#3661)
* Restore last closed window tabs Save split view and tab URIs on window close and restore them when starting Nemo with no explicit locations. * adding tabs * adding tabs * adding tabs * adding tabs * adding tabs * adding tabs * adding tabs * option under 'behaviour' in preferences to toggle on restoring tabs * simplified sessions save logic to only save the window that exits * addressing pr comments regarding last window logic
1 parent 227e295 commit 66d4299

8 files changed

Lines changed: 461 additions & 11 deletions

gresources/nemo-file-management-properties.glade

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,23 @@ along with . If not, see <http://www.gnu.org/licenses/>.
12561256
<property name="position">3</property>
12571257
</packing>
12581258
</child>
1259+
<child>
1260+
<object class="GtkCheckButton" id="restore_tabs_on_startup_checkbutton">
1261+
<property name="label" translatable="yes">Restore last window tabs on startup</property>
1262+
<property name="visible">True</property>
1263+
<property name="can-focus">True</property>
1264+
<property name="receives-default">False</property>
1265+
<property name="use-underline">True</property>
1266+
<property name="xalign">0</property>
1267+
<property name="draw-indicator">True</property>
1268+
</object>
1269+
<packing>
1270+
<property name="expand">False</property>
1271+
<property name="fill">False</property>
1272+
<property name="padding">3</property>
1273+
<property name="position">4</property>
1274+
</packing>
1275+
</child>
12591276
<child>
12601277
<object class="GtkCheckButton" id="expand_row_on_dnd_dwell_checkbutton">
12611278
<property name="label" translatable="yes">Automatically expand rows during drag-and-drop</property>
@@ -1269,7 +1286,7 @@ along with . If not, see <http://www.gnu.org/licenses/>.
12691286
<packing>
12701287
<property name="expand">False</property>
12711288
<property name="fill">False</property>
1272-
<property name="position">4</property>
1289+
<property name="position">5</property>
12731290
</packing>
12741291
</child>
12751292
</object>

libnemo-private/nemo-global-preferences.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ typedef enum
122122
#define NEMO_WINDOW_STATE_DEVICES_EXPANDED "devices-expanded"
123123
#define NEMO_WINDOW_STATE_NETWORK_EXPANDED "network-expanded"
124124

125+
/* Saved session (last closed window) */
126+
#define NEMO_WINDOW_STATE_SAVED_SPLIT_VIEW "saved-split-view"
127+
#define NEMO_WINDOW_STATE_SAVED_TABS_LEFT "saved-tabs-left"
128+
#define NEMO_WINDOW_STATE_SAVED_TABS_RIGHT "saved-tabs-right"
129+
#define NEMO_WINDOW_STATE_SAVED_ACTIVE_TAB_LEFT "saved-active-tab-left"
130+
#define NEMO_WINDOW_STATE_SAVED_ACTIVE_TAB_RIGHT "saved-active-tab-right"
131+
125132
/* Sorting order */
126133
#define NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST "sort-directories-first"
127134
#define NEMO_PREFERENCES_SORT_FAVORITES_FIRST "sort-favorites-first"
@@ -137,6 +144,7 @@ typedef enum
137144
#define NEMO_PREFERENCES_CLOSE_DEVICE_VIEW_ON_EJECT "close-device-view-on-device-eject"
138145

139146
#define NEMO_PREFERENCES_START_WITH_DUAL_PANE "start-with-dual-pane"
147+
#define NEMO_PREFERENCES_RESTORE_TABS_ON_STARTUP "restore-tabs-on-startup"
140148
#define NEMO_PREFERENCES_IGNORE_VIEW_METADATA "ignore-view-metadata"
141149
#define NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS "show-bookmarks-in-to-menus"
142150
#define NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS "show-places-in-to-menus"

libnemo-private/org.nemo.gschema.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,11 @@
346346
<summary>Whether to default to showing dual-pane view when a new window is opened</summary>
347347
<description>If set to true, new Nemo windows will default to showing two panes</description>
348348
</key>
349+
<key name="restore-tabs-on-startup" type="b">
350+
<default>false</default>
351+
<summary>Restore the previous window tabs on startup</summary>
352+
<description>If set to true, Nemo will restore the last saved window tab state when launched without explicit locations.</description>
353+
</key>
349354
<key name="ignore-view-metadata" type="b">
350355
<default>false</default>
351356
<summary>Whether to ignore folder metadata for view zoom levels and layouts</summary>
@@ -702,6 +707,33 @@
702707
<summary>Side pane view</summary>
703708
<description>The side pane view to show in newly opened windows.</description>
704709
</key>
710+
711+
<!-- Saved session (last closed window) -->
712+
<key name="saved-split-view" type="b">
713+
<default>false</default>
714+
<summary>Whether split view was enabled when the last window was closed</summary>
715+
<description>Internal setting used to restore the last closed window's split view and tabs.</description>
716+
</key>
717+
<key name="saved-tabs-left" type="as">
718+
<default>[]</default>
719+
<summary>Saved tab URIs for the left pane</summary>
720+
<description>Internal setting used to restore the last closed window's tabs for the left pane.</description>
721+
</key>
722+
<key name="saved-tabs-right" type="as">
723+
<default>[]</default>
724+
<summary>Saved tab URIs for the right pane</summary>
725+
<description>Internal setting used to restore the last closed window's tabs for the right pane.</description>
726+
</key>
727+
<key name="saved-active-tab-left" type="i">
728+
<default>0</default>
729+
<summary>Index of the active tab in the left pane</summary>
730+
<description>Internal setting used to restore which tab was active in the left pane.</description>
731+
</key>
732+
<key name="saved-active-tab-right" type="i">
733+
<default>0</default>
734+
<summary>Index of the active tab in the right pane</summary>
735+
<description>Internal setting used to restore which tab was active in the right pane.</description>
736+
</key>
705737
</schema>
706738

707739
<schema id="org.nemo.plugins" path="/org/nemo/plugins/" gettext-domain="nemo">

src/nemo-application.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
#include "nemo-application.h"
3232

33+
#include "nemo-desktop-window.h"
34+
3335
#if (defined(ENABLE_EMPTY_VIEW) && ENABLE_EMPTY_VIEW)
3436
#include "nemo-empty-view.h"
3537
#endif /* ENABLE_EMPTY_VIEW */
@@ -534,6 +536,33 @@ nemo_application_quit (NemoApplication *self)
534536
GList *windows;
535537

536538
windows = gtk_application_get_windows (GTK_APPLICATION (app));
539+
540+
/* Save session state once, before we destroy all windows.
541+
* Save the last non-desktop window we find. */
542+
{
543+
NemoWindow *last_window = NULL;
544+
545+
for (GList *l = windows; l != NULL; l = l->next) {
546+
GtkWindow *w = GTK_WINDOW (l->data);
547+
548+
if (!NEMO_IS_WINDOW (w)) {
549+
continue;
550+
}
551+
552+
/* Avoid saving the desktop window */
553+
if (NEMO_IS_DESKTOP_WINDOW (w)) {
554+
continue;
555+
}
556+
557+
last_window = NEMO_WINDOW (w);
558+
break;
559+
}
560+
561+
if (last_window != NULL) {
562+
nemo_window_save_session_state (last_window);
563+
}
564+
}
565+
537566
g_list_foreach (windows, (GFunc) gtk_widget_destroy, NULL);
538567

539568
/* we have been asked to force quit */

src/nemo-file-management-properties.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
#define NEMO_FILE_MANAGEMENT_PROPERTIES_DETECT_CONTENT_MEDIA_WIDGET "media_detect_content_checkbutton"
100100
#define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_ADVANCED_PERMISSIONS_WIDGET "show_advanced_permissions_checkbutton"
101101
#define NEMO_FILE_MANAGEMENT_PROPERTIES_START_WITH_DUAL_PANE_WIDGET "start_with_dual_pane_checkbutton"
102+
#define NEMO_FILE_MANAGEMENT_PROPERTIES_RESTORE_TABS_ON_STARTUP_WIDGET "restore_tabs_on_startup_checkbutton"
102103
#define NEMO_FILE_MANAGEMENT_PROPERTIES_IGNORE_VIEW_METADATA_WIDGET "ignore_view_metadata_checkbutton"
103104
#define NEMO_FILE_MANAGEMENT_PROPERTIES_BOOKMARKS_IN_TO_MENUS_WIDGET "bookmarks_in_to_checkbutton"
104105
#define NEMO_FILE_MANAGEMENT_PROPERTIES_PLACES_IN_TO_MENUS_WIDGET "places_in_to_checkbutton"
@@ -1067,6 +1068,10 @@ nemo_file_management_properties_dialog_setup (GtkBuilder *builder,
10671068
NEMO_FILE_MANAGEMENT_PROPERTIES_START_WITH_DUAL_PANE_WIDGET,
10681069
NEMO_PREFERENCES_START_WITH_DUAL_PANE);
10691070

1071+
bind_builder_bool (builder, nemo_preferences,
1072+
NEMO_FILE_MANAGEMENT_PROPERTIES_RESTORE_TABS_ON_STARTUP_WIDGET,
1073+
NEMO_PREFERENCES_RESTORE_TABS_ON_STARTUP);
1074+
10701075
bind_builder_bool (builder, nemo_preferences,
10711076
NEMO_FILE_MANAGEMENT_PROPERTIES_IGNORE_VIEW_METADATA_WIDGET,
10721077
NEMO_PREFERENCES_IGNORE_VIEW_METADATA);

src/nemo-main-application.c

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,34 @@ open_windows (NemoMainApplication *application,
483483
gint i;
484484

485485
if (files == NULL || files[0] == NULL) {
486-
/* Open a window pointing at the default location. */
487-
open_window (application, NULL, screen, geometry);
486+
/* No explicit locations requested: try restoring the last session. */
487+
NemoWindow *window;
488+
gboolean have_geometry;
489+
gboolean do_restore;
490+
491+
window = nemo_main_application_create_window (NEMO_APPLICATION (application), screen);
492+
493+
have_geometry = geometry != NULL && strcmp (geometry, "") != 0;
494+
if (have_geometry && !gtk_widget_get_visible (GTK_WIDGET (window))) {
495+
/* never maximize windows opened from shell if a
496+
* custom geometry has been requested.
497+
*/
498+
gtk_window_unmaximize (GTK_WINDOW (window));
499+
eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window),
500+
geometry,
501+
APPLICATION_WINDOW_MIN_WIDTH,
502+
APPLICATION_WINDOW_MIN_HEIGHT,
503+
FALSE);
504+
}
505+
506+
do_restore = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_RESTORE_TABS_ON_STARTUP);
507+
508+
if (!do_restore || !nemo_window_restore_saved_tabs (window)) {
509+
/* Fall back to a safe default location */
510+
GFile *home = g_file_new_for_path (g_get_home_dir ());
511+
nemo_window_go_to (window, home);
512+
g_object_unref (home);
513+
}
488514
} else {
489515
if (open_in_existing_window) {
490516
/* Open one tab at each requested location in an existing window */
@@ -542,6 +568,7 @@ nemo_main_application_open (GApplication *app,
542568
gboolean open_in_tabs = FALSE;
543569
gchar *geometry = NULL;
544570
gboolean open_in_existing_window = strcmp (options, "EXISTING_WINDOW") == 0;
571+
gboolean default_no_args = FALSE;
545572
const char splitter = '=';
546573

547574
g_debug ("Open called on the GApplication instance; %d files", n_files);
@@ -550,7 +577,12 @@ nemo_main_application_open (GApplication *app,
550577
/* Check if local command line passed --geometry or --tabs */
551578
if (strlen (options) > 0) {
552579
gchar** split_options = g_strsplit (options, &splitter, 2);
553-
if (strcmp (split_options[0], "NULL") != 0) {
580+
if (g_str_has_prefix (split_options[0], "DEFAULT")) {
581+
default_no_args = TRUE;
582+
if (g_str_has_prefix (split_options[0], "DEFAULT+")) {
583+
geometry = g_strdup (split_options[0] + strlen ("DEFAULT+"));
584+
}
585+
} else if (strcmp (split_options[0], "NULL") != 0) {
554586
geometry = g_strdup (split_options[0]);
555587
}
556588
sscanf (split_options[1], "%d", &open_in_tabs);
@@ -565,7 +597,13 @@ nemo_main_application_open (GApplication *app,
565597
geometry ? geometry : "none",
566598
open_in_existing_window ? "yes" : "no");
567599

568-
open_windows (self, files, n_files, gdk_screen_get_default (), geometry, open_in_tabs, open_in_existing_window);
600+
if (default_no_args) {
601+
/* Treat this as a no-arg launch; open_windows() will attempt session restore
602+
* and fall back to Home if restore isn't possible. */
603+
open_windows (self, NULL, 0, gdk_screen_get_default (), geometry, open_in_tabs, open_in_existing_window);
604+
} else {
605+
open_windows (self, files, n_files, gdk_screen_get_default (), geometry, open_in_tabs, open_in_existing_window);
606+
}
569607

570608
g_clear_pointer (&geometry, g_free);
571609
}
@@ -807,9 +845,11 @@ nemo_main_application_local_command_line (GApplication *application,
807845

808846
GFile **files;
809847
gint idx, len;
848+
gboolean used_default_location;
810849

811850
len = 0;
812851
files = NULL;
852+
used_default_location = FALSE;
813853

814854
/* Convert args to GFiles */
815855
if (remaining != NULL) {
@@ -831,32 +871,50 @@ nemo_main_application_local_command_line (GApplication *application,
831871
}
832872

833873
if (files == NULL && !no_default_window) {
874+
/* Original behavior: default to Home when no URIs are provided. */
834875
files = g_malloc0 (2 * sizeof (GFile *));
835876
len = 1;
836877

837878
files[0] = g_file_new_for_path (g_get_home_dir ());
838879
files[1] = NULL;
880+
881+
/* Mark that this was a no-arg launch, not an explicit URI. */
882+
used_default_location = TRUE;
839883
}
840-
/* Invoke "Open" to open in existing window or create new windows */
884+
885+
/* Invoke "Open" to open in existing window or create new windows.
886+
*/
841887
if (len > 0) {
842888
gchar* concatOptions = g_malloc0(64);
843889
if (open_in_existing_window) {
844890
g_stpcpy (concatOptions, "EXISTING_WINDOW");
845891
} else {
846892
if (self->priv->geometry == NULL) {
847-
g_snprintf (concatOptions, 64, "NULL=%d", open_in_tabs);
893+
/* If Home was synthesized because no URIs were passed, signal that
894+
* to the primary instance so it can attempt session restore. */
895+
if (used_default_location) {
896+
g_snprintf (concatOptions, 64, "DEFAULT=%d", open_in_tabs);
897+
} else {
898+
g_snprintf (concatOptions, 64, "NULL=%d", open_in_tabs);
899+
}
848900
} else {
849-
g_snprintf (concatOptions, 64, "%s=%d", self->priv->geometry, open_in_tabs);
901+
if (used_default_location) {
902+
g_snprintf (concatOptions, 64, "DEFAULT+%s=%d", self->priv->geometry, open_in_tabs);
903+
} else {
904+
g_snprintf (concatOptions, 64, "%s=%d", self->priv->geometry, open_in_tabs);
905+
}
850906
}
851907
}
852908
g_application_open (application, files, len, concatOptions);
853909
g_free (concatOptions);
854910
}
855911

856-
for (idx = 0; idx < len; idx++) {
857-
g_object_unref (files[idx]);
912+
if (files != NULL) {
913+
for (idx = 0; idx < len; idx++) {
914+
g_object_unref (files[idx]);
915+
}
916+
g_free (files);
858917
}
859-
g_free (files);
860918

861919
out:
862920
g_option_context_free (context);

src/nemo-window-private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ void nemo_window_set_active_pane (NemoWindow
154154
NemoWindowPane *new_pane);
155155
NemoWindowPane * nemo_window_get_active_pane (NemoWindow *window);
156156

157+
gboolean nemo_window_restore_saved_tabs (NemoWindow *window);
158+
void nemo_window_save_session_state (NemoWindow *window);
159+
157160

158161
/* sync window GUI with current slot. Used when changing slots,
159162
* and when updating the slot state.

0 commit comments

Comments
 (0)