Merge branch 'master' into feature/xdg-popup

This commit is contained in:
Tony Crisci 2017-10-03 18:58:38 -04:00
commit 30eabf38b8
15 changed files with 386 additions and 83 deletions

View file

@ -13,7 +13,7 @@ upstream. Try this:
1. Fork wlroots 1. Fork wlroots
2. `git clone https://github.com/username/wlroots && cd wlroots` 2. `git clone https://github.com/username/wlroots && cd wlroots`
3. `git remote add upstream https://github.com/SirCmpwn/wlroots` 3. `git remote add upstream https://github.com/swaywm/wlroots`
You only need to do this once. You're never going to use your fork's master You only need to do this once. You're never going to use your fork's master
branch. Instead, when you start working on a feature, do this: branch. Instead, when you start working on a feature, do this:

View file

@ -1,13 +1,13 @@
# wlroots [![](https://api.travis-ci.org/SirCmpwn/wlroots.svg)](https://travis-ci.org/SirCmpwn/wlroots) # wlroots [![](https://api.travis-ci.org/swaywm/wlroots.svg)](https://travis-ci.org/swaywm/wlroots)
Pluggable, composable modules for building a Pluggable, composable modules for building a
[Wayland](http://wayland.freedesktop.org/) compositor. [Wayland](http://wayland.freedesktop.org/) compositor.
This is a WIP: [status](https://github.com/SirCmpwn/wlroots/issues/9) This is a WIP: [status](https://github.com/swaywm/wlroots/issues/9)
## Contributing ## Contributing
See [CONTRIBUTING.md](https://github.com/SirCmpwn/wlroots/blob/master/CONTRIBUTING.md) See [CONTRIBUTING.md](https://github.com/swaywm/wlroots/blob/master/CONTRIBUTING.md)
## Building ## Building

View file

@ -16,8 +16,8 @@ depends=(
"libxcb" "libxcb"
) )
arch=("x86_64") arch=("x86_64")
url="https://github.com/SirCmpwn/wlroots" url="https://github.com/swaywm/wlroots"
source=("${pkgname}::git+https://github.com/SirCmpwn/wlroots.git") source=("${pkgname}::git+https://github.com/swaywm/wlroots.git")
sha1sums=('SKIP') sha1sums=('SKIP')
provides=('wlroots') provides=('wlroots')
conflicts=('wlroots') conflicts=('wlroots')

View file

@ -18,6 +18,14 @@ struct device_config {
struct wl_list link; struct wl_list link;
}; };
struct binding_config {
uint32_t modifiers;
xkb_keysym_t *keysyms;
size_t keysyms_len;
char *command;
struct wl_list link;
};
struct roots_config { struct roots_config {
// TODO: Multiple cursors, multiseat // TODO: Multiple cursors, multiseat
struct { struct {
@ -27,6 +35,7 @@ struct roots_config {
struct wl_list outputs; struct wl_list outputs;
struct wl_list devices; struct wl_list devices;
struct wl_list bindings;
char *config_path; char *config_path;
}; };

View file

@ -10,11 +10,15 @@
#include "rootston/view.h" #include "rootston/view.h"
#include "rootston/server.h" #include "rootston/server.h"
#define ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP 32
struct roots_keyboard { struct roots_keyboard {
struct roots_input *input; struct roots_input *input;
struct wlr_input_device *device; struct wlr_input_device *device;
struct wl_listener key; struct wl_listener key;
struct wl_list link; struct wl_list link;
xkb_keysym_t pressed_keysyms[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP];
}; };
struct roots_pointer { struct roots_pointer {

View file

@ -6,11 +6,25 @@
#include <wayland-server.h> #include <wayland-server.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
enum WLR_KEYBOARD_LED { #define WLR_LED_COUNT 3
enum wlr_keyboard_led {
WLR_LED_NUM_LOCK = 1, WLR_LED_NUM_LOCK = 1,
WLR_LED_CAPS_LOCK = 2, WLR_LED_CAPS_LOCK = 2,
WLR_LED_SCROLL_LOCK = 4, WLR_LED_SCROLL_LOCK = 4,
WLR_LED_LAST };
#define WLR_MODIFIER_COUNT 8
enum wlr_keyboard_modifier {
WLR_MODIFIER_SHIFT = 1,
WLR_MODIFIER_CAPS = 2,
WLR_MODIFIER_CTRL = 4,
WLR_MODIFIER_ALT = 8,
WLR_MODIFIER_MOD2 = 16,
WLR_MODIFIER_MOD3 = 32,
WLR_MODIFIER_LOGO = 64,
WLR_MODIFIER_MOD5 = 128,
}; };
struct wlr_keyboard_impl; struct wlr_keyboard_impl;
@ -23,18 +37,25 @@ struct wlr_keyboard {
size_t keymap_size; size_t keymap_size;
struct xkb_keymap *keymap; struct xkb_keymap *keymap;
struct xkb_state *xkb_state; struct xkb_state *xkb_state;
xkb_led_index_t leds[WLR_LED_LAST]; xkb_led_index_t led_indexes[WLR_LED_COUNT];
xkb_mod_index_t mod_indexes[WLR_MODIFIER_COUNT];
struct {
xkb_mod_mask_t depressed;
xkb_mod_mask_t latched;
xkb_mod_mask_t locked;
xkb_mod_mask_t group;
} modifiers;
struct { struct {
struct wl_signal key; struct wl_signal key;
struct wl_signal modifiers;
struct wl_signal keymap; struct wl_signal keymap;
} events; } events;
void *data; void *data;
}; };
void wlr_keyboard_led_update(struct wlr_keyboard *keyboard, uint32_t leds);
enum wlr_key_state { enum wlr_key_state {
WLR_KEY_RELEASED, WLR_KEY_RELEASED,
WLR_KEY_PRESSED, WLR_KEY_PRESSED,
@ -49,5 +70,7 @@ struct wlr_event_keyboard_key {
void wlr_keyboard_set_keymap(struct wlr_keyboard *kb, void wlr_keyboard_set_keymap(struct wlr_keyboard *kb,
struct xkb_keymap *keymap); struct xkb_keymap *keymap);
void wlr_keyboard_led_update(struct wlr_keyboard *keyboard, uint32_t leds);
uint32_t wlr_keyboard_get_modifiers(struct wlr_keyboard *keyboard);
#endif #endif

View file

@ -37,6 +37,7 @@ struct wlr_seat_keyboard {
struct wlr_seat *seat; struct wlr_seat *seat;
struct wlr_keyboard *keyboard; struct wlr_keyboard *keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener modifiers;
struct wl_listener keymap; struct wl_listener keymap;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_list link; struct wl_list link;

View file

@ -24,6 +24,7 @@ struct wlr_frame_callback {
struct wlr_surface_state { struct wlr_surface_state {
uint32_t invalid; uint32_t invalid;
struct wl_resource *buffer; struct wl_resource *buffer;
struct wl_listener buffer_destroy_listener;
int32_t sx, sy; int32_t sx, sy;
pixman_region32_t surface_damage, buffer_damage; pixman_region32_t surface_damage, buffer_damage;
pixman_region32_t opaque, input; pixman_region32_t opaque, input;

View file

@ -171,6 +171,59 @@ static int config_ini_handler(void *user, const char *section, const char *name,
} else { } else {
wlr_log(L_ERROR, "got unknown device config: %s", name); wlr_log(L_ERROR, "got unknown device config: %s", name);
} }
} else if (strcmp(section, "bindings") == 0) {
struct binding_config *bc = calloc(1, sizeof(struct binding_config));
wl_list_insert(&config->bindings, &bc->link);
bc->command = strdup(value);
size_t keysyms_len = 1;
char *symnames = strdup(name);
for (char *c = symnames; *c != '\0'; c++) {
if (*c == '+') {
*c = '\0';
keysyms_len++;
}
}
// TODO: bc->keysyms is larger than needed
bc->keysyms = calloc(1, keysyms_len * sizeof(xkb_keysym_t));
char *symname = symnames;
for (size_t i = 0; i < keysyms_len; i++) {
if (strcmp(symname, "Shift") == 0) {
bc->modifiers |= WLR_MODIFIER_SHIFT;
} else if (strcmp(symname, "Caps") == 0) {
bc->modifiers |= WLR_MODIFIER_CAPS;
} else if (strcmp(symname, "Ctrl") == 0) {
bc->modifiers |= WLR_MODIFIER_CTRL;
} else if (strcmp(symname, "Alt") == 0) {
bc->modifiers |= WLR_MODIFIER_ALT;
} else if (strcmp(symname, "Mod2") == 0) {
bc->modifiers |= WLR_MODIFIER_MOD2;
} else if (strcmp(symname, "Mod3") == 0) {
bc->modifiers |= WLR_MODIFIER_MOD3;
} else if (strcmp(symname, "Logo") == 0) {
bc->modifiers |= WLR_MODIFIER_LOGO;
} else if (strcmp(symname, "Mod5") == 0) {
bc->modifiers |= WLR_MODIFIER_MOD5;
} else {
xkb_keysym_t sym = xkb_keysym_from_name(symname,
XKB_KEYSYM_NO_FLAGS);
if (sym == XKB_KEY_NoSymbol) {
wlr_log(L_ERROR, "got unknown key binding symbol: %s",
symname);
wl_list_remove(&bc->link);
free(bc->keysyms);
free(bc);
break;
}
bc->keysyms[bc->keysyms_len] = sym;
bc->keysyms_len++;
}
symname += strlen(symname) + 1;
}
free(symnames);
} else { } else {
wlr_log(L_ERROR, "got unknown config section: %s", section); wlr_log(L_ERROR, "got unknown config section: %s", section);
} }
@ -182,6 +235,7 @@ struct roots_config *parse_args(int argc, char *argv[]) {
struct roots_config *config = calloc(1, sizeof(struct roots_config)); struct roots_config *config = calloc(1, sizeof(struct roots_config));
wl_list_init(&config->outputs); wl_list_init(&config->outputs);
wl_list_init(&config->devices); wl_list_init(&config->devices);
wl_list_init(&config->bindings);
int c; int c;
while ((c = getopt(argc, argv, "C:h")) != -1) { while ((c = getopt(argc, argv, "C:h")) != -1) {
@ -212,6 +266,15 @@ struct roots_config *parse_args(int argc, char *argv[]) {
if (result == -1) { if (result == -1) {
wlr_log(L_DEBUG, "No config file found. Using empty config."); wlr_log(L_DEBUG, "No config file found. Using empty config.");
struct binding_config *bc = calloc(1, sizeof(struct binding_config));
wl_list_insert(&config->bindings, &bc->link);
bc->command = strdup("exit");
bc->modifiers = WLR_MODIFIER_LOGO;
bc->keysyms_len = 2;
bc->keysyms = calloc(1, bc->keysyms_len * sizeof(xkb_keysym_t));
bc->keysyms[0] = XKB_KEY_Meta_L;
bc->keysyms[1] = XKB_KEY_q;
} else if (result == -2) { } else if (result == -2) {
wlr_log(L_ERROR, "Could not allocate memory to parse config file"); wlr_log(L_ERROR, "Could not allocate memory to parse config file");
exit(1); exit(1);
@ -238,6 +301,13 @@ void roots_config_destroy(struct roots_config *config) {
free(dc); free(dc);
} }
struct binding_config *bc, *btmp = NULL;
wl_list_for_each_safe(bc, btmp, &config->bindings, link) {
free(bc->keysyms);
free(bc->command);
free(bc);
}
free(config->config_path); free(config->config_path);
free(config->cursor.mapped_output); free(config->cursor.mapped_output);
free(config->cursor.mapped_box); free(config->cursor.mapped_box);

View file

@ -1,6 +1,7 @@
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_pointer.h> #include <wlr/types/wlr_pointer.h>
@ -10,32 +11,100 @@
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include "rootston/input.h" #include "rootston/input.h"
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static ssize_t keyboard_pressed_keysym_index(struct roots_keyboard *keyboard,
struct wlr_event_keyboard_key *event = data; xkb_keysym_t keysym) {
struct roots_keyboard *keyboard = wl_container_of(listener, keyboard, key); for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; i++) {
struct roots_input *input = keyboard->input; if (keyboard->pressed_keysyms[i] == keysym) {
struct roots_server *server = input->server; return i;
}
}
return -1;
}
enum wlr_key_state key_state = event->state; static void keyboard_binding_execute(struct roots_keyboard *keyboard,
uint32_t keycode = event->keycode + 8; char *command) {
const xkb_keysym_t *syms; struct roots_server *server = keyboard->input->server;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, if (strcmp(command, "exit") == 0) {
keycode, &syms);
for (int i = 0; i < nsyms; ++i) {
xkb_keysym_t sym = syms[i];
if (sym == XKB_KEY_Escape) {
// TEMPORARY, probably
wl_display_terminate(server->wl_display); wl_display_terminate(server->wl_display);
} else if (key_state == WLR_KEY_PRESSED && } else {
sym >= XKB_KEY_XF86Switch_VT_1 && pid_t pid = fork();
sym <= XKB_KEY_XF86Switch_VT_12) { if (pid < 0) {
wlr_log(L_ERROR, "cannot execute binding command: fork() failed");
return;
} else if (pid == 0) {
execl("/bin/sh", "/bin/sh", "-c", command, (void *)NULL);
}
}
}
static void keyboard_keysym_press(struct roots_keyboard *keyboard,
xkb_keysym_t keysym) {
ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym);
if (i < 0) {
i = keyboard_pressed_keysym_index(keyboard, XKB_KEY_NoSymbol);
if (i >= 0) {
keyboard->pressed_keysyms[i] = keysym;
}
}
if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
keysym <= XKB_KEY_XF86Switch_VT_12) {
struct roots_server *server = keyboard->input->server;
if (wlr_backend_is_multi(server->backend)) { if (wlr_backend_is_multi(server->backend)) {
struct wlr_session *session = struct wlr_session *session =
wlr_multi_get_session(server->backend); wlr_multi_get_session(server->backend);
if (session) { if (session) {
wlr_session_change_vt(session, sym - XKB_KEY_XF86Switch_VT_1 + 1); unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
wlr_session_change_vt(session, vt);
} }
} }
return;
}
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
struct wl_list *bindings = &keyboard->input->server->config->bindings;
struct binding_config *bc;
wl_list_for_each(bc, bindings, link) {
if (modifiers ^ bc->modifiers) {
continue;
}
bool ok = true;
for (size_t i = 0; i < bc->keysyms_len; i++) {
ssize_t j = keyboard_pressed_keysym_index(keyboard, bc->keysyms[i]);
if (j < 0) {
ok = false;
break;
}
}
if (ok) {
keyboard_binding_execute(keyboard, bc->command);
}
}
}
static void keyboard_keysym_release(struct roots_keyboard *keyboard,
xkb_keysym_t keysym) {
ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym);
if (i >= 0) {
keyboard->pressed_keysyms[i] = XKB_KEY_NoSymbol;
}
}
static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct wlr_event_keyboard_key *event = data;
struct roots_keyboard *keyboard = wl_container_of(listener, keyboard, key);
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int syms_len = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state,
keycode, &syms);
for (int i = 0; i < syms_len; i++) {
if (event->state == WLR_KEY_PRESSED) {
keyboard_keysym_press(keyboard, syms[i]);
} else { // WLR_KEY_RELEASED
keyboard_keysym_release(keyboard, syms[i]);
} }
} }
} }

View file

@ -41,6 +41,7 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
setenv("WAYLAND_DISPLAY", socket, true);
wl_display_run(server.wl_display); wl_display_run(server.wl_display);
return 0; return 0;
} }

View file

@ -24,3 +24,9 @@ geometry = 2500x800
map-to-output = VGA-1 map-to-output = VGA-1
# Restrict cursor movements for this mouse to concrete rectangle # Restrict cursor movements for this mouse to concrete rectangle
geometry = 2500x800 geometry = 2500x800
# Keybindings
# Maps key combinations with commands to execute
# The special command "exit" stops the compositor
[bindings]
Logo+q=exit

View file

@ -12,20 +12,46 @@ int os_create_anonymous_file(off_t size);
static void keyboard_led_update(struct wlr_keyboard *keyboard) { static void keyboard_led_update(struct wlr_keyboard *keyboard) {
uint32_t leds = 0; uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_LAST; ++i) { for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->leds[i])) { if (xkb_state_led_index_is_active(keyboard->xkb_state,
keyboard->led_indexes[i])) {
leds |= (1 << i); leds |= (1 << i);
} }
} }
wlr_keyboard_led_update(keyboard, leds); wlr_keyboard_led_update(keyboard, leds);
} }
static void keyboard_modifier_update(struct wlr_keyboard *keyboard) {
xkb_mod_mask_t depressed = xkb_state_serialize_mods(keyboard->xkb_state,
XKB_STATE_MODS_DEPRESSED);
xkb_mod_mask_t latched = xkb_state_serialize_mods(keyboard->xkb_state,
XKB_STATE_MODS_LATCHED);
xkb_mod_mask_t locked = xkb_state_serialize_mods(keyboard->xkb_state,
XKB_STATE_MODS_LOCKED);
xkb_mod_mask_t group = xkb_state_serialize_layout(keyboard->xkb_state,
XKB_STATE_LAYOUT_EFFECTIVE);
if (depressed == keyboard->modifiers.depressed &&
latched == keyboard->modifiers.latched &&
locked == keyboard->modifiers.locked &&
group == keyboard->modifiers.group) {
return;
}
keyboard->modifiers.depressed = depressed;
keyboard->modifiers.latched = latched;
keyboard->modifiers.locked = locked;
keyboard->modifiers.group = group;
wl_signal_emit(&keyboard->events.modifiers, keyboard);
}
void wlr_keyboard_update_state(struct wlr_keyboard *keyboard, void wlr_keyboard_update_state(struct wlr_keyboard *keyboard,
struct wlr_event_keyboard_key *event) { struct wlr_event_keyboard_key *event) {
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
xkb_state_update_key(keyboard->xkb_state, keycode, xkb_state_update_key(keyboard->xkb_state, keycode,
event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
keyboard_led_update(keyboard); keyboard_led_update(keyboard);
keyboard_modifier_update(keyboard);
wl_signal_emit(&keyboard->events.key, event); wl_signal_emit(&keyboard->events.key, event);
} }
@ -33,6 +59,7 @@ void wlr_keyboard_init(struct wlr_keyboard *kb,
struct wlr_keyboard_impl *impl) { struct wlr_keyboard_impl *impl) {
kb->impl = impl; kb->impl = impl;
wl_signal_init(&kb->events.key); wl_signal_init(&kb->events.key);
wl_signal_init(&kb->events.modifiers);
wl_signal_init(&kb->events.keymap); wl_signal_init(&kb->events.keymap);
} }
@ -42,6 +69,8 @@ void wlr_keyboard_destroy(struct wlr_keyboard *kb) {
} else { } else {
wl_list_remove(&kb->events.key.listener_list); wl_list_remove(&kb->events.key.listener_list);
} }
xkb_state_unref(kb->xkb_state);
xkb_map_unref(kb->keymap);
close(kb->keymap_fd); close(kb->keymap_fd);
free(kb); free(kb);
} }
@ -57,14 +86,31 @@ void wlr_keyboard_set_keymap(struct wlr_keyboard *kb,
wlr_log(L_DEBUG, "Keymap set"); wlr_log(L_DEBUG, "Keymap set");
kb->keymap = keymap; kb->keymap = keymap;
assert(kb->xkb_state = xkb_state_new(kb->keymap)); assert(kb->xkb_state = xkb_state_new(kb->keymap));
const char *led_names[3] = {
const char *led_names[WLR_LED_COUNT] = {
XKB_LED_NAME_NUM, XKB_LED_NAME_NUM,
XKB_LED_NAME_CAPS, XKB_LED_NAME_CAPS,
XKB_LED_NAME_SCROLL XKB_LED_NAME_SCROLL,
}; };
for (uint32_t i = 0; i < 3; ++i) { for (size_t i = 0; i < WLR_LED_COUNT; ++i) {
kb->leds[i] = xkb_map_led_get_index(kb->keymap, led_names[i]); kb->led_indexes[i] = xkb_map_led_get_index(kb->keymap, led_names[i]);
} }
const char *mod_names[WLR_MODIFIER_COUNT] = {
XKB_MOD_NAME_SHIFT,
XKB_MOD_NAME_CAPS,
XKB_MOD_NAME_CTRL, // "Control"
XKB_MOD_NAME_ALT, // "Mod1"
XKB_MOD_NAME_NUM, // "Mod2"
"Mod3",
XKB_MOD_NAME_LOGO, // "Mod4"
"Mod5",
};
// TODO: there's also "Ctrl", "Alt"?
for (size_t i = 0; i < WLR_MODIFIER_COUNT; ++i) {
kb->mod_indexes[i] = xkb_map_mod_get_index(kb->keymap, mod_names[i]);
}
char *keymap_str = xkb_keymap_get_as_string(kb->keymap, char *keymap_str = xkb_keymap_get_as_string(kb->keymap,
XKB_KEYMAP_FORMAT_TEXT_V1); XKB_KEYMAP_FORMAT_TEXT_V1);
kb->keymap_size = strlen(keymap_str) + 1; kb->keymap_size = strlen(keymap_str) + 1;
@ -73,5 +119,18 @@ void wlr_keyboard_set_keymap(struct wlr_keyboard *kb,
PROT_READ | PROT_WRITE, MAP_SHARED, kb->keymap_fd, 0); PROT_READ | PROT_WRITE, MAP_SHARED, kb->keymap_fd, 0);
strcpy(ptr, keymap_str); strcpy(ptr, keymap_str);
free(keymap_str); free(keymap_str);
wl_signal_emit(&kb->events.keymap, kb); wl_signal_emit(&kb->events.keymap, kb);
} }
uint32_t wlr_keyboard_get_modifiers(struct wlr_keyboard *kb) {
xkb_mod_mask_t mask = kb->modifiers.depressed | kb->modifiers.latched;
uint32_t modifiers = 0;
for (size_t i = 0; i < WLR_MODIFIER_COUNT; ++i) {
if (kb->mod_indexes[i] != XKB_MOD_INVALID &&
(mask & (1 << kb->mod_indexes[i]))) {
modifiers |= (1 << i);
}
}
return modifiers;
}

