Fix tab_bar_min_tabs not tab_bar_filter

Fixes #9278
This commit is contained in:
Kovid Goyal
2025-12-12 17:11:43 +05:30
parent 94106aa79e
commit 399354cbe5
8 changed files with 32 additions and 38 deletions

View File

@@ -190,6 +190,8 @@ Detailed list of changes
- Linux: Fix a bug causing colors to occasionally all go black when using mesa
>= 25.3.0 with nouveau GPU driver (:iss:`9235`)
- Fix :opt:`tab_bar_min_tabs` not respecting :opt:`tab_bar_filter` (:iss:`9278`)
0.44.0 [2025-11-03]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -720,7 +720,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
!global_state.supports_framebuffer_srgb || effective_os_window_alpha(os_window) < 1.f ||
os_window->live_resize.in_progress || (os_window->bgimage && os_window->bgimage->texture_id > 0)
);
if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) {
if (TD.screen && os_window->num_tabs && !os_window->has_too_few_tabs) {
if (!os_window->tab_bar_data_updated) {
call_boss(update_tab_bar_data, "K", os_window->id);
os_window->tab_bar_data_updated = true;
@@ -817,7 +817,7 @@ render_prepared_os_window(OSWindow *os_window, unsigned int active_window_id, co
BorderRects *br = &tab->border_rects;
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, active_window_bg, num_visible_windows, all_windows_have_same_bg, os_window);
br->is_dirty = false;
if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) draw_cells(&TD, os_window, true, true, false, NULL);
if (TD.screen && os_window->num_tabs && !os_window->has_too_few_tabs) draw_cells(&TD, os_window, true, true, false, NULL);
unsigned int num_of_visible_windows = 0;
Window *active_window = NULL;
for (unsigned int i = 0; i < tab->num_windows; i++) { if (tab->windows[i].visible) num_of_visible_windows++; }

View File

@@ -1065,7 +1065,7 @@ def next_window_id() -> int:
pass
def mark_tab_bar_dirty(os_window_id: int) -> None:
def mark_tab_bar_dirty(os_window_id: int, should_be_shown: bool) -> None:
pass

View File

@@ -1498,10 +1498,9 @@ The horizontal alignment of the tab bar, can be one of: :code:`left`,
'''
)
opt('tab_bar_min_tabs', '2',
option_type='tab_bar_min_tabs', ctype='uint',
opt('tab_bar_min_tabs', '2', option_type='tab_bar_min_tabs',
long_text='The minimum number of tabs that must exist before the tab bar is shown.'
)
)
opt('tab_switch_strategy', 'previous',
choices=('last', 'left', 'previous', 'right'),

View File

@@ -980,19 +980,6 @@ convert_from_opts_tab_bar_style(PyObject *py_opts, Options *opts) {
Py_DECREF(ret);
}
static void
convert_from_python_tab_bar_min_tabs(PyObject *val, Options *opts) {
opts->tab_bar_min_tabs = PyLong_AsUnsignedLong(val);
}
static void
convert_from_opts_tab_bar_min_tabs(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "tab_bar_min_tabs");
if (ret == NULL) return;
convert_from_python_tab_bar_min_tabs(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_tab_bar_background(PyObject *val, Options *opts) {
opts->tab_bar_background = color_or_none_as_int(val);
@@ -1509,8 +1496,6 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_tab_bar_style(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_tab_bar_min_tabs(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_tab_bar_background(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_tab_bar_margin_color(py_opts, opts);

View File

@@ -597,7 +597,7 @@ pyset_borders_rects(PyObject *self UNUSED, PyObject *args) {
void
os_window_regions(OSWindow *os_window, Region *central, Region *tab_bar) {
if (!OPT(tab_bar_hidden) && os_window->num_tabs >= OPT(tab_bar_min_tabs)) {
if (!OPT(tab_bar_hidden) && os_window->num_tabs && !os_window->has_too_few_tabs) {
long margin_outer = pt_to_px_for_os_window(OPT(tab_bar_margin_height.outer), os_window);
long margin_inner = pt_to_px_for_os_window(OPT(tab_bar_margin_height.inner), os_window);
central->left = 0; central->right = os_window->viewport_width;
@@ -950,9 +950,10 @@ PYWRAP1(set_os_window_chrome) {
}
PYWRAP1(mark_tab_bar_dirty) {
id_type os_window_id = PyLong_AsUnsignedLongLong(args);
if (PyErr_Occurred()) return NULL;
id_type os_window_id; int should_be_shown;
PA("Kp", &os_window_id, &should_be_shown);
WITH_OS_WINDOW(os_window_id)
os_window->has_too_few_tabs = !should_be_shown;
os_window->tab_bar_data_updated = false;
END_WITH_OS_WINDOW
Py_RETURN_NONE;
@@ -1519,7 +1520,7 @@ static PyMethodDef module_methods[] = {
MW(current_application_quit_request, METH_NOARGS),
MW(set_os_window_chrome, METH_VARARGS),
MW(focus_os_window, METH_VARARGS),
MW(mark_tab_bar_dirty, METH_O),
MW(mark_tab_bar_dirty, METH_VARARGS),
MW(run_with_activation_token, METH_O),
MW(change_background_opacity, METH_VARARGS),
MW(background_opacity_of, METH_O),

View File

@@ -91,7 +91,6 @@ typedef struct Options {
bool dynamic_background_opacity;
float inactive_text_alpha;
Edge tab_bar_edge;
unsigned long tab_bar_min_tabs;
DisableLigature disable_ligatures;
bool force_ltr;
bool resize_in_steps;
@@ -323,6 +322,7 @@ typedef struct OSWindow {
bool has_received_cursor_pos_event;
double mouse_x, mouse_y;
bool mouse_button_pressed[32];
bool has_too_few_tabs;
PyObject *window_title;
bool disallow_title_changes, title_is_overriden;
bool viewport_size_dirty, viewport_updated_at_least_once;

View File

@@ -1138,7 +1138,14 @@ class TabManager: # {{{
@property
def tab_bar_should_be_visible(self) -> bool:
return len(self.tabs) >= get_options().tab_bar_min_tabs
count = get_options().tab_bar_min_tabs
if count < 1:
return True
for t in self.tabs_to_be_shown_in_tab_bar:
count -= 1
if count < 1:
return True
return count < 1
def _add_tab(self, tab: Tab) -> None:
visible_before = self.tab_bar_should_be_visible
@@ -1160,9 +1167,14 @@ class TabManager: # {{{
self._active_tab_idx = idx
set_active_tab(self.os_window_id, idx)
def layout_tab_bar(self) -> None:
# set tab_bar_should_be_visible so that tab_bar.layout() gets correct dimensions
self.mark_tab_bar_dirty()
self.tab_bar.layout()
def tabbar_visibility_changed(self) -> None:
if not self.tab_bar_hidden:
self.tab_bar.layout()
self.layout_tab_bar()
self.resize(only_tabs=True)
@property
@@ -1173,8 +1185,8 @@ class TabManager: # {{{
return None
def mark_tab_bar_dirty(self) -> None:
if self.tab_bar_should_be_visible and not self.tab_bar_hidden:
mark_tab_bar_dirty(self.os_window_id)
should_be_shown = self.tab_bar_should_be_visible and not self.tab_bar_hidden
mark_tab_bar_dirty(self.os_window_id, should_be_shown)
w = self.active_window or self.any_window
if w is not None:
data = {'tab_manager': self}
@@ -1193,8 +1205,7 @@ class TabManager: # {{{
def resize(self, only_tabs: bool = False) -> None:
if not only_tabs:
if not self.tab_bar_hidden:
self.tab_bar.layout()
self.mark_tab_bar_dirty()
self.layout_tab_bar()
for tab in self.tabs:
tab.relayout()
@@ -1217,15 +1228,12 @@ class TabManager: # {{{
h.pop()
return True
def filtered_tabs(self, filter_expression: str) -> Iterator[Tab]:
yield from get_boss().match_tabs(filter_expression, all_tabs=self)
@property
def tabs_to_be_shown_in_tab_bar(self) -> Iterable[Tab]:
f = get_options().tab_bar_filter
if f:
at = self.active_tab
m = set(self.filtered_tabs(f))
m = set(get_boss().match_tabs(f, all_tabs=self))
return (t for t in self if t is at or t in m)
return self.tabs
@@ -1561,6 +1569,5 @@ class TabManager: # {{{
self.tab_bar_hidden = get_options().tab_bar_style == 'hidden'
self.tab_bar.apply_options()
self.update_tab_bar_data()
self.mark_tab_bar_dirty()
self.tab_bar.layout()
self.layout_tab_bar()
# }}}