We now create a copy of the config for each client, and updates it
with the values passed from the client.
Since we're not actually cloning it (and e.g. strdup() all strings
etc) we can't call conf_destroy() to free it, but need to free just
the strings we've replaced.
Track whether app-sync updates were enabled or disabled while handling
the current chunk of PTMX data.
This fixes and issue where we called render_refresh() unnecessarily
under (at least) the following conditions:
* Application sent "BSU <data> ESU" in the *same* chunk. In this case
we never saw that app sync was enabled and triggered delayed
rendering as usual.
* Application sent ESU. While we had noticed app sync updates being
enabled in earlier PTMX reads, when it was disabled *in the current*
PTMX read, we treated it as if it had not been enabled at all.
This caused us to trigger delayed rendering.
Now we call render_refresh() directly from ESU, and detect the "flip
off" case in PTMX read and avoid triggering a delayed rendering.
The end result of all this is that each key press (for e.g. scrolling
in a pager application) went from two frames being rendered, to a
single frame.
This fixes an issue where we failed to restore the cursor correctly
when exiting from the alternate screen, if the client had sent escapes
to save the cursor position while inside the alternate screen.
This was because we used the *same* storage for saving the cursor
position through escapes, as for saving it when entering the alternate
screen.
Fix by using a custom variable dedicated to normal <--> alt screen
switching.
Update the sixels' 'row' attribute when re-flowing a grid, to ensure
it is rendered at the correct place.
This should work in most cases, but will break when the cell size has
changed (e.g. font size increase/decrease, or a DPI change).
This patch also moves the sixel image list from the terminal struct
into the grid struct. The sixels are per-grid after all.
Handle the CSDs and the search box the same way we handle the main
grid; when we need to redraw them, call
render_refresh_{csd,search}(). This sets a flag that is checked after
each FDM iteration. All actual rendering is done here.
This also ties the commits of the Wayland sub-surfaces to the commit
of the main surface.
When the compositor wants us to decide the size (it sends a configure
event with width/height == 0), then use the last unmaximized size, if
there is one.
If there isn't one, use the size from the user configuration.
This is needed to handle pointer motion and button events correctly,
since mouse actions in e.g. CSD surfaces are very different from mouse
actions in the main window.
In unhook, add the generated image to a list of finished sixel images,
along with positioning and size information.
When rendering, loop this list of images, and render the images (or
parts of) that are visible.
When scrolling, check if any part of the images cover the re-cycled
lines, and if so, remove the *entire* image from the list.
This means we have the following limitations:
* The renderer always renders the whole (visible area of) the
image(s). There are times when this isn't necessary - for example,
when the image is scrolled inside the visible area.
* It would be nice if we could crop the image when parts of it is
scrolled out.
This implements basic parsing of sixel data. Lots of limitations and
temporary solutions as this is still work-in-progress:
* Maximum image size hardcoded to 800x800
* No HLS color format support
* Image is always rendered at 0x0 in the terminal
This function reloads the font *if* the DPI has changed. To handle
user run-time adjusted font sizes, we record the number of adjustments
made.
Then, when re-loading the font, we first load the font as specified in
the configuration. Then, we re-apply the size adjustment using
font_size_adjust().
Note that this means we end up loading the fonts twice; first using
the default size (but with adjusted DPI), and then again with the
adjusted size. This can probably be improved upon.
The existing font code has been refactored to avoid code
duplication. For example, term_init() now calls
term_font_dpi_changed() to load the initial fonts, instead of directly
instantiating them.
Finally, the way we calculate the DPI to use has changed: instead of
using the highest DPI of all available outputs, we use the highest DPI
of the output's we're actually mapped on. If we're not mapped at all,
we use the globally highest DPI.
Doing it this way means we usually only have to load the fonts
once. Otherwise, we'd end up using the default DPI of 96 when the
terminal is first instantiated (since it's not mapped at that time).
On a single monitor system, we'll use the globally highest DPI at
first, before being mapped. Then when we get mapped, we re-load the
fonts using the highest mapped DPI. But since they'll be the same,
we can skip actually reloading the fonts.
To do text reflow, we only need to know if a line has been explicitly
linebreaked or not. If not, that means it wrapped, and that we
should *not* insert a linebreak when reflowing text.
When reflowing text, when reaching the end of a row in the old grid,
only insert a linebreak in the new grid if the old row had been
explicitly linebreaked.
Furthermore, when reflowing text and wrapping a row in the new grid,
mark the previous row as linebreaked if either the last cell was
(the last column in the last row) empty, or the current cell (the
first column in the new row) is empty. If both are non-empty, then we
assume a linewrap.
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.
Add data structure to term->vt. This structure tracks the free-form
data that is passed-through, and the handler to call at the end.
Intermediates and parameters are collected by the normal VT
parser. Then, when we enter the passthrough state, we call dcs_hook().
This function checks the intermediate(s) and parameters, and selects
the appropriate unhook handler (and optionally does some execution
already).
In passthrough mode, we simply append strings to an internal
buffer. This might have to be changed in the future, if we need to
support a DCS that needs to execute as we go.
In unhook (i.e. when the DCS is terminated), we execute the unhook
handler.
As a proof-of-concept, handlers for BSU/ESU (Begin/End Synchronized
Update) has been added (but are left unimplemented).
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).
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.
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.