mirror of
https://github.com/tmux/tmux.git
synced 2025-04-17 09:18:48 +00:00
Add mode 2031 support (automatic dark/light mode).
Co-Author: Nicholas Marriott <nicholas.marriott@gmail.com>
This commit is contained in:
parent
ef68debc8d
commit
e536f48d0e
32
colour.c
32
colour.c
@ -182,6 +182,38 @@ colour_tostring(int c)
|
|||||||
return ("invalid");
|
return ("invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert background colour to theme. */
|
||||||
|
enum client_theme
|
||||||
|
colour_totheme(int c)
|
||||||
|
{
|
||||||
|
int r, g, b, brightness;
|
||||||
|
|
||||||
|
if (c == -1)
|
||||||
|
return (THEME_UNKNOWN);
|
||||||
|
|
||||||
|
if (c & COLOUR_FLAG_RGB) {
|
||||||
|
r = (c >> 16) & 0xff;
|
||||||
|
g = (c >> 8) & 0xff;
|
||||||
|
b = (c >> 0) & 0xff;
|
||||||
|
|
||||||
|
brightness = r + g + b;
|
||||||
|
if (brightness > 382)
|
||||||
|
return (THEME_LIGHT);
|
||||||
|
return (THEME_DARK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c & COLOUR_FLAG_256)
|
||||||
|
return (colour_totheme(colour_256toRGB(c)));
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
return (THEME_DARK);
|
||||||
|
case 7:
|
||||||
|
return (THEME_LIGHT);
|
||||||
|
}
|
||||||
|
return (THEME_UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert colour from string. */
|
/* Convert colour from string. */
|
||||||
int
|
int
|
||||||
colour_fromstring(const char *s)
|
colour_fromstring(const char *s)
|
||||||
|
20
format.c
20
format.c
@ -1544,6 +1544,23 @@ format_cb_client_written(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for client_theme. */
|
||||||
|
static void *
|
||||||
|
format_cb_client_theme(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
if (ft->c != NULL) {
|
||||||
|
switch (ft->c->theme) {
|
||||||
|
case THEME_DARK:
|
||||||
|
return (xstrdup("dark"));
|
||||||
|
case THEME_LIGHT:
|
||||||
|
return (xstrdup("light"));
|
||||||
|
case THEME_UNKNOWN:
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for config_files. */
|
/* Callback for config_files. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_config_files(__unused struct format_tree *ft)
|
format_cb_config_files(__unused struct format_tree *ft)
|
||||||
@ -2881,6 +2898,9 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "client_termtype", FORMAT_TABLE_STRING,
|
{ "client_termtype", FORMAT_TABLE_STRING,
|
||||||
format_cb_client_termtype
|
format_cb_client_termtype
|
||||||
},
|
},
|
||||||
|
{ "client_theme", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_client_theme
|
||||||
|
},
|
||||||
{ "client_tty", FORMAT_TABLE_STRING,
|
{ "client_tty", FORMAT_TABLE_STRING,
|
||||||
format_cb_client_tty
|
format_cb_client_tty
|
||||||
},
|
},
|
||||||
|
@ -307,6 +307,12 @@ static struct input_key_entry input_key_defaults[] = {
|
|||||||
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
|
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
|
||||||
.data = "\033[3;_~"
|
.data = "\033[3;_~"
|
||||||
},
|
},
|
||||||
|
{ .key = KEYC_REPORT_DARK_THEME,
|
||||||
|
.data = "\033[?997;1n"
|
||||||
|
},
|
||||||
|
{ .key = KEYC_REPORT_LIGHT_THEME,
|
||||||
|
.data = "\033[?997;2n"
|
||||||
|
},
|
||||||
};
|
};
|
||||||
static const key_code input_key_modifiers[] = {
|
static const key_code input_key_modifiers[] = {
|
||||||
0,
|
0,
|
||||||
|
135
input.c
135
input.c
@ -133,7 +133,7 @@ static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
|
|||||||
static void input_set_state(struct input_ctx *,
|
static void input_set_state(struct input_ctx *,
|
||||||
const struct input_transition *);
|
const struct input_transition *);
|
||||||
static void input_reset_cell(struct input_ctx *);
|
static void input_reset_cell(struct input_ctx *);
|
||||||
|
static void input_report_current_theme(struct input_ctx *);
|
||||||
static void input_osc_4(struct input_ctx *, const char *);
|
static void input_osc_4(struct input_ctx *, const char *);
|
||||||
static void input_osc_8(struct input_ctx *, const char *);
|
static void input_osc_8(struct input_ctx *, const char *);
|
||||||
static void input_osc_10(struct input_ctx *, const char *);
|
static void input_osc_10(struct input_ctx *, const char *);
|
||||||
@ -243,6 +243,7 @@ enum input_csi_type {
|
|||||||
INPUT_CSI_DECSTBM,
|
INPUT_CSI_DECSTBM,
|
||||||
INPUT_CSI_DL,
|
INPUT_CSI_DL,
|
||||||
INPUT_CSI_DSR,
|
INPUT_CSI_DSR,
|
||||||
|
INPUT_CSI_DSR_PRIVATE,
|
||||||
INPUT_CSI_ECH,
|
INPUT_CSI_ECH,
|
||||||
INPUT_CSI_ED,
|
INPUT_CSI_ED,
|
||||||
INPUT_CSI_EL,
|
INPUT_CSI_EL,
|
||||||
@ -251,6 +252,7 @@ enum input_csi_type {
|
|||||||
INPUT_CSI_IL,
|
INPUT_CSI_IL,
|
||||||
INPUT_CSI_MODOFF,
|
INPUT_CSI_MODOFF,
|
||||||
INPUT_CSI_MODSET,
|
INPUT_CSI_MODSET,
|
||||||
|
INPUT_CSI_QUERY_PRIVATE,
|
||||||
INPUT_CSI_RCP,
|
INPUT_CSI_RCP,
|
||||||
INPUT_CSI_REP,
|
INPUT_CSI_REP,
|
||||||
INPUT_CSI_RM,
|
INPUT_CSI_RM,
|
||||||
@ -259,8 +261,8 @@ enum input_csi_type {
|
|||||||
INPUT_CSI_SD,
|
INPUT_CSI_SD,
|
||||||
INPUT_CSI_SGR,
|
INPUT_CSI_SGR,
|
||||||
INPUT_CSI_SM,
|
INPUT_CSI_SM,
|
||||||
INPUT_CSI_SM_PRIVATE,
|
|
||||||
INPUT_CSI_SM_GRAPHICS,
|
INPUT_CSI_SM_GRAPHICS,
|
||||||
|
INPUT_CSI_SM_PRIVATE,
|
||||||
INPUT_CSI_SU,
|
INPUT_CSI_SU,
|
||||||
INPUT_CSI_TBC,
|
INPUT_CSI_TBC,
|
||||||
INPUT_CSI_VPA,
|
INPUT_CSI_VPA,
|
||||||
@ -304,6 +306,8 @@ static const struct input_table_entry input_csi_table[] = {
|
|||||||
{ 'm', ">", INPUT_CSI_MODSET },
|
{ 'm', ">", INPUT_CSI_MODSET },
|
||||||
{ 'n', "", INPUT_CSI_DSR },
|
{ 'n', "", INPUT_CSI_DSR },
|
||||||
{ 'n', ">", INPUT_CSI_MODOFF },
|
{ 'n', ">", INPUT_CSI_MODOFF },
|
||||||
|
{ 'n', "?", INPUT_CSI_DSR_PRIVATE },
|
||||||
|
{ 'p', "?$", INPUT_CSI_QUERY_PRIVATE },
|
||||||
{ 'q', " ", INPUT_CSI_DECSCUSR },
|
{ 'q', " ", INPUT_CSI_DECSCUSR },
|
||||||
{ 'q', ">", INPUT_CSI_XDA },
|
{ 'q', ">", INPUT_CSI_XDA },
|
||||||
{ 'r', "", INPUT_CSI_DECSTBM },
|
{ 'r', "", INPUT_CSI_DECSTBM },
|
||||||
@ -1531,6 +1535,20 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
if (n != -1)
|
if (n != -1)
|
||||||
screen_write_deleteline(sctx, n, bg);
|
screen_write_deleteline(sctx, n, bg);
|
||||||
break;
|
break;
|
||||||
|
case INPUT_CSI_DSR_PRIVATE:
|
||||||
|
switch (input_get(ictx, 0, 0, 0)) {
|
||||||
|
case 996:
|
||||||
|
input_report_current_theme(ictx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INPUT_CSI_QUERY_PRIVATE:
|
||||||
|
switch (input_get(ictx, 0, 0, 0)) {
|
||||||
|
case 2031:
|
||||||
|
input_reply(ictx, "\033[?2031;2$y");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case INPUT_CSI_DSR:
|
case INPUT_CSI_DSR:
|
||||||
switch (input_get(ictx, 0, 0, 0)) {
|
switch (input_get(ictx, 0, 0, 0)) {
|
||||||
case -1:
|
case -1:
|
||||||
@ -1781,6 +1799,9 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
|
|||||||
case 2004:
|
case 2004:
|
||||||
screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
|
screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
|
||||||
break;
|
break;
|
||||||
|
case 2031:
|
||||||
|
screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
@ -1876,6 +1897,9 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
|
|||||||
case 2004:
|
case 2004:
|
||||||
screen_write_mode_set(sctx, MODE_BRACKETPASTE);
|
screen_write_mode_set(sctx, MODE_BRACKETPASTE);
|
||||||
break;
|
break;
|
||||||
|
case 2031:
|
||||||
|
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
@ -2697,84 +2721,6 @@ bad:
|
|||||||
free(id);
|
free(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a client with a foreground for the pane. There isn't much to choose
|
|
||||||
* between them so just use the first.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
input_get_fg_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct window *w = wp->window;
|
|
||||||
struct client *loop;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(loop, &clients, entry) {
|
|
||||||
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
|
||||||
continue;
|
|
||||||
if (loop->session == NULL || !session_has(loop->session, w))
|
|
||||||
continue;
|
|
||||||
if (loop->tty.fg == -1)
|
|
||||||
continue;
|
|
||||||
return (loop->tty.fg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get a client with a background for the pane. */
|
|
||||||
static int
|
|
||||||
input_get_bg_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct window *w = wp->window;
|
|
||||||
struct client *loop;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(loop, &clients, entry) {
|
|
||||||
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
|
||||||
continue;
|
|
||||||
if (loop->session == NULL || !session_has(loop->session, w))
|
|
||||||
continue;
|
|
||||||
if (loop->tty.bg == -1)
|
|
||||||
continue;
|
|
||||||
return (loop->tty.bg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If any control mode client exists that has provided a bg color, return it.
|
|
||||||
* Otherwise, return -1.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
input_get_bg_control_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct client *c;
|
|
||||||
|
|
||||||
if (wp->control_bg == -1)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
|
||||||
if (c->flags & CLIENT_CONTROL)
|
|
||||||
return (wp->control_bg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If any control mode client exists that has provided a fg color, return it.
|
|
||||||
* Otherwise, return -1.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
input_get_fg_control_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct client *c;
|
|
||||||
|
|
||||||
if (wp->control_fg == -1)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
|
||||||
if (c->flags & CLIENT_CONTROL)
|
|
||||||
return (wp->control_fg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
||||||
static void
|
static void
|
||||||
@ -2787,11 +2733,11 @@ input_osc_10(struct input_ctx *ictx, const char *p)
|
|||||||
if (strcmp(p, "?") == 0) {
|
if (strcmp(p, "?") == 0) {
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
return;
|
return;
|
||||||
c = input_get_fg_control_client(wp);
|
c = window_pane_get_fg_control_client(wp);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
tty_default_colours(&defaults, wp);
|
tty_default_colours(&defaults, wp);
|
||||||
if (COLOUR_DEFAULT(defaults.fg))
|
if (COLOUR_DEFAULT(defaults.fg))
|
||||||
c = input_get_fg_client(wp);
|
c = window_pane_get_fg(wp);
|
||||||
else
|
else
|
||||||
c = defaults.fg;
|
c = defaults.fg;
|
||||||
}
|
}
|
||||||
@ -2832,20 +2778,12 @@ static void
|
|||||||
input_osc_11(struct input_ctx *ictx, const char *p)
|
input_osc_11(struct input_ctx *ictx, const char *p)
|
||||||
{
|
{
|
||||||
struct window_pane *wp = ictx->wp;
|
struct window_pane *wp = ictx->wp;
|
||||||
struct grid_cell defaults;
|
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if (strcmp(p, "?") == 0) {
|
if (strcmp(p, "?") == 0) {
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
return;
|
return;
|
||||||
c = input_get_bg_control_client(wp);
|
c = window_pane_get_bg(wp);
|
||||||
if (c == -1) {
|
|
||||||
tty_default_colours(&defaults, wp);
|
|
||||||
if (COLOUR_DEFAULT(defaults.bg))
|
|
||||||
c = input_get_bg_client(wp);
|
|
||||||
else
|
|
||||||
c = defaults.bg;
|
|
||||||
}
|
|
||||||
input_osc_colour_reply(ictx, 11, c);
|
input_osc_colour_reply(ictx, 11, c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3064,3 +3002,18 @@ input_set_buffer_size(size_t buffer_size)
|
|||||||
log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
|
log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
|
||||||
input_buffer_size = buffer_size;
|
input_buffer_size = buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
input_report_current_theme(struct input_ctx *ictx)
|
||||||
|
{
|
||||||
|
switch (window_pane_get_theme(ictx->wp)) {
|
||||||
|
case THEME_DARK:
|
||||||
|
input_reply(ictx, "\033[?997;1n");
|
||||||
|
break;
|
||||||
|
case THEME_LIGHT:
|
||||||
|
input_reply(ictx, "\033[?997;2n");
|
||||||
|
break;
|
||||||
|
case THEME_UNKNOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1454,6 +1454,8 @@ const struct options_table_entry options_table[] = {
|
|||||||
OPTIONS_TABLE_HOOK("client-focus-out", ""),
|
OPTIONS_TABLE_HOOK("client-focus-out", ""),
|
||||||
OPTIONS_TABLE_HOOK("client-resized", ""),
|
OPTIONS_TABLE_HOOK("client-resized", ""),
|
||||||
OPTIONS_TABLE_HOOK("client-session-changed", ""),
|
OPTIONS_TABLE_HOOK("client-session-changed", ""),
|
||||||
|
OPTIONS_TABLE_HOOK("client-light-theme", ""),
|
||||||
|
OPTIONS_TABLE_HOOK("client-dark-theme", ""),
|
||||||
OPTIONS_TABLE_HOOK("command-error", ""),
|
OPTIONS_TABLE_HOOK("command-error", ""),
|
||||||
OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
|
OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
|
||||||
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
|
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
|
||||||
|
@ -878,6 +878,9 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
|
|||||||
|
|
||||||
log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
|
log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
|
||||||
|
|
||||||
|
if (wp->flags & PANE_STYLECHANGED)
|
||||||
|
window_pane_send_theme_update(wp);
|
||||||
|
|
||||||
if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
|
if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
|
||||||
return;
|
return;
|
||||||
if (ctx->statustop)
|
if (ctx->statustop)
|
||||||
|
@ -56,11 +56,11 @@ static void server_client_set_title(struct client *);
|
|||||||
static void server_client_set_path(struct client *);
|
static void server_client_set_path(struct client *);
|
||||||
static void server_client_reset_state(struct client *);
|
static void server_client_reset_state(struct client *);
|
||||||
static void server_client_update_latest(struct client *);
|
static void server_client_update_latest(struct client *);
|
||||||
|
|
||||||
static void server_client_dispatch(struct imsg *, void *);
|
static void server_client_dispatch(struct imsg *, void *);
|
||||||
static void server_client_dispatch_command(struct client *, struct imsg *);
|
static void server_client_dispatch_command(struct client *, struct imsg *);
|
||||||
static void server_client_dispatch_identify(struct client *, struct imsg *);
|
static void server_client_dispatch_identify(struct client *, struct imsg *);
|
||||||
static void server_client_dispatch_shell(struct client *);
|
static void server_client_dispatch_shell(struct client *);
|
||||||
|
static void server_client_report_theme(struct client *, enum client_theme);
|
||||||
|
|
||||||
/* Compare client windows. */
|
/* Compare client windows. */
|
||||||
static int
|
static int
|
||||||
@ -299,6 +299,7 @@ server_client_create(int fd)
|
|||||||
|
|
||||||
c->tty.sx = 80;
|
c->tty.sx = 80;
|
||||||
c->tty.sy = 24;
|
c->tty.sy = 24;
|
||||||
|
c->theme = THEME_UNKNOWN;
|
||||||
|
|
||||||
status_init(c);
|
status_init(c);
|
||||||
c->flags |= CLIENT_FOCUSED;
|
c->flags |= CLIENT_FOCUSED;
|
||||||
@ -2383,6 +2384,16 @@ server_client_key_callback(struct cmdq_item *item, void *data)
|
|||||||
event->key = key;
|
event->key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle theme reporting keys. */
|
||||||
|
if (key == KEYC_REPORT_LIGHT_THEME) {
|
||||||
|
server_client_report_theme(c, THEME_LIGHT);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (key == KEYC_REPORT_DARK_THEME) {
|
||||||
|
server_client_report_theme(c, THEME_DARK);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find affected pane. */
|
/* Find affected pane. */
|
||||||
if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
|
if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
|
||||||
cmd_find_from_client(&fs, c, 0);
|
cmd_find_from_client(&fs, c, 0);
|
||||||
@ -3909,3 +3920,21 @@ out:
|
|||||||
if (!parse)
|
if (!parse)
|
||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
server_client_report_theme(struct client *c, enum client_theme theme)
|
||||||
|
{
|
||||||
|
if (theme == THEME_LIGHT) {
|
||||||
|
c->theme = THEME_LIGHT;
|
||||||
|
notify_client("client-light-theme", c);
|
||||||
|
} else {
|
||||||
|
c->theme = THEME_DARK;
|
||||||
|
notify_client("client-dark-theme", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request foregroundand background colour again. Don't forward 2031 to
|
||||||
|
* panes until a response is received.
|
||||||
|
*/
|
||||||
|
tty_puts(&c->tty, "\033]10;?\033\\\033]11;?\033\\");
|
||||||
|
}
|
||||||
|
20
tmux.h
20
tmux.h
@ -377,6 +377,10 @@ enum {
|
|||||||
KEYC_KP_ZERO,
|
KEYC_KP_ZERO,
|
||||||
KEYC_KP_PERIOD,
|
KEYC_KP_PERIOD,
|
||||||
|
|
||||||
|
/* Theme reporting. */
|
||||||
|
KEYC_REPORT_DARK_THEME,
|
||||||
|
KEYC_REPORT_LIGHT_THEME,
|
||||||
|
|
||||||
/* End of special keys. */
|
/* End of special keys. */
|
||||||
KEYC_BASE_END
|
KEYC_BASE_END
|
||||||
};
|
};
|
||||||
@ -644,6 +648,7 @@ enum tty_code_code {
|
|||||||
#define MODE_CURSOR_VERY_VISIBLE 0x10000
|
#define MODE_CURSOR_VERY_VISIBLE 0x10000
|
||||||
#define MODE_CURSOR_BLINKING_SET 0x20000
|
#define MODE_CURSOR_BLINKING_SET 0x20000
|
||||||
#define MODE_KEYS_EXTENDED_2 0x40000
|
#define MODE_KEYS_EXTENDED_2 0x40000
|
||||||
|
#define MODE_THEME_UPDATES 0x80000
|
||||||
|
|
||||||
#define ALL_MODES 0xffffff
|
#define ALL_MODES 0xffffff
|
||||||
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
|
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
|
||||||
@ -1863,6 +1868,12 @@ struct overlay_ranges {
|
|||||||
u_int nx[OVERLAY_MAX_RANGES];
|
u_int nx[OVERLAY_MAX_RANGES];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum client_theme {
|
||||||
|
THEME_UNKNOWN,
|
||||||
|
THEME_LIGHT,
|
||||||
|
THEME_DARK
|
||||||
|
};
|
||||||
|
|
||||||
/* Client connection. */
|
/* Client connection. */
|
||||||
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
|
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
|
||||||
typedef void (*prompt_free_cb)(void *);
|
typedef void (*prompt_free_cb)(void *);
|
||||||
@ -1922,6 +1933,7 @@ struct client {
|
|||||||
struct mouse_event click_event;
|
struct mouse_event click_event;
|
||||||
|
|
||||||
struct status_line status;
|
struct status_line status;
|
||||||
|
enum client_theme theme;
|
||||||
|
|
||||||
#define CLIENT_TERMINAL 0x1
|
#define CLIENT_TERMINAL 0x1
|
||||||
#define CLIENT_LOGIN 0x2
|
#define CLIENT_LOGIN 0x2
|
||||||
@ -2929,6 +2941,8 @@ void input_parse_screen(struct input_ctx *, struct screen *,
|
|||||||
void input_reply_clipboard(struct bufferevent *, const char *, size_t,
|
void input_reply_clipboard(struct bufferevent *, const char *, size_t,
|
||||||
const char *);
|
const char *);
|
||||||
void input_set_buffer_size(size_t);
|
void input_set_buffer_size(size_t);
|
||||||
|
int input_get_bg_client(struct window_pane *);
|
||||||
|
int input_get_bg_control_client(struct window_pane *);
|
||||||
|
|
||||||
/* input-key.c */
|
/* input-key.c */
|
||||||
void input_key_build(void);
|
void input_key_build(void);
|
||||||
@ -2943,7 +2957,8 @@ int colour_join_rgb(u_char, u_char, u_char);
|
|||||||
void colour_split_rgb(int, u_char *, u_char *, u_char *);
|
void colour_split_rgb(int, u_char *, u_char *, u_char *);
|
||||||
int colour_force_rgb(int);
|
int colour_force_rgb(int);
|
||||||
const char *colour_tostring(int);
|
const char *colour_tostring(int);
|
||||||
int colour_fromstring(const char *s);
|
enum client_theme colour_totheme(int);
|
||||||
|
int colour_fromstring(const char *);
|
||||||
int colour_256toRGB(int);
|
int colour_256toRGB(int);
|
||||||
int colour_256to16(int);
|
int colour_256to16(int);
|
||||||
int colour_byname(const char *);
|
int colour_byname(const char *);
|
||||||
@ -3244,6 +3259,9 @@ void window_set_fill_character(struct window *);
|
|||||||
void window_pane_default_cursor(struct window_pane *);
|
void window_pane_default_cursor(struct window_pane *);
|
||||||
int window_pane_mode(struct window_pane *);
|
int window_pane_mode(struct window_pane *);
|
||||||
int window_pane_show_scrollbar(struct window_pane *, int);
|
int window_pane_show_scrollbar(struct window_pane *, int);
|
||||||
|
int window_pane_get_bg(struct window_pane *);
|
||||||
|
enum client_theme window_pane_get_theme(struct window_pane *);
|
||||||
|
void window_pane_send_theme_update(struct window_pane *);
|
||||||
|
|
||||||
/* layout.c */
|
/* layout.c */
|
||||||
u_int layout_count_cells(struct layout_cell *);
|
u_int layout_count_cells(struct layout_cell *);
|
||||||
|
20
tty-keys.c
20
tty-keys.c
@ -59,6 +59,7 @@ static int tty_keys_device_attributes2(struct tty *, const char *, size_t,
|
|||||||
size_t *);
|
size_t *);
|
||||||
static int tty_keys_extended_device_attributes(struct tty *, const char *,
|
static int tty_keys_extended_device_attributes(struct tty *, const char *,
|
||||||
size_t, size_t *);
|
size_t, size_t *);
|
||||||
|
static void tty_keys_send_theme_updates(struct tty *);
|
||||||
|
|
||||||
/* A key tree entry. */
|
/* A key tree entry. */
|
||||||
struct tty_key {
|
struct tty_key {
|
||||||
@ -213,6 +214,10 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
|
|||||||
|
|
||||||
/* Extended keys. */
|
/* Extended keys. */
|
||||||
{ "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT },
|
{ "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT },
|
||||||
|
|
||||||
|
/* Theme reporting. */
|
||||||
|
{ "\033[?997;1n", KEYC_REPORT_DARK_THEME },
|
||||||
|
{ "\033[?997;2n", KEYC_REPORT_LIGHT_THEME },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default xterm keys. */
|
/* Default xterm keys. */
|
||||||
@ -791,10 +796,12 @@ tty_keys_next(struct tty *tty)
|
|||||||
switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) {
|
switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) {
|
||||||
case 0: /* yes */
|
case 0: /* yes */
|
||||||
key = KEYC_UNKNOWN;
|
key = KEYC_UNKNOWN;
|
||||||
|
tty_keys_send_theme_updates(tty);
|
||||||
goto complete_key;
|
goto complete_key;
|
||||||
case -1: /* no, or not valid */
|
case -1: /* no, or not valid */
|
||||||
break;
|
break;
|
||||||
case 1: /* partial */
|
case 1: /* partial */
|
||||||
|
tty_keys_send_theme_updates(tty);
|
||||||
goto partial_key;
|
goto partial_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1679,3 +1686,16 @@ tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size,
|
|||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update theme in every pane for client's session. */
|
||||||
|
static void
|
||||||
|
tty_keys_send_theme_updates(struct tty *tty)
|
||||||
|
{
|
||||||
|
struct window_pane *wp;
|
||||||
|
struct winlink *wl;
|
||||||
|
|
||||||
|
RB_FOREACH(wl, winlinks, &tty->client->session->windows) {
|
||||||
|
TAILQ_FOREACH(wp, &wl->window->panes, entry)
|
||||||
|
window_pane_send_theme_update(wp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
8
tty.c
8
tty.c
@ -356,6 +356,11 @@ tty_start_tty(struct tty *tty)
|
|||||||
if (tty_term_has(tty->term, TTYC_ENBP))
|
if (tty_term_has(tty->term, TTYC_ENBP))
|
||||||
tty_putcode(tty, TTYC_ENBP);
|
tty_putcode(tty, TTYC_ENBP);
|
||||||
|
|
||||||
|
if (tty->term->flags & TERM_VT100LIKE) {
|
||||||
|
tty_puts(tty, "\033[?2031h"); /* Subscribe for theme updates. */
|
||||||
|
tty_puts(tty, "\033[?996n"); /* Request theme right away. */
|
||||||
|
}
|
||||||
|
|
||||||
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
|
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
|
||||||
evtimer_add(&tty->start_timer, &tv);
|
evtimer_add(&tty->start_timer, &tv);
|
||||||
|
|
||||||
@ -468,6 +473,9 @@ tty_stop_tty(struct tty *tty)
|
|||||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
|
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
|
||||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
|
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
|
||||||
|
|
||||||
|
if (tty->term->flags & TERM_VT100LIKE)
|
||||||
|
tty_raw(tty, "\033[?2031l");
|
||||||
|
|
||||||
setblocking(c->fd, 1);
|
setblocking(c->fd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
154
window.c
154
window.c
@ -1756,3 +1756,157 @@ window_pane_show_scrollbar(struct window_pane *wp, int sb_option)
|
|||||||
return (1);
|
return (1);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
window_pane_get_bg(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
struct grid_cell defaults;
|
||||||
|
|
||||||
|
c = window_pane_get_bg_control_client(wp);
|
||||||
|
if (c == -1) {
|
||||||
|
tty_default_colours(&defaults, wp);
|
||||||
|
if (COLOUR_DEFAULT(defaults.bg))
|
||||||
|
c = window_get_bg_client(wp);
|
||||||
|
else
|
||||||
|
c = defaults.bg;
|
||||||
|
}
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a client with a background for the pane. */
|
||||||
|
int
|
||||||
|
window_get_bg_client(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct window *w = wp->window;
|
||||||
|
struct client *loop;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(loop, &clients, entry) {
|
||||||
|
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
||||||
|
continue;
|
||||||
|
if (loop->session == NULL || !session_has(loop->session, w))
|
||||||
|
continue;
|
||||||
|
if (loop->tty.bg == -1)
|
||||||
|
continue;
|
||||||
|
return (loop->tty.bg);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If any control mode client exists that has provided a bg color, return it.
|
||||||
|
* Otherwise, return -1.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
window_pane_get_bg_control_client(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct client *c;
|
||||||
|
|
||||||
|
if (wp->control_bg == -1)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
|
if (c->flags & CLIENT_CONTROL)
|
||||||
|
return (wp->control_bg);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a client with a foreground for the pane. There isn't much to choose
|
||||||
|
* between them so just use the first.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
window_pane_get_fg(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct window *w = wp->window;
|
||||||
|
struct client *loop;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(loop, &clients, entry) {
|
||||||
|
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
||||||
|
continue;
|
||||||
|
if (loop->session == NULL || !session_has(loop->session, w))
|
||||||
|
continue;
|
||||||
|
if (loop->tty.fg == -1)
|
||||||
|
continue;
|
||||||
|
return (loop->tty.fg);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If any control mode client exists that has provided a fg color, return it.
|
||||||
|
* Otherwise, return -1.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
window_pane_get_fg_control_client(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct client *c;
|
||||||
|
|
||||||
|
if (wp->control_fg == -1)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
|
if (c->flags & CLIENT_CONTROL)
|
||||||
|
return (wp->control_fg);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum client_theme
|
||||||
|
window_pane_get_theme(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct window *w = wp->window;
|
||||||
|
struct client *loop;
|
||||||
|
enum client_theme theme;
|
||||||
|
int found_light = 0, found_dark = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derive theme from pane background color, if it's not the default
|
||||||
|
* colour.
|
||||||
|
*/
|
||||||
|
theme = colour_totheme(window_pane_get_bg(wp));
|
||||||
|
if (theme != THEME_UNKNOWN)
|
||||||
|
return (theme);
|
||||||
|
|
||||||
|
/* Try to find a client that has a theme. */
|
||||||
|
TAILQ_FOREACH(loop, &clients, entry) {
|
||||||
|
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
||||||
|
continue;
|
||||||
|
if (loop->session == NULL || !session_has(loop->session, w))
|
||||||
|
continue;
|
||||||
|
switch (loop->theme) {
|
||||||
|
case THEME_LIGHT:
|
||||||
|
found_light = 1;
|
||||||
|
break;
|
||||||
|
case THEME_DARK:
|
||||||
|
found_dark = 1;
|
||||||
|
break;
|
||||||
|
case THEME_UNKNOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_dark && !found_light)
|
||||||
|
return (THEME_DARK);
|
||||||
|
if (found_light && !found_dark)
|
||||||
|
return (THEME_LIGHT);
|
||||||
|
return (THEME_UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
window_pane_send_theme_update(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
if (~wp->screen->mode & MODE_THEME_UPDATES)
|
||||||
|
return;
|
||||||
|
switch (window_pane_get_theme(wp)) {
|
||||||
|
case THEME_LIGHT:
|
||||||
|
input_key_pane(wp, KEYC_REPORT_LIGHT_THEME, NULL);
|
||||||
|
break;
|
||||||
|
case THEME_DARK:
|
||||||
|
input_key_pane(wp, KEYC_REPORT_LIGHT_THEME, NULL);
|
||||||
|
break;
|
||||||
|
case THEME_UNKNOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user