Commit graph

205 commits

Author SHA1 Message Date
Daniel Eklöf
ec63a24c80
render: reflow: erase row when wrapping around the scrollback 2020-02-14 19:03:13 +01:00
Daniel Eklöf
cb015d5eec
render: reflow: mark all "new" rows as dirty 2020-02-14 19:02:36 +01:00
Daniel Eklöf
4b328ead5e
render: resize: do linefeed *after* updating cursor position 2020-02-12 20:39:43 +01:00
Daniel Eklöf
a96a6c2c58
render: resize; heuristics to prevent prompt from being printed on a newline 2020-02-12 20:26:14 +01:00
Daniel Eklöf
ea52d3e570
render: resize: temporarily disable row adjustment
This was intended to prevent a new prompt from being printed on a
newline. However, it breaks normal output under certain conditions,
that have yet to be determined exactly what they are.
2020-02-12 20:16:42 +01:00
Daniel Eklöf
c28c0ab9c2
render: resize: only stay on current row if col is within grid width 2020-02-12 19:49:39 +01:00
Daniel Eklöf
bcd28bcd14
render: spelling 2020-02-12 18:06:15 +01:00
Daniel Eklöf
e56523f326
render: resize: calculated cursor row *should* never be beyond the screen bottom 2020-02-10 22:40:16 +01:00
Daniel Eklöf
88e2ab21b3
render: reflow: clear new line if already allocated 2020-02-10 22:38:30 +01:00
Daniel Eklöf
3ad2ee7681
render: resize: fix cursor positioning at grid wrap around
When current view is at a grid wrap around (last emitted row index is
< grid offset), the cursor row ended up being negative which we then
mapped to the top line.

This is wrong. When we're at a wrap around, re-adjust cursor by adding
the grid's row count.
2020-02-10 22:36:39 +01:00
Daniel Eklöf
8d262e71c1
render: reflow: initial line is always unallocated 2020-02-10 22:36:17 +01:00
Daniel Eklöf
4a169f5643
vt: tag cells that were form-feed:ed, to allow correct text reflow
To handle text reflow correctly when a line has a printable character
in the last column, but was still line breaked, we need to track the
fact that the slave inserted a line break here.

Otherwise, when the window width is increased, we'll end up pulling up
the next line, when we really should have inserted a line break.
2020-02-10 21:54:37 +01:00
Daniel Eklöf
80e8f91270
render: reflow: no need to clear cells
We set initialize=true when allocating a new row. This initializes the
cell to 0, with clean=1.
2020-02-10 20:46:02 +01:00
Daniel Eklöf
61b43620fc
render: initial support for text reflow
The algorithm is as follows:

Start at the beginning of the scrollback. That is, at the oldest
emitted lines. This is done by taking the current offset, and adding
the number of (old) screen rows, and then iterating until we find the
first allocated line.

Next, we iterate the entire old grid. At the beginning, we allocate a
line for the new grid, and setup a global pointer for that line, and
the current cell index.

For each line in the old grid, iterate its cells. Copy the the cells
over to the new line. Whenever the new line reaches its maximum number
of columns, we line break it by increasing the current row index and
allocating a new row (if necessary - we may be overwriting old
scrollback if the new grid is smaller than the old grid).

Whenever we reach the end of a line of the old grid, we insert a line
break in the new grid's line too **if** the last cell in the old line
was empty. If it was **not** empty, we **don't** line break the new
line.

Furthermore, empty cells in general need special consideration. A line
ending with a string of empty cells doesn't have to be copied the new
line. And more importantly, should **not** increase the new line's
cell index (which may cause line breaks, which is incorrect).

However, if a string of empty cells is followed by non empty cells, we
need to copy all the preceding empty cells to the line too.

When the entire scrollback history has been reflowed, we need to
figure out the new grid's offset.

This is done by trying to put the **last** emitted line at the bottom
of the screen. I.e. the new offset is typically "last_line_idx -
term->rows". However, we need to handle empty lines. So, after
subtracting the number of screen rows, we _increase_ the offset until
we see a non-empty line. This ensures we handle grid's that doesn't
fill an entire screen.

