Add input_manager capabilities

This commit is contained in:
project-repo 2021-09-11 13:48:08 +02:00
commit 985b5f65db
10 changed files with 857 additions and 61 deletions

View file

@ -1,4 +1,4 @@
/*
*
* Cagebreak: A Wayland tiling compositor.
*
* Copyright (C) 2018-2020 Jente Hidskes
@ -49,6 +49,7 @@
#include "message.h"
#include "output.h"
#include "parse.h"
#include "input_manager.h"
#include "seat.h"
#include "server.h"
#include "xdg_shell.h"
@ -264,6 +265,8 @@ main(int argc, char *argv[]) {
wlr_log_init(WLR_ERROR, NULL);
#endif
wl_list_init(&server.input_config);
server.modes = malloc(4 * sizeof(char *));
if(!server.modes) {
wlr_log(WLR_ERROR, "Error allocating mode array");
@ -358,6 +361,10 @@ main(int argc, char *argv[]) {
goto end;
}
server.input = input_manager_create(&server);
fprintf(stderr, "input_manager_create:%d\n",wl_list_length(&server.input->devices));
data_control_manager =
wlr_data_control_manager_v1_create(server.wl_display);
if(!data_control_manager) {

14
input.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef _LIBINPUT_H
#define _LIBINPUT_H
#include <stdbool.h>
struct cg_input_device;
void cg_input_configure_libinput_device(struct cg_input_device *device);
void cg_input_reset_libinput_device(struct cg_input_device *device);
bool cg_libinput_device_is_builtin(struct cg_input_device *device);
#endif

267
input_manager.c Normal file
View file

@ -0,0 +1,267 @@
/*
* Cagebreak: A Wayland tiling compositor.
*
* Copyright (C) 2020 The Cagebreak Authors
* Copyright (C) 2018-2020 Jente Hidskes
*
* See the LICENSE file accompanying this file.
*/
#define _POSIX_C_SOURCE 200812L
#include "config.h"
#include "server.h"
#include "seat.h"
#include "input_manager.h"
#include "input.h"
#include <wlr/backend/libinput.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wayland-server-core.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
void strip_whitespace(char *str) {
static const char whitespace[] = " \f\n\r\t\v";
size_t len = strlen(str);
size_t start = strspn(str, whitespace);
memmove(str, &str[start], len + 1 - start);
if (*str) {
for (len -= start + 1; isspace(str[len]); --len) {}
str[len + 1] = '\0';
}
}
char *input_device_get_identifier(struct wlr_input_device *device) {
int vendor = device->vendor;
int product = device->product;
char *name = strdup(device->name ? device->name : "");
strip_whitespace(name);
char *p = name;
for (; *p; ++p) {
// There are in fact input devices with unprintable characters in its name
if (*p == ' ' || !isprint(*p)) {
*p = '_';
}
}
const char *fmt = "%d:%d:%s";
int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1;
char *identifier = malloc(len);
if (!identifier) {
wlr_log(WLR_ERROR, "Unable to allocate unique input device name");
return NULL;
}
snprintf(identifier, len, fmt, vendor, product, name);
free(name);
return identifier;
}
void input_manager_handle_device_destroy(struct wl_listener *listener, void *data) {
struct cg_input_device *input_device =
wl_container_of(listener, input_device, device_destroy);
if (!input_device) {
wlr_log(WLR_ERROR, "Could not find cagebreak input device to destroy");
return;
}
seat_remove_device(input_device->server->seat, input_device);
wl_list_remove(&input_device->link);
wl_list_remove(&input_device->device_destroy.link);
free(input_device->identifier);
free(input_device);
}
static void handle_new_input(struct wl_listener *listener, void *data) {
struct cg_input_manager *input =
wl_container_of(listener, input, new_input);
struct cg_server *server= input->server;
struct wlr_input_device *device = data;
struct cg_input_device *input_device =
calloc(1, sizeof(struct cg_input_device));
if (!input_device) {
wlr_log(WLR_ERROR,"Could not allocate input device");
return;
}
device->data = input_device;
input_device->wlr_device = device;
input_device->identifier = input_device_get_identifier(device);
input_device->server=server;
input_device->pointer=NULL;
input_device->touch=NULL;
wl_list_insert(&input->devices, &input_device->link);
cg_input_configure_libinput_device(input_device);
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
input_device->device_destroy.notify = input_manager_handle_device_destroy;
struct cg_seat *seat = server->seat;
seat_add_device(seat, input_device);
}
void handle_virtual_keyboard(struct wl_listener *listener, void *data) {
struct cg_input_manager *input_manager =
wl_container_of(listener, input_manager, virtual_keyboard_new);
struct wlr_virtual_keyboard_v1 *keyboard = data;
struct wlr_input_device *device = &keyboard->input_device;
struct cg_seat *seat = input_manager->server->seat;
struct cg_input_device *input_device =
calloc(1, sizeof(struct cg_input_device));
if (!input_device) {
wlr_log(WLR_ERROR, "could not allocate input device");
return;
}
device->data = input_device;
input_device->is_virtual = true;
input_device->wlr_device = device;
input_device->identifier = input_device_get_identifier(device);
wl_list_insert(&input_manager->devices, &input_device->link);
input_device->server=input_manager->server;
input_device->pointer=NULL;
input_device->touch=NULL;
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
input_device->device_destroy.notify = input_manager_handle_device_destroy;
seat_add_device(seat, input_device);
}
void handle_virtual_pointer(struct wl_listener *listener, void *data) {
struct cg_input_manager *input_manager =
wl_container_of(listener, input_manager, virtual_pointer_new);
struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
struct wlr_virtual_pointer_v1 *pointer = event->new_pointer;
struct wlr_input_device *device = &pointer->input_device;
struct cg_seat *seat = input_manager->server->seat;
struct cg_input_device *input_device =
calloc(1, sizeof(struct cg_input_device));
if (!input_device) {
wlr_log(WLR_ERROR, "could not allocate input device");
return;
}
device->data = input_device;
input_device->is_virtual = true;
input_device->wlr_device = device;
input_device->identifier = input_device_get_identifier(device);
wl_list_insert(&input_manager->devices, &input_device->link);
input_device->server=input_manager->server;
input_device->pointer=NULL;
input_device->touch=NULL;
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
input_device->device_destroy.notify = input_manager_handle_device_destroy;
seat_add_device(seat, input_device);
if (event->suggested_output) {
wlr_cursor_map_input_to_output(seat->cursor, device,
event->suggested_output);
}
}
struct cg_input_manager *input_manager_create(struct cg_server *server) {
struct cg_input_manager *input =
calloc(1, sizeof(struct cg_input_manager));
if (!input) {
return NULL;
}
wl_list_init(&input->devices);
input->server=server;
input->new_input.notify = handle_new_input;
wl_signal_add(&server->backend->events.new_input, &input->new_input);
input->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(
server->wl_display);
wl_signal_add(&input->virtual_keyboard->events.new_virtual_keyboard,
&input->virtual_keyboard_new);
input->virtual_keyboard_new.notify = handle_virtual_keyboard;
input->virtual_pointer = wlr_virtual_pointer_manager_v1_create(
server->wl_display
);
wl_signal_add(&input->virtual_pointer->events.new_virtual_pointer,
&input->virtual_pointer_new);
input->virtual_pointer_new.notify = handle_virtual_pointer;
return input;
}
static bool device_is_touchpad(struct cg_input_device *device) {
if (device->wlr_device->type != WLR_INPUT_DEVICE_POINTER ||
!wlr_input_device_is_libinput(device->wlr_device)) {
return false;
}
struct libinput_device *libinput_device =
wlr_libinput_get_device_handle(device->wlr_device);
return libinput_device_config_tap_get_finger_count(libinput_device) > 0;
}
const char *input_device_get_type(struct cg_input_device *device) {
switch (device->wlr_device->type) {
case WLR_INPUT_DEVICE_POINTER:
if (device_is_touchpad(device)) {
return "touchpad";
} else {
return "pointer";
}
case WLR_INPUT_DEVICE_KEYBOARD:
return "keyboard";
case WLR_INPUT_DEVICE_TOUCH:
return "touch";
case WLR_INPUT_DEVICE_TABLET_TOOL:
return "tablet_tool";
case WLR_INPUT_DEVICE_TABLET_PAD:
return "tablet_pad";
case WLR_INPUT_DEVICE_SWITCH:
return "switch";
}
return "unknown";
}
struct cg_input_config *input_device_get_config(struct cg_input_device *device) {
struct cg_server *server=device->server;
struct cg_input_config *wildcard_config = NULL;
struct cg_input_config *config = NULL;
wl_list_for_each(config, &server->input_config, link) {
if (strcmp(config->identifier, device->identifier) == 0) {
return config;
} else if (strcmp(config->identifier, "*") == 0) {
wildcard_config = config;
}
}
const char *device_type = input_device_get_type(device);
wl_list_for_each(config, &server->input_config, link) {
if (strncmp(config->identifier,"type:",5)&&strcmp(config->identifier + 5, device_type) == 0) {
return config;
}
}
return wildcard_config;
}

