Start work on implementing multiple tab management

This commit is contained in:
Kovid Goyal 2016-12-07 08:22:24 +05:30
parent 26c7297de6
commit 6bfd6d6dbb
4 changed files with 91 additions and 12 deletions

View File

@ -220,8 +220,7 @@ class Boss(Thread):
def apply_pending_resize(self, w, h):
viewport_size.width, viewport_size.height = w, h
for tab in self.tab_manager:
tab.relayout()
self.tab_manager.resize()
self.resize_gl_viewport = True
self.pending_resize = False
glfw_post_empty_event()
@ -367,6 +366,7 @@ class Boss(Thread):
tab.render()
render_data = {window: window.char_grid.prepare_for_render(self.sprites) for window in tab.visible_windows() if not window.needs_layout}
with self.cell_program:
self.tab_manager.render(self.cell_program, self.sprites)
for window, rd in render_data.items():
if rd is not None:
window.char_grid.render_cells(rd, self.cell_program, self.sprites)

View File

@ -207,6 +207,15 @@ class Selection: # {{{
# }}}
def calculate_gl_geometry(window_geometry):
dx, dy = 2 * cell_size.width / viewport_size.width, 2 * cell_size.height / viewport_size.height
xmargin = window_geometry.left / viewport_size.width
ymargin = window_geometry.top / viewport_size.height
xstart = -1 + 2 * xmargin
ystart = 1 - 2 * ymargin
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
class CharGrid:
url_pat = re.compile('(?:http|https|file|ftp)://\S+', re.IGNORECASE)
@ -237,12 +246,7 @@ class CharGrid:
self.sprite_map_type = self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
def update_position(self, window_geometry):
dx, dy = 2 * cell_size.width / viewport_size.width, 2 * cell_size.height / viewport_size.height
xmargin = window_geometry.left / viewport_size.width
ymargin = window_geometry.top / viewport_size.height
xstart = -1 + 2 * xmargin
ystart = 1 - 2 * ymargin
self.screen_geometry = ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
self.screen_geometry = calculate_gl_geometry(window_geometry)
def resize(self, window_geometry):
self.update_position(window_geometry)

View File

@ -3,10 +3,18 @@
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from collections import deque
from threading import Lock
from ctypes import addressof
from .child import Child
from .constants import get_boss, appname, shell_path, cell_size, queue_action
from .fast_data_types import glfw_post_empty_event
from .config import build_ansi_color_table
from .constants import get_boss, appname, shell_path, cell_size, queue_action, viewport_size, WindowGeometry, GLuint
from .fast_data_types import (
glfw_post_empty_event, Screen, DECAWM, DATA_CELL_SIZE,
ColorProfile, glUniform2ui, glUniform4f, glUniform1i, glUniform2f,
glDrawArraysInstanced, GL_TRIANGLE_FAN
)
from .char_grid import calculate_gl_geometry
from .layout import all_layouts
from .borders import Borders
from .window import Window
@ -14,8 +22,9 @@ from .window import Window
class Tab:
def __init__(self, opts, args, session_tab=None):
def __init__(self, opts, args, on_title_change, session_tab=None):
self.opts, self.args = opts, args
self.on_title_change = on_title_change
self.enabled_layouts = list((session_tab or opts).enabled_layouts)
self.borders = Borders(opts)
self.windows = deque()
@ -46,6 +55,10 @@ class Tab:
def title(self):
return getattr(self.active_window, 'title', appname)
def title_changed(self, window):
if window is self.active_window:
self.on_title_change(window.title)
def visible_windows(self):
for w in self.windows:
if w.is_visible_in_layout:
@ -141,8 +154,28 @@ class TabManager:
def __init__(self, opts, args, startup_session):
self.opts, self.args = opts, args
self.tabs = [Tab(opts, args, t) for t in startup_session.tabs]
self.tabs = [Tab(opts, args, self.title_changed, t) for t in startup_session.tabs]
self.active_tab_idx = startup_session.active_tab_idx
self.tabbar_lock = Lock()
self.tabbar_dirty = True
self.color_profile = ColorProfile()
self.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
def resize(self):
for tab in self.tabs:
tab.relayout()
ncells = viewport_size.width // cell_size.width
s = Screen(None, 1, ncells)
s.reset_mode(DECAWM)
self.sprite_map_type = (GLuint * (s.lines * s.columns * DATA_CELL_SIZE))
with self.tabbar_lock:
self.sprite_map = self.sprite_map_type()
self.tab_bar_screen = s
self.tabbar_dirty = True
margin = (viewport_size.width - ncells * cell_size.width) // 2
self.screen_geometry = calculate_gl_geometry(WindowGeometry(
margin, viewport_size.height - cell_size.height, viewport_size.width - margin, viewport_size.height, s.columns, s.lines))
self.screen = s
def __iter__(self):
return iter(self.tabs)
@ -158,7 +191,46 @@ class TabManager:
def tab_bar_height(self):
return 0 if len(self.tabs) < 2 else cell_size.height
def title_changed(self, new_title):
with self.tabbar_lock:
self.tabbar_dirty = True
def remove(self, tab):
' Must be called in the GUI thread '
self.tabs.remove(tab)
tab.destroy()
def update_tab_bar_data(self, sprites):
s = self.tab_bar_screen
for t in self.tabs:
title = (t.title or appname)
s.draw(title)
if s.cursor.x > s.columns - 3:
# TODO: Handle trailing wide character
s.cursor.x = s.columns - 4
s.draw('')
s.draw(' X┇')
if s.cursor.x > s.columns - 5:
s.draw('')
break
s.update_cell_data(
sprites.backend, self.color_profile, addressof(self.sprite_map), self.default_fg, self.default_bg, True)
if self.buffer_id is None:
self.buffer_id = sprites.add_sprite_map()
sprites.set_sprite_map(self.buffer_id, self.sprite_map)
def render(self, cell_program, sprites):
if not hasattr(self, 'screen_geometry') or len(self.tabs) < 2:
return
with self.tabbar_lock:
if self.tabbar_dirty:
self.update_tab_bar_data(sprites)
sprites.bind_sprite_map(self.buffer_id)
ul, sg = cell_program.uniform_location, self.screen_geometry
ul = cell_program.uniform_location
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
glUniform1i(ul('sprites'), sprites.sampler_num)
glUniform1i(ul('sprite_map'), sprites.buffer_sampler_num)
glUniform2f(ul('sprite_layout'), *(sprites.layout))
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum)

View File

@ -115,6 +115,9 @@ class Window:
def title_changed(self, new_title):
self.title = sanitize_title(new_title or appname)
t = self.tabref()
if t is not None:
t.title_changed(self)
glfw_post_empty_event()
def icon_changed(self, new_icon):