refactor: coord prefs/theme saves in one staged path; drop broken manager wrappers

This commit is contained in:
2026-03-16 22:45:30 -06:00
parent 896a761e24
commit 9e808c57b4
11 changed files with 346 additions and 64 deletions

View File

@@ -1009,15 +1009,51 @@ load_config (void)
return 0;
}
int
save_config (void)
static int
save_config_write_to_fd (int fh)
{
int fh, i;
char *config, *new_config;
int i;
if (!cfg_put_str (fh, "version", PACKAGE_VERSION))
return 0;
i = 0;
do
{
switch (vars[i].type)
{
case TYPE_STR:
if (!cfg_put_str (fh, vars[i].name, (char *) &prefs + vars[i].offset))
return 0;
break;
case TYPE_INT:
case TYPE_BOOL:
if (!cfg_put_int (fh, *((int *) &prefs + vars[i].offset), vars[i].name))
return 0;
}
if (vars[i].after_update != NULL)
vars[i].after_update();
i++;
}
while (vars[i].name);
return 1;
}
int
save_config_prepare (char **temp_path)
{
int fh;
char *config;
char *new_config;
if (check_config_dir () != 0)
make_config_dirs ();
if (!temp_path)
return 0;
config = default_file ();
new_config = g_strconcat (config, ".new", NULL);
@@ -1028,63 +1064,67 @@ save_config (void)
return 0;
}
if (!cfg_put_str (fh, "version", PACKAGE_VERSION))
if (!save_config_write_to_fd (fh))
{
close (fh);
g_free (new_config);
return 0;
}
i = 0;
do
{
switch (vars[i].type)
{
case TYPE_STR:
if (!cfg_put_str (fh, vars[i].name, (char *) &prefs + vars[i].offset))
{
close (fh);
g_free (new_config);
return 0;
}
break;
case TYPE_INT:
case TYPE_BOOL:
if (!cfg_put_int (fh, *((int *) &prefs + vars[i].offset), vars[i].name))
{
close (fh);
g_free (new_config);
return 0;
}
}
if (vars[i].after_update != NULL)
{
vars[i].after_update();
}
i++;
}
while (vars[i].name);
if (close (fh) == -1)
{
g_free (new_config);
return 0;
}
#ifdef WIN32
g_unlink (config); /* win32 can't rename to an existing file */
#endif
if (g_rename (new_config, config) == -1)
{
g_free (new_config);
*temp_path = new_config;
return 1;
}
int
save_config_finalize (const char *temp_path)
{
char *config;
if (!temp_path)
return 0;
config = default_file ();
#ifdef WIN32
g_unlink (config);
#endif
if (g_rename (temp_path, config) == -1)
return 0;
}
g_free (new_config);
return 1;
}
void
save_config_discard (const char *temp_path)
{
if (!temp_path)
return;
g_unlink (temp_path);
}
int
save_config (void)
{
char *temp_path = NULL;
int result;
if (!save_config_prepare (&temp_path))
return 0;
result = save_config_finalize (temp_path);
if (!result)
save_config_discard (temp_path);
g_free (temp_path);
return result;
}
static void
set_showval (session *sess, const struct prefs *var, char *tbuf)
{

View File

@@ -43,6 +43,9 @@ int make_config_dirs (void);
int make_dcc_dirs (void);
int load_config (void);
int save_config (void);
int save_config_prepare (char **temp_path);
int save_config_finalize (const char *temp_path);
void save_config_discard (const char *temp_path);
void list_free (GSList ** list);
void list_loadconf (char *file, GSList ** list, char *defaultconf);
int list_delentry (GSList ** list, char *name);

View File

@@ -61,6 +61,7 @@ powershell "Get-Content -Encoding UTF8 '$(ZoiteChatLib)zoitechat.rc.utf8' | Out-
<ClInclude Include="icon-resolver.h" />
<ClInclude Include="joind.h" />
<ClInclude Include="maingui.h" />
<ClInclude Include="preferences-persistence.h" />
<ClInclude Include="menu.h" />
<ClInclude Include="notifications\notification-backend.h" />
<ClInclude Include="notifygui.h" />
@@ -107,6 +108,7 @@ powershell "Get-Content -Encoding UTF8 '$(ZoiteChatLib)zoitechat.rc.utf8' | Out-
<ClCompile Include="notifications\notification-windows.c" />
<ClCompile Include="notifygui.c" />
<ClCompile Include="pixmaps.c" />
<ClCompile Include="preferences-persistence.c" />
<ClCompile Include="plugin-notification.c" />
<ClCompile Include="plugin-tray.c" />
<ClCompile Include="plugingui.c" />

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
@@ -51,6 +51,9 @@
<ClInclude Include="maingui.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="preferences-persistence.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="menu.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -182,6 +185,9 @@
<ClCompile Include="pixmaps.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="preferences-persistence.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="plugingui.c">
<Filter>Source Files</Filter>
</ClCompile>

View File

@@ -52,6 +52,7 @@
#include "theme/theme-palette.h"
#include "maingui.h"
#include "menu.h"
#include "preferences-persistence.h"
#include "fkeys.h"
#include "userlistgui.h"
#include "chanview.h"
@@ -178,15 +179,37 @@ static void mg_apply_emoji_fallback_widget (GtkWidget *widget);
static guint mg_config_save_source_id = 0;
static gboolean mg_config_prefs_dirty = FALSE;
static void
mg_show_save_failure (const PreferencesPersistenceResult *save_result)
{
char buffer[192];
if (!save_result || save_result->success)
return;
if (save_result->partial_failure)
{
fe_message (_("Could not fully save preferences. zoitechat.conf was written, but colors.conf failed. Retry is possible."), FE_MSG_ERROR);
return;
}
g_snprintf (buffer, sizeof (buffer), _("Could not save preferences (%s). Retry is possible."), save_result->failed_file ? save_result->failed_file : _("unknown file"));
fe_message (buffer, FE_MSG_ERROR);
}
static gboolean
mg_config_save_timeout_cb (gpointer userdata)
{
PreferencesPersistenceResult save_result;
mg_config_save_source_id = 0;
if (!mg_config_prefs_dirty)
return G_SOURCE_REMOVE;
save_config ();
save_result = preferences_persistence_save_all ();
if (!save_result.success)
mg_show_save_failure (&save_result);
mg_config_prefs_dirty = FALSE;
return G_SOURCE_REMOVE;
@@ -209,6 +232,8 @@ mg_schedule_config_save (void)
static void
mg_flush_config_save (void)
{
PreferencesPersistenceResult save_result;
if (mg_config_save_source_id != 0)
{
g_source_remove (mg_config_save_source_id);
@@ -217,7 +242,9 @@ mg_flush_config_save (void)
if (mg_config_prefs_dirty)
{
save_config ();
save_result = preferences_persistence_save_all ();
if (!save_result.success)
mg_show_save_failure (&save_result);
mg_config_prefs_dirty = FALSE;
}
}

View File

@@ -28,6 +28,7 @@ zoitechat_gtk_sources = [
'maingui.c',
'notifygui.c',
'pixmaps.c',
'preferences-persistence.c',
'plugin-tray.c',
'plugin-notification.c',
'rawlog.c',

View File

@@ -0,0 +1,66 @@
#include "preferences-persistence.h"
#include "../common/cfgfiles.h"
#include "theme/theme-runtime.h"
PreferencesPersistenceResult
preferences_persistence_save_all (void)
{
PreferencesPersistenceResult result;
char *config_temp;
char *theme_temp;
result.success = FALSE;
result.retry_possible = TRUE;
result.partial_failure = FALSE;
result.config_failed = FALSE;
result.theme_failed = FALSE;
result.failed_file = NULL;
config_temp = NULL;
theme_temp = NULL;
if (!save_config_prepare (&config_temp))
{
result.config_failed = TRUE;
goto done;
}
if (!theme_runtime_save_prepare (&theme_temp))
{
result.theme_failed = TRUE;
goto done;
}
if (!save_config_finalize (config_temp))
{
result.config_failed = TRUE;
goto done;
}
if (!theme_runtime_save_finalize (theme_temp))
{
result.theme_failed = TRUE;
result.partial_failure = TRUE;
goto done;
}
result.success = TRUE;
done:
if (!result.success)
{
if (result.config_failed && result.theme_failed)
result.failed_file = "zoitechat.conf and colors.conf";
else if (result.config_failed)
result.failed_file = "zoitechat.conf";
else if (result.theme_failed)
result.failed_file = "colors.conf";
}
save_config_discard (config_temp);
theme_runtime_save_discard (theme_temp);
g_free (config_temp);
g_free (theme_temp);
return result;
}

View File

@@ -0,0 +1,18 @@
#ifndef ZOITECHAT_PREFERENCES_PERSISTENCE_H
#define ZOITECHAT_PREFERENCES_PERSISTENCE_H
#include <glib.h>
typedef struct
{
gboolean success;
gboolean retry_possible;
gboolean partial_failure;
gboolean config_failed;
gboolean theme_failed;
const char *failed_file;
} PreferencesPersistenceResult;
PreferencesPersistenceResult preferences_persistence_save_all (void);
#endif

View File

@@ -40,6 +40,7 @@
#include "maingui.h"
#include "pixmaps.h"
#include "menu.h"
#include "preferences-persistence.h"
#include "plugin-tray.h"
#include "notifications/notification-backend.h"
@@ -2191,12 +2192,23 @@ setup_apply (struct zoitechatprefs *pr)
static void
setup_ok_cb (GtkWidget *but, GtkWidget *win)
{
PreferencesPersistenceResult save_result;
char buffer[192];
gtk_widget_destroy (win);
setup_apply (&setup_prefs);
if (!save_config ())
fe_message (_("Could not save zoitechat.conf."), FE_MSG_ERROR);
if (!theme_manager_save_preferences ())
fe_message (_("Could not save colors.conf."), FE_MSG_ERROR);
save_result = preferences_persistence_save_all ();
if (save_result.success)
return;
if (save_result.partial_failure)
{
fe_message (_("Preferences were partially saved. zoitechat.conf succeeded, colors.conf failed. Retry is possible."), FE_MSG_ERROR);
return;
}
g_snprintf (buffer, sizeof (buffer), _("Could not save preferences (%s). Retry is possible."), save_result.failed_file ? save_result.failed_file : _("unknown file"));
fe_message (buffer, FE_MSG_ERROR);
}
static GtkWidget *

View File

@@ -449,12 +449,11 @@ theme_runtime_load (void)
user_colors_valid = TRUE;
}
gboolean
theme_runtime_save (void)
static gboolean
theme_runtime_save_to_fd (int fh)
{
size_t i;
size_t j;
int fh;
ThemePalettePersistenceMode modes[] = {
{ "light", "color", &light_palette, &user_colors_valid },
{ "dark", "dark_color", &dark_palette, &dark_user_colors_valid },
@@ -485,15 +484,8 @@ theme_runtime_save (void)
else
modes[1].palette = &dark_palette;
fh = zoitechat_open_file ("colors.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
if (fh == -1)
return FALSE;
if (!cfg_put_int (fh, THEME_PALETTE_MIGRATION_MARKER_VALUE, (char *) THEME_PALETTE_MIGRATION_MARKER_KEY))
{
close (fh);
return FALSE;
}
for (i = 0; i < mode_count; i++)
{
@@ -512,19 +504,131 @@ theme_runtime_save (void)
continue;
g_assert (theme_palette_get_color (modes[i].palette, def->token, &color));
if (!palette_write_token_color (fh, modes[i].mode_name, def, &color))
{
close (fh);
return FALSE;
}
}
}
return TRUE;
}
gboolean
theme_runtime_save_prepare (char **temp_path)
{
int fh;
const char *temp_name;
if (!temp_path)
return FALSE;
temp_name = "colors.conf.new";
fh = zoitechat_open_file (temp_name, O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
if (fh == -1)
return FALSE;
if (!theme_runtime_save_to_fd (fh))
{
close (fh);
return FALSE;
}
if (close (fh) == -1)
return FALSE;
*temp_path = g_strdup (temp_name);
return TRUE;
}
gboolean
theme_runtime_save_finalize (const char *temp_path)
{
int src_fh;
int dst_fh;
char buffer[4096];
ssize_t read_len;
if (!temp_path)
return FALSE;
src_fh = zoitechat_open_file (temp_path, O_RDONLY, 0, XOF_DOMODE);
if (src_fh == -1)
return FALSE;
dst_fh = zoitechat_open_file ("colors.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
if (dst_fh == -1)
{
close (src_fh);
return FALSE;
}
while ((read_len = read (src_fh, buffer, sizeof (buffer))) > 0)
{
ssize_t offset;
offset = 0;
while (offset < read_len)
{
ssize_t written;
written = write (dst_fh, buffer + offset, (size_t) (read_len - offset));
if (written <= 0)
{
close (src_fh);
close (dst_fh);
return FALSE;
}
offset += written;
}
}
if (read_len < 0)
{
close (src_fh);
close (dst_fh);
return FALSE;
}
if (close (src_fh) == -1)
{
close (dst_fh);
return FALSE;
}
if (close (dst_fh) == -1)
return FALSE;
return TRUE;
}
void
theme_runtime_save_discard (const char *temp_path)
{
int fh;
if (!temp_path)
return;
fh = zoitechat_open_file (temp_path, O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
if (fh != -1)
close (fh);
}
gboolean
theme_runtime_save (void)
{
char *temp_path = NULL;
gboolean result;
if (!theme_runtime_save_prepare (&temp_path))
return FALSE;
result = theme_runtime_save_finalize (temp_path);
if (!result)
theme_runtime_save_discard (temp_path);
g_free (temp_path);
return result;
}
static gboolean
palette_color_eq (const GdkRGBA *a, const GdkRGBA *b)
{

View File

@@ -19,6 +19,9 @@ typedef struct
void theme_runtime_load (void);
gboolean theme_runtime_save (void);
gboolean theme_runtime_save_prepare (char **temp_path);
gboolean theme_runtime_save_finalize (const char *temp_path);
void theme_runtime_save_discard (const char *temp_path);
gboolean theme_runtime_apply_mode (unsigned int mode, gboolean *palette_changed);
gboolean theme_runtime_apply_dark_mode (gboolean enable);
void theme_runtime_user_set_color (ThemeSemanticToken token, const GdkRGBA *col);