108
input_manager.h Normal file
View file

@ -0,0 +1,108 @@
#ifndef CG_INPUT_MANAGER_H
#define CG_INPUT_MANAGER_H
#include "seat.h"
#include "server.h"
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
struct cg_input_manager *input_manager_create(struct cg_server *server);
struct cg_input_config *input_device_get_config(struct cg_input_device *device);
void input_manager_handle_device_destroy(struct wl_listener *listener, void *data);
struct cg_input_manager {
struct wl_list devices;
struct cg_server *server;
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
struct wl_listener new_input;
struct wl_listener virtual_keyboard_new;
struct wl_listener virtual_pointer_new;
};
struct cg_input_config_mapped_from_region {
double x1, y1;
double x2, y2;
bool mm;
};
struct calibration_matrix {
bool configured;
float matrix[6];
};
enum cg_input_config_mapped_to {
MAPPED_TO_DEFAULT,
MAPPED_TO_OUTPUT,
MAPPED_TO_REGION,
};
/**
* options for input devices
*/
struct cg_input_config {
char *identifier;
const char *input_type;
int accel_profile;
struct calibration_matrix calibration_matrix;
int click_method;
int drag;
int drag_lock;
int dwt;
int left_handed;
int middle_emulation;
int natural_scroll;
float pointer_accel;
float scroll_factor;
int repeat_delay;
int repeat_rate;
int scroll_button;
int scroll_method;
int send_events;
int tap;
int tap_button_map;
char *xkb_layout;
char *xkb_model;
char *xkb_options;
char *xkb_rules;
char *xkb_variant;
char *xkb_file;
bool xkb_file_is_set;
int xkb_numlock;
int xkb_capslock;
struct wl_list link;
struct cg_input_config_mapped_from_region *mapped_from_region;
enum cg_input_config_mapped_to mapped_to;
char *mapped_to_output;
struct wlr_box *mapped_to_region;
struct wl_list tools;
bool capturable;
struct wlr_box region;
};
struct cg_input_device {
char *identifier;
struct cg_server *server;
struct wlr_input_device *wlr_device;
struct wl_list link;
struct wl_listener device_destroy;
bool is_virtual;
/* Only one of the following is non-NULL depending on the type of the input device */
struct cg_pointer *pointer;
struct cg_touch *touch;
};
#endif