Finally, we need to re-position the cursor. This is done by trying to
place the cursor **at** (_not_ after) the last emitted line. We keep
the current cursor column as is (but possibly truncated, if the grid's
width decreased).
2020-02-10 20:35:24 +01:00
Daniel Eklöf
fd5782d6e6
render: resize: reset scroll damage
We've resized, and reset the render's 'last-buf' pointer; any scroll
damage we have is **not** valid anymore.
2020-02-08 18:22:14 +01:00
Daniel Eklöf
9e2ca2b1a3
render: add render_resize_force()
This forces a full resize operation, even though actual window
size (or scale) hasn't changed.
2020-02-08 14:08:16 +01:00
Daniel Eklöf
d6ea676ef2
presentation: store input timestamp in a per-commit context
This should reduce the risk of mixing up an input timestamp with the
corresponding rendered frame.
2020-01-21 18:51:04 +01:00
Daniel Eklöf
2c8b31204f
render: fallback to background color if cursor text color is not set 2020-01-20 18:36:44 +01:00
Daniel Eklöf
767a0ec232
fcft: update to 1.0.0
Allow/disallow subpixel antialiasing in font_glyph_for_wc(), not using
font_enable_subpixel_antialias().
2020-01-19 12:44:21 +01:00
Daniel Eklöf
727be358df
render: resize: TIOCSWINSZ: don't include padding in ws_{x,y}pixel 2020-01-12 14:42:49 +01:00
Daniel Eklöf
1623fc0c0a
term: shorten application_synchronized_updates -> app_sync_updates 2020-01-12 12:55:19 +01:00
Daniel Eklöf
bdf127fc7e
term/render: move {enable,disable}_application_synchronized_updates()
From render -> terminal
2020-01-12 12:43:28 +01:00
Daniel Eklöf
afa1dbb7cc
render: add a timeout for application synchronized updates
This ensures we can recover from a crashing (or bad behaving)
application that sends a BSU but then never sends an ESU.
2020-01-12 12:40:42 +01:00
Daniel Eklöf
6e474e77e5
render: rename render_{enable,disable}_refresh() 2020-01-12 12:28:00 +01:00
Daniel Eklöf
cb8a0260f3
term: rename refresh_prohibited -> application_synchronized_updates 2020-01-12 12:25:58 +01:00
Daniel Eklöf
b2935e2b89
render: add render_{enable,disable}_refresh()
Calling render_disable_refresh() causes update requests to that
terminal to be ignored.

Calling render_enable_refresh() re-enables updates.
2020-01-12 12:19:38 +01:00
Daniel Eklöf
0b30316261
render: don't bother trying to lookup glyph for empty cells
Depending on the font, it may not have an entry for code point '0',
which will cause us to try to load fallback fonts.
2020-01-12 01:19:41 +01:00
Daniel Eklöf
457eb573c4
selection: update: don't dirty cells that don't change state
Previously when updating a selection, we would unmark *all* cells in
the old selection, and then mark all cells in the new selection.

This caused *all* cells to be dirtied and thus re-rendered.

Avoid this, by adding a temporary state to the cells' selected state.

Before unmarking the old selection, pre-mark the new selection using a
temporary state.

When unmarking the old selection, ignore cells in this temporary state.
When marking the new selection, ignore cells in this temporary
state (except clearing the temporary state).
2020-01-06 11:56:18 +01:00
Daniel Eklöf
7e178d6337
search: rename render.search_offset -> render.search_glyph_offset 2020-01-05 15:25:24 +01:00
Daniel Eklöf
5a89520274
render: ensure cursor is always visible in the search box
Maintain a view 'offset' (which glyph from the search string to start
rendering at).

This defines the start of the viewable area. The end is the offset +
the search box size (which is limited to the window size).

Adjust this offset whenever the cursor moves outside the viewable
area. For now, this is always done in the same way: set the offset to
the cursor position.

