Skip to content

Commit

Permalink
seat: implement input methods
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Apr 15, 2024
1 parent 5e2cdef commit daf5229
Show file tree
Hide file tree
Showing 44 changed files with 2,165 additions and 75 deletions.
2 changes: 2 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,12 @@ Jay supports the following wayland protocols:
| zwlr_layer_shell_v1 | 4[^no_exclusive] | Yes |
| zwlr_screencopy_manager_v1 | 3 | Yes |
| zwp_idle_inhibit_manager_v1 | 1 | |
| zwp_input_method_manager_v2 | 1 | Yes |
| zwp_linux_dmabuf_v1 | 5 | |
| zwp_pointer_constraints_v1 | 1 | |
| zwp_primary_selection_device_manager_v1 | 1 | |
| zwp_relative_pointer_manager_v1 | 1 | |
| zwp_text_input_manager_v3 | 1 | |
| zwp_virtual_keyboard_manager_v1 | 1 | Yes |
| zxdg_decoration_manager_v1 | 1 | |
| zxdg_output_manager_v1 | 3 | |
Expand Down
2 changes: 2 additions & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
- Add support for wp-alpha-modifier.
- Add support for per-device keymaps.
- Add support for virtual-keyboard-unstable-v1.
- Add support for zwp_input_method_manager_v2.
- Add support for zwp_text_input_manager_v3.

# 1.0.3 (2024-04-11)

