TextInput/InputRelay: style nits

There should be no functional changes in this commit
This commit is contained in:
Isaac Freund 2024-01-01 00:37:16 -06:00
parent 134a6bcfb5
commit 6f311af3b3
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
4 changed files with 126 additions and 118 deletions

View File

@ -173,48 +173,18 @@ fn handleNewConstraint(
}; };
} }
fn handleNewInputMethod( fn handleNewInputMethod(_: *wl.Listener(*wlr.InputMethodV2), input_method: *wlr.InputMethodV2) void {
_: *wl.Listener(*wlr.InputMethodV2), const seat: *Seat = @ptrFromInt(input_method.seat.data);
input_method: *wlr.InputMethodV2,
) void {
//const self = @fieldParentPtr(Self, "new_input_method", listener);
const seat = @as(*Seat, @ptrFromInt(input_method.seat.data));
const relay = &seat.relay;
// Only one input_method can be bound to a seat. log.debug("new input method on seat {s}", .{seat.wlr_seat.name});
if (relay.input_method != null) {
log.debug("attempted to connect second input method to a seat", .{}); seat.relay.newInputMethod(input_method);
input_method.sendUnavailable();
return;
} }
relay.input_method = input_method; fn handleNewTextInput(_: *wl.Listener(*wlr.TextInputV3), wlr_text_input: *wlr.TextInputV3) void {
TextInput.create(wlr_text_input) catch {
input_method.events.commit.add(&relay.input_method_commit); log.err("out of memory", .{});
input_method.events.grab_keyboard.add(&relay.grab_keyboard);
input_method.events.destroy.add(&relay.input_method_destroy);
log.debug("new input method on seat {s}", .{relay.seat.wlr_seat.name});
if (seat.focused.surface()) |surface| {
relay.focus(surface);
}
}
fn handleNewTextInput(
_: *wl.Listener(*wlr.TextInputV3),
wlr_text_input: *wlr.TextInputV3,
) void {
//const self = @fieldParentPtr(Self, "new_text_input", listener);
const seat = @as(*Seat, @ptrFromInt(wlr_text_input.seat.data));
const relay = &seat.relay;
const text_input_node = util.gpa.create(std.TailQueue(TextInput).Node) catch {
wlr_text_input.resource.postNoMemory(); wlr_text_input.resource.postNoMemory();
return; return;
}; };
text_input_node.data.init(relay, wlr_text_input);
relay.text_inputs.append(text_input_node);
log.debug("new text input on seat {s}", .{relay.seat.wlr_seat.name});
} }

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
const Self = @This(); const InputRelay = @This();
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
@ -30,17 +30,18 @@ const Seat = @import("Seat.zig");
const log = std.log.scoped(.input_relay); const log = std.log.scoped(.input_relay);
/// The Relay structure manages the communication between text_inputs /// List of all text input objects for the seat.
/// and input_method on a given seat. /// Multiple text input objects may be created per seat, even multiple from the same client.
seat: *Seat, /// However, only one text input per seat may be enabled at a time.
text_inputs: wl.list.Head(TextInput, .link),
/// List of all TextInput bound to the relay.
/// Multiple wlr_text_input interfaces can be bound to a relay,
/// but only one at a time can receive events.
text_inputs: std.TailQueue(TextInput) = .{},
/// The input method currently in use for this seat.
/// Only one input method per seat may be used at a time and if one is
/// already in use new input methods are ignored.
/// If this is null, no text input enter events will be sent.
input_method: ?*wlr.InputMethodV2 = null, input_method: ?*wlr.InputMethodV2 = null,
/// The currently enabled text input for the currently focused surface. /// The currently enabled text input for the currently focused surface.
/// Always null if there is no input method.
text_input: ?*TextInput = null, text_input: ?*TextInput = null,
input_method_commit: wl.Listener(*wlr.InputMethodV2) = input_method_commit: wl.Listener(*wlr.InputMethodV2) =
@ -53,19 +54,44 @@ input_method_destroy: wl.Listener(*wlr.InputMethodV2) =
grab_keyboard_destroy: wl.Listener(*wlr.InputMethodV2.KeyboardGrab) = grab_keyboard_destroy: wl.Listener(*wlr.InputMethodV2.KeyboardGrab) =
wl.Listener(*wlr.InputMethodV2.KeyboardGrab).init(handleInputMethodGrabKeyboardDestroy), wl.Listener(*wlr.InputMethodV2.KeyboardGrab).init(handleInputMethodGrabKeyboardDestroy),
pub fn init(self: *Self, seat: *Seat) void { pub fn init(relay: *InputRelay) void {
self.* = .{ .seat = seat }; relay.* = .{ .text_inputs = undefined };
relay.text_inputs.init();
}
pub fn newInputMethod(relay: *InputRelay, input_method: *wlr.InputMethodV2) void {
const seat = @fieldParentPtr(Seat, "relay", relay);
log.debug("new input method on seat {s}", .{seat.wlr_seat.name});
// Only one input_method can be bound to a seat.
if (relay.input_method != null) {
log.info("seat {s} already has an input method", .{seat.wlr_seat.name});
input_method.sendUnavailable();
return;
}
relay.input_method = input_method;
input_method.events.commit.add(&relay.input_method_commit);
input_method.events.grab_keyboard.add(&relay.grab_keyboard);
input_method.events.destroy.add(&relay.input_method_destroy);
if (seat.focused.surface()) |surface| {
relay.focus(surface);
}
} }
fn handleInputMethodCommit( fn handleInputMethodCommit(
listener: *wl.Listener(*wlr.InputMethodV2), listener: *wl.Listener(*wlr.InputMethodV2),
input_method: *wlr.InputMethodV2, input_method: *wlr.InputMethodV2,
) void { ) void {
const self = @fieldParentPtr(Self, "input_method_commit", listener); const relay = @fieldParentPtr(InputRelay, "input_method_commit", listener);
assert(input_method == self.input_method); assert(input_method == relay.input_method);
if (!input_method.client_active) return; if (!input_method.client_active) return;
const text_input = self.text_input orelse return; const text_input = relay.text_input orelse return;
if (input_method.current.preedit.text) |preedit_text| { if (input_method.current.preedit.text) |preedit_text| {
text_input.wlr_text_input.sendPreeditString( text_input.wlr_text_input.sendPreeditString(
@ -95,56 +121,59 @@ fn handleInputMethodDestroy(
listener: *wl.Listener(*wlr.InputMethodV2), listener: *wl.Listener(*wlr.InputMethodV2),
input_method: *wlr.InputMethodV2, input_method: *wlr.InputMethodV2,
) void { ) void {
const self = @fieldParentPtr(Self, "input_method_destroy", listener); const relay = @fieldParentPtr(InputRelay, "input_method_destroy", listener);
assert(input_method == self.input_method); assert(input_method == relay.input_method);
self.input_method_commit.link.remove(); relay.input_method_commit.link.remove();
self.grab_keyboard.link.remove(); relay.grab_keyboard.link.remove();
self.input_method_destroy.link.remove(); relay.input_method_destroy.link.remove();
self.input_method = null; relay.input_method = null;
self.focus(null); relay.focus(null);
assert(relay.text_input == null);
} }
fn handleInputMethodGrabKeyboard( fn handleInputMethodGrabKeyboard(
listener: *wl.Listener(*wlr.InputMethodV2.KeyboardGrab), listener: *wl.Listener(*wlr.InputMethodV2.KeyboardGrab),
keyboard_grab: *wlr.InputMethodV2.KeyboardGrab, keyboard_grab: *wlr.InputMethodV2.KeyboardGrab,
) void { ) void {
const self = @fieldParentPtr(Self, "grab_keyboard", listener); const relay = @fieldParentPtr(InputRelay, "grab_keyboard", listener);
const seat = @fieldParentPtr(Seat, "relay", relay);
const active_keyboard = self.seat.wlr_seat.getKeyboard(); const active_keyboard = seat.wlr_seat.getKeyboard();
keyboard_grab.setKeyboard(active_keyboard); keyboard_grab.setKeyboard(active_keyboard);
keyboard_grab.events.destroy.add(&self.grab_keyboard_destroy); keyboard_grab.events.destroy.add(&relay.grab_keyboard_destroy);
} }
fn handleInputMethodGrabKeyboardDestroy( fn handleInputMethodGrabKeyboardDestroy(
listener: *wl.Listener(*wlr.InputMethodV2.KeyboardGrab), listener: *wl.Listener(*wlr.InputMethodV2.KeyboardGrab),
keyboard_grab: *wlr.InputMethodV2.KeyboardGrab, keyboard_grab: *wlr.InputMethodV2.KeyboardGrab,
) void { ) void {
const self = @fieldParentPtr(Self, "grab_keyboard_destroy", listener); const relay = @fieldParentPtr(InputRelay, "grab_keyboard_destroy", listener);
self.grab_keyboard_destroy.link.remove(); relay.grab_keyboard_destroy.link.remove();
if (keyboard_grab.keyboard) |keyboard| { if (keyboard_grab.keyboard) |keyboard| {
keyboard_grab.input_method.seat.keyboardNotifyModifiers(&keyboard.modifiers); keyboard_grab.input_method.seat.keyboardNotifyModifiers(&keyboard.modifiers);
} }
} }
pub fn disableTextInput(self: *Self) void { pub fn disableTextInput(relay: *InputRelay) void {
assert(self.text_input != null); assert(relay.text_input != null);
if (self.input_method) |input_method| { if (relay.input_method) |input_method| {
input_method.sendDeactivate(); input_method.sendDeactivate();
input_method.sendDone(); input_method.sendDone();
} }
self.text_input = null; relay.text_input = null;
} }
pub fn sendInputMethodState(self: *Self) void { pub fn sendInputMethodState(relay: *InputRelay) void {
const input_method = self.input_method.?; const input_method = relay.input_method.?;
const wlr_text_input = self.text_input.?.wlr_text_input; const wlr_text_input = relay.text_input.?.wlr_text_input;
// TODO Send these events only if something changed. // TODO Send these events only if something changed.
// On activation all events must be sent for all active features. // On activation all events must be sent for all active features.
@ -171,13 +200,11 @@ pub fn sendInputMethodState(self: *Self) void {
input_method.sendDone(); input_method.sendDone();
} }
pub fn focus(self: *Self, new_focus: ?*wlr.Surface) void { pub fn focus(relay: *InputRelay, new_focus: ?*wlr.Surface) void {
// Send leave events // Send leave events
{ {
var it = self.text_inputs.first; var it = relay.text_inputs.iterator(.forward);
while (it) |node| : (it = node.next) { while (it.next()) |text_input| {
const text_input = &node.data;
if (text_input.wlr_text_input.focused_surface) |surface| { if (text_input.wlr_text_input.focused_surface) |surface| {
// This function should not be called unless focus changes // This function should not be called unless focus changes
assert(surface != new_focus); assert(surface != new_focus);
@ -187,19 +214,17 @@ pub fn focus(self: *Self, new_focus: ?*wlr.Surface) void {
} }
// Clear currently enabled text input // Clear currently enabled text input
if (self.text_input != null) { if (relay.text_input != null) {
self.disableTextInput(); relay.disableTextInput();
} }
// Send enter events if we have an input method. // Send enter events if we have an input method.
// No text input for the new surface should be enabled yet as the client // No text input for the new surface should be enabled yet as the client
// should wait until it receives an enter event. // should wait until it receives an enter event.
if (new_focus) |surface| { if (new_focus) |surface| {
if (self.input_method != null) { if (relay.input_method != null) {
var it = self.text_inputs.first; var it = relay.text_inputs.iterator(.forward);
while (it) |node| : (it = node.next) { while (it.next()) |text_input| {
const text_input = &node.data;
if (text_input.wlr_text_input.resource.getClient() == surface.resource.getClient()) { if (text_input.wlr_text_input.resource.getClient() == surface.resource.getClient()) {
text_input.wlr_text_input.sendEnter(surface); text_input.wlr_text_input.sendEnter(surface);
} }

View File

@ -68,7 +68,9 @@ pub const FocusTarget = union(enum) {
wlr_seat: *wlr.Seat, wlr_seat: *wlr.Seat,
/// Multiple mice are handled by the same Cursor /// Multiple mice are handled by the same Cursor
cursor: Cursor = undefined, cursor: Cursor,
/// Input Method handling
relay: InputRelay,
/// ID of the current keymap mode /// ID of the current keymap mode
mode_id: u32 = 0, mode_id: u32 = 0,
@ -99,9 +101,6 @@ drag: enum {
touch, touch,
} = .none, } = .none,
/// Relay for communication between text_input and input_method.
relay: InputRelay = undefined,
request_set_selection: wl.Listener(*wlr.Seat.event.RequestSetSelection) = request_set_selection: wl.Listener(*wlr.Seat.event.RequestSetSelection) =
wl.Listener(*wlr.Seat.event.RequestSetSelection).init(handleRequestSetSelection), wl.Listener(*wlr.Seat.event.RequestSetSelection).init(handleRequestSetSelection),
request_start_drag: wl.Listener(*wlr.Seat.event.RequestStartDrag) = request_start_drag: wl.Listener(*wlr.Seat.event.RequestStartDrag) =
@ -119,12 +118,14 @@ pub fn init(self: *Self, name: [*:0]const u8) !void {
self.* = .{ self.* = .{
// This will be automatically destroyed when the display is destroyed // This will be automatically destroyed when the display is destroyed
.wlr_seat = try wlr.Seat.create(server.wl_server, name), .wlr_seat = try wlr.Seat.create(server.wl_server, name),
.cursor = undefined,
.relay = undefined,
.mapping_repeat_timer = mapping_repeat_timer, .mapping_repeat_timer = mapping_repeat_timer,
}; };
self.wlr_seat.data = @intFromPtr(self); self.wlr_seat.data = @intFromPtr(self);
try self.cursor.init(self); try self.cursor.init(self);
self.relay.init(self); self.relay.init();
self.wlr_seat.events.request_set_selection.add(&self.request_set_selection); self.wlr_seat.events.request_set_selection.add(&self.request_set_selection);
self.wlr_seat.events.request_start_drag.add(&self.request_start_drag); self.wlr_seat.events.request_start_drag.add(&self.request_start_drag);

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
const Self = @This(); const TextInput = @This();
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
@ -29,7 +29,8 @@ const Seat = @import("Seat.zig");
const log = std.log.scoped(.text_input); const log = std.log.scoped(.text_input);
relay: *InputRelay, link: wl.list.Link,
wlr_text_input: *wlr.TextInputV3, wlr_text_input: *wlr.TextInputV3,
enable: wl.Listener(*wlr.TextInputV3) = enable: wl.Listener(*wlr.TextInputV3) =
@ -41,68 +42,79 @@ disable: wl.Listener(*wlr.TextInputV3) =
destroy: wl.Listener(*wlr.TextInputV3) = destroy: wl.Listener(*wlr.TextInputV3) =
wl.Listener(*wlr.TextInputV3).init(handleDestroy), wl.Listener(*wlr.TextInputV3).init(handleDestroy),
pub fn init(self: *Self, relay: *InputRelay, wlr_text_input: *wlr.TextInputV3) void { pub fn create(wlr_text_input: *wlr.TextInputV3) !void {
self.* = .{ const seat: *Seat = @ptrFromInt(wlr_text_input.seat.data);
.relay = relay,
const text_input = try util.gpa.create(TextInput);
log.debug("new text input on seat {s}", .{seat.wlr_seat.name});
text_input.* = .{
.link = undefined,
.wlr_text_input = wlr_text_input, .wlr_text_input = wlr_text_input,
}; };
wlr_text_input.events.enable.add(&self.enable); seat.relay.text_inputs.append(text_input);
wlr_text_input.events.commit.add(&self.commit);
wlr_text_input.events.disable.add(&self.disable); wlr_text_input.events.enable.add(&text_input.enable);
wlr_text_input.events.destroy.add(&self.destroy); wlr_text_input.events.commit.add(&text_input.commit);
wlr_text_input.events.disable.add(&text_input.disable);
wlr_text_input.events.destroy.add(&text_input.destroy);
} }
fn handleEnable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void { fn handleEnable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
const self = @fieldParentPtr(Self, "enable", listener); const text_input = @fieldParentPtr(TextInput, "enable", listener);
const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
if (self.relay.text_input != null) { if (seat.relay.text_input != null) {
log.err("client requested to enable more than one text input on a single seat, ignoring request", .{}); log.err("client requested to enable more than one text input on a single seat, ignoring request", .{});
return; return;
} }
self.relay.text_input = self; seat.relay.text_input = text_input;
if (self.relay.input_method) |input_method| { if (seat.relay.input_method) |input_method| {
input_method.sendActivate(); input_method.sendActivate();
self.relay.sendInputMethodState(); seat.relay.sendInputMethodState();
} }
} }
fn handleCommit(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void { fn handleCommit(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
const self = @fieldParentPtr(Self, "commit", listener); const text_input = @fieldParentPtr(TextInput, "commit", listener);
const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
if (self.relay.text_input != self) { if (seat.relay.text_input != text_input) {
log.err("inactive text input tried to commit an update, client bug?", .{}); log.err("inactive text input tried to commit an update, client bug?", .{});
return; return;
} }
if (self.relay.input_method != null) { if (seat.relay.input_method != null) {
self.relay.sendInputMethodState(); seat.relay.sendInputMethodState();
} }
} }
fn handleDisable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void { fn handleDisable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
const self = @fieldParentPtr(Self, "disable", listener); const text_input = @fieldParentPtr(TextInput, "disable", listener);
const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
if (self.relay.text_input == self) { if (seat.relay.text_input == text_input) {
self.relay.disableTextInput(); seat.relay.disableTextInput();
} }
} }
fn handleDestroy(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void { fn handleDestroy(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
const self = @fieldParentPtr(Self, "destroy", listener); const text_input = @fieldParentPtr(TextInput, "destroy", listener);
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self); const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
if (self.relay.text_input == self) { if (seat.relay.text_input == text_input) {
self.relay.disableTextInput(); seat.relay.disableTextInput();
} }
self.enable.link.remove(); text_input.enable.link.remove();
self.commit.link.remove(); text_input.commit.link.remove();
self.disable.link.remove(); text_input.disable.link.remove();
self.destroy.link.remove(); text_input.destroy.link.remove();
self.relay.text_inputs.remove(node); text_input.link.remove();
util.gpa.destroy(node); util.gpa.destroy(text_input);
} }