View file

@ -12,6 +12,13 @@ static void resource_destroy(struct wl_client *client,
wl_resource_destroy(resource); wl_resource_destroy(resource);
} }
static void pointer_send_frame(struct wl_resource *resource) {
if (wl_resource_get_version(resource) >=
WL_POINTER_FRAME_SINCE_VERSION) {
wl_pointer_send_frame(resource);
}
}
static void wl_pointer_set_cursor(struct wl_client *client, static void wl_pointer_set_cursor(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *resource,
uint32_t serial, uint32_t serial,
@ -159,7 +166,9 @@ static void wl_seat_bind(struct wl_client *wl_client, void *_wlr_seat,
wl_resource_set_implementation(handle->wl_resource, &wl_seat_impl, wl_resource_set_implementation(handle->wl_resource, &wl_seat_impl,
handle, wlr_seat_handle_resource_destroy); handle, wlr_seat_handle_resource_destroy);
wl_list_insert(&wlr_seat->handles, &handle->link); wl_list_insert(&wlr_seat->handles, &handle->link);
if (version >= WL_SEAT_NAME_SINCE_VERSION) {
wl_seat_send_name(handle->wl_resource, wlr_seat->name); wl_seat_send_name(handle->wl_resource, wlr_seat->name);
}
wl_seat_send_capabilities(handle->wl_resource, wlr_seat->capabilities); wl_seat_send_capabilities(handle->wl_resource, wlr_seat->capabilities);
wl_signal_emit(&wlr_seat->events.client_bound, handle); wl_signal_emit(&wlr_seat->events.client_bound, handle);
} }
@ -296,7 +305,7 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
uint32_t serial = wl_display_next_serial(wlr_seat->display); uint32_t serial = wl_display_next_serial(wlr_seat->display);
wl_pointer_send_leave(focused_handle->pointer, serial, wl_pointer_send_leave(focused_handle->pointer, serial,
focused_surface->resource); focused_surface->resource);
wl_pointer_send_frame(focused_handle->pointer); pointer_send_frame(focused_handle->pointer);
} }
// enter the current surface // enter the current surface
@ -304,7 +313,7 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
uint32_t serial = wl_display_next_serial(wlr_seat->display); uint32_t serial = wl_display_next_serial(wlr_seat->display);
wl_pointer_send_enter(handle->pointer, serial, surface->resource, wl_pointer_send_enter(handle->pointer, serial, surface->resource,
wl_fixed_from_double(sx), wl_fixed_from_double(sy)); wl_fixed_from_double(sx), wl_fixed_from_double(sy));
wl_pointer_send_frame(handle->pointer); pointer_send_frame(handle->pointer);
} }
// reinitialize the focus destroy events // reinitialize the focus destroy events
@ -341,7 +350,7 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
wl_pointer_send_motion(wlr_seat->pointer_state.focused_handle->pointer, wl_pointer_send_motion(wlr_seat->pointer_state.focused_handle->pointer,
time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); time, wl_fixed_from_double(sx), wl_fixed_from_double(sy));
wl_pointer_send_frame(wlr_seat->pointer_state.focused_handle->pointer); pointer_send_frame(wlr_seat->pointer_state.focused_handle->pointer);
} }
uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
@ -353,7 +362,7 @@ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
uint32_t serial = wl_display_next_serial(wlr_seat->display); uint32_t serial = wl_display_next_serial(wlr_seat->display);
wl_pointer_send_button(wlr_seat->pointer_state.focused_handle->pointer, wl_pointer_send_button(wlr_seat->pointer_state.focused_handle->pointer,
serial, time, button, state); serial, time, button, state);
wl_pointer_send_frame(wlr_seat->pointer_state.focused_handle->pointer); pointer_send_frame(wlr_seat->pointer_state.focused_handle->pointer);
return serial; return serial;
} }
@ -369,56 +378,72 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
if (value) { if (value) {
wl_pointer_send_axis(pointer, time, orientation, wl_pointer_send_axis(pointer, time, orientation,
wl_fixed_from_double(value)); wl_fixed_from_double(value));
} else { } else if (wl_resource_get_version(pointer) >=
WL_POINTER_AXIS_STOP_SINCE_VERSION) {
wl_pointer_send_axis_stop(pointer, time, orientation); wl_pointer_send_axis_stop(pointer, time, orientation);
} }
wl_pointer_send_frame(pointer); pointer_send_frame(pointer);
} }
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_switch_seat_keyboard(struct wlr_seat_handle *handle,
struct wlr_seat_keyboard *seat_kb = wl_container_of( struct wlr_seat_keyboard *seat_kb) {
listener, seat_kb, key); if (handle->seat_keyboard == seat_kb) {
struct wlr_seat *seat = seat_kb->seat;
struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle;
if (!handle || !handle->keyboard) {
return; return;
} }
struct wlr_keyboard *keyboard = seat_kb->keyboard;
struct wlr_event_keyboard_key *event = data;
enum wlr_key_state key_state = event->state;
if (handle->seat_keyboard != seat_kb) {
// TODO: We should probably lift all of the keys set by the other // TODO: We should probably lift all of the keys set by the other
// keyboard // keyboard
wl_keyboard_send_keymap(handle->keyboard, wl_keyboard_send_keymap(handle->keyboard,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, seat_kb->keyboard->keymap_fd,
seat_kb->keyboard->keymap_fd,
seat_kb->keyboard->keymap_size); seat_kb->keyboard->keymap_size);
if (wl_resource_get_version(handle->keyboard) >= 2) { if (wl_resource_get_version(handle->keyboard) >=
WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
// TODO: Make this better // TODO: Make this better
wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); wl_keyboard_send_repeat_info(handle->keyboard, 25, 600);
} }
handle->seat_keyboard = seat_kb; handle->seat_keyboard = seat_kb;
} }
uint32_t depressed = xkb_state_serialize_mods(keyboard->xkb_state, static void keyboard_key_notify(struct wl_listener *listener, void *data) {
XKB_STATE_MODS_DEPRESSED); struct wlr_seat_keyboard *seat_kb = wl_container_of(listener, seat_kb, key);
uint32_t latched = xkb_state_serialize_mods(keyboard->xkb_state, struct wlr_seat *seat = seat_kb->seat;
XKB_STATE_MODS_LATCHED); struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle;
uint32_t locked = xkb_state_serialize_mods(keyboard->xkb_state, if (!handle || !handle->keyboard) {
XKB_STATE_MODS_LOCKED); return;
uint32_t group = xkb_state_serialize_layout(keyboard->xkb_state, }
XKB_STATE_LAYOUT_EFFECTIVE);
keyboard_switch_seat_keyboard(handle, seat_kb);
struct wlr_event_keyboard_key *event = data;
enum wlr_key_state key_state = event->state;
uint32_t modifiers_serial = wl_display_next_serial(seat->display);
uint32_t key_serial = wl_display_next_serial(seat->display); uint32_t key_serial = wl_display_next_serial(seat->display);
wl_keyboard_send_modifiers(handle->keyboard, modifiers_serial,
depressed, latched, locked, group);
wl_keyboard_send_key(handle->keyboard, key_serial, wl_keyboard_send_key(handle->keyboard, key_serial,
(uint32_t)event->time_usec, event->keycode, key_state); (uint32_t)event->time_usec, event->keycode, key_state);
} }
static void keyboard_modifiers_notify(struct wl_listener *listener,
void *data) {
struct wlr_seat_keyboard *seat_kb = wl_container_of(listener, seat_kb,
modifiers);
struct wlr_seat *seat = seat_kb->seat;
struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle;
if (!handle || !handle->keyboard) {
return;
}
keyboard_switch_seat_keyboard(handle, seat_kb);
struct wlr_keyboard *keyboard = seat_kb->keyboard;
uint32_t modifiers_serial = wl_display_next_serial(seat->display);
wl_keyboard_send_modifiers(handle->keyboard, modifiers_serial,
keyboard->modifiers.depressed, keyboard->modifiers.latched,
keyboard->modifiers.locked, keyboard->modifiers.group);
}
static void keyboard_keymap_notify(struct wl_listener *listener, void *data) { static void keyboard_keymap_notify(struct wl_listener *listener, void *data) {
struct wlr_seat_keyboard *seat_kb = wl_container_of( struct wlr_seat_keyboard *seat_kb = wl_container_of(
listener, seat_kb, keymap); listener, seat_kb, keymap);
@ -442,6 +467,9 @@ void wlr_seat_attach_keyboard(struct wlr_seat *seat,
wl_list_init(&seat_kb->key.link); wl_list_init(&seat_kb->key.link);
seat_kb->key.notify = keyboard_key_notify; seat_kb->key.notify = keyboard_key_notify;
wl_signal_add(&kb->events.key, &seat_kb->key); wl_signal_add(&kb->events.key, &seat_kb->key);
wl_list_init(&seat_kb->modifiers.link);
seat_kb->modifiers.notify = keyboard_modifiers_notify;
wl_signal_add(&kb->events.modifiers, &seat_kb->modifiers);
wl_list_init(&seat_kb->keymap.link); wl_list_init(&seat_kb->keymap.link);
seat_kb->keymap.notify = keyboard_keymap_notify; seat_kb->keymap.notify = keyboard_keymap_notify;
wl_signal_add(&kb->events.keymap, &seat_kb->keymap); wl_signal_add(&kb->events.keymap, &seat_kb->keymap);
@ -458,6 +486,7 @@ void wlr_seat_detach_keyboard(struct wlr_seat *seat, struct wlr_keyboard *kb) {
if (seat_kb->keyboard == kb) { if (seat_kb->keyboard == kb) {
wl_list_remove(&seat_kb->link); wl_list_remove(&seat_kb->link);
wl_list_remove(&seat_kb->key.link); wl_list_remove(&seat_kb->key.link);
wl_list_remove(&seat_kb->modifiers.link);
wl_list_remove(&seat_kb->keymap.link); wl_list_remove(&seat_kb->keymap.link);
wl_list_remove(&seat_kb->destroy.link); wl_list_remove(&seat_kb->destroy.link);
free(seat_kb); free(seat_kb);

View file

@ -7,6 +7,39 @@
#include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_surface.h>
#include <wlr/render/matrix.h> #include <wlr/render/matrix.h>
static void wlr_surface_state_reset_buffer(struct wlr_surface_state *state) {
if (state->buffer) {
wl_list_remove(&state->buffer_destroy_listener.link);
state->buffer = NULL;
}
}
static void buffer_destroy(struct wl_listener *listener, void *data) {
struct wlr_surface_state *state =
wl_container_of(listener, state, buffer_destroy_listener);
wl_list_remove(&state->buffer_destroy_listener.link);
state->buffer = NULL;
}
static void wlr_surface_state_release_buffer(struct wlr_surface_state *state) {
if (state->buffer) {
wl_resource_post_event(state->buffer, WL_BUFFER_RELEASE);
wl_list_remove(&state->buffer_destroy_listener.link);
state->buffer = NULL;
}
}
static void wlr_surface_state_set_buffer(struct wlr_surface_state *state,
struct wl_resource *buffer) {
state->buffer = buffer;
if (buffer) {
wl_resource_add_destroy_listener(buffer,
&state->buffer_destroy_listener);
state->buffer_destroy_listener.notify = buffer_destroy;
}
}
static void surface_destroy(struct wl_client *client, static void surface_destroy(struct wl_client *client,
struct wl_resource *resource) { struct wl_resource *resource) {
wl_resource_destroy(resource); wl_resource_destroy(resource);
@ -18,7 +51,8 @@ static void surface_attach(struct wl_client *client,
struct wlr_surface *surface = wl_resource_get_user_data(resource); struct wlr_surface *surface = wl_resource_get_user_data(resource);
surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER; surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER;
surface->pending->buffer = buffer; wlr_surface_state_reset_buffer(surface->pending);
wlr_surface_state_set_buffer(surface->pending, buffer);
} }
static void surface_damage(struct wl_client *client, static void surface_damage(struct wl_client *client,
@ -223,12 +257,9 @@ static void wlr_surface_move_state(struct wlr_surface *surface, struct wlr_surfa
update_size = true; update_size = true;
} }
if ((next->invalid & WLR_SURFACE_INVALID_BUFFER)) { if ((next->invalid & WLR_SURFACE_INVALID_BUFFER)) {
if (state->buffer) { wlr_surface_state_release_buffer(state);
wl_resource_post_event(state->buffer, WL_BUFFER_RELEASE); wlr_surface_state_set_buffer(state, next->buffer);
} wlr_surface_state_reset_buffer(next);
state->buffer = next->buffer;
next->buffer = NULL;
update_size = true; update_size = true;
} }
if (update_size) { if (update_size) {
@ -460,8 +491,7 @@ release:
pixman_region32_clear(&surface->current->surface_damage); pixman_region32_clear(&surface->current->surface_damage);
pixman_region32_clear(&surface->current->buffer_damage); pixman_region32_clear(&surface->current->buffer_damage);
wl_resource_post_event(surface->current->buffer, WL_BUFFER_RELEASE); wlr_surface_state_release_buffer(surface->current);
surface->current->buffer = NULL;
} }
static void surface_set_buffer_transform(struct wl_client *client, static void surface_set_buffer_transform(struct wl_client *client,
@ -522,6 +552,7 @@ static struct wlr_surface_state *wlr_surface_state_create() {
} }
static void wlr_surface_state_destroy(struct wlr_surface_state *state) { static void wlr_surface_state_destroy(struct wlr_surface_state *state) {
wlr_surface_state_reset_buffer(state);
struct wlr_frame_callback *cb, *tmp; struct wlr_frame_callback *cb, *tmp;
wl_list_for_each_safe(cb, tmp, &state->frame_callback_list, link) { wl_list_for_each_safe(cb, tmp, &state->frame_callback_list, link) {
wl_resource_destroy(cb->resource); wl_resource_destroy(cb->resource);