View file

@ -12,6 +12,7 @@
#include "keybinding.h"
#include "message.h"
#include "output.h"
#include "input_manager.h"
#include "seat.h"
#include "server.h"
#include "view.h"
@ -870,6 +871,11 @@ keybinding_configure_output(struct cg_server *server,
}
}
void
keybinding_configure_input_dev(struct cg_server *server, struct cg_input_config *cfg) {
}
/* Hint: see keybinding.h for details on "data" */
int
run_action(enum keybinding_action action, struct cg_server *server,

349
libinput.c Normal file
View file

@ -0,0 +1,349 @@
#include <float.h>
#include <libinput.h>
#include <libudev.h>
#include <limits.h>
#include <wlr/backend/libinput.h>
#include <wlr/util/log.h>
#include <strings.h>
#include "input.h"
#include "output.h"
#include "input_manager.h"
static void log_status(enum libinput_config_status status) {
if (status != LIBINPUT_CONFIG_STATUS_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to apply libinput config: %s",
libinput_config_status_to_str(status));
}
}
static bool set_send_events(struct libinput_device *device, uint32_t mode) {
if (libinput_device_config_send_events_get_mode(device) == mode) {
return false;
}
wlr_log(WLR_DEBUG, "send_events_set_mode(%" PRIu32 ")", mode);
log_status(libinput_device_config_send_events_set_mode(device, mode));
return true;
}
static bool set_tap(struct libinput_device *device,
enum libinput_config_tap_state tap) {
if (libinput_device_config_tap_get_finger_count(device) <= 0 ||
libinput_device_config_tap_get_enabled(device) == tap) {
return false;
}
wlr_log(WLR_DEBUG, "tap_set_enabled(%d)", tap);
log_status(libinput_device_config_tap_set_enabled(device, tap));
return true;
}
static bool set_tap_button_map(struct libinput_device *device,
enum libinput_config_tap_button_map map) {
if (libinput_device_config_tap_get_finger_count(device) <= 0 ||
libinput_device_config_tap_get_button_map(device) == map) {
return false;
}
wlr_log(WLR_DEBUG, "tap_set_button_map(%d)", map);
log_status(libinput_device_config_tap_set_button_map(device, map));
return true;
}
static bool set_tap_drag(struct libinput_device *device,
enum libinput_config_drag_state drag) {
if (libinput_device_config_tap_get_finger_count(device) <= 0 ||
libinput_device_config_tap_get_drag_enabled(device) == drag) {
return false;
}
wlr_log(WLR_DEBUG, "tap_set_drag_enabled(%d)", drag);
log_status(libinput_device_config_tap_set_drag_enabled(device, drag));
return true;
}
static bool set_tap_drag_lock(struct libinput_device *device,
enum libinput_config_drag_lock_state lock) {
if (libinput_device_config_tap_get_finger_count(device) <= 0 ||
libinput_device_config_tap_get_drag_lock_enabled(device) == lock) {
return false;
}
wlr_log(WLR_DEBUG, "tap_set_drag_lock_enabled(%d)", lock);
log_status(libinput_device_config_tap_set_drag_lock_enabled(device, lock));
return true;
}
static bool set_accel_speed(struct libinput_device *device, double speed) {
if (!libinput_device_config_accel_is_available(device) ||
libinput_device_config_accel_get_speed(device) == speed) {
return false;
}
wlr_log(WLR_DEBUG, "accel_set_speed(%f)", speed);
log_status(libinput_device_config_accel_set_speed(device, speed));
return true;
}
static bool set_accel_profile(struct libinput_device *device,
enum libinput_config_accel_profile profile) {
if (!libinput_device_config_accel_is_available(device) ||
libinput_device_config_accel_get_profile(device) == profile) {
return false;
}
wlr_log(WLR_DEBUG, "accel_set_profile(%d)", profile);
log_status(libinput_device_config_accel_set_profile(device, profile));
return true;
}
static bool set_natural_scroll(struct libinput_device *d, bool n) {
if (!libinput_device_config_scroll_has_natural_scroll(d) ||
libinput_device_config_scroll_get_natural_scroll_enabled(d) == n) {
return false;
}
wlr_log(WLR_DEBUG, "scroll_set_natural_scroll(%d)", n);
log_status(libinput_device_config_scroll_set_natural_scroll_enabled(d, n));
return true;
}
static bool set_left_handed(struct libinput_device *device, bool left) {
if (!libinput_device_config_left_handed_is_available(device) ||
libinput_device_config_left_handed_get(device) == left) {
return false;
}
wlr_log(WLR_DEBUG, "left_handed_set(%d)", left);
log_status(libinput_device_config_left_handed_set(device, left));
return true;
}
static bool set_click_method(struct libinput_device *device,
enum libinput_config_click_method method) {
uint32_t click = libinput_device_config_click_get_methods(device);
if ((click & ~LIBINPUT_CONFIG_CLICK_METHOD_NONE) == 0 ||
libinput_device_config_click_get_method(device) == method) {
return false;
}
wlr_log(WLR_DEBUG, "click_set_method(%d)", method);
log_status(libinput_device_config_click_set_method(device, method));
return true;
}
static bool set_middle_emulation(struct libinput_device *dev,
enum libinput_config_middle_emulation_state mid) {
if (!libinput_device_config_middle_emulation_is_available(dev) ||
libinput_device_config_middle_emulation_get_enabled(dev) == mid) {
return false;
}
wlr_log(WLR_DEBUG, "middle_emulation_set_enabled(%d)", mid);
log_status(libinput_device_config_middle_emulation_set_enabled(dev, mid));
return true;
}
static bool set_scroll_method(struct libinput_device *device,
enum libinput_config_scroll_method method) {
uint32_t scroll = libinput_device_config_scroll_get_methods(device);
if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 ||
libinput_device_config_scroll_get_method(device) == method) {
return false;
}
wlr_log(WLR_DEBUG, "scroll_set_method(%d)", method);
log_status(libinput_device_config_scroll_set_method(device, method));
return true;
}
static bool set_scroll_button(struct libinput_device *dev, uint32_t button) {
uint32_t scroll = libinput_device_config_scroll_get_methods(dev);
if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 ||
libinput_device_config_scroll_get_button(dev) == button) {
return false;
}
wlr_log(WLR_DEBUG, "scroll_set_button(%" PRIu32 ")", button);
log_status(libinput_device_config_scroll_set_button(dev, button));
return true;
}
static bool set_dwt(struct libinput_device *device, bool dwt) {
if (!libinput_device_config_dwt_is_available(device) ||
libinput_device_config_dwt_get_enabled(device) == dwt) {
return false;
}
wlr_log(WLR_DEBUG, "dwt_set_enabled(%d)", dwt);
log_status(libinput_device_config_dwt_set_enabled(device, dwt));
return true;
}
static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
if (!libinput_device_config_calibration_has_matrix(dev)) {
return false;
}
bool changed = false;
float current[6];
libinput_device_config_calibration_get_matrix(dev, current);
for (int i = 0; i < 6; i++) {
if (current[i] != mat[i]) {
changed = true;
break;
}
}
if (changed) {
wlr_log(WLR_DEBUG, "calibration_set_matrix(%f, %f, %f, %f, %f, %f)",
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
log_status(libinput_device_config_calibration_set_matrix(dev, mat));
}
return changed;
}
void output_get_identifier(char *identifier, size_t len,
struct cg_output *output) {
struct wlr_output *wlr_output = output->wlr_output;
snprintf(identifier, len, "%s %s %s", wlr_output->make, wlr_output->model,
wlr_output->serial);
}
struct cg_output *output_by_name_or_id(const char *name_or_id, struct cg_server *server) {
struct cg_output *output=NULL;
wl_list_for_each(output,&server->outputs,link) {
char identifier[128];
output_get_identifier(identifier, sizeof(identifier), output);
if (strcasecmp(identifier, name_or_id) == 0
|| strcasecmp(output->wlr_output->name, name_or_id) == 0) {
return output;
}
}
return NULL;
}
void cg_input_configure_libinput_device(struct cg_input_device *input_device) {
struct cg_input_config *ic = input_device_get_config(input_device);
if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
return;
}
struct libinput_device *device =
wlr_libinput_get_device_handle(input_device->wlr_device);
wlr_log(WLR_DEBUG, "cg_input_configure_libinput_device('%s' on '%s')",
ic->identifier, input_device->identifier);
bool changed = false;
if (ic->mapped_to_output &&
!output_by_name_or_id(ic->mapped_to_output,input_device->server)) {
wlr_log(WLR_DEBUG,
"%s '%s' is mapped to offline output '%s'; disabling input",
ic->input_type, ic->identifier, ic->mapped_to_output);
changed |= set_send_events(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
} else if (ic->send_events != INT_MIN) {
changed |= set_send_events(device, ic->send_events);
} else {
// Have to reset to the default mode here, otherwise if ic->send_events
// is unset and a mapped output just came online after being disabled,
// we'd remain stuck sending no events.
changed |= set_send_events(device,
libinput_device_config_send_events_get_default_mode(device));
}
if (ic->tap != INT_MIN) {
changed |= set_tap(device, ic->tap);
}
if (ic->tap_button_map != INT_MIN) {
changed |= set_tap_button_map(device, ic->tap_button_map);
}
if (ic->drag != INT_MIN) {
changed |= set_tap_drag(device, ic->drag);
}
if (ic->drag_lock != INT_MIN) {
changed |= set_tap_drag_lock(device, ic->drag_lock);
}
if (ic->pointer_accel != FLT_MIN) {
changed |= set_accel_speed(device, ic->pointer_accel);
}
if (ic->accel_profile != INT_MIN) {
changed |= set_accel_profile(device, ic->accel_profile);
}
if (ic->natural_scroll != INT_MIN) {
changed |= set_natural_scroll(device, ic->natural_scroll);
}
if (ic->left_handed != INT_MIN) {
changed |= set_left_handed(device, ic->left_handed);
}
if (ic->click_method != INT_MIN) {
changed |= set_click_method(device, ic->click_method);
}
if (ic->middle_emulation != INT_MIN) {
changed |= set_middle_emulation(device, ic->middle_emulation);
}
if (ic->scroll_method != INT_MIN) {
changed |= set_scroll_method(device, ic->scroll_method);
}
if (ic->scroll_button != INT_MIN) {
changed |= set_scroll_button(device, ic->scroll_button);
}
if (ic->dwt != INT_MIN) {
changed |= set_dwt(device, ic->dwt);
}
if (ic->calibration_matrix.configured) {
changed |= set_calibration_matrix(device, ic->calibration_matrix.matrix);
}
}
void cg_input_reset_libinput_device(struct cg_input_device *input_device) {
if (!wlr_input_device_is_libinput(input_device->wlr_device)) {
return;
}
struct libinput_device *device =
wlr_libinput_get_device_handle(input_device->wlr_device);
wlr_log(WLR_DEBUG, "cg_input_reset_libinput_device(%s)",
input_device->identifier);
bool changed = false;
changed |= set_send_events(device,
libinput_device_config_send_events_get_default_mode(device));
changed |= set_tap(device,
libinput_device_config_tap_get_default_enabled(device));
changed |= set_tap_button_map(device,
libinput_device_config_tap_get_default_button_map(device));
changed |= set_tap_drag(device,
libinput_device_config_tap_get_default_drag_enabled(device));
changed |= set_tap_drag_lock(device,
libinput_device_config_tap_get_default_drag_lock_enabled(device));
changed |= set_accel_speed(device,
libinput_device_config_accel_get_default_speed(device));
changed |= set_accel_profile(device,
libinput_device_config_accel_get_default_profile(device));
changed |= set_natural_scroll(device,
libinput_device_config_scroll_get_default_natural_scroll_enabled(
device));
changed |= set_left_handed(device,
libinput_device_config_left_handed_get_default(device));
changed |= set_click_method(device,
libinput_device_config_click_get_default_method(device));
changed |= set_middle_emulation(device,
libinput_device_config_middle_emulation_get_default_enabled(device));
changed |= set_scroll_method(device,
libinput_device_config_scroll_get_default_method(device));
changed |= set_scroll_button(device,
libinput_device_config_scroll_get_default_button(device));
changed |= set_dwt(device,
libinput_device_config_dwt_get_default_enabled(device));
float matrix[6];
libinput_device_config_calibration_get_default_matrix(device, matrix);
changed |= set_calibration_matrix(device, matrix);
}
bool cg_libinput_device_is_builtin(struct cg_input_device *cg_device) {
if (!wlr_input_device_is_libinput(cg_device->wlr_device)) {
return false;
}
struct libinput_device *device =
wlr_libinput_get_device_handle(cg_device->wlr_device);
struct udev_device *udev_device =
libinput_device_get_udev_device(device);
if (!udev_device) {
return false;
}
const char *id_path = udev_device_get_property_value(udev_device, "ID_PATH");
if (!id_path) {
return false;
}
const char prefix[] = "platform-";
return strncmp(id_path, prefix, strlen(prefix)) == 0;
}

