Merge branch 'master' of https://codeberg.org/river/river
This commit is contained in:
commit
8488cd9d97
@ -4,10 +4,6 @@ function __riverctl_completion ()
|
|||||||
if [ "${COMP_CWORD}" -eq 1 ]
|
if [ "${COMP_CWORD}" -eq 1 ]
|
||||||
then
|
then
|
||||||
OPTS=" \
|
OPTS=" \
|
||||||
keyboard-group-create \
|
|
||||||
keyboard-group-destroy \
|
|
||||||
keyboard-group-add \
|
|
||||||
keyboard-group-remove \
|
|
||||||
keyboard-layout \
|
keyboard-layout \
|
||||||
keyboard-layout-file \
|
keyboard-layout-file \
|
||||||
close \
|
close \
|
||||||
|
@ -72,11 +72,6 @@ complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'hide-cursor'
|
|||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-repeat' -d 'Set the keyboard repeat rate and repeat delay'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-repeat' -d 'Set the keyboard repeat rate and repeat delay'
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-cursor-warp' -d 'Set the cursor warp mode'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-cursor-warp' -d 'Set the cursor warp mode'
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'xcursor-theme' -d 'Set the xcursor theme'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'xcursor-theme' -d 'Set the xcursor theme'
|
||||||
# Keyboardgroups
|
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-create' -d 'Create a keyboard group'
|
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-destroy' -d 'Destroy a keyboard group'
|
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-add' -d 'Add a keyboard to a keyboard group'
|
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-remove' -d 'Remove a keyboard from a keyboard group'
|
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout' -d 'Set the keyboard layout'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout' -d 'Set the keyboard layout'
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout-file' -d 'Set the keyboard layout from a file.'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout-file' -d 'Set the keyboard layout from a file.'
|
||||||
|
|
||||||
|
@ -62,11 +62,6 @@ _riverctl_commands()
|
|||||||
'set-repeat:Set the keyboard repeat rate and repeat delay'
|
'set-repeat:Set the keyboard repeat rate and repeat delay'
|
||||||
'set-cursor-warp:Set the cursor warp mode.'
|
'set-cursor-warp:Set the cursor warp mode.'
|
||||||
'xcursor-theme:Set the xcursor theme'
|
'xcursor-theme:Set the xcursor theme'
|
||||||
# Keyboard groups
|
|
||||||
'keyboard-group-create:Create a keyboard group'
|
|
||||||
'keyboard-group-destroy:Destroy a keyboard group'
|
|
||||||
'keyboard-group-add:Add a keyboard to a keyboard group'
|
|
||||||
'keyboard-group-remove:Remove a keyboard from a keyboard group'
|
|
||||||
'keyboard-layout:Set the keyboard layout'
|
'keyboard-layout:Set the keyboard layout'
|
||||||
'keyboard-layout-file:Set the keyboard layout from a file'
|
'keyboard-layout-file:Set the keyboard layout from a file'
|
||||||
# Input
|
# Input
|
||||||
|
@ -462,25 +462,6 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
following URL:
|
following URL:
|
||||||
https://xkbcommon.org/doc/current/keymap-text-format-v1.html
|
https://xkbcommon.org/doc/current/keymap-text-format-v1.html
|
||||||
|
|
||||||
*keyboard-group-create* _group_name_
|
|
||||||
Create a keyboard group. A keyboard group collects multiple keyboards in
|
|
||||||
a single logical keyboard. This means that all state, like the active
|
|
||||||
modifiers, is shared between the keyboards in a group.
|
|
||||||
|
|
||||||
*keyboard-group-destroy* _group_name_
|
|
||||||
Destroy the keyboard group with the given name. All attached keyboards
|
|
||||||
will be released, making them act as separate devices again.
|
|
||||||
|
|
||||||
*keyboard-group-add* _group_name_ _input_device_name_
|
|
||||||
Add a keyboard to a keyboard group, identified by the keyboard's
|
|
||||||
input device name. Any currently connected and future keyboards with
|
|
||||||
the given name will be added to the group. Simple globbing patterns are
|
|
||||||
supported, see the rules section for further information on globs.
|
|
||||||
|
|
||||||
*keyboard-group-remove* _group_name_ _input_device_name_
|
|
||||||
Remove a keyboard from a keyboard group, identified by the keyboard's
|
|
||||||
input device name.
|
|
||||||
|
|
||||||
The _input_ command can be used to create a configuration rule for an input
|
The _input_ command can be used to create a configuration rule for an input
|
||||||
device identified by its _name_.
|
device identified by its _name_.
|
||||||
The _name_ of an input device consists of its type, its decimal vendor id,
|
The _name_ of an input device consists of its type, its decimal vendor id,
|
||||||
|
@ -108,6 +108,19 @@ const LayoutPoint = struct {
|
|||||||
ly: f64,
|
ly: f64,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Image = union(enum) {
|
||||||
|
/// No cursor image
|
||||||
|
none,
|
||||||
|
/// Name of the current Xcursor shape
|
||||||
|
xcursor: [*:0]const u8,
|
||||||
|
/// Cursor surface configured by a client
|
||||||
|
client: struct {
|
||||||
|
surface: *wlr.Surface,
|
||||||
|
hotspot_x: i32,
|
||||||
|
hotspot_y: i32,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const log = std.log.scoped(.cursor);
|
const log = std.log.scoped(.cursor);
|
||||||
|
|
||||||
/// Current cursor mode as well as any state needed to implement that mode
|
/// Current cursor mode as well as any state needed to implement that mode
|
||||||
@ -124,9 +137,8 @@ wlr_cursor: *wlr.Cursor,
|
|||||||
|
|
||||||
/// Xcursor manager for the currently configured Xcursor theme.
|
/// Xcursor manager for the currently configured Xcursor theme.
|
||||||
xcursor_manager: *wlr.XcursorManager,
|
xcursor_manager: *wlr.XcursorManager,
|
||||||
/// Name of the current Xcursor shape, or null if a client has configured a
|
image: Image = .none,
|
||||||
/// surface to be used as the cursor shape instead.
|
image_surface_destroy: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleImageSurfaceDestroy),
|
||||||
xcursor_name: ?[*:0]const u8 = null,
|
|
||||||
|
|
||||||
/// Number of distinct buttons currently pressed
|
/// Number of distinct buttons currently pressed
|
||||||
pressed_count: u32 = 0,
|
pressed_count: u32 = 0,
|
||||||
@ -286,18 +298,40 @@ pub fn setTheme(cursor: *Cursor, theme: ?[*:0]const u8, _size: ?u32) !void {
|
|||||||
cursor.xcursor_manager.destroy();
|
cursor.xcursor_manager.destroy();
|
||||||
cursor.xcursor_manager = xcursor_manager;
|
cursor.xcursor_manager = xcursor_manager;
|
||||||
|
|
||||||
if (cursor.xcursor_name) |name| {
|
switch (cursor.image) {
|
||||||
cursor.setXcursor(name);
|
.none, .client => {},
|
||||||
|
.xcursor => |name| cursor.wlr_cursor.setXcursor(xcursor_manager, name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setXcursor(cursor: *Cursor, name: [*:0]const u8) void {
|
pub fn setImage(cursor: *Cursor, image: Image) void {
|
||||||
cursor.wlr_cursor.setXcursor(cursor.xcursor_manager, name);
|
switch (cursor.image) {
|
||||||
cursor.xcursor_name = name;
|
.none, .xcursor => {},
|
||||||
|
.client => {
|
||||||
|
cursor.image_surface_destroy.link.remove();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cursor.image = image;
|
||||||
|
switch (cursor.image) {
|
||||||
|
.none => cursor.wlr_cursor.unsetImage(),
|
||||||
|
.xcursor => |name| cursor.wlr_cursor.setXcursor(cursor.xcursor_manager, name),
|
||||||
|
.client => |client| {
|
||||||
|
cursor.wlr_cursor.setSurface(client.surface, client.hotspot_x, client.hotspot_y);
|
||||||
|
client.surface.events.destroy.add(&cursor.image_surface_destroy);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handleImageSurfaceDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||||
|
const cursor: *Cursor = @fieldParentPtr("image_surface_destroy", listener);
|
||||||
|
// wlroots calls wlr_cursor_unset_image() automatically
|
||||||
|
// when the cursor surface is destroyed.
|
||||||
|
cursor.image = .none;
|
||||||
|
cursor.image_surface_destroy.link.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clearFocus(cursor: *Cursor) void {
|
fn clearFocus(cursor: *Cursor) void {
|
||||||
cursor.setXcursor("default");
|
cursor.setImage(.{ .xcursor = "default" });
|
||||||
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,8 +774,15 @@ fn handleRequestSetCursor(
|
|||||||
// on the output that it's currently on and continue to do so as the
|
// on the output that it's currently on and continue to do so as the
|
||||||
// cursor moves between outputs.
|
// cursor moves between outputs.
|
||||||
log.debug("focused client set cursor", .{});
|
log.debug("focused client set cursor", .{});
|
||||||
cursor.wlr_cursor.setSurface(event.surface, event.hotspot_x, event.hotspot_y);
|
if (event.surface) |surface| {
|
||||||
cursor.xcursor_name = null;
|
cursor.setImage(.{ .client = .{
|
||||||
|
.surface = surface,
|
||||||
|
.hotspot_x = event.hotspot_x,
|
||||||
|
.hotspot_y = event.hotspot_y,
|
||||||
|
} });
|
||||||
|
} else {
|
||||||
|
cursor.setImage(.none);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,8 +798,6 @@ pub fn hide(cursor: *Cursor) void {
|
|||||||
|
|
||||||
cursor.hidden = true;
|
cursor.hidden = true;
|
||||||
cursor.wlr_cursor.unsetImage();
|
cursor.wlr_cursor.unsetImage();
|
||||||
cursor.xcursor_name = null;
|
|
||||||
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
|
||||||
cursor.hide_cursor_timer.timerUpdate(0) catch {
|
cursor.hide_cursor_timer.timerUpdate(0) catch {
|
||||||
log.err("failed to update cursor hide timeout", .{});
|
log.err("failed to update cursor hide timeout", .{});
|
||||||
};
|
};
|
||||||
@ -770,6 +809,7 @@ pub fn unhide(cursor: *Cursor) void {
|
|||||||
};
|
};
|
||||||
if (!cursor.hidden) return;
|
if (!cursor.hidden) return;
|
||||||
cursor.hidden = false;
|
cursor.hidden = false;
|
||||||
|
cursor.setImage(cursor.image);
|
||||||
cursor.updateState();
|
cursor.updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,7 +908,7 @@ fn computeEdges(cursor: *const Cursor, view: *const View) wlr.Edges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor_name: [*:0]const u8) void {
|
fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor: [*:0]const u8) void {
|
||||||
assert(cursor.mode == .passthrough or cursor.mode == .down);
|
assert(cursor.mode == .passthrough or cursor.mode == .down);
|
||||||
assert(mode == .move or mode == .resize);
|
assert(mode == .move or mode == .resize);
|
||||||
|
|
||||||
@ -884,7 +924,7 @@ fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor_name: [*:0]const
|
|||||||
}
|
}
|
||||||
|
|
||||||
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
||||||
cursor.setXcursor(xcursor_name);
|
cursor.setImage(.{ .xcursor = xcursor });
|
||||||
|
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
}
|
}
|
||||||
|
@ -101,16 +101,9 @@ pub fn init(keyboard: *Keyboard, seat: *Seat, wlr_device: *wlr.InputDevice) !voi
|
|||||||
// wlroots will log a more detailed error if this fails.
|
// wlroots will log a more detailed error if this fails.
|
||||||
if (!wlr_keyboard.setKeymap(server.config.keymap)) return error.OutOfMemory;
|
if (!wlr_keyboard.setKeymap(server.config.keymap)) return error.OutOfMemory;
|
||||||
|
|
||||||
// Add to keyboard-group, if applicable.
|
if (wlr.KeyboardGroup.fromKeyboard(wlr_keyboard) == null) {
|
||||||
var group_it = seat.keyboard_groups.first;
|
// wlroots will log an error on failure
|
||||||
outer: while (group_it) |group_node| : (group_it = group_node.next) {
|
_ = seat.keyboard_group.addKeyboard(wlr_keyboard);
|
||||||
for (group_node.data.globs.items) |glob| {
|
|
||||||
if (globber.match(glob, keyboard.device.identifier)) {
|
|
||||||
// wlroots will log an error if this fails explaining the reason.
|
|
||||||
_ = group_node.data.wlr_group.addKeyboard(wlr_keyboard);
|
|
||||||
break :outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
|
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
// This file is part of river, a dynamic tiling wayland compositor.
|
|
||||||
//
|
|
||||||
// Copyright 2022 The River Developers
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, version 3.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
const KeyboardGroup = @This();
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const mem = std.mem;
|
|
||||||
|
|
||||||
const globber = @import("globber");
|
|
||||||
const wlr = @import("wlroots");
|
|
||||||
const wl = @import("wayland").server.wl;
|
|
||||||
const xkb = @import("xkbcommon");
|
|
||||||
|
|
||||||
const log = std.log.scoped(.keyboard_group);
|
|
||||||
|
|
||||||
const server = &@import("main.zig").server;
|
|
||||||
const util = @import("util.zig");
|
|
||||||
|
|
||||||
const Seat = @import("Seat.zig");
|
|
||||||
const Keyboard = @import("Keyboard.zig");
|
|
||||||
|
|
||||||
seat: *Seat,
|
|
||||||
wlr_group: *wlr.KeyboardGroup,
|
|
||||||
name: []const u8,
|
|
||||||
globs: std.ArrayListUnmanaged([]const u8) = .{},
|
|
||||||
|
|
||||||
pub fn create(seat: *Seat, name: []const u8) !void {
|
|
||||||
log.debug("new keyboard group: '{s}'", .{name});
|
|
||||||
|
|
||||||
const node = try util.gpa.create(std.TailQueue(KeyboardGroup).Node);
|
|
||||||
errdefer util.gpa.destroy(node);
|
|
||||||
|
|
||||||
const wlr_group = try wlr.KeyboardGroup.create();
|
|
||||||
errdefer wlr_group.destroy();
|
|
||||||
|
|
||||||
const owned_name = try util.gpa.dupe(u8, name);
|
|
||||||
errdefer util.gpa.free(owned_name);
|
|
||||||
|
|
||||||
node.data = .{
|
|
||||||
.wlr_group = wlr_group,
|
|
||||||
.name = owned_name,
|
|
||||||
.seat = seat,
|
|
||||||
};
|
|
||||||
|
|
||||||
seat.addDevice(&wlr_group.keyboard.base);
|
|
||||||
seat.keyboard_groups.append(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy(group: *KeyboardGroup) void {
|
|
||||||
log.debug("destroying keyboard group: '{s}'", .{group.name});
|
|
||||||
|
|
||||||
util.gpa.free(group.name);
|
|
||||||
|
|
||||||
for (group.globs.items) |glob| {
|
|
||||||
util.gpa.free(glob);
|
|
||||||
}
|
|
||||||
group.globs.deinit(util.gpa);
|
|
||||||
|
|
||||||
group.wlr_group.destroy();
|
|
||||||
|
|
||||||
const node: *std.TailQueue(KeyboardGroup).Node = @fieldParentPtr("data", group);
|
|
||||||
group.seat.keyboard_groups.remove(node);
|
|
||||||
util.gpa.destroy(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addIdentifier(group: *KeyboardGroup, new_id: []const u8) !void {
|
|
||||||
for (group.globs.items) |glob| {
|
|
||||||
if (mem.eql(u8, glob, new_id)) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("keyboard group '{s}' adding identifier: '{s}'", .{ group.name, new_id });
|
|
||||||
|
|
||||||
const owned_id = try util.gpa.dupe(u8, new_id);
|
|
||||||
errdefer util.gpa.free(owned_id);
|
|
||||||
|
|
||||||
// Glob is validated in the command handler.
|
|
||||||
try group.globs.append(util.gpa, owned_id);
|
|
||||||
errdefer {
|
|
||||||
// Not used now, but if at any point this function is modified to that
|
|
||||||
// it may return an error after the glob pattern is added to the list,
|
|
||||||
// the list will have a pointer to freed memory in its last position.
|
|
||||||
_ = group.globs.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add any existing matching keyboards to the group.
|
|
||||||
var it = server.input_manager.devices.iterator(.forward);
|
|
||||||
while (it.next()) |device| {
|
|
||||||
if (device.seat != group.seat) continue;
|
|
||||||
if (device.wlr_device.type != .keyboard) continue;
|
|
||||||
|
|
||||||
if (globber.match(device.identifier, new_id)) {
|
|
||||||
log.debug("found existing matching keyboard; adding to group", .{});
|
|
||||||
|
|
||||||
if (!group.wlr_group.addKeyboard(device.wlr_device.toKeyboard())) {
|
|
||||||
// wlroots logs an error message to explain why this failed.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue, because we may have more than one device with the exact
|
|
||||||
// same identifier. That is in fact one reason for the keyboard group
|
|
||||||
// feature to exist in the first place.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn removeIdentifier(group: *KeyboardGroup, id: []const u8) !void {
|
|
||||||
for (group.globs.items, 0..) |glob, index| {
|
|
||||||
if (mem.eql(u8, glob, id)) {
|
|
||||||
_ = group.globs.orderedRemove(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var it = server.input_manager.devices.iterator(.forward);
|
|
||||||
while (it.next()) |device| {
|
|
||||||
if (device.seat != group.seat) continue;
|
|
||||||
if (device.wlr_device.type != .keyboard) continue;
|
|
||||||
|
|
||||||
if (globber.match(device.identifier, id)) {
|
|
||||||
const wlr_keyboard = device.wlr_device.toKeyboard();
|
|
||||||
assert(wlr_keyboard.group == group.wlr_group);
|
|
||||||
group.wlr_group.removeKeyboard(wlr_keyboard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -33,7 +33,6 @@ const InputDevice = @import("InputDevice.zig");
|
|||||||
const InputManager = @import("InputManager.zig");
|
const InputManager = @import("InputManager.zig");
|
||||||
const InputRelay = @import("InputRelay.zig");
|
const InputRelay = @import("InputRelay.zig");
|
||||||
const Keyboard = @import("Keyboard.zig");
|
const Keyboard = @import("Keyboard.zig");
|
||||||
const KeyboardGroup = @import("KeyboardGroup.zig");
|
|
||||||
const LayerSurface = @import("LayerSurface.zig");
|
const LayerSurface = @import("LayerSurface.zig");
|
||||||
const LockSurface = @import("LockSurface.zig");
|
const LockSurface = @import("LockSurface.zig");
|
||||||
const Mapping = @import("Mapping.zig");
|
const Mapping = @import("Mapping.zig");
|
||||||
@ -84,7 +83,7 @@ mapping_repeat_timer: *wl.EventSource,
|
|||||||
/// Currently repeating mapping, if any
|
/// Currently repeating mapping, if any
|
||||||
repeating_mapping: ?*const Mapping = null,
|
repeating_mapping: ?*const Mapping = null,
|
||||||
|
|
||||||
keyboard_groups: std.TailQueue(KeyboardGroup) = .{},
|
keyboard_group: *wlr.KeyboardGroup,
|
||||||
|
|
||||||
/// Currently focused output. Null only when there are no outputs at all.
|
/// Currently focused output. Null only when there are no outputs at all.
|
||||||
focused_output: ?*Output = null,
|
focused_output: ?*Output = null,
|
||||||
@ -121,12 +120,15 @@ pub fn init(seat: *Seat, name: [*:0]const u8) !void {
|
|||||||
.cursor = undefined,
|
.cursor = undefined,
|
||||||
.relay = undefined,
|
.relay = undefined,
|
||||||
.mapping_repeat_timer = mapping_repeat_timer,
|
.mapping_repeat_timer = mapping_repeat_timer,
|
||||||
|
.keyboard_group = try wlr.KeyboardGroup.create(),
|
||||||
};
|
};
|
||||||
seat.wlr_seat.data = @intFromPtr(seat);
|
seat.wlr_seat.data = @intFromPtr(seat);
|
||||||
|
|
||||||
try seat.cursor.init(seat);
|
try seat.cursor.init(seat);
|
||||||
seat.relay.init();
|
seat.relay.init();
|
||||||
|
|
||||||
|
try seat.tryAddDevice(&seat.keyboard_group.keyboard.base);
|
||||||
|
|
||||||
seat.wlr_seat.events.request_set_selection.add(&seat.request_set_selection);
|
seat.wlr_seat.events.request_set_selection.add(&seat.request_set_selection);
|
||||||
seat.wlr_seat.events.request_start_drag.add(&seat.request_start_drag);
|
seat.wlr_seat.events.request_start_drag.add(&seat.request_start_drag);
|
||||||
seat.wlr_seat.events.start_drag.add(&seat.start_drag);
|
seat.wlr_seat.events.start_drag.add(&seat.start_drag);
|
||||||
@ -142,9 +144,7 @@ pub fn deinit(seat: *Seat) void {
|
|||||||
seat.cursor.deinit();
|
seat.cursor.deinit();
|
||||||
seat.mapping_repeat_timer.remove();
|
seat.mapping_repeat_timer.remove();
|
||||||
|
|
||||||
while (seat.keyboard_groups.first) |node| {
|
seat.keyboard_group.destroy();
|
||||||
node.data.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
seat.request_set_selection.link.remove();
|
seat.request_set_selection.link.remove();
|
||||||
seat.request_start_drag.link.remove();
|
seat.request_start_drag.link.remove();
|
||||||
|
@ -519,7 +519,7 @@ fn handleRequestSetCursorShape(
|
|||||||
// actually has pointer focus first.
|
// actually has pointer focus first.
|
||||||
if (focused_client == event.seat_client) {
|
if (focused_client == event.seat_client) {
|
||||||
const name = wlr.CursorShapeManagerV1.shapeName(event.shape);
|
const name = wlr.CursorShapeManagerV1.shapeName(event.shape);
|
||||||
seat.cursor.setXcursor(name);
|
seat.cursor.setImage(.{ .xcursor = name });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,77 +24,13 @@ const util = @import("../util.zig");
|
|||||||
|
|
||||||
const Error = @import("../command.zig").Error;
|
const Error = @import("../command.zig").Error;
|
||||||
const Seat = @import("../Seat.zig");
|
const Seat = @import("../Seat.zig");
|
||||||
const KeyboardGroup = @import("../KeyboardGroup.zig");
|
|
||||||
|
|
||||||
pub fn keyboardGroupCreate(
|
pub const keyboardGroupCreate = keyboardGroupDeprecated;
|
||||||
seat: *Seat,
|
pub const keyboardGroupDestroy = keyboardGroupDeprecated;
|
||||||
args: []const [:0]const u8,
|
pub const keyboardGroupAdd = keyboardGroupDeprecated;
|
||||||
out: *?[]const u8,
|
pub const keyboardGroupRemove = keyboardGroupDeprecated;
|
||||||
) Error!void {
|
|
||||||
if (args.len < 2) return Error.NotEnoughArguments;
|
|
||||||
if (args.len > 2) return Error.TooManyArguments;
|
|
||||||
|
|
||||||
if (keyboardGroupFromName(seat, args[1]) != null) {
|
fn keyboardGroupDeprecated(_: *Seat, _: []const [:0]const u8, out: *?[]const u8) Error!void {
|
||||||
const msg = try util.gpa.dupe(u8, "error: failed to create keybaord group: group of same name already exists\n");
|
out.* = try util.gpa.dupe(u8, "warning: explicit keyboard groups are deprecated, " ++
|
||||||
out.* = msg;
|
"all keyboards are now automatically added to a single group\n");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try KeyboardGroup.create(seat, args[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn keyboardGroupDestroy(
|
|
||||||
seat: *Seat,
|
|
||||||
args: []const [:0]const u8,
|
|
||||||
out: *?[]const u8,
|
|
||||||
) Error!void {
|
|
||||||
if (args.len < 2) return Error.NotEnoughArguments;
|
|
||||||
if (args.len > 2) return Error.TooManyArguments;
|
|
||||||
const group = keyboardGroupFromName(seat, args[1]) orelse {
|
|
||||||
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
|
|
||||||
out.* = msg;
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
group.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn keyboardGroupAdd(
|
|
||||||
seat: *Seat,
|
|
||||||
args: []const [:0]const u8,
|
|
||||||
out: *?[]const u8,
|
|
||||||
) Error!void {
|
|
||||||
if (args.len < 3) return Error.NotEnoughArguments;
|
|
||||||
if (args.len > 3) return Error.TooManyArguments;
|
|
||||||
|
|
||||||
const group = keyboardGroupFromName(seat, args[1]) orelse {
|
|
||||||
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
|
|
||||||
out.* = msg;
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
try globber.validate(args[2]);
|
|
||||||
try group.addIdentifier(args[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn keyboardGroupRemove(
|
|
||||||
seat: *Seat,
|
|
||||||
args: []const [:0]const u8,
|
|
||||||
out: *?[]const u8,
|
|
||||||
) Error!void {
|
|
||||||
if (args.len < 3) return Error.NotEnoughArguments;
|
|
||||||
if (args.len > 3) return Error.TooManyArguments;
|
|
||||||
|
|
||||||
const group = keyboardGroupFromName(seat, args[1]) orelse {
|
|
||||||
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
|
|
||||||
out.* = msg;
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
try group.removeIdentifier(args[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn keyboardGroupFromName(seat: *Seat, name: []const u8) ?*KeyboardGroup {
|
|
||||||
var it = seat.keyboard_groups.first;
|
|
||||||
while (it) |node| : (it = node.next) {
|
|
||||||
if (mem.eql(u8, node.data.name, name)) return &node.data;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user