Expand Down
1 change: 1 addition & 0 deletions src/backends/metal/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ impl MetalConnector {
Some(output.global.pos.get()),
Some(rr),
output.global.persistent.scale.get(),
true,
render_hw_cursor,
output.has_fullscreen(),
output.global.persistent.transform.get(),
Expand Down
4 changes: 3 additions & 1 deletion src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use {
globals::Globals,
ifs::{
wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
wl_surface::NoneSurfaceExt,
wl_surface::{zwp_input_popup_surface_v2::input_popup_positioning, NoneSurfaceExt},
},
io_uring::{IoUring, IoUringError},
leaks,
Expand Down Expand Up @@ -172,6 +172,7 @@ fn start_compositor2(
pending_output_render_data: Default::default(),
pending_float_layout: Default::default(),
pending_float_titles: Default::default(),
pending_input_popup_positioning: Default::default(),
dbus: Dbus::new(&engine, &ring, &run_toplevel),
fdcloser: FdCloser::new(),
logger: logger.clone(),
Expand Down Expand Up @@ -327,6 +328,7 @@ fn start_global_event_handlers(
eng.spawn2(Phase::Layout, float_layout(state.clone())),
eng.spawn2(Phase::PostLayout, float_titles(state.clone())),
eng.spawn2(Phase::PostLayout, idle(state.clone(), backend.clone())),
eng.spawn2(Phase::PostLayout, input_popup_positioning(state.clone())),
]
}

Expand Down
30 changes: 24 additions & 6 deletions src/gfx_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ impl dyn GfxFramebuffer {
cursor_rect: Option<Rect>,
result: Option<&mut RenderResult>,
scale: Scale,
render_cursor: bool,
render_hardware_cursor: bool,
black_background: bool,
transform: Transform,
Expand All @@ -347,6 +348,18 @@ impl dyn GfxFramebuffer {
let seats = state.globals.lock_seats();
for seat in seats.values() {
let (mut x, mut y) = seat.get_position();
if let Some(im) = seat.input_method() {
for (_, popup) in &im.popups {
if popup.surface.node_visible() {
let pos = popup.surface.buffer_abs_pos.get();
let extents = popup.surface.extents.get().move_(pos.x1(), pos.y1());
if extents.intersects(&rect) {
let (x, y) = rect.translate(pos.x1(), pos.y1());
renderer.render_surface(&popup.surface, x, y, None);
}
}
}
}
if let Some(drag) = seat.toplevel_drag() {
if let Some(tl) = drag.toplevel.get() {
if tl.xdg.surface.buffer.get().is_some() {
Expand All @@ -368,12 +381,14 @@ impl dyn GfxFramebuffer {
renderer.render_surface(&dnd_icon, x, y, None);
}
}
if let Some(cursor) = seat.get_cursor() {
if render_hardware_cursor || !seat.hardware_cursor() {
cursor.tick();
x -= Fixed::from_int(rect.x1());
y -= Fixed::from_int(rect.y1());
cursor.render(&mut renderer, x, y);
if render_cursor {
if let Some(cursor) = seat.get_cursor() {
if render_hardware_cursor || !seat.hardware_cursor() {
cursor.tick();
x -= Fixed::from_int(rect.x1());
y -= Fixed::from_int(rect.y1());
cursor.render(&mut renderer, x, y);
}
}
}
}
Expand Down Expand Up @@ -407,6 +422,7 @@ impl dyn GfxFramebuffer {
cursor_rect,
result,
scale,
true,
render_hardware_cursor,
node.has_fullscreen(),
node.global.persistent.transform.get(),
Expand All @@ -420,6 +436,7 @@ impl dyn GfxFramebuffer {
cursor_rect: Option<Rect>,
result: Option<&mut RenderResult>,
scale: Scale,
render_cursor: bool,
render_hardware_cursor: bool,
black_background: bool,
transform: Transform,
Expand All @@ -430,6 +447,7 @@ impl dyn GfxFramebuffer {
cursor_rect,
result,
scale,
render_cursor,
render_hardware_cursor,
black_background,
transform,
Expand Down
9 changes: 8 additions & 1 deletion src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ use {
wl_output::WlOutputGlobal,
wl_registry::WlRegistry,
wl_seat::{
text_input::{
zwp_input_method_manager_v2::ZwpInputMethodManagerV2Global,
zwp_text_input_manager_v3::ZwpTextInputManagerV3Global,
},
zwp_pointer_constraints_v1::ZwpPointerConstraintsV1Global,
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1Global,
zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1Global, WlSeatGlobal,
zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1Global,
WlSeatGlobal,
},
wl_shm::WlShmGlobal,
wl_subcompositor::WlSubcompositorGlobal,
Expand Down Expand Up @@ -177,6 +182,8 @@ impl Globals {
add_singleton!(ZwlrDataControlManagerV1Global);
add_singleton!(WpAlphaModifierV1Global);
add_singleton!(ZwpVirtualKeyboardManagerV1Global);
add_singleton!(ZwpInputMethodManagerV2Global);
add_singleton!(ZwpTextInputManagerV3Global);
}

pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
Expand Down
49 changes: 32 additions & 17 deletions src/ifs/wl_seat.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod event_handling;
mod kb_owner;
mod pointer_owner;
pub mod text_input;
pub mod wl_keyboard;
pub mod wl_pointer;
pub mod wl_touch;
Expand Down Expand Up @@ -37,6 +38,10 @@ use {
wl_seat::{
kb_owner::KbOwnerHolder,
pointer_owner::PointerOwnerHolder,
text_input::{
zwp_input_method_keyboard_grab_v2::ZwpInputMethodKeyboardGrabV2,
zwp_input_method_v2::ZwpInputMethodV2, zwp_text_input_v3::ZwpTextInputV3,
},
wl_keyboard::{WlKeyboard, WlKeyboardError, REPEAT_INFO_SINCE},
wl_pointer::WlPointer,
wl_touch::WlTouch,
Expand All @@ -63,7 +68,7 @@ use {
wire::{
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
WlSeatId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
ZwpRelativePointerV1Id,
ZwpRelativePointerV1Id, ZwpTextInputV3Id,
},
xkbcommon::{DynKeyboardState, KeyboardState, KeymapId, XkbKeymap, XkbState},
},
Expand All @@ -78,7 +83,7 @@ use {
rc::{Rc, Weak},
},
thiserror::Error,
uapi::{c, Errno, OwnedFd},
uapi::OwnedFd,
};

pub const POINTER: u32 = 1;
Expand Down Expand Up @@ -166,6 +171,10 @@ pub struct WlSeatGlobal {
constraint: CloneCell<Option<Rc<SeatConstraint>>>,
idle_notifications: CopyHashMap<(ClientId, ExtIdleNotificationV1Id), Rc<ExtIdleNotificationV1>>,
last_input_usec: Cell<u64>,
text_inputs: RefCell<AHashMap<ClientId, CopyHashMap<ZwpTextInputV3Id, Rc<ZwpTextInputV3>>>>,
text_input: CloneCell<Option<Rc<ZwpTextInputV3>>>,
input_method: CloneCell<Option<Rc<ZwpInputMethodV2>>>,
input_method_grab: CloneCell<Option<Rc<ZwpInputMethodKeyboardGrabV2>>>,
}

const CHANGE_CURSOR_MOVED: u32 = 1 << 0;
Expand Down Expand Up @@ -230,6 +239,10 @@ impl WlSeatGlobal {
idle_notifications: Default::default(),
last_input_usec: Cell::new(now_usec()),
wlr_data_devices: Default::default(),
text_inputs: Default::default(),
text_input: Default::default(),
input_method: Default::default(),
input_method_grab: Default::default(),
});
state.add_cursor_size(*DEFAULT_CURSOR_SIZE);
let seat = slf.clone();
Expand All @@ -250,6 +263,10 @@ impl WlSeatGlobal {
self.seat_kb_map.get()
}

pub fn input_method(&self) -> Option<Rc<ZwpInputMethodV2>> {
self.input_method.get()
}

pub fn toplevel_drag(&self) -> Option<Rc<XdgToplevelDragV1>> {
self.pointer_owner.toplevel_drag()
}
Expand Down Expand Up @@ -731,6 +748,9 @@ impl WlSeatGlobal {
}
}
}
if let Some(grab) = self.input_method_grab.get() {
grab.send_repeat_info();
}
}

pub fn close(self: &Rc<Self>) {
Expand Down Expand Up @@ -1048,6 +1068,10 @@ impl WlSeatGlobal {
self.tree_changed_handler.set(None);
self.output.set(self.state.dummy_output.get().unwrap());
self.constraint.take();
self.text_inputs.borrow_mut().clear();
self.text_input.take();
self.input_method.take();
self.input_method_grab.take();
}

pub fn id(&self) -> SeatId {
Expand Down Expand Up @@ -1116,6 +1140,11 @@ impl WlSeatGlobal {
tl.tl_set_visible(visible);
}
}
if let Some(im) = self.input_method.get() {
for (_, popup) in &im.popups {
popup.update_visible();
}
}
}
}

Expand Down Expand Up @@ -1175,21 +1204,7 @@ impl WlSeat {
if self.version >= READ_ONLY_KEYMAP_SINCE {
return Ok(state.map.clone());
}
let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) {
Ok(fd) => fd,
Err(e) => return Err(WlKeyboardError::KeymapMemfd(e.into())),
};
let target = state.map_len as c::off_t;
let mut pos = 0;
while pos < target {
let rem = target - pos;
let res = uapi::sendfile(fd.raw(), state.map.raw(), Some(&mut pos), rem as usize);
match res {
Ok(_) | Err(Errno(c::EINTR)) => {}
Err(e) => return Err(WlKeyboardError::KeymapCopy(e.into())),
}
}
Ok(Rc::new(fd))
Ok(state.create_new_keymap_fd()?)
}
}

Expand Down
31 changes: 29 additions & 2 deletions src/ifs/wl_seat/event_handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use {
DynDataSource,
},
wl_seat::{
text_input::TextDisconnectReason,
wl_keyboard::{self, WlKeyboard},
wl_pointer::{
self, PendingScroll, WlPointer, AXIS_DISCRETE_SINCE_VERSION,
Expand Down Expand Up @@ -393,8 +394,12 @@ impl WlSeatGlobal {
t.send_key(self.id, time_usec, key, key_state);
});
let node = self.keyboard_node.get();
let input_method_grab = self.input_method_grab.get();
if shortcuts.is_empty() {
node.node_on_key(self, time_usec, key, state, &xkb_state.kb_state);
match &input_method_grab {
Some(g) => g.on_key(time_usec, key, state, &xkb_state.kb_state),
_ => node.node_on_key(self, time_usec, key, state, &xkb_state.kb_state),
}
} else if let Some(config) = self.state.config.get() {
let id = xkb_state.kb_state.id;
drop(xkb_state);
Expand All @@ -411,7 +416,10 @@ impl WlSeatGlobal {
self.state.for_each_seat_tester(|t| {
t.send_modifiers(self.id, &xkb_state.kb_state.mods);
});
node.node_on_mods(self, &xkb_state.kb_state);
match &input_method_grab {
Some(g) => g.on_modifiers(&xkb_state.kb_state),
_ => node.node_on_mods(self, &xkb_state.kb_state),
}
}
match key_state {
KeyState::Released => {
Expand Down Expand Up @@ -760,6 +768,18 @@ impl WlSeatGlobal {
// Unfocus callbacks
impl WlSeatGlobal {
pub fn unfocus_surface(&self, surface: &WlSurface) {
if let Some(ti) = self.text_input.take() {
if let Some(con) = ti.connection.get() {
con.disconnect(TextDisconnectReason::FocusLost);
}
}
if let Some(tis) = self.text_inputs.borrow().get(&surface.client.id) {
for ti in tis.lock().values() {
ti.send_leave(surface);
ti.send_done();
}
}

let serial = surface.client.next_serial();
self.surface_kb_event(Version::ALL, surface, |k| k.send_leave(serial, surface.id))
}
Expand All @@ -785,6 +805,13 @@ impl WlSeatGlobal {
&surface.client,
);
}

if let Some(tis) = self.text_inputs.borrow_mut().get(&surface.client.id) {
for ti in tis.lock().values() {
ti.send_enter(surface);
ti.send_done();
}
}
}
}

Expand Down
Loading

0 comments on commit daf5229

Please sign in to comment.