View file

@ -64,6 +64,8 @@ cairo = dependency('cairo')
pango = dependency('pango')
pangocairo = dependency('pangocairo')
fontconfig = dependency('fontconfig')
libinput = dependency('libinput')
libudev = dependency('libudev')
math = cc.find_library('m')
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
@ -123,6 +125,7 @@ conf_data.set_quoted('CG_VERSION', version)
cagebreak_main_file = [ 'cagebreak.c', ]
cagebreak_source_strings = [
'idle_inhibit_v1.c',
'input_manager.c',
'ipc_server.c',
'keybinding.c',
'workspace.c',
@ -133,6 +136,7 @@ cagebreak_source_strings = [
'util.c',
'view.c',
'xdg_shell.c',
'libinput.c',
'server.c',
'message.c',
'pango.c',
@ -186,6 +190,8 @@ cagebreak_dependencies_dict = {
'wlroots': [wlroots,true],
'xkbcommon': [xkbcommon,true],
'fontconfig': [fontconfig,true],
'libinput': [libinput,true],
'libudev': [libudev,true],
'pixman': [pixman,true],
'pango': [pango,true],
'cairo': [cairo,true],
@ -201,6 +207,8 @@ reproducible_build_versions = {
'wlroots': '0.14.1',
'xkbcommon': '1.3.0',
'fontconfig': '2.13.94',
'libinput': '2.13.94',
'libudev': '2.13.94',
'pixman': '0.40.0',
'pango': '1.48.7',
'cairo': '1.17.4',

136
seat.c
View file

@ -32,6 +32,7 @@
#endif
#include "keybinding.h"
#include "input_manager.h"
#include "message.h"
#include "output.h"
#include "seat.h"
@ -112,13 +113,13 @@ static void
update_capabilities(const struct cg_seat *seat) {
uint32_t caps = 0;
if(!wl_list_empty(&seat->keyboard_groups)) {
if(seat->num_keyboards>0) {
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
}
if(!wl_list_empty(&seat->pointers)) {
if(seat->num_pointers>0) {
caps |= WL_SEAT_CAPABILITY_POINTER;
}
if(!wl_list_empty(&seat->touch)) {
if(seat->num_touch>0) {
caps |= WL_SEAT_CAPABILITY_TOUCH;
}
wlr_seat_set_capabilities(seat->seat, caps);
@ -133,20 +134,21 @@ update_capabilities(const struct cg_seat *seat) {
}
static void
handle_touch_destroy(struct wl_listener *listener, void *_data) {
struct cg_touch *touch = wl_container_of(listener, touch, destroy);
struct cg_seat *seat = touch->seat;
remove_touch(struct cg_seat *seat, struct cg_touch *touch) {
if(!touch) {
return;
}
wl_list_remove(&touch->link);
wlr_cursor_detach_input_device(seat->cursor, touch->device);
wl_list_remove(&touch->destroy.link);
wlr_cursor_detach_input_device(seat->cursor, touch->device->wlr_device);
--seat->num_touch;
free(touch);
update_capabilities(seat);
}
static void
handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) {
new_touch(struct cg_seat *seat, struct cg_input_device *input_device) {
struct wlr_input_device *device=input_device->wlr_device;
struct cg_touch *touch = calloc(1, sizeof(struct cg_touch));
if(!touch) {
wlr_log(WLR_ERROR, "Cannot allocate touch");
@ -154,12 +156,10 @@ handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) {
}
touch->seat = seat;
touch->device = device;
touch->device = input_device;
wlr_cursor_attach_input_device(seat->cursor, device);
wl_list_insert(&seat->touch, &touch->link);
touch->destroy.notify = handle_touch_destroy;
wl_signal_add(&touch->device->events.destroy, &touch->destroy);
input_device->touch=touch;
++seat->num_touch;
if(device->output_name != NULL) {
struct cg_output *output;
@ -174,20 +174,20 @@ handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) {
}
static void
handle_pointer_destroy(struct wl_listener *listener, void *_data) {
struct cg_pointer *pointer = wl_container_of(listener, pointer, destroy);
struct cg_seat *seat = pointer->seat;
wl_list_remove(&pointer->link);
wlr_cursor_detach_input_device(seat->cursor, pointer->device);
wl_list_remove(&pointer->destroy.link);
remove_pointer(struct cg_seat *seat, struct cg_pointer *pointer) {
if(!pointer) {
return;
}
wlr_cursor_detach_input_device(seat->cursor, pointer->device->wlr_device);
--seat->num_pointers;
free(pointer);
update_capabilities(seat);
}
static void
handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) {
new_pointer(struct cg_seat *seat, struct cg_input_device *input_device) {
struct wlr_input_device *device=input_device->wlr_device;
struct cg_pointer *pointer = calloc(1, sizeof(struct cg_pointer));
if(!pointer) {
wlr_log(WLR_ERROR, "Cannot allocate pointer");
@ -195,12 +195,10 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) {
}
pointer->seat = seat;
pointer->device = device;
pointer->device = input_device;
wlr_cursor_attach_input_device(seat->cursor, device);
wl_list_insert(&seat->pointers, &pointer->link);
pointer->destroy.notify = handle_pointer_destroy;
wl_signal_add(&device->events.destroy, &pointer->destroy);
input_device->pointer=pointer;
++seat->num_pointers;
if(device->output_name != NULL) {
struct cg_output *output;
@ -431,10 +429,11 @@ cleanup:
}
static void
handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) {
new_keyboard(struct cg_seat *seat, struct cg_input_device *input_device) {
struct wlr_input_device *device= input_device->wlr_device;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if(!context) {
wlr_log(WLR_ERROR, "Unable to create XBK context");
wlr_log(WLR_ERROR, "Unable to create XKB context");
return;
}
@ -460,24 +459,63 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) {
wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
cg_keyboard_group_add(device, seat);
++seat->num_keyboards;
wlr_seat_set_keyboard(seat->seat, device);
}
static void
handle_new_input(struct wl_listener *listener, void *data) {
struct cg_seat *seat = wl_container_of(listener, seat, new_input);
struct wlr_input_device *device = data;
switch(device->type) {
void
seat_add_device(struct cg_seat *seat, struct cg_input_device *device) {
switch(device->wlr_device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
handle_new_keyboard(seat, device);
new_keyboard(seat, device);
break;
case WLR_INPUT_DEVICE_POINTER:
handle_new_pointer(seat, device);
new_pointer(seat, device);
break;
case WLR_INPUT_DEVICE_TOUCH:
handle_new_touch(seat, device);
new_touch(seat, device);
break;
case WLR_INPUT_DEVICE_SWITCH:
wlr_log(WLR_DEBUG, "Switch input is not implemented");
return;
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET_PAD:
wlr_log(WLR_DEBUG, "Tablet input is not implemented");
return;
}
update_capabilities(seat);
}
void remove_keyboard(struct cg_seat *seat, struct cg_input_device *keyboard) {
if (!keyboard) {
return;
}
struct wlr_seat *wlr_seat = seat->seat;
struct wlr_keyboard *wlr_keyboard = keyboard->wlr_device->keyboard;
if (keyboard->wlr_device->keyboard->group) {
wlr_keyboard_group_remove_keyboard(wlr_keyboard->group,wlr_keyboard);
}
if (wlr_seat_get_keyboard(wlr_seat) == wlr_keyboard) {
wlr_seat_set_keyboard(wlr_seat, NULL);
}
--seat->num_keyboards;
}
void
seat_remove_device(struct cg_seat *seat, struct cg_input_device *device) {
switch(device->wlr_device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
remove_keyboard(seat, device);
break;
case WLR_INPUT_DEVICE_POINTER:
remove_pointer(seat, device->pointer);
device->pointer=NULL;
break;
case WLR_INPUT_DEVICE_TOUCH:
remove_touch(seat, device->touch);
device->touch=NULL;
break;
case WLR_INPUT_DEVICE_SWITCH:
wlr_log(WLR_DEBUG, "Switch input is not implemented");
@ -801,15 +839,11 @@ handle_destroy(struct wl_listener *listener, void *_data) {
wl_event_source_remove(group->key_repeat_timer);
free(group);
}
struct cg_pointer *pointer, *pointer_tmp;
wl_list_for_each_safe(pointer, pointer_tmp, &seat->pointers, link) {
handle_pointer_destroy(&pointer->destroy, NULL);
struct cg_input_device *it, *it_tmp;
wl_list_for_each_safe(it, it_tmp, &seat->server->input->devices, link) {
input_manager_handle_device_destroy(&it->device_destroy,NULL);
}
struct cg_touch *touch, *touch_tmp;
wl_list_for_each_safe(touch, touch_tmp, &seat->touch, link) {
handle_touch_destroy(&touch->destroy, NULL);
}
wl_list_remove(&seat->new_input.link);
wlr_xcursor_manager_destroy(seat->xcursor_manager);
if(seat->cursor) {
@ -898,11 +932,9 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) {
&seat->request_set_primary_selection);
wl_list_init(&seat->keyboard_groups);
wl_list_init(&seat->pointers);
wl_list_init(&seat->touch);
seat->new_input.notify = handle_new_input;
wl_signal_add(&backend->events.new_input, &seat->new_input);
seat->num_keyboards=0;
seat->num_pointers=0;
seat->num_touch=0;
wl_list_init(&seat->drag_icons);
seat->request_start_drag.notify = handle_request_start_drag;

20
seat.h
View file

@ -7,6 +7,7 @@ struct cg_server;
struct cg_view;
struct wlr_cursor;
struct wlr_input_device;
struct cg_input_device;
struct wlr_seat;
struct wlr_xcursor_manager;
struct wlr_backend;
@ -20,9 +21,10 @@ struct cg_seat {
struct wl_listener destroy;
struct wl_list keyboard_groups;
struct wl_list pointers;
struct wl_list touch;
struct wl_listener new_input;
uint16_t num_keyboards;
uint16_t num_pointers;
uint16_t num_touch;
struct wlr_cursor *cursor;
struct wlr_xcursor_manager *xcursor_manager;
@ -70,17 +72,13 @@ struct cg_keyboard_group {
struct cg_pointer {
struct wl_list link; // seat::pointers
struct cg_seat *seat;
struct wlr_input_device *device;
struct wl_listener destroy;
struct cg_input_device *device;
};
struct cg_touch {
struct wl_list link; // seat::touch
struct cg_seat *seat;
struct wlr_input_device *device;
struct wl_listener destroy;
struct cg_input_device *device;
};
struct cg_drag_icon {
@ -102,5 +100,9 @@ struct cg_view *
seat_get_focus(const struct cg_seat *seat);
void
seat_set_focus(struct cg_seat *seat, struct cg_view *view);
void
seat_add_device(struct cg_seat *seat, struct cg_input_device *device);
void
seat_remove_device(struct cg_seat *seat, struct cg_input_device *device);
#endif

View file

@ -13,12 +13,14 @@ struct keybinding_list;
struct wlr_output_layout;
struct wlr_idle_inhibit_manager_v1;
struct cg_output_config;
struct cg_input_manager;
struct cg_server {
struct wl_display *wl_display;
struct wl_event_loop *event_loop;
struct cg_seat *seat;
struct cg_input_manager *input;
struct wlr_backend *backend;
struct wlr_idle *idle;
struct wlr_idle_inhibit_manager_v1 *idle_inhibit_v1;
@ -39,6 +41,7 @@ struct cg_server {
struct keybinding_list *keybindings;
struct wl_list output_config;
struct wl_list input_config;
enum wl_output_transform output_transform;