Merge the char_grid and window modules

This commit is contained in:
Kovid Goyal 2017-09-13 14:43:17 +05:30
parent 240c683504
commit 42329e5d46
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 169 additions and 190 deletions

View File

@ -5,7 +5,6 @@
from gettext import gettext as _ from gettext import gettext as _
from weakref import WeakValueDictionary from weakref import WeakValueDictionary
from .char_grid import load_shader_programs
from .config import MINIMUM_FONT_SIZE from .config import MINIMUM_FONT_SIZE
from .constants import ( from .constants import (
MODIFIER_KEYS, cell_size, is_key_pressed, mouse_button_pressed, MODIFIER_KEYS, cell_size, is_key_pressed, mouse_button_pressed,
@ -13,8 +12,8 @@ from .constants import (
) )
from .fast_data_types import ( from .fast_data_types import (
GLFW_MOUSE_BUTTON_1, GLFW_PRESS, GLFW_REPEAT, ChildMonitor, GLFW_MOUSE_BUTTON_1, GLFW_PRESS, GLFW_REPEAT, ChildMonitor,
destroy_global_data, destroy_sprite_map, destroy_global_data, destroy_sprite_map, glfw_post_empty_event,
glfw_post_empty_event, layout_sprite_map layout_sprite_map
) )
from .fonts.render import render_cell_wrapper, set_font_family from .fonts.render import render_cell_wrapper, set_font_family
from .keys import ( from .keys import (
@ -23,6 +22,7 @@ from .keys import (
from .session import create_session from .session import create_session
from .tabs import SpecialWindow, TabManager from .tabs import SpecialWindow, TabManager
from .utils import safe_print from .utils import safe_print
from .window import load_shader_programs
class DumpCommands: # {{{ class DumpCommands: # {{{

View File

@ -1,152 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import re
from enum import Enum
from .config import build_ansi_color_table
from .constants import ScreenGeometry, cell_size, viewport_size
from .fast_data_types import (
CELL_PROGRAM, CURSOR_PROGRAM, compile_program, init_cell_program,
init_cursor_program
)
from .rgb import to_color
from .utils import color_as_int, load_shaders, open_url, set_primary_selection
class DynamicColor(Enum):
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
def load_shader_programs():
compile_program(CELL_PROGRAM, *load_shaders('cell'))
init_cell_program()
compile_program(CURSOR_PROGRAM, *load_shaders('cursor'))
init_cursor_program()
def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell_width, cell_height):
dx, dy = 2 * cell_width / viewport_width, 2 * cell_height / viewport_height
xmargin = window_geometry.left / viewport_width
ymargin = window_geometry.top / viewport_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)
def __init__(self, screen, opts):
self.screen_reversed = False
self.screen = screen
self.opts = opts
self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
self.screen.color_profile.set_configured_colors(*map(color_as_int, (
opts.foreground, opts.background, opts.cursor, opts.selection_foreground, opts.selection_background)))
self.opts = opts
self.opts = opts
def update_position(self, window_geometry):
self.screen_geometry = sg = calculate_gl_geometry(window_geometry, viewport_size.width, viewport_size.height, cell_size.width, cell_size.height)
return sg
def change_colors(self, changes):
dirtied = False
def item(raw):
if raw is None:
return 0
val = to_color(raw)
return None if val is None else (color_as_int(val) << 8) | 2
for which, val in changes.items():
val = item(val)
if val is None:
continue
dirtied = True
setattr(self.screen.color_profile, which.name, val)
if dirtied:
self.screen.mark_as_dirty()
def cell_for_pos(self, x, y):
x, y = int(x // cell_size.width), int(y // cell_size.height)
if 0 <= x < self.screen.columns and 0 <= y < self.screen.lines:
return x, y
return None, None
def update_drag(self, is_press, mx, my):
x, y = self.cell_for_pos(mx, my)
if x is None:
x = 0 if mx <= cell_size.width else self.screen.columns - 1
y = 0 if my <= cell_size.height else self.screen.lines - 1
ps = None
if is_press:
self.screen.start_selection(x, y)
elif self.screen.is_selection_in_progress():
ended = is_press is False
self.screen.update_selection(x, y, ended)
if ended:
ps = self.text_for_selection()
if ps and ps.strip():
set_primary_selection(ps)
def has_url_at(self, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
l = self.screen.visual_line(y)
if l is not None:
text = str(l)
for m in self.url_pat.finditer(text):
if m.start() <= x < m.end():
return True
return False
def click_url(self, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
l = self.screen.visual_line(y)
if l is not None:
text = str(l)
for m in self.url_pat.finditer(text):
if m.start() <= x < m.end():
url = ''.join(l[i] for i in range(*m.span())).rstrip('.')
# Remove trailing "] and similar
url = re.sub(r'''["'][)}\]]$''', '', url)
# Remove closing trailing character if it is matched by it's
# corresponding opening character before the url
if m.start() > 0:
before = l[m.start() - 1]
closing = {'(': ')', '[': ']', '{': '}', '<': '>', '"': '"', "'": "'", '`': '`', '|': '|', ':': ':'}.get(before)
if closing is not None and url.endswith(closing):
url = url[:-1]
if url:
open_url(url, self.opts.open_url_with)
def multi_click(self, count, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
line = self.screen.visual_line(y)
if line is not None and count in (2, 3):
if count == 2:
start_x, xlimit = self.screen.selection_range_for_word(x, y, self.opts.select_by_word_characters)
end_x = max(start_x, xlimit - 1)
elif count == 3:
start_x, xlimit = self.screen.selection_range_for_line(y)
end_x = max(start_x, xlimit - 1)
self.screen.start_selection(start_x, y)
self.screen.update_selection(end_x, y, True)
ps = self.text_for_selection()
if ps:
set_primary_selection(ps)
def get_scrollback_as_ansi(self):
ans = []
self.screen.historybuf.as_ansi(ans.append)
self.screen.linebuf.as_ansi(ans.append)
return ''.join(ans).encode('utf-8')
def text_for_selection(self):
return ''.join(self.screen.text_for_selection())

View File

@ -7,7 +7,6 @@ from functools import partial
from itertools import count from itertools import count
from .borders import Borders from .borders import Borders
from .char_grid import calculate_gl_geometry
from .child import Child from .child import Child
from .config import build_ansi_color_table from .config import build_ansi_color_table
from .constants import ( from .constants import (
@ -20,7 +19,7 @@ from .fast_data_types import (
) )
from .layout import Rect, all_layouts from .layout import Rect, all_layouts
from .utils import color_as_int from .utils import color_as_int
from .window import Window from .window import Window, calculate_gl_geometry
TabbarData = namedtuple('TabbarData', 'title is_active is_last') TabbarData = namedtuple('TabbarData', 'title is_active is_last')
borders = None borders = None

View File

@ -2,30 +2,42 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import re
import sys import sys
import weakref import weakref
from collections import deque from collections import deque
from enum import Enum
from itertools import count from itertools import count
from time import monotonic from time import monotonic
from .char_grid import CharGrid, DynamicColor from .config import build_ansi_color_table
from .constants import ( from .constants import (
WindowGeometry, appname, cell_size, get_boss, is_key_pressed, ScreenGeometry, WindowGeometry, appname, cell_size, get_boss,
mouse_button_pressed, wakeup is_key_pressed, mouse_button_pressed, viewport_size, wakeup
) )
from .fast_data_types import ( from .fast_data_types import (
ANY_MODE, BRACKETED_PASTE_END, BRACKETED_PASTE_START, GLFW_KEY_DOWN, ANY_MODE, BRACKETED_PASTE_END, BRACKETED_PASTE_START, CELL_PROGRAM,
GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, GLFW_KEY_UP, GLFW_MOD_SHIFT, CURSOR_PROGRAM, GLFW_KEY_DOWN, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT,
GLFW_MOUSE_BUTTON_1, GLFW_MOUSE_BUTTON_4, GLFW_MOUSE_BUTTON_5, GLFW_KEY_UP, GLFW_MOD_SHIFT, GLFW_MOUSE_BUTTON_1, GLFW_MOUSE_BUTTON_4,
GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE, MOTION_MODE, GLFW_MOUSE_BUTTON_5, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE,
SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, create_cell_vao, MOTION_MODE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen,
glfw_post_empty_event, remove_vao, set_window_render_data, compile_program, create_cell_vao, glfw_post_empty_event, init_cell_program,
init_cursor_program, remove_vao, set_window_render_data,
update_window_title, update_window_visibility update_window_title, update_window_visibility
) )
from .keys import get_key_map from .keys import get_key_map
from .mouse import DRAG, MOVE, PRESS, RELEASE, encode_mouse_event from .mouse import DRAG, MOVE, PRESS, RELEASE, encode_mouse_event
from .rgb import to_color
from .terminfo import get_capabilities from .terminfo import get_capabilities
from .utils import get_primary_selection, parse_color_set, sanitize_title from .utils import (
color_as_int, get_primary_selection, load_shaders, open_url,
parse_color_set, sanitize_title, set_primary_selection
)
class DynamicColor(Enum):
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
DYNAMIC_COLOR_CODES = { DYNAMIC_COLOR_CODES = {
10: DynamicColor.default_fg, 10: DynamicColor.default_fg,
@ -39,6 +51,22 @@ window_counter = count()
next(window_counter) next(window_counter)
def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell_width, cell_height):
dx, dy = 2 * cell_width / viewport_width, 2 * cell_height / viewport_height
xmargin = window_geometry.left / viewport_width
ymargin = window_geometry.top / viewport_height
xstart = -1 + 2 * xmargin
ystart = 1 - 2 * ymargin
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
def load_shader_programs():
compile_program(CELL_PROGRAM, *load_shaders('cell'))
init_cell_program()
compile_program(CURSOR_PROGRAM, *load_shaders('cursor'))
init_cursor_program()
class Window: class Window:
def __init__(self, tab, child, opts, args): def __init__(self, tab, child, opts, args):
@ -56,7 +84,9 @@ class Window:
self.is_visible_in_layout = True self.is_visible_in_layout = True
self.child, self.opts = child, opts self.child, self.opts = child, opts
self.screen = Screen(self, 24, 80, opts.scrollback_lines) self.screen = Screen(self, 24, 80, opts.scrollback_lines)
self.char_grid = CharGrid(self.screen, opts) self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
self.screen.color_profile.set_configured_colors(*map(color_as_int, (
opts.foreground, opts.background, opts.cursor, opts.selection_foreground, opts.selection_background)))
def __repr__(self): def __repr__(self):
return 'Window(title={}, id={})'.format(self.title, self.id) return 'Window(title={}, id={})'.format(self.title, self.id)
@ -73,6 +103,10 @@ class Window:
self.screen.mark_as_dirty() self.screen.mark_as_dirty()
wakeup() wakeup()
def update_position(self, window_geometry):
self.screen_geometry = sg = calculate_gl_geometry(window_geometry, viewport_size.width, viewport_size.height, cell_size.width, cell_size.height)
return sg
def set_geometry(self, window_idx, new_geometry): def set_geometry(self, window_idx, new_geometry):
if self.destroyed: if self.destroyed:
return return
@ -82,11 +116,11 @@ class Window:
current_pty_size = ( current_pty_size = (
self.screen.lines, self.screen.columns, self.screen.lines, self.screen.columns,
max(0, new_geometry.right - new_geometry.left), max(0, new_geometry.bottom - new_geometry.top)) max(0, new_geometry.right - new_geometry.left), max(0, new_geometry.bottom - new_geometry.top))
sg = self.char_grid.update_position(new_geometry) sg = self.update_position(new_geometry)
self.needs_layout = False self.needs_layout = False
boss.child_monitor.resize_pty(self.id, *current_pty_size) boss.child_monitor.resize_pty(self.id, *current_pty_size)
else: else:
sg = self.char_grid.update_position(new_geometry) sg = self.update_position(new_geometry)
set_window_render_data(self.tab_id, window_idx, self.vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen) set_window_render_data(self.tab_id, window_idx, self.vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen)
self.geometry = new_geometry self.geometry = new_geometry
@ -105,8 +139,7 @@ class Window:
boss = get_boss() boss = get_boss()
self.screen.reset_callbacks() self.screen.reset_callbacks()
boss.gui_close_window(self) boss.gui_close_window(self)
self.screen = self.char_grid.screen = None self.screen = None
self.char_grid = None
def write_to_child(self, data): def write_to_child(self, data):
if data: if data:
@ -115,6 +148,7 @@ class Window:
else: else:
print('Failed to write to child %d as it does not exist' % self.id, file=sys.stderr) print('Failed to write to child %d as it does not exist' % self.id, file=sys.stderr)
# screen callbacks {{{
def bell(self): def bell(self):
boss = get_boss() boss = get_boss()
boss.request_attention() boss.request_attention()
@ -143,6 +177,24 @@ class Window:
def icon_changed(self, new_icon): def icon_changed(self, new_icon):
pass # TODO: Implement this pass # TODO: Implement this
def change_colors(self, changes):
dirtied = False
def item(raw):
if raw is None:
return 0
val = to_color(raw)
return None if val is None else (color_as_int(val) << 8) | 2
for which, val in changes.items():
val = item(val)
if val is None:
continue
dirtied = True
setattr(self.screen.color_profile, which.name, val)
if dirtied:
self.screen.mark_as_dirty()
def set_dynamic_color(self, code, value): def set_dynamic_color(self, code, value):
if isinstance(value, bytes): if isinstance(value, bytes):
value = value.decode('utf-8') value = value.decode('utf-8')
@ -154,11 +206,11 @@ class Window:
val = None val = None
color_changes[w] = val color_changes[w] = val
code += 1 code += 1
self.char_grid.change_colors(color_changes) self.change_colors(color_changes)
glfw_post_empty_event() glfw_post_empty_event()
def set_color_table_color(self, code, value): def set_color_table_color(self, code, value):
cp = self.char_grid.screen.color_profile cp = self.screen.color_profile
if code == 4: if code == 4:
for c, val in parse_color_set(value): for c, val in parse_color_set(value):
cp.set_color(c, val) cp.set_color(c, val)
@ -181,14 +233,93 @@ class Window:
def request_capabilities(self, q): def request_capabilities(self, q):
self.write_to_child(get_capabilities(q)) self.write_to_child(get_capabilities(q))
def buf_toggled(self, is_main_linebuf):
self.screen.scroll(SCROLL_FULL, False)
# }}}
# mouse handling {{{
def multi_click(self, count, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
line = self.screen.visual_line(y)
if line is not None and count in (2, 3):
if count == 2:
start_x, xlimit = self.screen.selection_range_for_word(x, y, self.opts.select_by_word_characters)
end_x = max(start_x, xlimit - 1)
elif count == 3:
start_x, xlimit = self.screen.selection_range_for_line(y)
end_x = max(start_x, xlimit - 1)
self.screen.start_selection(start_x, y)
self.screen.update_selection(end_x, y, True)
ps = self.text_for_selection()
if ps:
set_primary_selection(ps)
def cell_for_pos(self, x, y):
x, y = int(x // cell_size.width), int(y // cell_size.height)
if 0 <= x < self.screen.columns and 0 <= y < self.screen.lines:
return x, y
return None, None
def dispatch_multi_click(self, x, y): def dispatch_multi_click(self, x, y):
if len(self.click_queue) > 2 and self.click_queue[-1] - self.click_queue[-3] <= 2 * self.opts.click_interval: if len(self.click_queue) > 2 and self.click_queue[-1] - self.click_queue[-3] <= 2 * self.opts.click_interval:
self.char_grid.multi_click(3, x, y) self.multi_click(3, x, y)
glfw_post_empty_event() glfw_post_empty_event()
elif len(self.click_queue) > 1 and self.click_queue[-1] - self.click_queue[-2] <= self.opts.click_interval: elif len(self.click_queue) > 1 and self.click_queue[-1] - self.click_queue[-2] <= self.opts.click_interval:
self.char_grid.multi_click(2, x, y) self.multi_click(2, x, y)
glfw_post_empty_event() glfw_post_empty_event()
def update_drag(self, is_press, mx, my):
x, y = self.cell_for_pos(mx, my)
if x is None:
x = 0 if mx <= cell_size.width else self.screen.columns - 1
y = 0 if my <= cell_size.height else self.screen.lines - 1
ps = None
if is_press:
self.screen.start_selection(x, y)
elif self.screen.is_selection_in_progress():
ended = is_press is False
self.screen.update_selection(x, y, ended)
if ended:
ps = self.text_for_selection()
if ps and ps.strip():
set_primary_selection(ps)
def has_url_at(self, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
l = self.screen.visual_line(y)
if l is not None:
text = str(l)
for m in self.url_pat.finditer(text):
if m.start() <= x < m.end():
return True
return False
def click_url(self, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
l = self.screen.visual_line(y)
if l is not None:
text = str(l)
for m in self.url_pat.finditer(text):
if m.start() <= x < m.end():
url = ''.join(l[i] for i in range(*m.span())).rstrip('.')
# Remove trailing "] and similar
url = re.sub(r'''["'][)}\]]$''', '', url)
# Remove closing trailing character if it is matched by it's
# corresponding opening character before the url
if m.start() > 0:
before = l[m.start() - 1]
closing = {'(': ')', '[': ']', '{': '}', '<': '>', '"': '"', "'": "'", '`': '`', '|': '|', ':': ':'}.get(before)
if closing is not None and url.endswith(closing):
url = url[:-1]
if url:
open_url(url, self.opts.open_url_with)
def text_for_selection(self):
return ''.join(self.screen.text_for_selection())
def on_mouse_button(self, button, action, mods): def on_mouse_button(self, button, action, mods):
mode = self.screen.mouse_tracking_mode() mode = self.screen.mouse_tracking_mode()
handle_event = mods == GLFW_MOD_SHIFT or mode == 0 or button == GLFW_MOUSE_BUTTON_MIDDLE or ( handle_event = mods == GLFW_MOD_SHIFT or mode == 0 or button == GLFW_MOUSE_BUTTON_MIDDLE or (
@ -196,17 +327,17 @@ class Window:
x, y = self.last_mouse_cursor_pos x, y = self.last_mouse_cursor_pos
if handle_event: if handle_event:
if button == GLFW_MOUSE_BUTTON_1: if button == GLFW_MOUSE_BUTTON_1:
self.char_grid.update_drag(action == GLFW_PRESS, x, y) self.update_drag(action == GLFW_PRESS, x, y)
if action == GLFW_RELEASE: if action == GLFW_RELEASE:
if mods == self.char_grid.opts.open_url_modifiers: if mods == self.opts.open_url_modifiers:
self.char_grid.click_url(x, y) self.click_url(x, y)
self.click_queue.append(monotonic()) self.click_queue.append(monotonic())
self.dispatch_multi_click(x, y) self.dispatch_multi_click(x, y)
elif button == GLFW_MOUSE_BUTTON_MIDDLE: elif button == GLFW_MOUSE_BUTTON_MIDDLE:
if action == GLFW_RELEASE: if action == GLFW_RELEASE:
self.paste_from_selection() self.paste_from_selection()
else: else:
x, y = self.char_grid.cell_for_pos(x, y) x, y = self.cell_for_pos(x, y)
if x is not None: if x is not None:
ev = encode_mouse_event(mode, self.screen.mouse_tracking_protocol(), ev = encode_mouse_event(mode, self.screen.mouse_tracking_protocol(),
button, PRESS if action == GLFW_PRESS else RELEASE, mods, x, y) button, PRESS if action == GLFW_PRESS else RELEASE, mods, x, y)
@ -225,9 +356,9 @@ class Window:
is_key_pressed[GLFW_KEY_LEFT_SHIFT] or is_key_pressed[GLFW_KEY_RIGHT_SHIFT]) is_key_pressed[GLFW_KEY_LEFT_SHIFT] or is_key_pressed[GLFW_KEY_RIGHT_SHIFT])
x, y = max(0, x - self.geometry.left), max(0, y - self.geometry.top) x, y = max(0, x - self.geometry.left), max(0, y - self.geometry.top)
self.last_mouse_cursor_pos = x, y self.last_mouse_cursor_pos = x, y
get_boss().change_mouse_cursor(self.char_grid.has_url_at(x, y)) get_boss().change_mouse_cursor(self.has_url_at(x, y))
if send_event: if send_event:
x, y = self.char_grid.cell_for_pos(x, y) x, y = self.cell_for_pos(x, y)
if x is not None: if x is not None:
ev = encode_mouse_event(mode, self.screen.mouse_tracking_protocol(), ev = encode_mouse_event(mode, self.screen.mouse_tracking_protocol(),
button, action, 0, x, y) button, action, 0, x, y)
@ -235,7 +366,7 @@ class Window:
self.write_to_child(ev) self.write_to_child(ev)
else: else:
if self.screen.is_selection_in_progress(): if self.screen.is_selection_in_progress():
self.char_grid.update_drag(None, x, y) self.update_drag(None, x, y)
margin = cell_size.height // 2 margin = cell_size.height // 2
if y <= margin or y >= self.geometry.bottom - margin: if y <= margin or y >= self.geometry.bottom - margin:
get_boss().ui_timers.add(0.02, self.drag_scroll) get_boss().ui_timers.add(0.02, self.drag_scroll)
@ -245,7 +376,7 @@ class Window:
margin = cell_size.height // 2 margin = cell_size.height // 2
if y <= margin or y >= self.geometry.bottom - margin: if y <= margin or y >= self.geometry.bottom - margin:
self.scroll_line_up() if y < 50 else self.scroll_line_down() self.scroll_line_up() if y < 50 else self.scroll_line_down()
self.char_grid.update_drag(None, x, y) self.update_drag(None, x, y)
return 0.02 # causes the timer to be re-added return 0.02 # causes the timer to be re-added
def on_mouse_scroll(self, x, y): def on_mouse_scroll(self, x, y):
@ -261,7 +392,7 @@ class Window:
send_event = mode > 0 send_event = mode > 0
if send_event: if send_event:
x, y = self.last_mouse_cursor_pos x, y = self.last_mouse_cursor_pos
x, y = self.char_grid.cell_for_pos(x, y) x, y = self.cell_for_pos(x, y)
if x is not None: if x is not None:
ev = encode_mouse_event(mode, self.screen.mouse_tracking_protocol(), ev = encode_mouse_event(mode, self.screen.mouse_tracking_protocol(),
GLFW_MOUSE_BUTTON_4 if upwards else GLFW_MOUSE_BUTTON_5, PRESS, 0, x, y) GLFW_MOUSE_BUTTON_4 if upwards else GLFW_MOUSE_BUTTON_5, PRESS, 0, x, y)
@ -270,9 +401,7 @@ class Window:
else: else:
k = get_key_map(self.screen)[GLFW_KEY_UP if upwards else GLFW_KEY_DOWN] k = get_key_map(self.screen)[GLFW_KEY_UP if upwards else GLFW_KEY_DOWN]
self.write_to_child(k * abs(s)) self.write_to_child(k * abs(s))
# }}}
def buf_toggled(self, is_main_linebuf):
self.screen.scroll(SCROLL_FULL, False)
def destroy(self): def destroy(self):
if self.vao_id is not None: if self.vao_id is not None:
@ -282,7 +411,10 @@ class Window:
# actions {{{ # actions {{{
def show_scrollback(self): def show_scrollback(self):
data = self.char_grid.get_scrollback_as_ansi() data = []
self.screen.historybuf.as_ansi(data.append)
self.screen.linebuf.as_ansi(data.append)
data = ''.join(data).encode('utf-8')
get_boss().display_scrollback(data) get_boss().display_scrollback(data)
def paste(self, text): def paste(self, text):
@ -301,7 +433,7 @@ class Window:
self.paste(text) self.paste(text)
def copy_to_clipboard(self): def copy_to_clipboard(self):
text = self.char_grid.text_for_selection() text = self.text_for_selection()
if text: if text:
get_boss().glfw_window.set_clipboard_string(text) get_boss().glfw_window.set_clipboard_string(text)