Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam
2026-06-26 00:30:07 +01:00
8 changed files with 478 additions and 29 deletions

View File

@@ -26,6 +26,85 @@
#include "tmux.h"
/* Theme colour slots and their server options. */
static const struct {
const char *name;
const char *dark_option;
const char *light_option;
int terminal_colour;
} colour_theme_table[] = {
{ "themeblack",
"dark-theme-black",
"light-theme-black",
0
},
{ "themewhite",
"dark-theme-white",
"light-theme-white",
7
},
{ "themelightgrey",
"dark-theme-light-grey",
"light-theme-light-grey",
7
},
{ "themedarkgrey",
"dark-theme-dark-grey",
"light-theme-dark-grey",
0
},
{ "themegreen",
"dark-theme-green",
"light-theme-green",
2
},
{ "themeyellow",
"dark-theme-yellow",
"light-theme-yellow",
3
},
{ "themered",
"dark-theme-red",
"light-theme-red",
1
},
{ "themeblue",
"dark-theme-blue",
"light-theme-blue",
4
},
{ "themecyan",
"dark-theme-cyan",
"light-theme-cyan",
6
},
{ "thememagenta",
"dark-theme-magenta",
"light-theme-magenta",
5
}
};
/* Get theme colour option. */
const char *
colour_theme_option(u_int n, enum client_theme theme)
{
if (n >= nitems(colour_theme_table))
return (NULL);
if (theme == THEME_LIGHT)
return (colour_theme_table[n].light_option);
return (colour_theme_table[n].dark_option);
}
/* Get theme terminal colour. */
int
colour_theme_terminal_colour(u_int n)
{
if (n >= nitems(colour_theme_table))
return (8);
return (colour_theme_table[n].terminal_colour);
}
static int
colour_dist_sq(int R, int G, int B, int r, int g, int b)
{
@@ -126,7 +205,7 @@ colour_dim(int c, u_int dim)
{
u_char r, g, b;
if (dim == 0 || COLOUR_DEFAULT(c))
if (dim == 0 || COLOUR_DEFAULT(c) || (c & COLOUR_FLAG_THEME))
return (c);
if (dim >= 100)
return (colour_join_rgb(0, 0, 0));
@@ -152,6 +231,13 @@ colour_tostring(int c)
if (c == -1)
return ("none");
if (c & COLOUR_FLAG_THEME) {
c &= 0xff;
if (c >= 0 && (u_int)c < nitems(colour_theme_table))
return (colour_theme_table[c].name);
return ("invalid");
}
if (c & COLOUR_FLAG_RGB) {
colour_split_rgb(c, &r, &g, &b);
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
@@ -252,6 +338,7 @@ colour_fromstring(const char *s)
const char *cp;
int n;
u_char r, g, b;
u_int i;
if (*s == '#' && strlen(s) == 7) {
for (cp = s + 1; isxdigit((u_char) *cp); cp++)
@@ -282,6 +369,11 @@ colour_fromstring(const char *s)
if (strcasecmp(s, "terminal") == 0)
return (9);
for (i = 0; i < nitems(colour_theme_table); i++) {
if (strcasecmp(s, colour_theme_table[i].name) == 0)
return (i|COLOUR_FLAG_THEME);
}
if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
return (0);
if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)

17
grid.c
View File

@@ -86,7 +86,8 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
return (1);
if (gc->data.size > 1 || gc->data.width > 1)
return (1);
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
if ((gc->fg & (COLOUR_FLAG_RGB|COLOUR_FLAG_THEME)) ||
(gc->bg & (COLOUR_FLAG_RGB|COLOUR_FLAG_THEME)))
return (1);
if (gc->us != 8) /* only supports 256 or RGB */
return (1);
@@ -218,7 +219,7 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg, int moved)
if (bg != 8)
gee->bg = bg;
} else if (bg != 8) {
if (bg & COLOUR_FLAG_RGB) {
if (bg & (COLOUR_FLAG_RGB|COLOUR_FLAG_THEME)) {
grid_get_extended_cell(gl, gce, gce->flags);
gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
gee->bg = bg;
@@ -798,7 +799,9 @@ grid_string_cells_fg(const struct grid_cell *gc, int *values)
u_char r, g, b;
n = 0;
if (gc->fg & COLOUR_FLAG_256) {
if (gc->fg & COLOUR_FLAG_THEME)
values[n++] = 39;
else if (gc->fg & COLOUR_FLAG_256) {
values[n++] = 38;
values[n++] = 5;
values[n++] = gc->fg & 0xff;
@@ -847,7 +850,9 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values)
u_char r, g, b;
n = 0;
if (gc->bg & COLOUR_FLAG_256) {
if (gc->bg & COLOUR_FLAG_THEME)
values[n++] = 49;
else if (gc->bg & COLOUR_FLAG_256) {
values[n++] = 48;
values[n++] = 5;
values[n++] = gc->bg & 0xff;
@@ -896,7 +901,9 @@ grid_string_cells_us(const struct grid_cell *gc, int *values)
u_char r, g, b;
n = 0;
if (gc->us & COLOUR_FLAG_256) {
if (gc->us & COLOUR_FLAG_THEME) {
values[n++] = 59;
} else if (gc->us & COLOUR_FLAG_256) {
values[n++] = 58;
values[n++] = 5;
values[n++] = gc->us & 0xff;

View File

@@ -108,6 +108,9 @@ static const char *options_table_extended_keys_format_list[] = {
static const char *options_table_allow_passthrough_list[] = {
"off", "on", "all", NULL
};
static const char *options_table_theme_list[] = {
"detect", "terminal", "light", "dark", NULL
};
static const char *options_table_copy_mode_line_numbers_list[] = {
"off", "default", "absolute", "relative", "hybrid", NULL
};
@@ -445,7 +448,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.flags = OPTIONS_TABLE_IS_STYLE,
.default_str = "default",
.default_str = "bg=themedarkgrey,fg=themewhite",
.separator = ",",
.text = "Default style of menu."
},
@@ -454,7 +457,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.flags = OPTIONS_TABLE_IS_STYLE,
.default_str = "bg=yellow,fg=black",
.default_str = "bg=themeyellow,fg=themeblack",
.separator = ",",
.text = "Default style of selected menu item."
},
@@ -462,7 +465,7 @@ const struct options_table_entry options_table[] = {
{ .name = "menu-border-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.default_str = "bg=themedarkgrey,fg=themelightgrey",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Default style of menu borders."
@@ -537,6 +540,175 @@ const struct options_table_entry options_table[] = {
"automatically detected."
},
{ .name = "theme",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SERVER,
.choices = options_table_theme_list,
.default_num = 0,
.text = "Whether tmux should detect the terminal theme, use terminal "
"ANSI colours, or force the light or dark theme."
},
{ .name = "dark-theme-black",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray5,black}",
.text = "Dark theme colour for black."
},
{ .name = "dark-theme-white",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray90,white}",
.text = "Dark theme colour for white."
},
{ .name = "dark-theme-light-grey",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray70,white}",
.text = "Dark theme colour for light grey."
},
{ .name = "dark-theme-dark-grey",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray15,black}",
.text = "Dark theme colour for dark grey."
},
{ .name = "dark-theme-green",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},palegreen,green}",
.text = "Dark theme colour for green."
},
{ .name = "dark-theme-yellow",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},lightgoldenrod,yellow}",
.text = "Dark theme colour for yellow."
},
{ .name = "dark-theme-red",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},lightsalmon,red}",
.text = "Dark theme colour for red."
},
{ .name = "dark-theme-blue",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},lightskyblue,blue}",
.text = "Dark theme colour for blue."
},
{ .name = "dark-theme-cyan",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},aquamarine,cyan}",
.text = "Dark theme colour for cyan."
},
{ .name = "dark-theme-magenta",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},plum,magenta}",
.text = "Dark theme colour for magenta."
},
{ .name = "light-theme-black",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray10,black}",
.text = "Light theme colour for black."
},
{ .name = "light-theme-white",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray95,white}",
.text = "Light theme colour for white."
},
{ .name = "light-theme-light-grey",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray80,white}",
.text = "Light theme colour for light grey."
},
{ .name = "light-theme-dark-grey",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},gray45,black}",
.text = "Light theme colour for dark grey."
},
{ .name = "light-theme-green",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},forestgreen,green}",
.text = "Light theme colour for green."
},
{ .name = "light-theme-yellow",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},darkgoldenrod,yellow}",
.text = "Light theme colour for yellow."
},
{ .name = "light-theme-red",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},violetred4,red}",
.text = "Light theme colour for red."
},
{ .name = "light-theme-blue",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},royalblue,blue}",
.text = "Light theme colour for blue."
},
{ .name = "light-theme-cyan",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},darkcyan,cyan}",
.text = "Light theme colour for cyan."
},
{ .name = "light-theme-magenta",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "#{?#{e|>=:#{client_colours},256},purple,magenta}",
.text = "Light theme colour for magenta."
},
{ .name = "user-keys",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
@@ -638,7 +810,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "red",
.default_str = "themered",
.text = "Colour of the active pane for 'display-panes'."
},
@@ -646,7 +818,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "blue",
.default_str = "themeblue",
.text = "Colour of not active panes for 'display-panes'."
},
@@ -737,7 +909,7 @@ const struct options_table_entry options_table[] = {
{ .name = "message-command-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=black,fg=yellow,fill=black",
.default_str = "bg=themegreen,fg=themeblack,fill=themegreen",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the command prompt when in command mode, if "
@@ -766,9 +938,9 @@ const struct options_table_entry options_table[] = {
{ .name = "message-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=yellow,fg=black,"
.default_str = "bg=themeyellow,fg=themeblack,"
"#{?#{m/r:(^|#,)IS(PANE|MODE)($|#,),#{prompt_flags}},,"
"fill=yellow}",
"fill=themeyellow}",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of messages and the command prompt. "
@@ -967,7 +1139,7 @@ const struct options_table_entry options_table[] = {
{ .name = "status-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=green,fg=black",
.default_str = "bg=themegreen,fg=themeblack",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the status line."
@@ -1151,7 +1323,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.flags = OPTIONS_TABLE_IS_COLOUR,
.default_str = "blue",
.default_str = "themeblue",
.text = "Colour of the clock in clock mode."
},
@@ -1166,7 +1338,7 @@ const struct options_table_entry options_table[] = {
{ .name = "copy-mode-match-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "bg=cyan,fg=black",
.default_str = "bg=themecyan,fg=themeblack",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of search matches in copy mode."
@@ -1175,7 +1347,7 @@ const struct options_table_entry options_table[] = {
{ .name = "copy-mode-current-match-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "bg=magenta,fg=black",
.default_str = "bg=thememagenta,fg=themeblack",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the current search match in copy mode."
@@ -1184,7 +1356,7 @@ const struct options_table_entry options_table[] = {
{ .name = "copy-mode-mark-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "bg=red,fg=black",
.default_str = "bg=themeyellow,fg=themeblack",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the marked line in copy mode."
@@ -1223,7 +1395,7 @@ const struct options_table_entry options_table[] = {
{ .name = "copy-mode-current-line-number-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "fg=yellow",
.default_str = "fg=themeyellow",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of current line number in copy mode."
@@ -1232,7 +1404,7 @@ const struct options_table_entry options_table[] = {
{ .name = "copy-mode-line-number-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "fg=white,dim",
.default_str = "fg=themelightgrey,dim",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of line numbers in copy mode."
@@ -1281,7 +1453,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.flags = OPTIONS_TABLE_IS_STYLE,
.default_str = "noattr,bg=yellow,fg=black",
.default_str = "noattr,bg=themeyellow,fg=themeblack",
.separator = ",",
.text = "Style of indicators and highlighting in modes."
},
@@ -1330,7 +1502,9 @@ const struct options_table_entry options_table[] = {
{ .name = "pane-active-border-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#{?pane_in_mode,fg=yellow,#{?synchronize-panes,fg=red,fg=green}}",
.default_str = "fg=#{?pane_marked,thememagenta,"
"#{?synchronize-panes,themered,"
"#{?pane_in_mode,themeyellow,themegreen}}}",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the active pane border."
@@ -1389,7 +1563,7 @@ const struct options_table_entry options_table[] = {
{ .name = "pane-border-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "default",
.default_str = "fg=themelightgrey",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the pane status lines."
@@ -1414,7 +1588,7 @@ const struct options_table_entry options_table[] = {
{ .name = "pane-scrollbars-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "bg=black,fg=white,width=1,pad=0",
.default_str = "bg=themedarkgrey,fg=themelightgrey,width=1,pad=0",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the pane scrollbar."
@@ -1431,7 +1605,7 @@ const struct options_table_entry options_table[] = {
{ .name = "popup-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.default_str = "bg=themedarkgrey,fg=themewhite",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Default style of popups."
@@ -1440,7 +1614,7 @@ const struct options_table_entry options_table[] = {
{ .name = "popup-border-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.default_str = "fg=themelightgrey",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Default style of popup borders."
@@ -1518,8 +1692,8 @@ const struct options_table_entry options_table[] = {
.default_str = "fg=#{?#{||:"
"#{&&:#{pane_format},#{pane_active}},"
"#{&&:#{window_format},#{window_active}}},"
"#{display-panes-active-colour},"
"#{display-panes-colour}}",
"themered,"
"themeblue}",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of preview indicator in tree mode."

View File

@@ -1214,6 +1214,17 @@ options_push_changes(const char *name)
log_debug("%s: %s", __func__, name);
if (strcmp(name, "theme") == 0 ||
strncmp(name, "dark-theme-", 11) == 0 ||
strncmp(name, "light-theme-", 12) == 0) {
TAILQ_FOREACH(loop, &clients, entry) {
server_client_update_theme_colours(loop);
if (loop->tty.flags & TTY_OPENED)
tty_invalidate(&loop->tty);
server_redraw_client(loop);
}
}
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)

View File

@@ -287,6 +287,7 @@ struct client *
server_client_create(int fd)
{
struct client *c;
u_int i;
setblocking(fd, 0);
@@ -309,6 +310,9 @@ server_client_create(int fd)
c->tty.sx = 80;
c->tty.sy = 24;
for (i = 0; i < COLOUR_THEME_COUNT; i++)
c->theme_colours[i] = 8;
c->theme = THEME_UNKNOWN;
status_init(c);
@@ -360,6 +364,7 @@ server_client_open(struct client *c, char **cause)
if (tty_open(&c->tty, cause) != 0)
return (-1);
server_client_update_theme_colours(c);
return (0);
}
@@ -1077,6 +1082,52 @@ have_event:
return (key);
}
/* Update client theme colours from server options. */
void
server_client_update_theme_colours(struct client *c)
{
struct format_tree *ft;
const char *name, *value;
enum client_theme theme;
char *expanded;
u_int i;
int colour, option;
if (c == NULL)
return;
option = options_get_number(global_options, "theme");
if (option == 1) {
for (i = 0; i < COLOUR_THEME_COUNT; i++)
c->theme_colours[i] = colour_theme_terminal_colour(i);
return;
}
ft = format_create(c, NULL, FORMAT_NONE, FORMAT_NOJOBS);
format_defaults(ft, c, NULL, NULL, NULL);
theme = c->theme;
if (option == 2)
theme = THEME_LIGHT;
else if (option == 3)
theme = THEME_DARK;
for (i = 0; i < COLOUR_THEME_COUNT; i++) {
c->theme_colours[i] = 8;
name = colour_theme_option(i, theme);
if (name == NULL)
continue;
value = options_get_string(global_options, name);
expanded = format_expand(ft, value);
colour = colour_fromstring(expanded);
free(expanded);
if (colour == -1 || (colour & COLOUR_FLAG_THEME))
continue;
c->theme_colours[i] = colour;
}
format_free(ft);
}
/* Is this a bracket paste key? */
static int
server_client_is_bracket_paste(struct client *c, key_code key)
@@ -2929,6 +2980,8 @@ out:
static void
server_client_report_theme(struct client *c, enum client_theme theme)
{
enum client_theme old = c->theme;
if (theme == THEME_LIGHT) {
c->theme = THEME_LIGHT;
notify_client("client-light-theme", c);
@@ -2937,6 +2990,17 @@ server_client_report_theme(struct client *c, enum client_theme theme)
notify_client("client-dark-theme", c);
}
/*
* If the theme has changed, update the theme colours and redraw the
* client.
*/
if (c->theme != old) {
server_client_update_theme_colours(c);
if (c->tty.flags & TTY_OPENED)
tty_invalidate(&c->tty);
server_redraw_client(c);
}
/*
* Request foreground and background colour again. Don't forward 2031 to
* panes until a response is received.

51
tmux.1
View File

@@ -4573,6 +4573,57 @@ where the number is a hexadecimal number, or a range of the form
Give the command to pipe to if the
.Ic copy\-pipe
copy mode command is used without arguments.
.It Xo Ic theme
.Op Ic detect | terminal | light | dark
.Xc
Whether tmux should use the detected client theme
.Pq Ic detect ,
use terminal ANSI colours
.Pq Ic terminal ,
or force the light or dark theme.
.It Xo Ic dark\-theme\-black ,
.Ic dark\-theme\-white ,
.Ic dark\-theme\-light\-grey ,
.Ic dark\-theme\-dark\-grey ,
.Ic dark\-theme\-green ,
.Ic dark\-theme\-yellow ,
.Ic dark\-theme\-red ,
.Ic dark\-theme\-blue ,
.Ic dark\-theme\-cyan ,
.Ic dark\-theme\-magenta ,
.Ic light\-theme\-black ,
.Ic light\-theme\-white ,
.Ic light\-theme\-light\-grey ,
.Ic light\-theme\-dark\-grey ,
.Ic light\-theme\-green ,
.Ic light\-theme\-yellow ,
.Ic light\-theme\-red ,
.Ic light\-theme\-blue ,
.Ic light\-theme\-cyan
.No and Ic light\-theme\-magenta Ar colour
.Xc
Set the theme colours.
These are the named colours
.Ic themeblack ,
.Ic themewhite ,
.Ic themelightgrey ,
.Ic themedarkgrey ,
.Ic themegreen ,
.Ic themeyellow ,
.Ic themered ,
.Ic themeblue ,
.Ic themecyan
and
.Ic thememagenta
which may be used in styles and elsewhere a
.Ar colour
is accepted.
The
.Ic dark\-theme\-*
set is used when the client reports a dark background and the
.Ic light\-theme\-*
set when it reports a light background;
an unknown background is treated as dark.
.It Ic default\-client\-command Ar command
Set the default command to run when tmux is called without a command.
The default is

21
tmux.h
View File

@@ -737,10 +737,26 @@ enum hanguljamo_state {
/* Colour flags. */
#define COLOUR_FLAG_256 0x01000000
#define COLOUR_FLAG_RGB 0x02000000
#define COLOUR_FLAG_THEME 0x04000000
/* Special colours. */
#define COLOUR_DEFAULT(c) ((c) == 8 || (c) == 9)
/* Theme colours. */
enum colour_theme {
COLOUR_THEME_BLACK,
COLOUR_THEME_WHITE,
COLOUR_THEME_LIGHT_GREY,
COLOUR_THEME_DARK_GREY,
COLOUR_THEME_GREEN,
COLOUR_THEME_YELLOW,
COLOUR_THEME_RED,
COLOUR_THEME_BLUE,
COLOUR_THEME_CYAN,
COLOUR_THEME_MAGENTA
};
#define COLOUR_THEME_COUNT 10
/* Replacement palette. */
struct colour_palette {
int fg;
@@ -2260,6 +2276,8 @@ struct client {
int references;
int theme_colours[COLOUR_THEME_COUNT];
void *pan_window;
u_int pan_ox;
u_int pan_oy;
@@ -3158,6 +3176,7 @@ void server_client_print(struct client *, int, struct evbuffer *);
/* server-fn.c */
void server_redraw_client(struct client *);
void server_client_update_theme_colours(struct client *);
void server_status_client(struct client *);
void server_redraw_session(struct session *);
void server_redraw_session_group(struct session *);
@@ -3271,6 +3290,8 @@ int colour_dim(int, u_int);
const char *colour_tostring(int);
enum client_theme colour_totheme(int);
int colour_fromstring(const char *);
const char *colour_theme_option(u_int, enum client_theme);
int colour_theme_terminal_colour(u_int);
int colour_256toRGB(int);
int colour_256to16(int);
int colour_byname(const char *);

29
tty.c
View File

@@ -51,6 +51,7 @@ static void tty_check_bg(struct tty *, struct colour_palette *,
struct grid_cell *);
static void tty_check_us(struct tty *, struct colour_palette *,
struct grid_cell *);
static int tty_map_theme_colour(struct tty *, int);
static void tty_colours_fg(struct tty *, const struct grid_cell *);
static void tty_colours_bg(struct tty *, const struct grid_cell *);
static void tty_colours_us(struct tty *, const struct grid_cell *);
@@ -2641,6 +2642,9 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
gc2.bg = changed;
}
}
gc2.fg = tty_map_theme_colour(tty, gc2.fg);
gc2.bg = tty_map_theme_colour(tty, gc2.bg);
gc2.us = tty_map_theme_colour(tty, gc2.us);
if (style_ctx->dim != 0) {
gc2.fg = tty_dim_default_colour(tty, gc2.fg, 1);
gc2.bg = tty_dim_default_colour(tty, gc2.bg, 0);
@@ -2790,6 +2794,28 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
tty_colours_us(tty, gc);
}
static int
tty_map_theme_colour(struct tty *tty, int colour)
{
struct client *c;
u_int n;
int m;
if (~colour & COLOUR_FLAG_THEME)
return (colour);
n = colour & 0xff;
if (n >= COLOUR_THEME_COUNT)
return (8);
if (tty == NULL || (c = tty->client) == NULL)
return (8);
m = c->theme_colours[n];
if (m == -1 || (m & COLOUR_FLAG_THEME))
return (8);
return (m);
}
static void
tty_check_fg(struct tty *tty, struct colour_palette *palette,
struct grid_cell *gc)
@@ -2812,6 +2838,7 @@ tty_check_fg(struct tty *tty, struct colour_palette *palette,
if ((c = colour_palette_get(palette, c)) != -1)
gc->fg = c;
}
gc->fg = tty_map_theme_colour(tty, gc->fg);
/* Is this a 24-bit colour? */
if (gc->fg & COLOUR_FLAG_RGB) {
@@ -2872,6 +2899,7 @@ tty_check_bg(struct tty *tty, struct colour_palette *palette,
if ((c = colour_palette_get(palette, gc->bg)) != -1)
gc->bg = c;
}
gc->bg = tty_map_theme_colour(tty, gc->bg);
/* Is this a 24-bit colour? */
if (gc->bg & COLOUR_FLAG_RGB) {
@@ -2922,6 +2950,7 @@ tty_check_us(__unused struct tty *tty, struct colour_palette *palette,
if ((c = colour_palette_get(palette, gc->us)) != -1)
gc->us = c;
}
gc->us = tty_map_theme_colour(tty, gc->us);
/* Convert underscore colour if only RGB can be supported. */
if (!tty_term_has(tty->term, TTYC_SETULC1)) {