After the changes of the previous commit, the event loop flow on Wayland is:
1. Render windows if window->render_pending is set
2. Wait for events [NOTE: this includes the frame callback]
3. Schedule render if menu->dirty is set
4. Handle events (return from render) and repeat
This can still miss renders since the menu->dirty flag is set in step (4),
but the menu->dirty flag is checked in step (3). So if the event loop only
does a single iteration (quite unusual as most user actions cause multiple
events), we can get stuck on step (2) for a while.
In order to avoid this problem, this changes the event loop order to:
1. Schedule render if menu->dirty is set
2. Wait for events [NOTE: this includes the frame callback]
3. Render windows if window->render_pending is set
4. Handle events (return from render) and repeat
Script (for Sway) to reproduce the issue / verify the fix:
#!/usr/bin/env sh
mousesety() { swaymsg seat - cursor set 200 "$1" >/dev/null; sleep 0.2; }
{ while true; do mousesety 200; mousesety 300; mousesety 400; done } &
trap 'kill $!' EXIT
export BEMENU_BACKEND=wayland BEMENU_OPTS='--list 40 --hb #0000FF'
yes | head -30 | bemenu
Fixes: #274Fixes: #275
Despite the fix in the previous commit (3d7e47c4e6), the following command:
{ echo one; echo two; } | BEMENU_BACKEND=wayland bemenu --grab
Will likely still show the 'Loading...' text after all items are available.
A related problem (also on Wayland) is that when pressing two keys (for the
filter) almost simultaneously, sometimes only one of the keys will be rendered.
The other key will only be shown on the next render. For example:
- Filter shows "s"
- User presses the "o" and "n" keys simultaneously
- Filter shows "so" ["n" appears to have been lost]
- User presses the "g" key
- Filter shows "song" [now the "n" has been rendered]
Both problems have the same root cause: If two events that cause a render happen
"close enough" to each other, often the second event will not cause a render.
As far as I can tell, the cause is that the "dirty && render_pending" render
check should not check the dirty flag at all, just "render_pending".
With "dirty && render_pending", if two events happen in close succession:
- On the first event, generally dirty==true, render_pending==true, a render
will happen, the frame callback will be set, and both flags will be cleared.
- For the second event, generally dirty==true and render_pending==false.
dirty will be unset and nothing will happen.
- When the frame triggers, render_pending is set, but no render will happen
because dirty==false
With just "render_pending" (the change in this commit):
- On the first event, generally dirty==true, render_pending==false, the frame
callback will be set, and dirty will be cleared.
- For the second event, generally dirty==true and render_pending==false.
dirty will be unset and nothing will happen.
- When the frame triggers, render_pending is set, then a render will be done.
We add a dirty flag on the menu to track if the menu actually need a
redraw. With it, we will not redraw if the touch is hold on the same
entry by example.
It works on Wayland and X11 and acts as a complement to margin. Exact
behavior is as follows:
- If width factor is 0, width minus margin is used.
- If width multiplied by factor is greater than width minus margin,
width minus is used. (so margin may be used to make sure that bemenu
is at least N pixels away from the view border)
- Otherwise width multiplied by factor is used.
I think it's fine to disable warnings about floating point numbers
comparision. We don't do any arithmetics on them anyway, so we can't
suffer from inaccuracy.
This adds an alias 'focused' for selecting the current monitor, which
becomes the default on x11 and wayland. The previous wayland default of
displaying on all outputs moves under '-2' or 'all'.
ref: https://github.com/Cloudef/bemenu/issues/102#issuecomment-604562234
Signed-off-by: Robert Günzler <r@gnzler.io>
With dmenu, monitor indices start at 0 and a value of -1 (the default)
is used to spawn dmenu on the current monitor. While bemenu strives to
be compatible with dmenu, bemenu monitor indices previously started at 1
and a value of 0 (the default) was used to spawn on the current monitor.
This commit aligns the behaviour of bemenu's x11 backend with dmenu. For
this purposes, the affected code in the x11 backend is synced with the
current dmenu implementation. While doing so the monitor type has also
been switched from a uint32_t to a int32_t.
epoll_create() takes a size argument not a flag like EPOLL_CLOEXEC [1].
[1] https://linux.die.net/man/2/epoll_create
Signed-off-by: Tobias Kortkamp <t@tobik.me>
This avoids locking oneself out when running bemenu interactively,
as input would be grabbed too early without that and layer shell
does not allow to 'ungrab' focus by clicking on another window
and provide BEMENU_BACKEND env variable. Change API to reflect this
change.
There is no reliable way to detect when running on terminal (especially
when stdin is a pipe), so we need to make curses backend explicit with
BEMENU_BACKEND=curses or bm_menu_new("curses"), otherwise GUI backend
will be choosed automatically.