/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * Session-managment stuff * Copyright (C) 1998 Sven Neumann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "libpikabase/pikabase.h" #include "libpikaconfig/pikaconfig.h" #include "gui-types.h" #include "config/pikaconfig-file.h" #include "config/pikaguiconfig.h" #include "core/pika.h" #include "core/pikaerror.h" #include "widgets/pikadialogfactory.h" #include "widgets/pikasessioninfo.h" #include "widgets/pikawidgets-utils.h" #include "dialogs/dialogs.h" #include "session.h" #include "pika-log.h" #include "pika-intl.h" enum { SESSION_INFO = 1, HIDE_DOCKS, SINGLE_WINDOW_MODE, SHOW_TABS, TABS_POSITION, LAST_TIP_SHOWN }; static GFile * session_file (Pika *pika); /* private variables */ static gboolean sessionrc_deleted = FALSE; /* public functions */ void session_init (Pika *pika) { GFile *file; GScanner *scanner; GTokenType token; GError *error = NULL; g_return_if_fail (PIKA_IS_PIKA (pika)); file = session_file (pika); scanner = pika_scanner_new_file (file, &error); if (! scanner && error->code == PIKA_CONFIG_ERROR_OPEN_ENOENT) { g_clear_error (&error); g_object_unref (file); file = pika_sysconf_directory_file ("sessionrc", NULL); scanner = pika_scanner_new_file (file, NULL); } if (! scanner) { g_clear_error (&error); g_object_unref (file); return; } if (pika->be_verbose) g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file)); g_scanner_scope_add_symbol (scanner, 0, "session-info", GINT_TO_POINTER (SESSION_INFO)); g_scanner_scope_add_symbol (scanner, 0, "hide-docks", GINT_TO_POINTER (HIDE_DOCKS)); g_scanner_scope_add_symbol (scanner, 0, "single-window-mode", GINT_TO_POINTER (SINGLE_WINDOW_MODE)); g_scanner_scope_add_symbol (scanner, 0, "show-tabs", GINT_TO_POINTER (SHOW_TABS)); g_scanner_scope_add_symbol (scanner, 0, "tabs-position", GINT_TO_POINTER (TABS_POSITION)); g_scanner_scope_add_symbol (scanner, 0, "last-tip-shown", GINT_TO_POINTER (LAST_TIP_SHOWN)); token = G_TOKEN_LEFT_PAREN; while (g_scanner_peek_next_token (scanner) == token) { token = g_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; break; case G_TOKEN_SYMBOL: if (scanner->value.v_symbol == GINT_TO_POINTER (SESSION_INFO)) { PikaDialogFactory *factory = NULL; PikaSessionInfo *info = NULL; gchar *factory_name = NULL; gchar *entry_name = NULL; PikaDialogFactoryEntry *entry = NULL; token = G_TOKEN_STRING; if (! pika_scanner_parse_string (scanner, &factory_name)) break; /* In versions <= PIKA 2.6 there was a "toolbox", a * "dock", a "display" and a "toplevel" factory. These * are now merged to a single pika_dialog_factory_get_singleton (). We * need the legacy name though, so keep it around. */ factory = pika_dialog_factory_get_singleton (); info = pika_session_info_new (); /* PIKA 2.6 has the entry name as part of the * session-info header, so try to get it */ pika_scanner_parse_string (scanner, &entry_name); if (entry_name) { /* Previously, PikaDock was a toplevel. That is why * versions <= PIKA 2.6 has "dock" as the entry name. We * want "dock" to be interpreted as 'dock window' * however so have some special-casing for that. When * the entry name is "dock" the factory name is either * "dock" or "toolbox". */ if (strcmp (entry_name, "dock") == 0) { entry = pika_dialog_factory_find_entry (factory, (strcmp (factory_name, "toolbox") == 0 ? "pika-toolbox-window" : "pika-dock-window")); } else { entry = pika_dialog_factory_find_entry (factory, entry_name); } } /* We're done with these now */ g_free (factory_name); g_free (entry_name); /* We can get the factory entry either now (the PIKA <= * 2.6 way), or when we deserialize (the PIKA 2.8 way) */ if (entry) { pika_session_info_set_factory_entry (info, entry); } /* Always try to deserialize */ if (pika_config_deserialize (PIKA_CONFIG (info), scanner, 1, NULL)) { /* Make sure we got a factory entry either the 2.6 * or 2.8 way */ if (pika_session_info_get_factory_entry (info)) { PIKA_LOG (DIALOG_FACTORY, "successfully parsed and added session info %p", info); pika_dialog_factory_add_session_info (factory, info); } else { PIKA_LOG (DIALOG_FACTORY, "failed to parse session info %p, not adding", info); } g_object_unref (info); } else { g_object_unref (info); /* set token to left paren so we won't set another * error below, pika_config_deserialize() already did */ token = G_TOKEN_LEFT_PAREN; goto error; } } else if (scanner->value.v_symbol == GINT_TO_POINTER (HIDE_DOCKS)) { gboolean hide_docks; token = G_TOKEN_IDENTIFIER; if (! pika_scanner_parse_boolean (scanner, &hide_docks)) break; g_object_set (pika->config, "hide-docks", hide_docks, NULL); } else if (scanner->value.v_symbol == GINT_TO_POINTER (SINGLE_WINDOW_MODE)) { gboolean single_window_mode; token = G_TOKEN_IDENTIFIER; if (! pika_scanner_parse_boolean (scanner, &single_window_mode)) break; g_object_set (pika->config, "single-window-mode", single_window_mode, NULL); } else if (scanner->value.v_symbol == GINT_TO_POINTER (SHOW_TABS)) { gboolean show_tabs; token = G_TOKEN_IDENTIFIER; if (! pika_scanner_parse_boolean (scanner, &show_tabs)) break; g_object_set (pika->config, "show-tabs", show_tabs, NULL); } else if (scanner->value.v_symbol == GINT_TO_POINTER (TABS_POSITION)) { gint tabs_position; token = G_TOKEN_INT; if (! pika_scanner_parse_int (scanner, &tabs_position)) break; g_object_set (pika->config, "tabs-position", tabs_position, NULL); } else if (scanner->value.v_symbol == GINT_TO_POINTER (LAST_TIP_SHOWN)) { gint last_tip_shown; token = G_TOKEN_INT; if (! pika_scanner_parse_int (scanner, &last_tip_shown)) break; g_object_set (pika->config, "last-tip-shown", last_tip_shown, NULL); } token = G_TOKEN_RIGHT_PAREN; break; case G_TOKEN_RIGHT_PAREN: token = G_TOKEN_LEFT_PAREN; break; default: /* do nothing */ break; } } error: if (token != G_TOKEN_LEFT_PAREN) { g_scanner_get_next_token (scanner); g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, _("fatal parse error"), TRUE); } if (error) { pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message); g_clear_error (&error); pika_config_file_backup_on_error (file, "sessionrc", NULL); } pika_scanner_unref (scanner); g_object_unref (file); dialogs_load_recent_docks (pika); } void session_exit (Pika *pika) { g_return_if_fail (PIKA_IS_PIKA (pika)); } void session_restore (Pika *pika, GdkMonitor *monitor) { g_return_if_fail (PIKA_IS_PIKA (pika)); g_return_if_fail (GDK_IS_MONITOR (monitor)); pika_dialog_factory_restore (pika_dialog_factory_get_singleton (), monitor); /* make sure PikaImageWindow acts upon hide-docks at the right time, * see bug #678043. */ if (PIKA_GUI_CONFIG (pika->config)->single_window_mode && PIKA_GUI_CONFIG (pika->config)->hide_docks) { g_object_notify (G_OBJECT (pika->config), "hide-docks"); } } void session_save (Pika *pika, gboolean always_save) { PikaConfigWriter *writer; GFile *file; GError *error = NULL; g_return_if_fail (PIKA_IS_PIKA (pika)); if (sessionrc_deleted && ! always_save) return; file = session_file (pika); if (pika->be_verbose) g_print ("Writing '%s'\n", pika_file_get_utf8_name (file)); writer = pika_config_writer_new_from_file (file, TRUE, "PIKA sessionrc\n\n" "This file takes session-specific info " "(that is info, you want to keep between " "two PIKA sessions). You are not supposed " "to edit it manually, but of course you " "can do. The sessionrc will be entirely " "rewritten every time you quit PIKA. " "If this file isn't found, defaults are " "used.", NULL); g_object_unref (file); if (!writer) return; pika_dialog_factory_save (pika_dialog_factory_get_singleton (), writer); pika_config_writer_linefeed (writer); pika_config_writer_open (writer, "hide-docks"); pika_config_writer_identifier (writer, PIKA_GUI_CONFIG (pika->config)->hide_docks ? "yes" : "no"); pika_config_writer_close (writer); pika_config_writer_open (writer, "single-window-mode"); pika_config_writer_identifier (writer, PIKA_GUI_CONFIG (pika->config)->single_window_mode ? "yes" : "no"); pika_config_writer_close (writer); pika_config_writer_open (writer, "show-tabs"); pika_config_writer_printf (writer, PIKA_GUI_CONFIG (pika->config)->show_tabs ? "yes" : "no"); pika_config_writer_close (writer); pika_config_writer_open (writer, "tabs-position"); pika_config_writer_printf (writer, "%d", PIKA_GUI_CONFIG (pika->config)->tabs_position); pika_config_writer_close (writer); pika_config_writer_open (writer, "last-tip-shown"); pika_config_writer_printf (writer, "%d", PIKA_GUI_CONFIG (pika->config)->last_tip_shown); pika_config_writer_close (writer); if (! pika_config_writer_finish (writer, "end of sessionrc", &error)) { pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message); g_clear_error (&error); } dialogs_save_recent_docks (pika); sessionrc_deleted = FALSE; } gboolean session_clear (Pika *pika, GError **error) { GFile *file; GError *my_error = NULL; gboolean success = TRUE; g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); file = session_file (pika); if (! g_file_delete (file, NULL, &my_error) && my_error->code != G_IO_ERROR_NOT_FOUND) { success = FALSE; g_set_error (error, PIKA_ERROR, PIKA_FAILED, _("Deleting \"%s\" failed: %s"), pika_file_get_utf8_name (file), my_error->message); } else { sessionrc_deleted = TRUE; } g_clear_error (&my_error); g_object_unref (file); return success; } static GFile * session_file (Pika *pika) { const gchar *basename; gchar *filename; GFile *file; basename = g_getenv ("PIKA_TESTING_SESSIONRC_NAME"); if (! basename) basename = "sessionrc"; if (pika->session_name) filename = g_strconcat (basename, ".", pika->session_name, NULL); else filename = g_strdup (basename); file = pika_directory_file (filename, NULL); g_free (filename); return file; }