mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-10 07:50:19 +00:00
dark mode
This commit is contained in:
@@ -433,6 +433,7 @@ const struct prefs vars[] =
|
|||||||
{"gui_tab_dialogs", P_OFFINT (hex_gui_tab_dialogs), TYPE_BOOL},
|
{"gui_tab_dialogs", P_OFFINT (hex_gui_tab_dialogs), TYPE_BOOL},
|
||||||
{"gui_tab_dots", P_OFFINT (hex_gui_tab_dots), TYPE_BOOL},
|
{"gui_tab_dots", P_OFFINT (hex_gui_tab_dots), TYPE_BOOL},
|
||||||
{"gui_tab_icons", P_OFFINT (hex_gui_tab_icons), TYPE_BOOL},
|
{"gui_tab_icons", P_OFFINT (hex_gui_tab_icons), TYPE_BOOL},
|
||||||
|
{"gui_dark_mode", P_OFFINT (hex_gui_dark_mode), TYPE_BOOL},
|
||||||
{"gui_tab_layout", P_OFFINT (hex_gui_tab_layout), TYPE_INT},
|
{"gui_tab_layout", P_OFFINT (hex_gui_tab_layout), TYPE_INT},
|
||||||
{"gui_tab_middleclose", P_OFFINT (hex_gui_tab_middleclose), TYPE_BOOL},
|
{"gui_tab_middleclose", P_OFFINT (hex_gui_tab_middleclose), TYPE_BOOL},
|
||||||
{"gui_tab_newtofront", P_OFFINT (hex_gui_tab_newtofront), TYPE_INT},
|
{"gui_tab_newtofront", P_OFFINT (hex_gui_tab_newtofront), TYPE_INT},
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ struct zoitechatprefs
|
|||||||
unsigned int hex_gui_tab_dialogs;
|
unsigned int hex_gui_tab_dialogs;
|
||||||
unsigned int hex_gui_tab_dots;
|
unsigned int hex_gui_tab_dots;
|
||||||
unsigned int hex_gui_tab_icons;
|
unsigned int hex_gui_tab_icons;
|
||||||
|
unsigned int hex_gui_dark_mode;
|
||||||
unsigned int hex_gui_tab_scrollchans;
|
unsigned int hex_gui_tab_scrollchans;
|
||||||
unsigned int hex_gui_tab_server;
|
unsigned int hex_gui_tab_server;
|
||||||
unsigned int hex_gui_tab_sort;
|
unsigned int hex_gui_tab_sort;
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ cv_tree_init (chanview *cv)
|
|||||||
|
|
||||||
((treeview *)cv)->tree = GTK_TREE_VIEW (view);
|
((treeview *)cv)->tree = GTK_TREE_VIEW (view);
|
||||||
((treeview *)cv)->scrollw = win;
|
((treeview *)cv)->scrollw = win;
|
||||||
|
chanview_apply_theme (cv);
|
||||||
gtk_widget_show (view);
|
gtk_widget_show (view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "maingui.h"
|
#include "maingui.h"
|
||||||
#include "gtkutil.h"
|
#include "gtkutil.h"
|
||||||
#include "chanview.h"
|
#include "chanview.h"
|
||||||
|
#include "palette.h"
|
||||||
|
|
||||||
/* treeStore columns */
|
/* treeStore columns */
|
||||||
#define COL_NAME 0 /* (char *) */
|
#define COL_NAME 0 /* (char *) */
|
||||||
@@ -103,6 +104,37 @@ static int cv_find_number_of_chan (chanview *cv, chan *find_ch);
|
|||||||
|
|
||||||
/* ==== ABSTRACT CHANVIEW ==== */
|
/* ==== ABSTRACT CHANVIEW ==== */
|
||||||
|
|
||||||
|
void
|
||||||
|
chanview_apply_theme (chanview *cv)
|
||||||
|
{
|
||||||
|
GtkWidget *w;
|
||||||
|
treeview *tv;
|
||||||
|
|
||||||
|
if (cv == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Only the tree implementation has a GtkTreeView we can explicitly style. */
|
||||||
|
if (cv->func_init != cv_tree_init)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tv = (treeview *) cv;
|
||||||
|
if (tv->tree == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
w = GTK_WIDGET (tv->tree);
|
||||||
|
if (prefs.hex_gui_dark_mode)
|
||||||
|
{
|
||||||
|
gtk_widget_modify_base (w, GTK_STATE_NORMAL, &colors[COL_BG]);
|
||||||
|
gtk_widget_modify_text (w, GTK_STATE_NORMAL, &colors[COL_FG]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Revert back to theme defaults. */
|
||||||
|
gtk_widget_modify_base (w, GTK_STATE_NORMAL, NULL);
|
||||||
|
gtk_widget_modify_text (w, GTK_STATE_NORMAL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
truncate_tab_name (char *name, int max)
|
truncate_tab_name (char *name, int max)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,6 +48,13 @@ gboolean chan_remove (chan *ch, gboolean force);
|
|||||||
gboolean chan_is_collapsed (chan *ch);
|
gboolean chan_is_collapsed (chan *ch);
|
||||||
chan * chan_get_parent (chan *ch);
|
chan * chan_get_parent (chan *ch);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply ZoiteChat's optional "dark mode" styling to the channel list.
|
||||||
|
*
|
||||||
|
* This is a no-op for implementations that don't have a tree view.
|
||||||
|
*/
|
||||||
|
void chanview_apply_theme (chanview *cv);
|
||||||
|
|
||||||
#define FOCUS_NEW_ALL 1
|
#define FOCUS_NEW_ALL 1
|
||||||
#define FOCUS_NEW_ONLY_ASKED 2
|
#define FOCUS_NEW_ONLY_ASKED 2
|
||||||
#define FOCUS_NEW_NONE 0
|
#define FOCUS_NEW_NONE 0
|
||||||
|
|||||||
@@ -317,6 +317,7 @@ void
|
|||||||
fe_init (void)
|
fe_init (void)
|
||||||
{
|
{
|
||||||
palette_load ();
|
palette_load ();
|
||||||
|
palette_apply_dark_mode (prefs.hex_gui_dark_mode);
|
||||||
key_init ();
|
key_init ();
|
||||||
pixmaps_init ();
|
pixmaps_init ();
|
||||||
|
|
||||||
|
|||||||
@@ -2480,7 +2480,20 @@ mg_create_userlist (session_gui *gui, GtkWidget *box)
|
|||||||
if (prefs.hex_gui_ulist_style)
|
if (prefs.hex_gui_ulist_style)
|
||||||
{
|
{
|
||||||
gtk_widget_set_style (ulist, input_style);
|
gtk_widget_set_style (ulist, input_style);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep the user list in sync with the chat palette.
|
||||||
|
*
|
||||||
|
* - When "Use the text box font and colors" is enabled, we already want the
|
||||||
|
* palette background.
|
||||||
|
* - When "Dark mode" is enabled, we also force the user list to use the
|
||||||
|
* palette colors so it doesn't stay blindingly white on GTK2 themes.
|
||||||
|
*/
|
||||||
|
if (prefs.hex_gui_ulist_style || prefs.hex_gui_dark_mode)
|
||||||
|
{
|
||||||
gtk_widget_modify_base (ulist, GTK_STATE_NORMAL, &colors[COL_BG]);
|
gtk_widget_modify_base (ulist, GTK_STATE_NORMAL, &colors[COL_BG]);
|
||||||
|
gtk_widget_modify_text (ulist, GTK_STATE_NORMAL, &colors[COL_FG]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_create_meters (gui, vbox);
|
mg_create_meters (gui, vbox);
|
||||||
|
|||||||
@@ -169,3 +169,86 @@ palette_save (void)
|
|||||||
close (fh);
|
close (fh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
palette_color_eq (const GdkColor *a, const GdkColor *b)
|
||||||
|
{
|
||||||
|
return a->red == b->red && a->green == b->green && a->blue == b->blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
palette_apply_dark_mode (gboolean enable)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Stock ZoiteChat defaults from this file (keep them in sync with the
|
||||||
|
* colors[] initializer above):
|
||||||
|
* - Foreground: 0x2512/0x29e8/0x2b85
|
||||||
|
* - Background: 0xfae0/0xfae0/0xf8c4
|
||||||
|
*/
|
||||||
|
static const GdkColor light_fg = {0, 0x2512, 0x29e8, 0x2b85};
|
||||||
|
static const GdkColor light_bg = {0, 0xfae0, 0xfae0, 0xf8c4};
|
||||||
|
|
||||||
|
/* Common legacy "defaults" seen in the wild (pure black/white). */
|
||||||
|
static const GdkColor legacy_light_fg = {0, 0x0000, 0x0000, 0x0000};
|
||||||
|
static const GdkColor legacy_light_bg = {0, 0xffff, 0xffff, 0xffff};
|
||||||
|
|
||||||
|
/* A readable "dark" preset (roughly #D4D4D4 on #1E1E1E). */
|
||||||
|
static const GdkColor dark_fg = {0, 0xd4d4, 0xd4d4, 0xd4d4};
|
||||||
|
static const GdkColor dark_bg = {0, 0x1e1e, 0x1e1e, 0x1e1e};
|
||||||
|
|
||||||
|
gboolean changed = FALSE;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
if (palette_color_eq (&colors[COL_FG], &light_fg) ||
|
||||||
|
palette_color_eq (&colors[COL_FG], &legacy_light_fg))
|
||||||
|
{
|
||||||
|
colors[COL_FG].red = dark_fg.red;
|
||||||
|
colors[COL_FG].green = dark_fg.green;
|
||||||
|
colors[COL_FG].blue = dark_fg.blue;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
if (palette_color_eq (&colors[COL_BG], &light_bg) ||
|
||||||
|
palette_color_eq (&colors[COL_BG], &legacy_light_bg))
|
||||||
|
{
|
||||||
|
colors[COL_BG].red = dark_bg.red;
|
||||||
|
colors[COL_BG].green = dark_bg.green;
|
||||||
|
colors[COL_BG].blue = dark_bg.blue;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (palette_color_eq (&colors[COL_FG], &dark_fg))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Revert to a predictable light default. Most users who hit this toggle
|
||||||
|
* are coming from black-on-white palettes.
|
||||||
|
*/
|
||||||
|
colors[COL_FG].red = legacy_light_fg.red;
|
||||||
|
colors[COL_FG].green = legacy_light_fg.green;
|
||||||
|
colors[COL_FG].blue = legacy_light_fg.blue;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
if (palette_color_eq (&colors[COL_BG], &dark_bg))
|
||||||
|
{
|
||||||
|
colors[COL_BG].red = legacy_light_bg.red;
|
||||||
|
colors[COL_BG].green = legacy_light_bg.green;
|
||||||
|
colors[COL_BG].blue = legacy_light_bg.blue;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the new colors have pixels allocated in the current colormap. */
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
GdkColormap *cmap = gdk_colormap_get_system ();
|
||||||
|
if (cmap)
|
||||||
|
{
|
||||||
|
gdk_colormap_alloc_color (cmap, &colors[COL_FG], TRUE, TRUE);
|
||||||
|
gdk_colormap_alloc_color (cmap, &colors[COL_BG], TRUE, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,4 +38,15 @@ void palette_alloc (GtkWidget * widget);
|
|||||||
void palette_load (void);
|
void palette_load (void);
|
||||||
void palette_save (void);
|
void palette_save (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply ZoiteChat's built-in "dark mode" background/foreground overrides.
|
||||||
|
*
|
||||||
|
* This is intentionally conservative: it only adjusts the palette if the
|
||||||
|
* colors are still at ZoiteChat's stock defaults, so user-customized palettes
|
||||||
|
* continue to take precedence.
|
||||||
|
*
|
||||||
|
* Returns TRUE if any palette entries were changed.
|
||||||
|
*/
|
||||||
|
gboolean palette_apply_dark_mode (gboolean enable);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "fe-gtk.h"
|
#include "fe-gtk.h"
|
||||||
#include "gtkutil.h"
|
#include "gtkutil.h"
|
||||||
#include "maingui.h"
|
#include "maingui.h"
|
||||||
|
#include "chanview.h"
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
#include "pixmaps.h"
|
#include "pixmaps.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@@ -341,6 +342,17 @@ static const setting color_settings[] =
|
|||||||
{ST_END, 0, 0, 0, 0, 0}
|
{ST_END, 0, 0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const setting dark_mode_setting =
|
||||||
|
{
|
||||||
|
ST_TOGGLE,
|
||||||
|
N_("Enable dark mode for chat views"),
|
||||||
|
P_OFFINTNL(hex_gui_dark_mode),
|
||||||
|
N_("Makes the chat buffer, channel list, and user list use a dark background/foreground.\n"
|
||||||
|
"This only changes the stock background/foreground colors. If you've customized them, your palette wins."),
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
static const char *const dccaccept[] =
|
static const char *const dccaccept[] =
|
||||||
{
|
{
|
||||||
N_("Ask for confirmation"),
|
N_("Ask for confirmation"),
|
||||||
@@ -1570,6 +1582,7 @@ setup_create_color_page (void)
|
|||||||
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);
|
||||||
|
setup_create_toggleL (tab, 13, &dark_mode_setting);
|
||||||
|
|
||||||
setup_create_header (tab, 15, N_("Color Stripping"));
|
setup_create_header (tab, 15, N_("Color Stripping"));
|
||||||
|
|
||||||
@@ -2048,10 +2061,25 @@ static void
|
|||||||
setup_apply_to_sess (session_gui *gui)
|
setup_apply_to_sess (session_gui *gui)
|
||||||
{
|
{
|
||||||
mg_update_xtext (gui->xtext);
|
mg_update_xtext (gui->xtext);
|
||||||
|
chanview_apply_theme ((chanview *) gui->chanview);
|
||||||
|
|
||||||
if (prefs.hex_gui_ulist_style)
|
if (prefs.hex_gui_ulist_style)
|
||||||
gtk_widget_set_style (gui->user_tree, input_style);
|
gtk_widget_set_style (gui->user_tree, input_style);
|
||||||
|
|
||||||
|
if (prefs.hex_gui_ulist_style || prefs.hex_gui_dark_mode)
|
||||||
|
{
|
||||||
|
gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_BG]);
|
||||||
|
if (prefs.hex_gui_dark_mode)
|
||||||
|
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_FG]);
|
||||||
|
else
|
||||||
|
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, NULL);
|
||||||
|
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (prefs.hex_gui_input_style)
|
if (prefs.hex_gui_input_style)
|
||||||
{
|
{
|
||||||
extern char cursor_color_rc[];
|
extern char cursor_color_rc[];
|
||||||
@@ -2168,6 +2196,7 @@ setup_apply (struct zoitechatprefs *pr)
|
|||||||
int do_ulist = FALSE;
|
int do_ulist = FALSE;
|
||||||
int do_layout = FALSE;
|
int do_layout = FALSE;
|
||||||
int do_identd = FALSE;
|
int do_identd = FALSE;
|
||||||
|
int old_dark_mode = prefs.hex_gui_dark_mode;
|
||||||
|
|
||||||
if (strcmp (pr->hex_text_background, prefs.hex_text_background) != 0)
|
if (strcmp (pr->hex_text_background, prefs.hex_text_background) != 0)
|
||||||
new_pix = TRUE;
|
new_pix = TRUE;
|
||||||
@@ -2238,6 +2267,20 @@ setup_apply (struct zoitechatprefs *pr)
|
|||||||
|
|
||||||
memcpy (&prefs, pr, sizeof (prefs));
|
memcpy (&prefs, pr, sizeof (prefs));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Dark mode" is mostly about the chat views. Be conservative: only adjust
|
||||||
|
* the stock Foreground/Background colors so user palettes keep winning.
|
||||||
|
*
|
||||||
|
* IMPORTANT: don't short-circuit this call.
|
||||||
|
* We MUST run palette_apply_dark_mode() when the toggle changes, otherwise
|
||||||
|
* the preference flips but the palette stays the same (aka: "nothing happens").
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
gboolean pal_changed = palette_apply_dark_mode (prefs.hex_gui_dark_mode);
|
||||||
|
if (prefs.hex_gui_dark_mode != old_dark_mode || pal_changed)
|
||||||
|
color_change = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
#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 */
|
||||||
old_desc = pango_font_description_from_string (prefs.hex_text_font_main);
|
old_desc = pango_font_description_from_string (prefs.hex_text_font_main);
|
||||||
|
|||||||
Reference in New Issue
Block a user