Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libtsm for openSUSE:Factory checked in at 2026-07-07 21:07:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libtsm (Old) and /work/SRC/openSUSE:Factory/.libtsm.new.1982 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libtsm" Tue Jul 7 21:07:02 2026 rev:9 rq:1364347 version:4.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libtsm/libtsm.changes 2026-04-30 20:31:58.674675447 +0200 +++ /work/SRC/openSUSE:Factory/.libtsm.new.1982/libtsm.changes 2026-07-07 21:09:38.387649219 +0200 @@ -1,0 +2,10 @@ +Tue Jul 7 14:55:02 UTC 2026 - Fabian Vogt <[email protected]> + +- Update to 4.6.0: + * vte: map mouse wheel up/down buttons correctly + * fix CSI default parameter + * vte: Fix ctrl+shift+arrows + * Add a new draw2 interface + * vte: Add dim support + +------------------------------------------------------------------- Old: ---- v4.5.0.tar.gz New: ---- v4.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libtsm.spec ++++++ --- /var/tmp/diff_new_pack.sDbFZh/_old 2026-07-07 21:09:39.019671033 +0200 +++ /var/tmp/diff_new_pack.sDbFZh/_new 2026-07-07 21:09:39.019671033 +0200 @@ -19,7 +19,7 @@ %global sover 4 %global lname libtsm%{sover} Name: libtsm -Version: 4.5.0 +Version: 4.6.0 Release: 0 Summary: DEC-VT terminal emulator state machine License: LGPL-2.1-or-later AND MIT ++++++ v4.5.0.tar.gz -> v4.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/NEWS.md new/libtsm-4.6.0/NEWS.md --- old/libtsm-4.5.0/NEWS.md 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/NEWS.md 2026-06-22 18:08:24.000000000 +0200 @@ -1,5 +1,22 @@ # libtsm Release News +## CHANGES WITH 4.6.0 +### New draw2 interface +A new tsm_screen_draw2() interface is available that provides a simplified drawing API. +In a future release, we may remove the existing tsm_screen_draw() interface, so it is +recommended to use tsm_screen_draw2() instead. + +### New features +* Add a new draw2 interface by @kdj0c in https://github.com/kmscon/libtsm/pull/50 +* vte: Add dim support by @kdj0c in https://github.com/kmscon/libtsm/pull/51 +### Bug fixes +* vte: map mouse wheel up/down buttons correctly by @mierenhoop in https://github.com/kmscon/libtsm/pull/45 +* fix CSI default parameter by @kdj0c in https://github.com/kmscon/libtsm/pull/47 +* vte: Fix ctrl+shift+arrows by @kdj0c in https://github.com/kmscon/libtsm/pull/49 + +## New Contributors +* @mierenhoop made their first contribution in https://github.com/kmscon/libtsm/pull/45 + ## CHANGES WITH 4.5.0 ### New features * Support for terminal bell and keyboard LEDs by @aruiz in https://github.com/kmscon/libtsm/pull/34 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/meson.build new/libtsm-4.6.0/meson.build --- old/libtsm-4.5.0/meson.build 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/meson.build 2026-06-22 18:08:24.000000000 +0200 @@ -3,7 +3,7 @@ project( 'libtsm', 'c', - version: '4.5.0', + version: '4.6.0', license: 'MIT', meson_version: '>=1.1', default_options: [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/src/tsm/libtsm-int.h new/libtsm-4.6.0/src/tsm/libtsm-int.h --- old/libtsm-4.5.0/src/tsm/libtsm-int.h 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/src/tsm/libtsm-int.h 2026-06-22 18:08:24.000000000 +0200 @@ -155,6 +155,10 @@ bool sel_active; struct selection_pos sel_start; struct selection_pos sel_end; + + /* draw2 interface */ + struct tsm_screen_cell *cells; + unsigned int cells_count; }; void screen_cell_init(struct tsm_screen *con, struct cell *cell); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/src/tsm/libtsm.h new/libtsm-4.6.0/src/tsm/libtsm.h --- old/libtsm-4.5.0/src/tsm/libtsm.h 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/src/tsm/libtsm.h 2026-06-22 18:08:24.000000000 +0200 @@ -170,6 +170,32 @@ unsigned int inverse : 1; /* inverse colors */ unsigned int protect : 1; /* cannot be erased */ unsigned int blink : 1; /* blinking character */ + unsigned int dim:1; /* dim color */ +}; + +/* Attributes that alter the glyph shape */ +typedef union{ + struct { + uint8_t bold : 1; + uint8_t italic : 1; + uint8_t underline : 1; + uint8_t blink : 1; + uint8_t reserved : 5; + }; + uint8_t u8; +} tsm_screen_attr2_t; + +struct tsm_screen_color { + uint8_t r; /* red */ + uint8_t g; /* green */ + uint8_t b; /* blue */ +}; + +struct tsm_screen_cell { + uint32_t ch; /* character */ + struct tsm_screen_color fg; /* foreground color */ + struct tsm_screen_color bg; /* background color */ + tsm_screen_attr2_t attr2; /* glyph attributes */ }; typedef int (*tsm_screen_draw_cb) (struct tsm_screen *con, @@ -268,6 +294,8 @@ tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, void *data); +const struct tsm_screen_cell *tsm_screen_draw2(struct tsm_screen *con); + /** @} */ /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/src/tsm/libtsm.sym new/libtsm-4.6.0/src/tsm/libtsm.sym --- old/libtsm-4.5.0/src/tsm/libtsm.sym 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/src/tsm/libtsm.sym 2026-06-22 18:08:24.000000000 +0200 @@ -148,3 +148,8 @@ tsm_vte_set_bell_cb; tsm_vte_set_led_cb; } LIBTSM_4_4; + +LIBTSM_4_6 { +global: + tsm_screen_draw2; +} LIBTSM_4_5; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/src/tsm/tsm-render.c new/libtsm-4.6.0/src/tsm/tsm-render.c --- old/libtsm-4.5.0/src/tsm/tsm-render.c 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/src/tsm/tsm-render.c 2026-06-22 18:08:24.000000000 +0200 @@ -30,7 +30,6 @@ * yourself. */ -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <stdlib.h> @@ -193,3 +192,114 @@ return con->age_cnt; } } + +static void color_dim(struct tsm_screen_color *out, const struct tsm_screen_color *fg, const struct tsm_screen_color *bg) +{ + out->r = bg->r / 2 + fg->r / 2; + out->g = bg->g / 2 + fg->g / 2; + out->b = bg->b / 2 + fg->b / 2; +} + +/* + * tsm_screen_draw2 returns a pointer to a table of tsm_screen_cell, one for each cell on the screen. + * It uses a bit more memory, but should be much faster, as each cell is only 12 bytes. + * The caller can read the table, until the next call to tsm_screen_draw2, or until con is destroyed. + */ +SHL_EXPORT +const struct tsm_screen_cell *tsm_screen_draw2(struct tsm_screen *con) +{ + unsigned int i, j, k; + struct line *line, *next_line = NULL; + struct cell *cell, empty; + struct tsm_screen_cell *out; + bool in_sel = false, sel_start = false, sel_end = false; + bool inverse = false; + + if (!con) + return NULL; + + if (con->cells_count < con->size_x * con->size_y) { + free(con->cells); + con->cells_count = 0; + con->cells = malloc(con->size_x * con->size_y * sizeof(struct tsm_screen_cell)); + if (!con->cells) + return NULL; + con->cells_count = con->size_x * con->size_y; + memset(con->cells, 0, con->cells_count * sizeof(struct tsm_screen_cell)); + } + + screen_cell_init(con, &empty); + + /* push each character into rendering pipeline */ + k = 0; + next_line = con->sb.pos; + + if (con->sel_active) { + if (!con->sel_start.line && con->sel_end.line) + in_sel = true; + + if (is_in_scrollback(&con->sel_start) + && (!con->sb.pos || con->sel_start.line->sb_id < con->sb.pos->sb_id)) + in_sel = !in_sel; + if (is_in_scrollback(&con->sel_end) + && (!con->sb.pos || con->sel_end.line->sb_id < con->sb.pos->sb_id)) + in_sel = !in_sel; + } + + for (i = 0; i < con->size_y; ++i) { + if (next_line) { + line = next_line; + next_line = shl_dlist_next(next_line, &con->sb.list, list); + } else { + line = con->lines[k]; + k++; + } + + if (con->sel_active) { + sel_start = (con->sel_start.line == line); + sel_end = (con->sel_end.line == line); + } + + for (j = 0; j < con->size_x; ++j) { + out = &con->cells[i * con->size_x + j]; + /* don't handle multiple codepoints yet */ + if (j < line->size && line->cells[j].ch <= TSM_UCS4_MAX) + cell = &line->cells[j]; + else + cell = ∅ + out->ch = cell->ch ? cell->ch : ' '; + out->attr2.bold = cell->attr.bold; + out->attr2.italic = cell->attr.italic; + out->attr2.underline = cell->attr.underline; + out->attr2.blink = cell->attr.blink; + + if (sel_start && j == con->sel_start.x) + in_sel = !in_sel; + + /* Inverse logic, cell attribute, selection, and whole screen inverse */ + inverse = cell->attr.inverse ^ in_sel ^ (con->flags & TSM_SCREEN_INVERSE); + + if (inverse) { + out->fg.r = cell->attr.br; + out->fg.g = cell->attr.bg; + out->fg.b = cell->attr.bb; + out->bg.r = cell->attr.fr; + out->bg.g = cell->attr.fg; + out->bg.b = cell->attr.fb; + } else { + out->fg.r = cell->attr.fr; + out->fg.g = cell->attr.fg; + out->fg.b = cell->attr.fb; + out->bg.r = cell->attr.br; + out->bg.g = cell->attr.bg; + out->bg.b = cell->attr.bb; + } + if (cell->attr.dim) + color_dim(&out->fg, &out->fg, &out->bg); + + if (sel_end && j == con->sel_end.x) + in_sel = !in_sel; + } + } + return con->cells; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/src/tsm/tsm-screen.c new/libtsm-4.6.0/src/tsm/tsm-screen.c --- old/libtsm-4.5.0/src/tsm/tsm-screen.c 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/src/tsm/tsm-screen.c 2026-06-22 18:08:24.000000000 +0200 @@ -543,6 +543,7 @@ free(con->alt_lines); free(con->tab_ruler); tsm_symbol_table_unref(con->sym_table); + free(con->cells); free(con); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.5.0/src/tsm/tsm-vte.c new/libtsm-4.6.0/src/tsm/tsm-vte.c --- old/libtsm-4.5.0/src/tsm/tsm-vte.c 2026-04-21 11:27:37.000000000 +0200 +++ new/libtsm-4.6.0/src/tsm/tsm-vte.c 2026-06-22 18:08:24.000000000 +0200 @@ -791,6 +791,7 @@ vte->saved_state.cattr.inverse = 0; vte->saved_state.cattr.protect = 0; vte->saved_state.cattr.blink = 0; + vte->saved_state.cattr.dim = 0; } static void save_state(struct tsm_vte *vte) @@ -1056,8 +1057,12 @@ int new; if (data == ';') { - if (vte->csi_argc < CSI_ARG_MAX) + if (vte->csi_argc < CSI_ARG_MAX) { + // default parameter value is 0 if omitted + if (vte->csi_argv[vte->csi_argc] == -1) + vte->csi_argv[vte->csi_argc] = 0; vte->csi_argc++; + } return; } @@ -1328,10 +1333,14 @@ vte->cattr.underline = 0; vte->cattr.inverse = 0; vte->cattr.blink = 0; + vte->cattr.dim = 0; break; case 1: vte->cattr.bold = 1; break; + case 2: + vte->cattr.dim = 1; + break; case 3: vte->cattr.italic = 1; break; @@ -1346,6 +1355,7 @@ break; case 22: vte->cattr.bold = 0; + vte->cattr.dim = 0; break; case 23: vte->cattr.italic = 0; @@ -2749,6 +2759,60 @@ vte->backspace_sends_delete = enable; } +/* +Code Modifiers +---------+--------------------------- + 2 | Shift + 3 | Alt + 4 | Shift + Alt + 5 | Control + 6 | Shift + Control + 7 | Alt + Control + 8 | Shift + Alt + Control +---------+--------------------------- +*/ + +static char csi_modifier_from_mask(unsigned int mods) +{ + mods = mods & (TSM_CONTROL_MASK | TSM_SHIFT_MASK | TSM_ALT_MASK); + switch(mods) { + case TSM_SHIFT_MASK: + return '2'; + case TSM_ALT_MASK: + return '3'; + case TSM_SHIFT_MASK | TSM_ALT_MASK: + return '4'; + case TSM_CONTROL_MASK: + return '5'; + case TSM_CONTROL_MASK | TSM_SHIFT_MASK: + return '6'; + case TSM_CONTROL_MASK | TSM_ALT_MASK: + return '7'; + case TSM_CONTROL_MASK | TSM_ALT_MASK | TSM_SHIFT_MASK: + return '8'; + default: + return 0; + } +} + +static void vte_write_arrow(struct tsm_vte *vte, char direction, unsigned int mods) +{ + char code_with_modifier[6] = {'\e', '[', '1', ';', '0', 'A'}; + char code[3] = {'\e', '[', 'A'}; + + int modifier = csi_modifier_from_mask(mods); + if (modifier) { + code_with_modifier[4] = modifier; + code_with_modifier[5] = direction; + vte_write(vte, code_with_modifier, 6); + } else { + if (vte->flags & TSM_VTE_FLAG_CURSOR_KEY_MODE) + code[1] = 'O'; + code[2] = direction; + vte_write(vte, code, 3); + } +} + SHL_EXPORT bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym, uint32_t ascii, unsigned int mods, @@ -3023,51 +3087,19 @@ return true; case XKB_KEY_Up: case XKB_KEY_KP_Up: - if (mods & TSM_CONTROL_MASK) { - vte_write(vte, "\e[1;5A", 6); - } else if (mods & TSM_SHIFT_MASK) { - vte_write(vte, "\e[1;2A", 6); - } else if (vte->flags & TSM_VTE_FLAG_CURSOR_KEY_MODE) { - vte_write(vte, "\eOA", 3); - } else { - vte_write(vte, "\e[A", 3); - } + vte_write_arrow(vte, 'A', mods); return true; case XKB_KEY_Down: case XKB_KEY_KP_Down: - if (mods & TSM_CONTROL_MASK) { - vte_write(vte, "\e[1;5B", 6); - } else if (mods & TSM_SHIFT_MASK) { - vte_write(vte, "\e[1;2B", 6); - } else if (vte->flags & TSM_VTE_FLAG_CURSOR_KEY_MODE) { - vte_write(vte, "\eOB", 3); - } else { - vte_write(vte, "\e[B", 3); - } + vte_write_arrow(vte, 'B', mods); return true; case XKB_KEY_Right: case XKB_KEY_KP_Right: - if (mods & TSM_CONTROL_MASK) { - vte_write(vte, "\e[1;5C", 6); - } else if (mods & TSM_SHIFT_MASK) { - vte_write(vte, "\e[1;2C", 6); - } else if (vte->flags & TSM_VTE_FLAG_CURSOR_KEY_MODE) { - vte_write(vte, "\eOC", 3); - } else { - vte_write(vte, "\e[C", 3); - } + vte_write_arrow(vte, 'C', mods); return true; case XKB_KEY_Left: case XKB_KEY_KP_Left: - if (mods & TSM_CONTROL_MASK) { - vte_write(vte, "\e[1;5D", 6); - } else if (mods & TSM_SHIFT_MASK) { - vte_write(vte, "\e[1;2D", 6); - } else if (vte->flags & TSM_VTE_FLAG_CURSOR_KEY_MODE) { - vte_write(vte, "\eOD", 3); - } else { - vte_write(vte, "\e[D", 3); - } + vte_write_arrow(vte, 'D', mods); return true; case XKB_KEY_KP_Insert: case XKB_KEY_KP_0: @@ -3372,18 +3404,18 @@ return false; } + if (button == TSM_MOUSE_BUTTON_WHEEL_UP) { + button = 64; + } else if (button == TSM_MOUSE_BUTTON_WHEEL_DOWN) { + button = 65; + } + if (vte->mouse_mode == TSM_VTE_MOUSE_MODE_SGR || vte->mouse_mode == TSM_VTE_MOUSE_MODE_PIXEL) { /* internally we use zero indexing but the xterm spec requires the * top left cell to have the coordinates 1,1 */ cell_x++; cell_y++; - if (button == TSM_MOUSE_BUTTON_WHEEL_UP) { - button = 64; - } else if (button == TSM_MOUSE_BUTTON_WHEEL_DOWN) { - button = 65; - } - reply_flags = button | modifiers; }
