- Replaced the dark mode checkbox with an Auto/Dark/Light selector in Preferences → Colors and added the new mode labels/setting metadata to match the combo box UI.

- Updated palette handling to respect the effective dark mode (including auto) when saving colors, applying themes, and refreshing user list styling.
- Added auto dark-mode tracking that listens to system theme changes and reapplies palette/styles live when Auto is selected, so updates happen without restart (including channel list styling updates via setup_apply_real).
- Synced the stored auto dark-mode state when preferences are applied, keeping Auto mode consistent after manual changes.
- Exposed a helper for keeping the Auto state synchronized from the GTK layer to preferences handling.
This commit is contained in:
2026-01-17 23:09:38 -07:00
parent 8d275ddb31
commit 7279e3592f
3 changed files with 136 additions and 59 deletions

View File

@@ -302,6 +302,35 @@ fe_system_prefers_dark (void)
return prefer_dark; return prefer_dark;
} }
static gboolean auto_dark_mode_enabled = FALSE;
static void
fe_auto_dark_mode_changed (GtkSettings *settings, GParamSpec *pspec, gpointer data)
{
gboolean enabled;
(void) settings;
(void) pspec;
(void) data;
if (prefs.hex_gui_dark_mode != ZOITECHAT_DARK_MODE_AUTO)
return;
enabled = fe_system_prefers_dark ();
if (enabled == auto_dark_mode_enabled)
return;
auto_dark_mode_enabled = enabled;
palette_apply_dark_mode (enabled);
setup_apply_real (0, TRUE, FALSE, FALSE);
}
void
fe_set_auto_dark_mode_state (gboolean enabled)
{
auto_dark_mode_enabled = enabled;
}
gboolean gboolean
fe_dark_mode_is_enabled_for (unsigned int mode) fe_dark_mode_is_enabled_for (unsigned int mode)
{ {
@@ -369,6 +398,8 @@ create_input_style (GtkStyle *style)
void void
fe_init (void) fe_init (void)
{ {
GtkSettings *settings;
palette_load (); palette_load ();
palette_apply_dark_mode (fe_dark_mode_is_enabled ()); palette_apply_dark_mode (fe_dark_mode_is_enabled ());
key_init (); key_init ();
@@ -379,6 +410,16 @@ fe_init (void)
#endif #endif
channelwin_pix = pixmap_load_from_file (prefs.hex_text_background); channelwin_pix = pixmap_load_from_file (prefs.hex_text_background);
input_style = create_input_style (gtk_style_new ()); input_style = create_input_style (gtk_style_new ());
settings = gtk_settings_get_default ();
if (settings)
{
auto_dark_mode_enabled = fe_system_prefers_dark ();
g_signal_connect (settings, "notify::gtk-application-prefer-dark-theme",
G_CALLBACK (fe_auto_dark_mode_changed), NULL);
g_signal_connect (settings, "notify::gtk-theme-name",
G_CALLBACK (fe_auto_dark_mode_changed), NULL);
}
} }
#ifdef HAVE_GTK_MAC #ifdef HAVE_GTK_MAC

View File

@@ -184,6 +184,7 @@ extern cairo_surface_t *dialogwin_pix;
gboolean fe_dark_mode_is_enabled (void); gboolean fe_dark_mode_is_enabled (void);
gboolean fe_dark_mode_is_enabled_for (unsigned int mode); gboolean fe_dark_mode_is_enabled_for (unsigned int mode);
void fe_set_auto_dark_mode_state (gboolean enabled);
#define SPELL_ENTRY_GET_TEXT(e) ((char *)(gtk_entry_get_text (GTK_ENTRY(e)))) #define SPELL_ENTRY_GET_TEXT(e) ((char *)(gtk_entry_get_text (GTK_ENTRY(e))))
#define SPELL_ENTRY_SET_TEXT(e,txt) gtk_entry_set_text(GTK_ENTRY(e),txt) #define SPELL_ENTRY_SET_TEXT(e,txt) gtk_entry_set_text(GTK_ENTRY(e),txt)

View File

@@ -58,7 +58,6 @@ static int last_selected_row = 0; /* sound row */
static gboolean color_change; static gboolean color_change;
static struct zoitechatprefs setup_prefs; static struct zoitechatprefs setup_prefs;
static GSList *color_selector_widgets; static GSList *color_selector_widgets;
static GtkWidget *dark_mode_toggle_widget;
static GtkWidget *cancel_button; static GtkWidget *cancel_button;
static GtkWidget *font_dialog = NULL; static GtkWidget *font_dialog = NULL;
void setup_apply_real (int new_pix, int do_ulist, int do_layout, int do_identd); void setup_apply_real (int new_pix, int do_ulist, int do_layout, int do_identd);
@@ -348,22 +347,30 @@ static const setting tabs_settings[] =
static const setting color_settings[] = static const setting color_settings[] =
{ {
{ST_TOGGLE, N_("Messages"), P_OFFINTNL(hex_text_stripcolor_msg), 0, 0, 0}, {ST_TOGGLE, N_("Messages"), P_OFFINTNL(hex_text_stripcolor_msg), 0, 0, 0},
{ST_TOGGLE, N_("Scrollback"), P_OFFINTNL(hex_text_stripcolor_replay), 0, 0, 0}, {ST_TOGGLE, N_("Scrollback"), P_OFFINTNL(hex_text_stripcolor_replay), 0, 0, 0},
{ST_TOGGLE, N_("Topic"), P_OFFINTNL(hex_text_stripcolor_topic), 0, 0, 0}, {ST_TOGGLE, N_("Topic"), P_OFFINTNL(hex_text_stripcolor_topic), 0, 0, 0},
{ST_END, 0, 0, 0, 0, 0} {ST_END, 0, 0, 0, 0, 0}
};
static const char *const dark_mode_modes[] =
{
N_("Auto (system)"),
N_("Dark"),
N_("Light"),
NULL
}; };
static const setting dark_mode_setting = static const setting dark_mode_setting =
{ {
ST_TOGGLE, ST_MENU,
N_("Enable dark mode"), N_("Dark mode:"),
P_OFFINTNL(hex_gui_dark_mode), P_OFFINTNL(hex_gui_dark_mode),
N_("Applies ZoiteChat's built-in dark palette to the chat buffer, channel list, and user list.\n" N_("Choose how ZoiteChat selects its color palette for the chat buffer, channel list, and user list.\n"
"This includes message colors, selection colors, and interface highlights.\n"), "This includes message colors, selection colors, and interface highlights.\n"),
0, dark_mode_modes,
0 0
}; };
static const char *const dccaccept[] = static const char *const dccaccept[] =
@@ -1440,12 +1447,41 @@ setup_color_selectors_set_sensitive (gboolean sensitive)
} }
static void static void
setup_dark_mode_ui_toggle_cb (GtkToggleButton *but, gpointer userdata) setup_dark_mode_menu_cb (GtkWidget *cbox, const setting *set)
{ {
(void) but; setup_menu_cb (cbox, set);
(void) userdata; /* Keep color selectors usable even when dark mode is enabled. */
/* Keep color selectors usable even when dark mode is enabled. */ setup_color_selectors_set_sensitive (TRUE);
setup_color_selectors_set_sensitive (TRUE); }
static GtkWidget *
setup_create_dark_mode_menu (GtkWidget *table, int row, const setting *set)
{
GtkWidget *wid, *cbox, *box;
const char **text = (const char **)set->list;
int i;
wid = gtk_label_new (_(set->label));
gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
cbox = gtk_combo_box_text_new ();
for (i = 0; text[i]; i++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbox), _(text[i]));
gtk_combo_box_set_active (GTK_COMBO_BOX (cbox),
setup_get_int (&setup_prefs, set) - set->extra);
g_signal_connect (G_OBJECT (cbox), "changed",
G_CALLBACK (setup_dark_mode_menu_cb), (gpointer)set);
box = gtk_hbox_new (0, 0);
gtk_box_pack_start (GTK_BOX (box), cbox, 0, 0, 0);
gtk_table_attach (GTK_TABLE (table), box, 3, 4, row, row + 1,
GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
return cbox;
} }
static void static void
@@ -1476,11 +1512,11 @@ setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog)
/* is this line correct?? */ /* is this line correct?? */
gdk_colormap_free_colors (gtk_widget_get_colormap (button), &old_color, 1); gdk_colormap_free_colors (gtk_widget_get_colormap (button), &old_color, 1);
/* Persist custom colors for the palette the user is editing. */ /* Persist custom colors for the palette the user is editing. */
if (setup_prefs.hex_gui_dark_mode) if (fe_dark_mode_is_enabled_for (setup_prefs.hex_gui_dark_mode))
palette_dark_set_color ((int)(col - colors), col); palette_dark_set_color ((int)(col - colors), col);
else else
palette_user_set_color ((int)(col - colors), col); palette_user_set_color ((int)(col - colors), col);
gtk_widget_destroy (dialog); gtk_widget_destroy (dialog);
} }
@@ -1571,11 +1607,10 @@ setup_create_other_color (char *text, int num, int row, GtkWidget *tab)
static GtkWidget * static GtkWidget *
setup_create_color_page (void) setup_create_color_page (void)
{ {
color_selector_widgets = NULL; color_selector_widgets = NULL;
dark_mode_toggle_widget = NULL;
GtkWidget *tab, *box, *label; GtkWidget *tab, *box, *label;
int i; int i;
box = gtk_vbox_new (FALSE, 0); box = gtk_vbox_new (FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (box), 6); gtk_container_set_border_width (GTK_CONTAINER (box), 6);
@@ -1616,15 +1651,13 @@ setup_create_color_page (void)
setup_create_other_color (_("New data:"), COL_NEW_DATA, 9, tab); setup_create_other_color (_("New data:"), COL_NEW_DATA, 9, tab);
setup_create_other_colorR (_("Marker line:"), COL_MARKER, 9, tab); setup_create_other_colorR (_("Marker line:"), COL_MARKER, 9, tab);
setup_create_other_color (_("New message:"), COL_NEW_MSG, 10, tab); setup_create_other_color (_("New message:"), COL_NEW_MSG, 10, tab);
setup_create_other_colorR (_("Away user:"), COL_AWAY, 10, tab); setup_create_other_colorR (_("Away user:"), COL_AWAY, 10, tab);
setup_create_other_color (_("Highlight:"), COL_HILIGHT, 11, tab); setup_create_other_color (_("Highlight:"), COL_HILIGHT, 11, tab);
setup_create_other_colorR (_("Spell checker:"), COL_SPELL, 11, tab); setup_create_other_colorR (_("Spell checker:"), COL_SPELL, 11, tab);
dark_mode_toggle_widget = setup_create_toggleL (tab, 13, &dark_mode_setting); setup_create_dark_mode_menu (tab, 13, &dark_mode_setting);
g_signal_connect (G_OBJECT (dark_mode_toggle_widget), "toggled", setup_color_selectors_set_sensitive (TRUE);
G_CALLBACK (setup_dark_mode_ui_toggle_cb), NULL); setup_create_header (tab, 15, N_("Color Stripping"));
setup_color_selectors_set_sensitive (TRUE);
setup_create_header (tab, 15, N_("Color Stripping"));
/* label = gtk_label_new (_("Strip colors from:")); /* label = gtk_label_new (_("Strip colors from:"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
@@ -1800,9 +1833,9 @@ setup_theme_apply_cb (GtkWidget *button, gpointer user_data)
g_unlink (events_dest); g_unlink (events_dest);
} }
palette_load (); palette_load ();
palette_apply_dark_mode (prefs.hex_gui_dark_mode); palette_apply_dark_mode (fe_dark_mode_is_enabled ());
color_change = TRUE; color_change = TRUE;
setup_apply_real (0, TRUE, FALSE, FALSE); setup_apply_real (0, TRUE, FALSE, FALSE);
setup_theme_show_message (GTK_MESSAGE_INFO, _("Theme applied. Some changes may require a restart to take full effect.")); setup_theme_show_message (GTK_MESSAGE_INFO, _("Theme applied. Some changes may require a restart to take full effect."));
@@ -2365,13 +2398,13 @@ setup_apply_to_sess (session_gui *gui)
if (prefs.hex_gui_ulist_style) if (prefs.hex_gui_ulist_style)
gtk_widget_modify_font (gui->user_tree, input_style->font_desc); gtk_widget_modify_font (gui->user_tree, input_style->font_desc);
if (prefs.hex_gui_ulist_style || prefs.hex_gui_dark_mode) if (prefs.hex_gui_ulist_style || fe_dark_mode_is_enabled ())
{ {
gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_BG]); gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_BG]);
if (prefs.hex_gui_dark_mode) if (fe_dark_mode_is_enabled ())
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_FG]); gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_FG]);
else else
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, NULL); gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, NULL);
} }
else else
{ {
@@ -2570,14 +2603,17 @@ setup_apply (struct zoitechatprefs *pr)
* "Dark mode" applies ZoiteChat's built-in dark palette to the chat views. * "Dark mode" applies ZoiteChat's built-in dark palette to the chat views.
* *
* IMPORTANT: don't short-circuit this call. * IMPORTANT: don't short-circuit this call.
* We MUST run palette_apply_dark_mode() when the toggle changes, otherwise * We MUST run palette_apply_dark_mode() when the setting changes, otherwise
* the preference flips but the palette stays the same (aka: "nothing happens"). * the preference flips but the palette stays the same (aka: "nothing happens").
*/ */
{ {
gboolean pal_changed = palette_apply_dark_mode (prefs.hex_gui_dark_mode); gboolean pal_changed = palette_apply_dark_mode (fe_dark_mode_is_enabled_for (prefs.hex_gui_dark_mode));
if (prefs.hex_gui_dark_mode != old_dark_mode || pal_changed) if (prefs.hex_gui_dark_mode != old_dark_mode || pal_changed)
color_change = TRUE; color_change = TRUE;
} }
if (prefs.hex_gui_dark_mode == ZOITECHAT_DARK_MODE_AUTO)
fe_set_auto_dark_mode_state (fe_dark_mode_is_enabled_for (ZOITECHAT_DARK_MODE_AUTO));
#ifdef WIN32 #ifdef WIN32
/* merge hex_font_main and hex_font_alternative into hex_font_normal */ /* merge hex_font_main and hex_font_alternative into hex_font_normal */
@@ -2674,12 +2710,11 @@ setup_close_cb (GtkWidget *win, GtkWidget **swin)
{ {
*swin = NULL; *swin = NULL;
if (color_selector_widgets) if (color_selector_widgets)
{ {
g_slist_free (color_selector_widgets); g_slist_free (color_selector_widgets);
color_selector_widgets = NULL; color_selector_widgets = NULL;
dark_mode_toggle_widget = NULL; }
}
if (font_dialog) if (font_dialog)
{ {