This means that when we're entering text at the end of the search
criteria (i.e. the normal case; we're simply typing), and the search
box reaches the window size, the cursor will jump to the start of the
search box, which will be empty. This could be confusing, but let's go
with for now.
2020-01-05 15:16:40 +01:00
Daniel Eklöf
f4e8a9c375
render: xcursor: remove render_xcursor_refresh() 2020-01-05 00:10:44 +01:00
Daniel Eklöf
30ce5ad386
renderer: destroy: actually free the renderer instance (doh!) 2020-01-04 23:41:26 +01:00
Daniel Eklöf
4cbd894803
wayland: use a low priority FDM hook to flush the wayland socket
This way, we don't have to manually insert flushes in code paths that
may execute outside of a wl_display_dispatch_pending().

(Those that execute inside a wl_display_dispatch_pending() are subject
to the flush performed at the end of the normal wayland FDM handler).
2020-01-04 23:27:59 +01:00
Daniel Eklöf
6534f64e6a
fdm: add hook priorities
There are now three hook priorities: low, normal, high.

High priority hooks are executed *first*. Normal next, and last the
low priority hooks.

The renderer's terminal refresh hook now runs as a normal priority
hook.
2020-01-04 23:26:27 +01:00
Daniel Eklöf
5ec447697c
render: throttle xcursor updates
With a bad behaving client (e.g. 'less' with mouse support enabled),
we can end up with a *lot* of xcursor updates (so much, that we
flooded the wayland socket before we implemented a blocking
wayl_flush()).

Since there's little point in updating the cursor more than once per
frame interval, use frame callbacks to throttle the updates.

This works more or lesslike normal terminal refreshes:

render_xcursor_set() stores the last terminal (window) that had (and
updated) the cursor.

The renderer's FDM hook checks if we have such a pending terminal set,
and if so, tries to refresh the cursor.

This is done by first checking if we're already waiting for a callback
from a previous cursor update, and if so we do nothing; the callback
will update the cursor for the next frame. If we're *not* already
waiting for a callback, we update the cursor immediately.
2020-01-04 22:58:32 +01:00
Daniel Eklöf
abc36d8f09
wayland: wl_display_flush() never blocks
Since it doesn't block, we need to detect EAGAIN failures and ensure
we actually flush everything.

If we don't, we sooner or later end up in a wayland client library
call that aborts due to the socket buffer being full.

Ideally, we'd simply enable POLLOUT in the FDM. However, we cannot
write *anything* to the wayland socket until we've actually managed to
send everything. This means enabling POLLOUT in the FDM wont work
since we may (*will*) end up trying to write more data to it before
we've flushed it.

So, add a wrapper function, wayl_flush(), that acts as a blocking
variant of wl_display_flush(), by detecting EAGAIN failiures and
calling poll() itself, on the wayland socket only, until all data has
been sent.
2020-01-04 21:10:08 +01:00
Daniel Eklöf
2128d5912f
render: remove debug logging 2020-01-04 21:09:50 +01:00
Daniel Eklöf
647a299315
render: attrs_to_font() is not used outside of render.c 2020-01-04 19:53:55 +01:00
Daniel Eklöf
99f471d738
render: trigger terminal refreshes in an FDM hook
In some cases, we end up calling render_refresh() multiple times in
the same FDM iteration. This means will render the first update
immediately, and then set the 'pending' flag, causing the updated
content to be rendered in the next frame.

This can cause flicker, or flashes, since we're presenting one or more
intermediate frames until the final content is shown.

Not to mention that it is inefficient to render multiple frames like
this.

Fix by:

* render_refresh() only sets a flag in the terminal

* install an FDM hook; this hook loops all terminals and executes what
  render_refresh() _used_ to do (that is, render immediately if we're
  not waiting for a frame callback, otherwise set 'pending' flag). for
  all terminals that have the 'refresh_needed' flag set.
2020-01-04 19:49:26 +01:00
Daniel Eklöf
f12b1473fd
selection: store cell 'selected' state in the cells' attributes
Instead of having the renderer calculate, for each cell, whether that
cell is currently selected or not, make selection_update() mark/unmark
the selected cells.

The renderer now only has to look at the cells' 'selected'
attribute. This makes the renderer both smaller and faster.
2020-01-04 12:03:04 +01:00
Daniel Eklöf
cb9ae4f6a1
render: coord_is_selected: handle block selections 2020-01-03 23:34:58 +01:00
Daniel Eklöf
f7362d381b
render: refresh: ensure window has been configured 2020-01-03 18:55:13 +01:00
Daniel Eklöf
d07fd7de39
render: remove 'refresh' from render_resize() 2020-01-03 13:56:10 +01:00
Daniel Eklöf
74aa604904
render: render_resize(): don't do anything if width or height is 0 2020-01-03 12:54:03 +01:00
Daniel Eklöf
af26f043fb
render: resize() now only calls refresh() if asked to 2020-01-03 12:44:29 +01:00
Daniel Eklöf
709dbfe18b
Merge branch 'master' into visual-focus 2020-01-03 12:08:51 +01:00
Daniel Eklöf
792b443918
render: use a unique buffer cookie for the 'search' surface
This fixes an issue where rendering the 'search' box caused the last
normal buffer from being purged.

This meant the terminal had a pointer to a now freed buffer, which we
de-referenced and occasionally memcpy:ied from.
2020-01-03 12:05:48 +01:00
Daniel Eklöf
29483f936f
render: draw_cursor: use terminal's visual focus to determine cursor shape 2020-01-02 19:37:21 +01:00
Daniel Eklöf
4ecb0ecf4d
wayland: rename focused/moused to kbd_focus/mouse_focus 2020-01-02 15:58:52 +01:00
Daniel Eklöf
19c0c3d2a4
render: presentation: cleanup 2020-01-01 11:37:47 +01:00