Release 1.8.0

- Add libinput configuration
- Add virtual keyboard and pointer support
This commit is contained in:
Cagebreak Signing Key 7 2021-09-26 21:25:46 +02:00
commit df167f2839
29 changed files with 1529 additions and 149 deletions

View file

@ -70,7 +70,7 @@ for this to work.
#### Man Pages
Cagebreak has man pages. To use them, make sure that you have `pandoc`
installed. Then, add `-Dman-pages=true to the `meson` command.
installed. Then, add `-Dman-pages=true` to the `meson` command.
### Running Cagebreak
@ -204,6 +204,21 @@ For every release after 1.0.5, hashes will be provided.
For every release after 1.7.0, hashes will be provided for man pages too.
1.8.0 cagebreak
* sha 256: ac84aa4a08c311da79ca29d92eef4254cb625674b255dbb75621ee6b171a1d79
* sha 512: c047bb1986fd1d444547e4d64aa7ef9138b3d30327ac3ad9b4c6976e8df6638bae07c39293b5bc9c20e959c0a22b0e40eb2b23b4766d9a5531377ff954b16229
1.8.0 cagebreak.1
* sha 256: 4de43de7bde67d6d806d206dffc34389f0b5c3ba648bfef673b7bc0adeb29202
* sha 512: 72aac9a2e9a47f2f85949222d5944dc293332a616e3b961c625fe876172f66638038057c30aa18904d6d969451f468b4fe45e918c0b204cf6952d58ea4c69c33
1.8.0 cagebreak-config.5
* sha 256: 678aadde06b5ff6bfbd9bc9460423210f9599bcaa0e50c2eae076dc6d6852781
* sha 512: 72056018fc1c559f26bd7e007b3f1db7d478cec7ec9337620e03a1e3d06910e244a52e8f655ea4f5d73669ffe064bbd23506005d9a6c06764b0f820d7a1df43f
1.7.4 cagebreak
* sha 256: c7442db906239b13f8d09e91cbe01f9e47b2a2c75bbb4b52adefd15dfbfa820f
@ -512,6 +527,10 @@ Adds support for non-build dependencies and an option for builds without pandoc.
Improve window ordering.
### Release 1.8.0
Adds libinput configuration and virtual keyboard and pointer support.
## Contributors
* Aisha Tammy

View file

@ -44,6 +44,7 @@
#endif
#include "idle_inhibit_v1.h"
#include "input_manager.h"
#include "ipc_server.h"
#include "keybinding.h"
#include "message.h"
@ -60,6 +61,8 @@
#define WAIT_ANY -1
#endif
bool show_info = false;
void
set_sig_handler(int sig, void (*action)(int)) {
struct sigaction act;
@ -133,7 +136,8 @@ usage(FILE *file, const char *const cage) {
" -D\t Turn on damage tracking debugging\n"
#endif
" -h\t Display this help message\n"
" -v\t Show the version number and exit\n",
" -v\t Show the version number and exit\n"
" -s\t Show information about the current setup and exit\n",
cage);
}
@ -141,9 +145,9 @@ static bool
parse_args(struct cg_server *server, int argc, char *argv[]) {
int c;
#ifdef DEBUG
while((c = getopt(argc, argv, "rDhv")) != -1) {
while((c = getopt(argc, argv, "rDhvs")) != -1) {
#else
while((c = getopt(argc, argv, "rhv")) != -1) {
while((c = getopt(argc, argv, "rhvs")) != -1) {
#endif
switch(c) {
case 'r':
@ -163,6 +167,9 @@ parse_args(struct cg_server *server, int argc, char *argv[]) {
case 'v':
fprintf(stdout, "Cagebreak version " CG_VERSION "\n");
exit(0);
case 's':
show_info = true;
break;
default:
usage(stderr, argv[0]);
return false;
@ -264,6 +271,9 @@ main(int argc, char *argv[]) {
wlr_log_init(WLR_ERROR, NULL);
#endif
wl_list_init(&server.input_config);
wl_list_init(&server.output_config);
server.modes = malloc(4 * sizeof(char *));
if(!server.modes) {
wlr_log(WLR_ERROR, "Error allocating mode array");
@ -328,8 +338,6 @@ main(int argc, char *argv[]) {
goto end;
}
wl_list_init(&server.output_config);
renderer = wlr_backend_get_renderer(backend);
wlr_renderer_init_wl_display(renderer, server.wl_display);
@ -358,6 +366,8 @@ main(int argc, char *argv[]) {
goto end;
}
server.input = input_manager_create(&server);
data_control_manager =
wlr_data_control_manager_v1_create(server.wl_display);
if(!data_control_manager) {
@ -523,6 +533,17 @@ main(int argc, char *argv[]) {
wlr_xwayland_set_seat(xwayland, server.seat->seat);
#endif
if(show_info) {
char *msg = server_show_info(&server);
if(msg != NULL) {
fprintf(stderr, "%s", msg);
free(msg);
} else {
wlr_log(WLR_ERROR, "Failed to get info on cagebreak setup\n");
}
exit(0);
}
if(ipc_init(&server) != 0) {
wlr_log(WLR_ERROR, "Failed to initialize IPC");
ret = 1;
@ -592,6 +613,7 @@ end:
wl_display_destroy(server.wl_display);
wlr_output_layout_destroy(server.output_layout);
free(server.input);
pango_cairo_font_map_set_default(NULL);
cairo_debug_reset_static_data();
FcFini();

View file

@ -78,3 +78,11 @@ definekey top XF86MonBrightnessUp exec xbacklight -inc 1
output eDP-1 pos 0 0 res 1366x768 rate 60
output eDP-1 disable
output eDP-1 enable
#####################
#Input configuration
#####################
input 1234:0:Device_Ident click_method clickfinger
input type:pointer scroll_method two_finger
input * calibration_matrix 1 2 3 4 5 6

View file

@ -25,6 +25,7 @@
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
@ -47,6 +48,7 @@
#endif
#include "../idle_inhibit_v1.h"
#include "../input_manager.h"
#include "../keybinding.h"
#include "../output.h"
#include "../parse.h"
@ -132,6 +134,7 @@ LLVMFuzzerInitialize(int *argc, char ***argv) {
struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL;
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL;
struct wlr_screencopy_manager_v1 *screencopy_manager = NULL;
struct wlr_data_control_manager_v1 *data_control_manager = NULL;
struct wlr_xdg_output_manager_v1 *output_manager = NULL;
struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL;
int ret = 0;
@ -146,6 +149,8 @@ LLVMFuzzerInitialize(int *argc, char ***argv) {
wlr_log_init(WLR_ERROR, NULL);
#endif
wl_list_init(&server.input_config);
/* Wayland requires XDG_RUNTIME_DIR to be set. */
if(!getenv("XDG_RUNTIME_DIR")) {
wlr_log(WLR_ERROR, "XDG_RUNTIME_DIR is not set in the environment");
@ -235,6 +240,16 @@ LLVMFuzzerInitialize(int *argc, char ***argv) {
goto end;
}
server.input = input_manager_create(&server);
data_control_manager =
wlr_data_control_manager_v1_create(server.wl_display);
if(!data_control_manager) {
wlr_log(WLR_ERROR, "Unable to create the data control manager");
ret = 1;
goto end;
}
/* Configure a listener to be notified when new outputs are
* available on the backend. We use this only to detect the
* first output and ignore subsequent outputs. */
@ -509,29 +524,14 @@ destroy_input_device(char *line, struct cg_server *server) {
--devn;
}
} else if(strncmp(line, "p", 1) == 0) {
if(wl_list_empty(&server->seat->pointers)) {
if(wl_list_empty(&server->input->devices)) {
return;
}
devn = devn % wl_list_length(&server->seat->pointers);
struct cg_pointer *pointer, *pointer_tmp;
wl_list_for_each_safe(pointer, pointer_tmp, &server->seat->pointers,
link) {
devn = devn % wl_list_length(&server->input->devices);
struct cg_input_device *dev, *dev_tmp;
wl_list_for_each_safe(dev, dev_tmp, &server->input->devices, link) {
if(devn == 0) {
pointer->destroy.notify(&pointer->destroy, NULL);
break;
}
--devn;
}
} else if(strncmp(line, "t", 1) == 0) {
if(wl_list_empty(&server->seat->touch)) {
return;
}
devn = devn % wl_list_length(&server->seat->touch);
struct cg_touch *touch, *touch_tmp;
wl_list_for_each_safe(touch, touch_tmp, &server->seat->touch,
link) {
if(devn == 0) {
touch->destroy.notify(&touch->destroy, NULL);
dev->device_destroy.notify(&dev->device_destroy, NULL);
break;
}
--devn;

22
input.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef _CG_INPUT_H
#define _CG_INPUT_H
#include <stdbool.h>
struct cg_input_device;
struct cg_input_config;
struct cg_server;
void
cg_input_configure_libinput_device(struct cg_input_device *device);
void
cg_input_apply_config(struct cg_input_config *config, struct cg_server *server);
void
cg_input_reset_libinput_device(struct cg_input_device *device);
bool
cg_libinput_device_is_builtin(struct cg_input_device *device);
#endif

271
input_manager.c Normal file
View file

@ -0,0 +1,271 @@
/*
* 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 "input_manager.h"
#include "config.h"
#include "input.h"
#include "seat.h"
#include "server.h"
#include <ctype.h>
#include <libevdev/libevdev.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/backend/libinput.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/util/log.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;
}
uint32_t
get_mouse_bindsym(const char *name, char **error) {
// Get event code from name
int code = libevdev_event_code_from_name(EV_KEY, name);
if(code == -1) {
size_t len = snprintf(NULL, 0, "Unknown event %s", name) + 1;
*error = malloc(len);
if(*error) {
snprintf(*error, len, "Unknown event %s", name);
}
return 0;
}
return code;
}
uint32_t
get_mouse_bindcode(const char *name, char **error) {
// Validate event code
errno = 0;
char *endptr;
int code = strtol(name, &endptr, 10);
if(endptr == name && code <= 0) {
*error = strdup("Button event code must be a positive integer.");
return 0;
} else if(errno == ERANGE) {
*error = strdup("Button event code out of range.");
return 0;
}
const char *event = libevdev_event_code_get_name(EV_KEY, code);
if(!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
size_t len = snprintf(NULL, 0, "Event code %d (%s) is not a button",
code, event ? event : "(null)") +
1;
*error = malloc(len);
if(*error) {
snprintf(*error, len, "Event code %d (%s) is not a button", code,
event ? event : "(null)");
}
return 0;
}
return code;
}
uint32_t
input_manager_get_mouse_button(const char *name, char **error) {
uint32_t button = get_mouse_bindsym(name, error);
if(!button && !*error) {
button = get_mouse_bindcode(name, error);
}
return button;
}

111
input_manager.h Normal file
View file

@ -0,0 +1,111 @@
#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);
uint32_t
input_manager_get_mouse_button(const char *name, char **error);
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;
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

@ -9,6 +9,8 @@
#include <wlr/types/wlr_output_layout.h>
#include <wlr/util/log.h>
#include "input.h"
#include "input_manager.h"
#include "keybinding.h"
#include "message.h"
#include "output.h"
@ -63,6 +65,16 @@ keybinding_free(struct keybinding *keybinding, bool recursive) {
case KEYBINDING_CONFIGURE_OUTPUT:
free(keybinding->data.o_cfg->output_name);
free(keybinding->data.o_cfg);
break;
case KEYBINDING_CONFIGURE_INPUT:
free(keybinding->data.i_cfg->identifier);
if(keybinding->data.i_cfg->mapped_from_region) {
free(keybinding->data.i_cfg->mapped_from_region);
}
if(keybinding->data.i_cfg->mapped_to_output) {
free(keybinding->data.i_cfg->mapped_to_output);
}
free(keybinding->data.o_cfg);
default:
break;
}
@ -103,6 +115,9 @@ keybinding_list_init() {
void
keybinding_list_free(struct keybinding_list *list) {
if(!list) {
return;
}
for(unsigned int i = 0; i < list->length; ++i) {
keybinding_free(list->keybindings[i], true);
}
@ -689,6 +704,18 @@ keybinding_show_time(struct cg_server *server) {
free(msg);
}
void
keybinding_show_info(struct cg_server *server) {
char *msg = server_show_info(server);
if(!msg) {
return;
}
message_printf(server->curr_output, "%s", msg);
free(msg);
}
void
keybinding_move_view_to_next_output(struct cg_server *server) {
if(wl_list_length(&server->outputs) <= 1) {
@ -870,6 +897,16 @@ keybinding_configure_output(struct cg_server *server,
}
}
void
keybinding_configure_input(struct cg_server *server,
struct cg_input_config *cfg) {
cg_input_apply_config(cfg, 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,
@ -918,6 +955,9 @@ run_action(enum keybinding_action action, struct cg_server *server,
case KEYBINDING_SHOW_TIME:
keybinding_show_time(server);
break;
case KEYBINDING_SHOW_INFO:
keybinding_show_info(server);
break;
case KEYBINDING_RESIZE_TILE_HORIZONTAL:
resize_tile(server, data.i, 0);
break;
@ -995,6 +1035,9 @@ run_action(enum keybinding_action action, struct cg_server *server,
case KEYBINDING_CONFIGURE_OUTPUT:
keybinding_configure_output(server, data.o_cfg);
break;
case KEYBINDING_CONFIGURE_INPUT:
keybinding_configure_input(server, data.i_cfg);
break;
case KEYBINDING_CLOSE_VIEW:
keybinding_close_view(
server->curr_output->workspaces[server->curr_output->curr_workspace]

View file

@ -4,6 +4,7 @@
#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <xkbcommon/xkbcommon.h>
@ -24,6 +25,8 @@ enum keybinding_action {
KEYBINDING_CYCLE_OUTPUT, // data.b is 0 if forward, 1 if reverse
KEYBINDING_CONFIGURE_OUTPUT, // data.o_cfg is the desired output
// configuration
KEYBINDING_CONFIGURE_INPUT, // data.i_cfg is the desired input
// configuration
KEYBINDING_QUIT,
KEYBINDING_NOOP,
KEYBINDING_SWITCH_WORKSPACE, // data.u is the desired workspace
@ -36,6 +39,7 @@ enum keybinding_action {
KEYBINDING_MOVE_VIEW_TO_WORKSPACE, // data.u is the desired workspace
KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT,
KEYBINDING_SHOW_TIME,
KEYBINDING_SHOW_INFO,
KEYBINDING_SWAP_LEFT,
KEYBINDING_SWAP_RIGHT,
@ -61,6 +65,7 @@ union keybinding_params {
float color[3];
struct keybinding *kb;
struct cg_output_config *o_cfg;
struct cg_input_config *i_cfg;
};
struct keybinding {

442
libinput.c Normal file
View file

@ -0,0 +1,442 @@
#include "input.h"
#include "input_manager.h"
#include "output.h"
#include <float.h>
#include <libinput.h>
#include <libudev.h>
#include <limits.h>
#include <strings.h>
#include <wlr/backend/libinput.h>
#include <wlr/util/log.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;
}
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";
}
void
apply_config_to_device(struct cg_input_config *config,
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);
if(config->mapped_to_output &&
!output_by_name_or_id(config->mapped_to_output, input_device->server)) {
wlr_log(WLR_DEBUG,
"'%s' is mapped to offline output '%s'; disabling input",
config->identifier, config->mapped_to_output);
set_send_events(device, LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
} else if(config->send_events != INT_MIN) {
set_send_events(device, config->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.
set_send_events(
device,
libinput_device_config_send_events_get_default_mode(device));
}
if(config->tap != INT_MIN) {
set_tap(device, config->tap);
}
if(config->tap_button_map != INT_MIN) {
set_tap_button_map(device, config->tap_button_map);
}
if(config->drag != INT_MIN) {
set_tap_drag(device, config->drag);
}
if(config->drag_lock != INT_MIN) {
set_tap_drag_lock(device, config->drag_lock);
}
if(config->pointer_accel != FLT_MIN) {
set_accel_speed(device, config->pointer_accel);
}
if(config->accel_profile != INT_MIN) {
set_accel_profile(device, config->accel_profile);
}
if(config->natural_scroll != INT_MIN) {
set_natural_scroll(device, config->natural_scroll);
}
if(config->left_handed != INT_MIN) {
set_left_handed(device, config->left_handed);
}
if(config->click_method != INT_MIN) {
set_click_method(device, config->click_method);
}
if(config->middle_emulation != INT_MIN) {
set_middle_emulation(device, config->middle_emulation);
}
if(config->scroll_method != INT_MIN) {
set_scroll_method(device, config->scroll_method);
}
if(config->scroll_button != INT_MIN) {
set_scroll_button(device, config->scroll_button);
}
if(config->dwt != INT_MIN) {
set_dwt(device, config->dwt);
}
if(config->calibration_matrix.configured) {
set_calibration_matrix(device, config->calibration_matrix.matrix);
}
}
void
cg_input_apply_config(struct cg_input_config *config,
struct cg_server *server) {
struct cg_input_device *device = NULL;
wl_list_for_each(device, &server->input->devices, link) {
if(strcmp(config->identifier, device->identifier) != 0 &&
strcmp(config->identifier, "*") != 0) {
continue;
}
const char *device_type = input_device_get_type(device);
if(strncmp(config->identifier, "type:", 5) == 0 &&
strcmp(config->identifier + 5, device_type) != 0) {
continue;
}
apply_config_to_device(config, device);
}
}
void
cg_input_configure_libinput_device(struct cg_input_device *input_device) {
struct cg_server *server = input_device->server;
struct cg_input_config *config = NULL;
wl_list_for_each(config, &server->input_config, link) {
if(strcmp(config->identifier, input_device->identifier) != 0 &&
strcmp(config->identifier, "*") != 0) {
continue;
}
const char *device_type = input_device_get_type(input_device);
if(!(strncmp(config->identifier, "type:", 5) &&
strcmp(config->identifier + 5, device_type) == 0)) {
continue;
}
apply_config_to_device(config, input_device);
}
}
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

@ -1,4 +1,4 @@
cagebreak-config(1) "Version 1.7.4" "Cagebreak Manual"
cagebreak-config(1) "Version 1.8.0" "Cagebreak Manual"
# NAME
@ -93,6 +93,75 @@ by prepending a line with the # symbol.
*hsplit*
Split current tile horizontally
*input <identifier> <setting> <value>*
Set the setting "<setting>" to "<value>" for device "<identifier>". The identifier can either be "\*" (wildcard), of the form "type:<device_type>" or the identifier of the device as printed for example by *cagebreak -s*. The supported input types are
- touchpad
- pointer
- keyboard
- touch
- tablet_tool
- tablet_pad
- switch
Configurations are applied sequentially. Currently, only libinput devices may be configured. The available settings and their corresponding values are as follows:
*accel_profile adaptive|flat*
Sets the pointer acceleration profile for the specified input device.
*calibration_matrix <6 space-separated floating point values>*
Sets the calibration matrix.
*click_method none|button_areas|clickfinger*
Changes the click method for the specified device.
*drag enabled|disabled*
Enables or disables tap-and-drag for specified input device.
*drag_lock enabled|disabled*
Enables or disables drag lock for specified input device.
*dwt enabled|disabled*
Enables or disables disable-while-typing for the specified input device.
*enabled|disabled|disabled_on_external_mouse*
Enables or disables send_events for specified input device. Disabling
send_events disables the input device.
*left_handed enabled|disabled*
Enables or disables left handed mode for specified input device.
*middle_emulation enabled|disabled*
Enables or disables middle click emulation.
*natural_scroll enabled|disabled*
Enables or disables natural (inverted) scrolling for the specified input
device.
*pointer_accel [<-1|1>]*
Changes the pointer acceleration for the specified input device.
*scroll_button disable|<event-code-or-name>*
Sets the button used for scroll_method on_button_down. The button can
be given as an event name or code, which can be obtained from *libinput
debug-events*. If set to
_disable_, it disables the scroll_method on_button_down.
*scroll_factor <floating point value>*
Changes the scroll factor for the specified input device. Scroll speed will
be scaled by the given value, which must be non-negative.
*scroll_method none|two_finger|edge|on_button_down*
Changes the scroll method for the specified input device.
*tap enabled|disabled*
Enables or disables tap for specified input device.
*tap_button_map lrm|lmr*
Specifies which button mapping to use for tapping. _lrm_ treats 1 finger as
left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_
treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as
right click.
*mode <mode>*
Enter mode "<mode>". After a keybinding is processed, return to default mode
@ -140,6 +209,10 @@ by prepending a line with the # symbol.
*resizeup*
Resize the current tile towards the top
*show_info*
Display info about the current setup. In particular, print the identifiers
of the available inputs and outputs.
*setmode <mode>*
Set the default mode to <mode>

View file

@ -1,4 +1,4 @@
cagebreak(1) "Version 1.7.4" "Cagebreak Manual"
cagebreak(1) "Version 1.8.0" "Cagebreak Manual"
# NAME
@ -38,6 +38,9 @@ are displayed in a message box at the top right of the screen.
*-r*
Rotate the output 90 degrees clockwise, can be specified up to three times
*-s*
Show all available inputs and outputs
*-v*
Show version number and exit

View file

@ -1,5 +1,5 @@
project('cagebreak', 'c',
version: '1.7.4',
version: '1.8.0',
license: 'MIT',
default_options: [
'c_std=c11',
@ -53,7 +53,7 @@ if is_freebsd
)
endif
wlroots = dependency('wlroots', version: ['>=0.14.0', '< 0.15.0'])
wlroots = dependency('wlroots', version: ['>=0.14.1', '< 0.15.0'])
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
wayland_server = dependency('wayland-server')
wayland_cursor = dependency('wayland-cursor')
@ -64,6 +64,9 @@ cairo = dependency('cairo')
pango = dependency('pango')
pangocairo = dependency('pangocairo')
fontconfig = dependency('fontconfig')
libinput = dependency('libinput')
libevdev = dependency('libevdev')
libudev = dependency('libudev')
math = cc.find_library('m')
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
@ -123,6 +126,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 +137,7 @@ cagebreak_source_strings = [
'util.c',
'view.c',
'xdg_shell.c',
'libinput.c',
'server.c',
'message.c',
'pango.c',
@ -186,6 +191,9 @@ cagebreak_dependencies_dict = {
'wlroots': [wlroots,true],
'xkbcommon': [xkbcommon,true],
'fontconfig': [fontconfig,true],
'libinput': [libinput,true],
'libevdev': [libevdev,true],
'libudev': [libudev,true],
'pixman': [pixman,true],
'pango': [pango,true],
'cairo': [cairo,true],
@ -198,13 +206,16 @@ reproducible_build_versions = {
'wayland_server': '1.19.0',
'wayland_client': '1.19.0',
'wayland_cursor': '1.19.0',
'wlroots': '0.14.0',
'xkbcommon': '1.3.0',
'wlroots': '0.14.1',
'xkbcommon': '1.3.1',
'fontconfig': '2.13.94',
'libinput': '1.19.0',
'libevdev': '1.11.0',
'libudev': '249',
'pixman': '0.40.0',
'pango': '1.48.6',
'pango': '1.48.10',
'cairo': '1.17.4',
'pangocairo': '1.48.6',
'pangocairo': '1.48.10',
'math': '-1'
}
@ -257,7 +268,7 @@ if get_option('man-pages')
output : 'cagebreak.1',
input : 'man/cagebreak.1.md',
capture : true,
command : [sh, '-c', 'export SOURCE_DATE_EPOCH=1625064321 ; @0@ < @INPUT@'.format(scdoc.path())],
command : [sh, '-c', 'export SOURCE_DATE_EPOCH=1632645085 ; @0@ < @INPUT@'.format(scdoc.path())],
install: true,
install_dir: mandir1
)
@ -266,7 +277,7 @@ if get_option('man-pages')
output : 'cagebreak-config.5',
input : 'man/cagebreak-config.5.md',
capture : true,
command : [sh, '-c', 'export SOURCE_DATE_EPOCH=1625064321 ; @0@ < @INPUT@'.format(scdoc.path())],
command : [sh, '-c', 'export SOURCE_DATE_EPOCH=1632645085 ; @0@ < @INPUT@'.format(scdoc.path())],
install: true,
install_dir: mandir5
)

View file

@ -12,6 +12,7 @@
#include "output.h"
#include "pango.h"
#include "server.h"
#include "util.h"
cairo_subpixel_order_t
to_cairo_subpixel_order(const enum wl_output_subpixel subpixel) {
@ -32,14 +33,14 @@ to_cairo_subpixel_order(const enum wl_output_subpixel subpixel) {
struct wlr_texture *
create_message_texture(const char *string, const struct cg_output *output) {
const int PADDING = 2;
const int MESSAGE_HEIGHT = 17 + 2 * PADDING;
const int WIDTH_PADDING = 8;
const int HEIGHT_PADDING = 2;
const char *font = "pango:Monospace 10";
struct wlr_texture *texture;
double scale = output->wlr_output->scale;
int width = 0;
int height = MESSAGE_HEIGHT * scale;
int height = 0;
// We must use a non-nil cairo_t for cairo_set_font_options to work.
// Therefore, we cannot use cairo_create(NULL).
@ -59,8 +60,9 @@ create_message_texture(const char *string, const struct cg_output *output) {
cairo_font_options_set_subpixel_order(
fo, to_cairo_subpixel_order(output->wlr_output->subpixel));
cairo_set_font_options(c, fo);
get_text_size(c, font, &width, NULL, NULL, scale, "%s", string);
width += 2 * PADDING;
get_text_size(c, font, &width, &height, NULL, scale, "%s", string);
width += 2 * WIDTH_PADDING;
height += 2 * HEIGHT_PADDING;
cairo_surface_destroy(dummy_surface);
cairo_destroy(c);
@ -77,7 +79,7 @@ create_message_texture(const char *string, const struct cg_output *output) {
cairo_set_line_width(cairo, 2);
cairo_rectangle(cairo, 0, 0, width, height);
cairo_stroke(cairo);
cairo_move_to(cairo, PADDING, PADDING);
cairo_move_to(cairo, WIDTH_PADDING, HEIGHT_PADDING);
pango_printf(cairo, font, scale, "%s", string);
@ -149,17 +151,14 @@ message_set_output(struct cg_output *output, const char *string,
void
message_printf(struct cg_output *output, const char *fmt, ...) {
uint16_t buf_len = 256;
char *buffer = (char *)malloc(buf_len * sizeof(char));
va_list ap;
va_start(ap, fmt);
char *buffer = malloc_vsprintf_va_list(fmt, ap);
va_end(ap);
if(buffer == NULL) {
wlr_log(WLR_ERROR, "Failed to allocate buffer in message_printf");
return;
}
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, buf_len, fmt, ap);
va_end(ap);
struct wlr_box *box = malloc(sizeof(struct wlr_box));
if(box == NULL) {

View file

@ -25,7 +25,7 @@ get_pango_layout(cairo_t *cairo, const char *font, const char *text,
pango_attr_list_insert(attrs, pango_attr_scale_new(scale));
PangoFontDescription *desc = pango_font_description_from_string(font);
pango_layout_set_font_description(layout, desc);
pango_layout_set_single_paragraph_mode(layout, 1);
pango_layout_set_single_paragraph_mode(layout, false);
pango_layout_set_attributes(layout, attrs);
pango_attr_list_unref(attrs);
pango_font_description_free(desc);

310
parse.c
View file

@ -1,30 +1,23 @@
#define _POSIX_C_SOURCE 200812L
#include <float.h>
#include <libinput.h>
#include <limits.h>
#include <string.h>
#include <wlr/util/log.h>
#include "input_manager.h"
#include "keybinding.h"
#include "output.h"
#include "parse.h"
#include "server.h"
char *
malloc_vsprintf(const char *fmt, va_list ap) {
va_list ap2;
va_copy(ap2, ap);
int len = vsnprintf(NULL, 0, fmt, ap);
char *ret = malloc(sizeof(char) * (len + 1));
vsnprintf(ret, len + 1, fmt, ap2);
va_end(ap2);
return ret;
}
#include "util.h"
char *
log_error(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char *ret = malloc_vsprintf(fmt, args);
char *ret = malloc_vsprintf_va_list(fmt, args);
if(ret != NULL) {
wlr_log(WLR_ERROR, "%s", ret);
}
@ -106,6 +99,267 @@ parse_keybinding(struct cg_server *server, char **saveptr, char **errstr) {
return keybinding;
}
float
parse_float(char **saveptr, const char *delim) {
char *uint_str = strtok_r(NULL, delim, saveptr);
if(uint_str == NULL) {
wlr_log(WLR_ERROR, "Expected a float, got nothing");
return -1;
}
float ufloat = strtof(uint_str, NULL);
if(ufloat != NAN && ufloat != INFINITY && errno != ERANGE) {
return ufloat;
} else {
wlr_log(WLR_ERROR, "Error parsing float");
return FLT_MIN;
}
}
struct cg_input_config *
parse_input_config(char **saveptr, char **errstr) {
struct cg_input_config *cfg = calloc(1, sizeof(struct cg_input_config));
char *value = NULL;
char *ident = NULL;
if(cfg == NULL) {
*errstr =
log_error("Failed to allocate memory for output configuration");
goto error;
}
cfg->tap = INT_MIN;
cfg->tap_button_map = INT_MIN;
cfg->drag = INT_MIN;
cfg->drag_lock = INT_MIN;
cfg->dwt = INT_MIN;
cfg->send_events = INT_MIN;
cfg->click_method = INT_MIN;
cfg->middle_emulation = INT_MIN;
cfg->natural_scroll = INT_MIN;
cfg->accel_profile = INT_MIN;
cfg->pointer_accel = FLT_MIN;
cfg->scroll_factor = FLT_MIN;
cfg->scroll_button = INT_MIN;
cfg->scroll_method = INT_MIN;
cfg->left_handed = INT_MIN;
/*cfg->repeat_delay = INT_MIN;
cfg->repeat_rate = INT_MIN;
cfg->xkb_numlock = INT_MIN;
cfg->xkb_capslock = INT_MIN;
cfg->xkb_file_is_set = false;
wl_list_init(&cfg->tools);*/
ident = strtok_r(NULL, " ", saveptr);
if(ident == NULL) {
*errstr = log_error(
"Expected identifier of input device to configure, got none");
goto error;
}
cfg->identifier = strdup(ident);
char *setting = strtok_r(NULL, " ", saveptr);
if(setting == NULL) {
*errstr =
log_error("Expected setting to be set on input device, got none");
goto error;
}
value = strdup(*saveptr);
if(value == NULL) {
*errstr = log_error("Failed to obtain value for input device "
"configuration of device \"%s\"",
ident);
goto error;
}
if(strcmp(setting, "accel_profile") == 0) {
if(strcmp(value, "adaptive") == 0) {
cfg->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
} else if(strcmp(value, "flat") == 0) {
cfg->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
} else {
*errstr = log_error(
"Invalid profile \"%s\" for accel_profile configuration",
value);
goto error;
}
} else if(strcmp(setting, "calibration_matrix") == 0) {
cfg->calibration_matrix.configured = true;
for(int i = 0; i < 6; ++i) {
cfg->calibration_matrix.matrix[i] = parse_float(saveptr, " ");
if(cfg->calibration_matrix.matrix[i] == FLT_MIN) {
*errstr =
log_error("Failed to read calibration matrix, expected 6 "
"floating point values separated by spaces");
goto error;
}
}
} else if(strcmp(setting, "click_method") == 0) {
if(strcmp(value, "none")) {
cfg->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
} else if(strcmp(value, "button_areas")) {
cfg->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
} else if(strcmp(value, "clickfinger")) {
cfg->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
} else {
*errstr = log_error(
"Invalid method \"%s\" for click_method configuration", value);
goto error;
}
} else if(strcmp(setting, "drag") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->drag = LIBINPUT_CONFIG_DRAG_ENABLED;
} else if(strcmp(value, "disabled") == 0) {
cfg->drag = LIBINPUT_CONFIG_DRAG_DISABLED;
} else {
*errstr =
log_error("Invalid option \"%s\" to setting \"drag\"", value);
goto error;
}
} else if(strcmp(setting, "drag_lock") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
} else if(strcmp(value, "disabled") == 0) {
cfg->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
} else {
*errstr = log_error(
"Invalid option \"%s\" to setting \"drag_lock\"", value);
goto error;
}
} else if(strcmp(setting, "dwt") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
} else if(strcmp(value, "disabled") == 0) {
cfg->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
} else {
*errstr =
log_error("Invalid option \"%s\" to setting \"dwt\"", value);
goto error;
}
} else if(strcmp(setting, "events") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
} else if(strcmp(value, "disabled") == 0) {
cfg->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
} else if(strcmp(value, "disabled_on_external_mouse") == 0) {
cfg->send_events =
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
} else {
*errstr =
log_error("Invalid option \"%s\" to setting \"events\"", value);
goto error;
}
} else if(strcmp(setting, "left_handed") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->left_handed = true;
} else if(strcmp(value, "disabled") == 0) {
cfg->left_handed = false;
} else {
*errstr = log_error(
"Invalid option \"%s\" to setting \"left_handed\"", value);
goto error;
}
} else if(strcmp(setting, "middle_emulation") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
} else if(strcmp(value, "disabled") == 0) {
cfg->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
} else {
*errstr = log_error(
"Invalid option \"%s\" to setting \"middle_emulation\"", value);
goto error;
}
} else if(strcmp(setting, "natural_scroll") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->natural_scroll = true;
} else if(strcmp(value, "disabled") == 0) {
cfg->natural_scroll = false;
} else {
*errstr = log_error(
"Invalid option \"%s\" to setting \"natural_scroll\"", value);
goto error;
}
} else if(strcmp(setting, "pointer_accel") == 0) {
cfg->pointer_accel = parse_float(saveptr, " ");
if(cfg->pointer_accel == FLT_MIN) {
*errstr = log_error("Invalid option \"%s\" to setting "
"\"pointer_accel\", expected float value",
value);
goto error;
}
} else if(strcmp(setting, "scroll_button") == 0) {
char *err = NULL;
cfg->scroll_button = input_manager_get_mouse_button(value, &err);
if(err) {
*errstr = log_error("Error parsing button for \"scroll_button\" "
"setting. Returned error \"%s\"",
err);
free(err);
goto error;
}
} else if(strcmp(setting, "scroll_factor") == 0) {
cfg->scroll_factor = parse_float(saveptr, " ");
if(cfg->scroll_factor == FLT_MIN) {
*errstr = log_error("Invalid option \"%s\" to setting "
"\"scroll_factor\", expected float value",
value);
goto error;
}
} else if(strcmp(setting, "scroll_method") == 0) {
if(strcmp(value, "none") == 0) {
cfg->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
} else if(strcmp(value, "two_finger") == 0) {
cfg->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
} else if(strcmp(value, "edge") == 0) {
cfg->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
} else if(strcmp(value, "on_button_down") == 0) {
cfg->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
} else {
*errstr = log_error(
"Invalid option \"%s\" to setting \"scroll_method\"", value);
goto error;
}
} else if(strcmp(setting, "tap") == 0) {
if(strcmp(value, "enabled") == 0) {
cfg->tap = LIBINPUT_CONFIG_TAP_ENABLED;
} else if(strcmp(value, "disabled") == 0) {
cfg->tap = LIBINPUT_CONFIG_TAP_DISABLED;
} else {
*errstr =
log_error("Invalid option \"%s\" to setting \"tap\"", value);
goto error;
}
} else if(strcmp(setting, "tap_button_map") == 0) {
if(strcmp(value, "lrm") == 0) {
cfg->tap = LIBINPUT_CONFIG_TAP_MAP_LRM;
} else if(strcmp(value, "lmr") == 0) {
cfg->tap = LIBINPUT_CONFIG_TAP_MAP_LMR;
} else {
*errstr = log_error(
"Invalid option \"%s\" to setting \"tap_button_map\"", value);
goto error;
}
}
free(value);
return cfg;
error:
if(cfg) {
if(cfg->identifier) {
free(cfg->identifier);
}
free(cfg);
}
if(value) {
free(value);
}
wlr_log(WLR_ERROR, "Input configuration must be of the form 'input "
"\"<ident>\" <setting> <value>'");
return NULL;
}
struct keybinding *
parse_bind(struct cg_server *server, char **saveptr, char **errstr) {
struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr);
@ -242,23 +496,6 @@ parse_uint(char **saveptr, const char *delim) {
}
}
float
parse_float(char **saveptr, const char *delim) {
char *uint_str = strtok_r(NULL, delim, saveptr);
if(uint_str == NULL) {
wlr_log(WLR_ERROR, "Expected a non-negative float, got nothing");
return -1;
}
float ufloat = strtof(uint_str, NULL);
if(ufloat >= 0) {
return ufloat;
} else {
wlr_log(WLR_ERROR, "Error parsing non-negative float. Must be a number "
"larger or equal to 0");
return -1;
}
}
int
parse_output_config_keyword(char *key_str, enum output_status *status) {
if(key_str == NULL) {
@ -352,9 +589,10 @@ parse_output_config(char **saveptr, char **errstr) {
cfg->refresh_rate = parse_float(saveptr, " ");
if(cfg->refresh_rate <= 0.0) {
*errstr = log_error(
"Error parsing refresh rate of output configuration for output %s",
name);
*errstr =
log_error("Error parsing refresh rate of output configuration for "
"output %s, expected positive float",
name);
goto error;
}
@ -383,6 +621,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
keybinding->action = KEYBINDING_SPLIT_HORIZONTAL;
} else if(strcmp(action, "quit") == 0) {
keybinding->action = KEYBINDING_QUIT;
} else if(strcmp(action, "show_info") == 0) {
keybinding->action = KEYBINDING_SHOW_INFO;
} else if(strcmp(action, "close") == 0) {
keybinding->action = KEYBINDING_CLOSE_VIEW;
} else if(strcmp(action, "focus") == 0) {
@ -562,6 +802,12 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
if(keybinding->data.o_cfg == NULL) {
return -1;
}
} else if(strcmp(action, "input") == 0) {
keybinding->action = KEYBINDING_CONFIGURE_INPUT;
keybinding->data.i_cfg = parse_input_config(&saveptr, errstr);
if(keybinding->data.i_cfg == NULL) {
return -1;
}
} else {
*errstr = log_error("Error, unsupported action \"%s\".", action);
return -1;

View file

@ -4,9 +4,15 @@
#define MAX_LINE_SIZE 256
#include <stdio.h>
struct cg_server;
int
parse_rc_line(struct cg_server *server, char *line, char **errstr);
char *
parse_malloc_vsprintf(const char *fmt, ...);
char *
parse_malloc_vsprintf_va_list(const char *fmt, va_list list);
#endif /* end of include guard PARSE_H */

145
seat.c
View file

@ -31,6 +31,7 @@
#include <wlr/xwayland.h>
#endif
#include "input_manager.h"
#include "keybinding.h"
#include "message.h"
#include "output.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,21 +429,16 @@ 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;
}
struct xkb_rule_names rules = {0};
rules.rules = getenv("XKB_DEFAULT_RULES");
rules.model = getenv("XKB_DEFAULT_MODEL");
rules.layout = getenv("XKB_DEFAULT_LAYOUT");
rules.variant = getenv("XKB_DEFAULT_VARIANT");
rules.options = getenv("XKB_DEFAULT_OPTIONS");
struct xkb_keymap *keymap =
xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_map_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS);
if(!keymap) {
wlr_log(WLR_ERROR,
"Unable to configure keyboard: keymap does not exist");
@ -460,24 +453,64 @@ 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 +834,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 +927,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

@ -9,11 +9,16 @@
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_output.h>
#include "input_manager.h"
#include "output.h"
#include "server.h"
#include "util.h"
void
display_terminate(struct cg_server *server) {
@ -35,3 +40,36 @@ get_mode_index_from_name(char *const *modes, const char *mode_name) {
}
return -1;
}
char *
server_show_info(struct cg_server *server) {
char *output_str = strdup(""), *output_str_tmp;
struct cg_output *output;
wl_list_for_each(output, &server->outputs, link) {
if(!output_str) {
return NULL;
}
output_str_tmp = output_str;
output_str = malloc_vsprintf("%s\t * %s\n", output_str,
output->wlr_output->name);
free(output_str_tmp);
}
char *input_str = strdup(""), *input_str_tmp;
struct cg_input_device *input;
wl_list_for_each(input, &server->input->devices, link) {
if(!input_str) {
return NULL;
}
input_str_tmp = input_str;
if(strcmp(input->identifier, "") != 0) {
input_str =
malloc_vsprintf("%s\t * %s\n", input_str, input->identifier);
}
free(input_str_tmp);
}
char *ret =
malloc_vsprintf("Outputs:\n%sInputs:\n%s", output_str, input_str);
free(output_str);
free(input_str);
return ret;
}

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;
@ -58,5 +61,7 @@ void
display_terminate(struct cg_server *server);
int
get_mode_index_from_name(char *const *modes, const char *mode_name);
char *
server_show_info(struct cg_server *server);
#endif

Binary file not shown.

Binary file not shown.

BIN
signatures/1.7.4.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

20
util.c
View file

@ -10,6 +10,7 @@
#include <wlr/types/wlr_box.h>
#include "util.h"
#include <stdlib.h>
int
scale_length(int length, int offset, double scale) {
@ -33,3 +34,22 @@ scale_box(struct wlr_box *box, double scale) {
box->x = (int)round(box->x * scale);
box->y = (int)round(box->y * scale);
}
char *
malloc_vsprintf_va_list(const char *fmt, va_list ap) {
va_list ap2;
va_copy(ap2, ap);
int len = vsnprintf(NULL, 0, fmt, ap);
char *ret = malloc(sizeof(char) * (len + 1));
vsnprintf(ret, len + 1, fmt, ap2);
va_end(ap2);
return ret;
}
char *
malloc_vsprintf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char *ret = malloc_vsprintf_va_list(fmt, args);
return ret;
}

7
util.h
View file

@ -1,6 +1,8 @@
#ifndef CG_UTIL_H
#define CG_UTIL_H
#include <stdio.h>
struct wlr_box;
/** Apply scale to a width or height. */
@ -10,4 +12,9 @@ scale_length(int length, int offset, double scale);
void
scale_box(struct wlr_box *box, double scale);
char *
malloc_vsprintf(const char *fmt, ...);
char *
malloc_vsprintf_va_list(const char *fmt, va_list list);
#endif