Commit graph

217 commits

Author SHA1 Message Date
Daniel Eklöf
c5a1af4e53
render: never render CSD and/or search box "immediately"
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.
2020-03-06 19:16:54 +01:00
Daniel Eklöf
9699c9b8bf
csd: initial implementation of minimize/maximize/close buttons 2020-03-02 20:29:28 +01:00
Daniel Eklöf
ddbfb3676c
render: remember, and use, last unmaximized size
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.
2020-02-26 20:59:11 +01:00
Daniel Eklöf
7f270a9f01
term: add term_surface_kind(), and track currently active surface
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.
2020-02-24 22:38:35 +01:00
Daniel Eklöf
d804bc8579
term: resize: pre-calculate right/bottom margins 2020-02-24 18:38:11 +01:00
Daniel Eklöf
a2b4bcbd4f
sixel: track which grid image was created on 2020-02-23 00:40:30 +01:00
Daniel Eklöf
25b09b909c
sixel: application configurable image max width/height 2020-02-22 21:03:24 +01:00
Daniel Eklöf
8e37a18083
sixel: application configurable palette size (color count)
This implements the CSI escapes for retrieving and (re)setting the
palette size.
2020-02-22 14:02:00 +01:00
Daniel Eklöf
7625264851
sixel: clean up state machine
Use proper state names, and implement the state machine using switch
statements.
2020-02-22 11:30:30 +01:00
Daniel Eklöf
f193695960
sixel: use a struct coord for current sixel position 2020-02-22 10:54:52 +01:00
Daniel Eklöf
1b728dcac8
sixel: rename state SIXEL_SIXEL -> SIXEL_GROUND 2020-02-22 10:50:05 +01:00
Daniel Eklöf
00c6d4dde1
sixel: resize image buffer dynamically 2020-02-22 10:46:35 +01:00
Daniel Eklöf
63140a68f5
sixel: calculate image height in (cell) rows 2020-02-22 00:05:25 +01:00
Daniel Eklöf
f0fc82f098
sixel: wip: maintain a list of finished, and "active" sixel images
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.
2020-02-21 23:40:35 +01:00
Daniel Eklöf
9e3bfb1eab
sixel: initial support
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
2020-02-21 21:53:23 +01:00
Daniel Eklöf
b5efe984bb
slave: prefix argv[0] with a '-' when spawning a login-shell 2020-02-20 18:36:09 +01:00
Daniel Eklöf
4d3ab6176d
term: implement term_font_dpi_changed()
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.
2020-02-15 19:08:14 +01:00
Daniel Eklöf
ce8005545d
term: convert cell 'linefeed' attribute to a row 'linebreak' property
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.
2020-02-14 22:39:26 +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
6c0d00fcee
term: add term_font_size_reset() 2020-02-08 17:57:50 +01:00
Daniel Eklöf
89cca2a5d1
term: add term_font_size_{increase,decrease}() 2020-02-08 14:09:06 +01:00
Daniel Eklöf
8f4ec9aa47
Implement --hold
When specified, we don't exit when the slave/client process exits.
2020-02-03 19:58:32 +01:00
Daniel Eklöf
f13adf50dc
vt: use 8-bit indices for parameters and sub parameters
We only support 16 (sub) parameters and thus there's no need for
64-bit index variables.
2020-02-01 19:24:46 +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
a3d919a90d
input: implement metaSendsEscape and eightBitMeta 2020-01-20 18:45:14 +01:00
Daniel Eklöf
4e87426712
csi: implement REP - CSI Ps b 2020-01-20 18:45:14 +01:00
Daniel Eklöf
300f83e66b
term: factor out character printing to new function term_print() 2020-01-20 18:34:32 +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
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
5a6cbb8c3e
dcs: initial handling of DCS in general
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).
2020-01-12 11:55:22 +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
1060a4250b
term: more comments in the 'render' sub-struct 2020-01-04 19:56:59 +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
2a531327dd
selection: selection_cancel() now sets 'kind' to SELECTION_NONE 2020-01-04 12:09:09 +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
d706e68280
selection: track selection type; normal or block selection 2020-01-03 23:29:45 +01:00
Daniel Eklöf
ce4e99ebe2
term: background alpha is not a floating point number 2020-01-03 21:53:16 +01:00
Daniel Eklöf
6f281cebfb
term: add term_visual_focus_{in,out}
These functions should be called when the terminal gets or loses
visual focus.

Note that this isn't necessarily the same as having keyboard focus.
2020-01-02 19:35:32 +01:00
Daniel Eklöf
e9325b958f
term: rename term_focus_{in,out} -> term_kbd_focus_{in,out} 2020-01-02 19:29:42 +01:00
Daniel Eklöf
eb1ea2d80d
term: add visually focused attribute to terminal struct 2020-01-02 16:06:35 +01:00
Daniel Eklöf
5a07419096
wayland: optionally use the presentation time protocol to measure input lag
This adds a flag, -p,--presentation-timings, that enables input lag
measuring using the presentation time Wayland protocol.

When enabled, we store a timestamp when we *send* a key to the
slave. Then, when we commit a frame for rendering to the compositor,
we request presentation feedback. We also store a timestamp for when
the frame was committed.

The 'presented' callback then looks at the input and commit
timestamps, and compares it with the presented timestamp.

The delay is logged at INFO when the delay was less than one frame
interval, at WARN when it was one frame interval, and at ERR when it
was two or more frame intervals.

We also update statistic counters that we log when foot is shut down.
2019-12-31 15:39:40 +01:00
Daniel Eklöf
39146fac5c
term: term_init: add 'cwd' argument
This is used when spawning the slave, to set its current working
directory just before we exec() the client.

In a regular foot instance, we set the cwd from getcwd().

In a foot server instance, each connecting client sends its cwd to the
server, and we use that.
2019-12-21 19:57:28 +01:00
Daniel Eklöf
016bde1bd4
term: wip: track current working directory
This sets the initial current working directory, as it is when the
terminal is instantiated.

We chdir() to it just before spawning a new terminal.
2019-12-21 15:35:54 +01:00
Daniel Eklöf
57de9feaa5
term: term_spawn_new(): new function, spawns a new foot/footclient process
Bind ctrl+shift+return to it
2019-12-21 15:27:17 +01:00
Daniel Eklöf
c22ae98729
render: get rid of 'all-clean' detection
Instead of trying to figure out if we had to render
something (i.e. something in the grid was dirty), and using that to
determine whether to post a callback or not, we now let
render_refresh() set a flag indication we need to render another
frame.

This simplifies render_grid(), which now _always_ renders, and pushes
it to the compositor.

The callback handler checks the pending flag and simply doesn't call
render_grid() when there's no more pending state to render.

This ends up reducing the number of wakeups when e.g. having a
blinking cursor.
2019-12-17 19:14:56 +01:00