Ref: 06275103f249cd2954630e59383342e102a6c1a3
(input-method-v2: Destroy keyboard grab before input method)
Background:
My MR in wlroots (!5107) stopped emitting `wlr_input_method_v2`
on its `commit`/`destroy` events, but didn't stop emitting
`wlr_input_method_keyboard_grab_v2` on its `destroy` event. That was
because `handle_keyboard_grab_destroy()` was called *after*
`handle_input_method_destroy()` for some reason, which caused segfault
when dereferencing `relay->input_method.keyboard_grab` in
`handle_keyboard_grab_destroy()`.
MR 5170 reversed this weired order of destroy handler calls, and finally
stopped emitting `wlr_input_method_keyboard_grab_v2` on its `destroy`
event.
wlr_scene_*_create() functions all allocate memory via calloc() and
return NULL if the allocation fails. Previously, the failures were
handled in any of 3 different ways:
- sending a wayland protocol error
- exiting labwc with an error
- segfault (no NULL check at all)
Since labwc does not attempt to survive heap exhaustion in other
allocation paths (such as `znew`), it seems more consistent to use the
same die_if_null() check used in those paths to exit with an error.
For the three most common create() functions (tree, rect, buffer),
add small lab_wlr_ wrappers to common/scene-helpers.
struct ssd_part and struct node_descriptor seem to have essentially the
same purpose: tag a wlr_scene_node with some extra data indicating what
we're using it for.
Also, as with enum ssd_part_type (now lab_node_type), ssd_part is used
for several types of nodes that are not part of SSD.
So instead of the current chaining (node_descriptor -> ssd_part), let's
flatten/unify the two structs.
In detail:
- First, merge node_descriptor_type into lab_node_type.
- Add a separate view pointer in node_descriptor, since in the case of
SSD buttons we need separate view and button data pointers.
- Rename ssd_part_button to simply ssd_button. It no longer contains
an ssd_part as base.
- Add node_try_ssd_button_from_node() which replaces
node_ssd_part_from_node() + button_try_from_ssd_part().
- Factor out ssd_button_free() to be called in node descriptor destroy.
- Finally, get_cursor_context() needs a little reorganization to handle
the unified structs.
Overall, this simplifies the code a bit, and in my opinion makes it
easier to understand. No functional change intended.
Fixes up e530f43.
When IME (e.g. fcitx5) is killed, relay->input_method is destroyed and
then relay->input_method->keyboard_grab is destroyed, which causes null
pointer dereference and crashes labwc.
Possible solutions are:
- Let wlroots keep emitting keyboard grab as `data` from keyboard grab's
destroy handler just like before
- Let wlroots destroy keyboard grab before input method
- Let compositor store keyboard grab as relay->keyboard_grab
But let's just revert the change in e530f43 for now.
This is a common practice in C projects, which simply enforces that
each header must compile cleanly without implicit dependencies on
other headers (see also the previous commit).
The workarounds added in #2498 and #2437 fixed stuck key/modifier bug
caused by wlroots commit e218990. But now that the commit was reverted in
0.19, the workarounds are no longer needed.
Removing the workarounds also fixes a minor regression with Fcitx5+Firefox
that pressing Ctrl+Enter in an input box causes stuck modifier.
683f67b7 introduced another regression that the modifier state (Ctrl) is
stuck when Ctrl+F is pressed in some applications like Firefox while
Fcitx5 is running. This caused mouse scrolls to zoom in/out the UI.
Let me explain the cause in detail. When Ctrl+F is pressed, an input box
is opened in the application and Fcitx5 creates a new virtual keyboard
(VK), whose initial modifiers is empty. Then prior to 683f67b7, the
key/modifiers events flowed like this:
- The compositor detects F key-release
- Modifiers (Ctrl pressed) are notified via _set_keyboard()
- F key-release is forwarded to IM
- IM sends modifiers (Ctrl) back to the compositor via VK
- **The modifiers on VK is updated (empty->Ctrl)**
- **Modifers (Ctrl) are notified to the app**
- IM sends F key-release back to the compositor via VK
- F key-release is notified to the app
- The compositor detects Ctrl key-release
- Ctrl key-release is forwarded to IM
- Modifiers (empty) are forwarded to IM
- IM sends Ctrl key-release back to the compsitor via VK
- Ctrl key-release is notified to IM
- IM sends modifiers (empty) back to the compositor via VK
- **The modifiers on VK is updated again (Ctrl->empty)**
- **Modifiers (empty) are notified to the app**
Thus, the final modifiers (empty) is notified to the application as
expected. However, after 683f67b7, the key/modifiers events flowed like
this:
- The compositor detects F key-release
- F key-release is directly notified to the app
- The modifiers (Ctrl) is also notified to the app
- The compositor detects Ctrl key-release
- Ctrl key-release is directly notified to the app
- Modifiers (empty) are forwarded to IM
- IM sends modifiers (empty) back to the compositor via VK
- **Modifier on VK is not updated (empty->empty)**
- **The compositor ignores it**
So the final modifier (empty) is never notified to the application, which
causes stuck Ctrl modifier.
This commit fixes this by not forwarding the modifiers when it hasn't been
updated since it was forwarded previously. So after this commit, the
key/modifiers events flow like this:
- The compositor detects F key-release
- F key-release is directly notified to the app
- The modifiers (Ctrl) is also notified to the app
- The compositor detects Ctrl key-release
- Ctrl key-release is directly notified to the app
- The modifiers are directly notified to the app because the modifiers
(empty) are the same as the last forwarded modifier (empty).
After commit e2189903 in wlroots, when ctrl-f is pressed in firefox with
a IME client running, the following key-release event for "f" is not
sent, thus "f" is repeated like "ffffffffff..." in the input box of
firefox. This is because the key-release event for "f" is firstly
forwarded to the IME client and then sent via the virtual keyboard created
by the IME client while the key-press event is sent via physical
keyboard, and with e2189903, key-release events without a corresponding
key-press event on the same keyboard is not emitted to the compositor.
So this commit fixes this problem by not forwarding the key-release event
to the IME client unless the corresponding key-press event was also
forwarded.
Before this commit, a popup surface was placed at (0,0) on its creation.
So if the popup surface is already mapped on its creation, the popup was
shown at (0,0) then quickly moved to the input-rect on surface commits
or input-rect updates.
Before this commit, scene-nodes for IME popup were destroyed when
the bound wl_surface is destroyed. However, this caused a bug that
multiple popup nodes are shown when input_popup_surface_v2 is recreated
with the same wl_surface.
We didn't support multiple IME popups since input-method-v2 protocol
has no way to position them individually, but we should support it to
provide IME developers with more programming flexibility.
When Fcitx5 is activated, it creates a virtual keyboard to send keycodes to
applications, then creates a keyboard grab to capture keycodes the user typed.
Before this commit, we set keyboard grab's modifiers to that of currently
active keyboard, which is the virtual keyboard created in the case described
above. However, since the modifiers of the virtual keyboard is empty at first,
we actually set empty modifiers, even when the user is pressing modifiers.
Then, Fcitx5 assumes no modifiers is pressed and redirect the modifier state
back to the compositor via the virtual keyboard. As a result, when the focus
is switched between windows by workspace-switcher, the workspace-switcher is
immediately terminated.
To fix this issue, with this commit, the modifier state of the currently active
keyboard is not set to the keyboard grab if the keyboard is a virtual keyboard
created by the same input-method client.
Fcitx5's commit below is also required to fix the issue.
b2924bd361