Support notifying applications on color scheme change

This commit is contained in:
Kovid Goyal 2024-12-20 09:55:49 +05:30
parent af9e9fbc6f
commit dd9d8353df
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
8 changed files with 39 additions and 4 deletions

View file

@ -93,6 +93,8 @@ Detailed list of changes
- Graphics: Fix deleted but not freed images without any references being incorrectly freed on a subsequent delete command (:disc:`8129`)
- Add support for `escape code protocol <https://github.com/contour-terminal/contour/blob/master/docs/vt-extensions/color-palette-update-notifications.md>`__ for notifying applications on dark/light color scheme change
0.38.0 [2024-12-15]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -1550,6 +1550,7 @@ class Boss:
def default_bg_changed_for(self, window_id: int) -> None:
w = self.window_id_map.get(window_id)
if w is not None:
w.on_color_scheme_preference_change()
tm = self.os_window_map.get(w.os_window_id)
if tm is not None:
tm.update_tab_bar_data()

View file

@ -673,7 +673,13 @@ rgb_get(Color *self, void *closure UNUSED) {
static PyObject*
luminance_get(Color *self, void *closure UNUSED) {
return PyFloat_FromDouble(rgb_luminance(self->color));
return PyFloat_FromDouble(rgb_luminance(self->color) / 255.0);
}
static PyObject*
is_dark_get(Color *self, void *closure UNUSED) {
if (rgb_luminance(self->color) / 255.0 < 0.5) Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
static PyObject*
@ -721,6 +727,7 @@ static PyGetSetDef color_getsetters[] = {
{"luminance", (getter) luminance_get, NULL, "luminance", NULL},
{"as_sgr", (getter) sgr_get, NULL, "as_sgr", NULL},
{"as_sharp", (getter) sharp_get, NULL, "as_sharp", NULL},
{"is_dark", (getter) is_dark_get, NULL, "is_dark", NULL},
{NULL} /* Sentinel */
};

View file

@ -746,6 +746,10 @@ class Color:
def luminance(self) -> float:
pass
@property
def is_dark(self) -> bool:
pass
@property
def as_sgr(self) -> str:
pass
@ -1191,6 +1195,7 @@ class Screen:
linebuf: LineBuf
in_bracketed_paste_mode: bool
in_band_resize_notification: bool
color_preference_notification: bool
cursor_visible: bool
scrolled_by: int
cursor: Cursor

View file

@ -85,6 +85,9 @@
// Pending updates mode
#define PENDING_UPDATE (2026 << 5)
// Notification of color preference change
#define COLOR_PREFERENCE_NOTIFICATION (2031 << 5)
// In-band resize notification mode
#define INBAND_RESIZE_NOTIFICATION (2048 << 5)

View file

@ -1116,6 +1116,7 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
SIMPLE_MODE(DECARM)
SIMPLE_MODE(BRACKETED_PASTE)
SIMPLE_MODE(FOCUS_TRACKING)
SIMPLE_MODE(COLOR_PREFERENCE_NOTIFICATION)
SIMPLE_MODE(HANDLE_TERMIOS_SIGNALS)
MOUSE_MODE(MOUSE_BUTTON_TRACKING, mouse_tracking_mode, BUTTON_MODE)
MOUSE_MODE(MOUSE_MOTION_TRACKING, mouse_tracking_mode, MOTION_MODE)
@ -1691,6 +1692,7 @@ copy_specific_mode(Screen *self, unsigned int mode, const ScreenModes *src, Scre
SIMPLE_MODE(DECARM)
SIMPLE_MODE(BRACKETED_PASTE)
SIMPLE_MODE(FOCUS_TRACKING)
SIMPLE_MODE(COLOR_PREFERENCE_NOTIFICATION)
SIMPLE_MODE(INBAND_RESIZE_NOTIFICATION)
SIMPLE_MODE(DECCKM)
SIMPLE_MODE(DECTCEM)
@ -1732,6 +1734,7 @@ copy_specific_modes(Screen *self, const ScreenModes *src, ScreenModes *dest) {
copy_specific_mode(self, DECARM, src, dest);
copy_specific_mode(self, BRACKETED_PASTE, src, dest);
copy_specific_mode(self, FOCUS_TRACKING, src, dest);
copy_specific_mode(self, COLOR_PREFERENCE_NOTIFICATION, src, dest);
copy_specific_mode(self, INBAND_RESIZE_NOTIFICATION, src, dest);
copy_specific_mode(self, DECCKM, src, dest);
copy_specific_mode(self, DECTCEM, src, dest);
@ -2191,8 +2194,6 @@ screen_manipulate_title_stack(Screen *self, unsigned int op, unsigned int which)
void
report_device_status(Screen *self, unsigned int which, bool private) {
// We don't implement the private device status codes, since I haven't come
// across any programs that use them
unsigned int x, y;
static char buf[64];
switch(which) {
@ -2210,6 +2211,10 @@ report_device_status(Screen *self, unsigned int which, bool private) {
int sz = snprintf(buf, sizeof(buf) - 1, "%s%u;%uR", (private ? "?": ""), y + 1, x + 1);
if (sz > 0) write_escape_code_to_child(self, ESC_CSI, buf);
break;
case 996: // https://github.com/contour-terminal/contour/blob/master/docs/vt-extensions/color-palette-update-notifications.md
if (private) {
CALLBACK("report_color_scheme_preference", NULL);
} break;
}
}
@ -2233,6 +2238,7 @@ report_mode_status(Screen *self, unsigned int which, bool private) {
KNOWN_MODE(DECCKM);
KNOWN_MODE(BRACKETED_PASTE);
KNOWN_MODE(FOCUS_TRACKING);
KNOWN_MODE(COLOR_PREFERENCE_NOTIFICATION);
KNOWN_MODE(INBAND_RESIZE_NOTIFICATION);
#undef KNOWN_MODE
case ALTERNATE_SCREEN:
@ -3872,6 +3878,7 @@ WRAP0(clear_scrollback)
MODE_GETSET(in_bracketed_paste_mode, BRACKETED_PASTE)
MODE_GETSET(focus_tracking_enabled, FOCUS_TRACKING)
MODE_GETSET(color_preference_notification, COLOR_PREFERENCE_NOTIFICATION)
MODE_GETSET(in_band_resize_notification, INBAND_RESIZE_NOTIFICATION)
MODE_GETSET(auto_repeat_enabled, DECARM)
MODE_GETSET(cursor_visible, DECTCEM)
@ -4898,6 +4905,7 @@ static PyMethodDef methods[] = {
static PyGetSetDef getsetters[] = {
GETSET(in_bracketed_paste_mode)
GETSET(color_preference_notification)
GETSET(auto_repeat_enabled)
GETSET(focus_tracking_enabled)
GETSET(in_band_resize_notification)

View file

@ -15,7 +15,7 @@
typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } ScrollType;
typedef struct {
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, mDECCKM,
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, mDECCKM, mCOLOR_PREFERENCE_NOTIFICATION,
mBRACKETED_PASTE, mFOCUS_TRACKING, mDECSACE, mHANDLE_TERMIOS_SIGNALS, mINBAND_RESIZE_NOTIFICATION;
MouseTrackingMode mouse_tracking_mode;
MouseTrackingProtocol mouse_tracking_protocol;

View file

@ -1325,6 +1325,15 @@ class Window:
if default_bg_changed:
get_boss().default_bg_changed_for(self.id)
def on_color_scheme_preference_change(self) -> None:
if self.screen.color_preference_notification:
self.report_color_scheme_preference()
def report_color_scheme_preference(self) -> None:
cp = self.screen.color_profile
n = 1 if cp.default_bg.is_dark else 2
self.screen.send_escape_code_to_child(ESC_CSI, f'?997;{n}n')
def set_color_table_color(self, code: int, bvalue: Optional[memoryview] = None) -> None:
value = str(bvalue or b'', 'utf-8', 'replace')
cp = self.screen.color_profile