From 4bdc2640a74ff66413ba3814fb3281f88f19017a Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 29 Mar 2020 11:47:44 +0000 Subject: [PATCH] Merge 1.0.6 for compatibility testing --- Bugs.md | 29 +++++ README.md | 48 ++++++-- meson.build | 74 +++++++----- meson_options.txt | 1 + seat.c | 243 ++++++++++----------------------------- seat.h | 23 ++-- signatures/cagebreak.sig | Bin 0 -> 566 bytes view.c | 12 +- 8 files changed, 194 insertions(+), 236 deletions(-) create mode 100644 signatures/cagebreak.sig diff --git a/Bugs.md b/Bugs.md index 90758b8..491d2c6 100644 --- a/Bugs.md +++ b/Bugs.md @@ -26,3 +26,32 @@ Steps to reproduce: * enter text into the "Tags" field * if autocompletion of tags pops up, the keyboard will not enter further keystrokes into the text field + +### Issue 2 + + * Github issue number: N/A + * Fixed: 1.0.4 + +This issue fixes wrong consumption of modifier key on some keyboards. + +### Issue 3 + + * github issue number: N/A + * Fixed: 1.0.5 + +This issue is a bug causing crashes in cagebreak under specific circumstances. + +Steps to reproduce: + + * start cagebreak + * vertical split + * open a terminal on the left pane + * open firefox on the right pane + * focus the left pane + * close the terminal + * close firefox using the mouse while keeping focus on the left pane + * this causes a crash with the following error message: + +``` +(EE) failed to read Wayland events: Broken pipe +``` diff --git a/README.md b/README.md index 8117d1f..c793ac0 100644 --- a/README.md +++ b/README.md @@ -74,13 +74,19 @@ it is merged into `master`, creating a new release, which is tagged and signed. Merging into master is always done by ``` -git merge --no-ff development -git tag -u keyid version -git push origin master +git checkout development +git pull origin development +git checkout master +git merge --squash development +git tag -u keyid version HEAD +git tag -v version +git push --tags origin master ``` and a log message roughly describing the features is added in the commit. +In the past, our git history did not always reflect this scheme. + ### Releases Release checklist @@ -99,6 +105,8 @@ Release checklist * [ ] wiki * [ ] Changelog in README * [ ] Document fixed bugs in Bugs.md + * [ ] Update hashes of the binary + * [ ] Update signature of the binary * [ ] Signature * [ ] Branching Strategy @@ -120,10 +128,36 @@ The full public keys can be found in `keys/` along with any revocation certifica ### Reproducible Builds -Currently our project seems to build the same way on any given system, when compiled -multiple times. However, at the moment we are unable to supply instructions -for building our software reproducibly. Reproducible builds are planned for the -near future. +Cagebreak offers reproducible builds given the exact library versions specified +in `meson.build`. Should a version mismatch occur, a warning will be emitted. We have +decided on this compromise to allow flexibility and security. In general we will +adapt the versions to the packages available under archlinux at the time of +release. + +#### Reproducible Build Instructions + +All hashes and signatures are provided for the following build instructions. + +``` +meson build -Dxwayland=true --buildtype=release +ninja -C build +``` + +#### Hashes for Builds + +For every release after 1.0.5, hashes will be provided. + +1.0.6 + + * sha 256: 712ae9a8f17a9e589e108f0d503da203cc5eaf1c4a6ca6efb5b4c83b432ce0b8 + * sha 512: d574003023a00cfd6623aac986a5a7f397cfd0bc9114017629a8c72731b0df3977c4a31768502dfa8a6607be06930089b2ccf6ffca9b5bcd1096b7ca0aede226 + +#### GPG Signatures + +For every release after 1.0.5, a GPG signature will be provided in `signatures`. + +The current signature is called `cagebreak.sig`, whereas all older signatures +will be named after their release version. ### Fuzzing diff --git a/meson.build b/meson.build index 9904430..a65d0b6 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.2', + version: '1.0.6', license: 'MIT', default_options: [ 'c_std=c11', @@ -101,18 +101,10 @@ else have_xwayland = false endif -version = '@0@'.format(meson.project_version()) -git = find_program('git', native: true, required: false) -if git.found() - git_commit = run_command([git, 'rev-parse', '--short', 'HEAD']) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD']) - if git_commit.returncode() == 0 and git_branch.returncode() == 0 - version = '@0@-@1@ (branch \'@2@\')'.format( - meson.project_version(), - git_commit.stdout().strip(), - git_branch.stdout().strip(), - ) - endif +if get_option('version_override') != '' + version = '@0@'.format(get_option('version_override')) +else + version = '@0@'.format(meson.project_version()) endif conf_data = configuration_data() @@ -173,21 +165,49 @@ endforeach foreach header : cagebreak_header_strings cagebreak_headers += files(header) endforeach +cagebreak_dependencies_dict = { + 'server_protos': server_protos, + 'wayland_server': wayland_server, + 'wayland_client': wayland_client, + 'wayland_cursor': wayland_cursor, + 'wlroots': wlroots, + 'xkbcommon': xkbcommon, + 'fontconfig': fontconfig, + 'pixman': pixman, + 'pango': pango, + 'cairo': cairo, + 'pangocairo': pangocairo, + 'math': math +} -cagebreak_dependencies = [ - server_protos, - wayland_server, - wayland_client, - wayland_cursor, - wlroots, - xkbcommon, - fontconfig, - pixman, - math, - pango, - cairo, - pangocairo, -] +reproducible_build_versions = { + 'server_protos': '1.0.6', + 'wayland_server': '1.18.0', + 'wayland_client': '1.18.0', + 'wayland_cursor': '1.18.0', + 'wlroots': '0.10.1', + 'xkbcommon': '0.10.0', + 'fontconfig': '2.13.91', + 'pixman': '0.38.4', + 'pango': '1.44.7', + 'cairo': '1.17.3', + 'pangocairo': '1.44.7', + 'math': '-1' +} + +cagebreak_dependencies = [] + +foreach name, dep : cagebreak_dependencies_dict + cagebreak_dependencies += dep +endforeach + +foreach name, dep : cagebreak_dependencies_dict + if reproducible_build_versions[name] != '-1' and reproducible_build_versions[name] != dep.version() + warning('The installed version of "' + name + '" on your machine (' + dep.version() + ') differs from the one used to generate the binary specified in the README section "Reproducible Builds" (' + reproducible_build_versions[name] + '). Cagebreak does not guarantee a reproducible build for this configuration.' + ) + break + endif +endforeach executable( meson.project_name(), diff --git a/meson_options.txt b/meson_options.txt index 5982c3d..bb96c4f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,3 @@ option('xwayland', type: 'boolean', value: 'false', description: 'Enable support for X11 applications') option('fuzz', type: 'boolean', value: 'false', description: 'Enable building fuzzer targets') +option('version_override', type: 'string', description: 'Set the project version to the string specified. Used for creating hashes for reproducible builds.') diff --git a/seat.c b/seat.c index 57c2b04..7567586 100644 --- a/seat.c +++ b/seat.c @@ -112,7 +112,7 @@ static void update_capabilities(const struct cg_seat *seat) { uint32_t caps = 0; - if(!wl_list_empty(&seat->keyboards)) { + if(!wl_list_empty(&seat->keyboard_groups)) { caps |= WL_SEAT_CAPABILITY_KEYBOARD; } if(!wl_list_empty(&seat->pointers)) { @@ -216,41 +216,41 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) { static int handle_keyboard_repeat(void *data) { - struct cg_keyboard *keyboard = (struct cg_keyboard *)data; - struct wlr_keyboard *wlr_device = keyboard->device->keyboard; - if(keyboard->repeat_keybinding != NULL) { + struct cg_keyboard_group *cg_group = data; + struct wlr_keyboard *wlr_device = + cg_group->wlr_group->input_device->keyboard; + if(cg_group->repeat_keybinding != NULL) { if(wlr_device->repeat_info.rate > 0) { if(wl_event_source_timer_update( - keyboard->key_repeat_timer, + cg_group->key_repeat_timer, 1000 / wlr_device->repeat_info.rate) < 0) { wlr_log(WLR_DEBUG, "failed to update key repeat timer"); } } - run_action((*keyboard->repeat_keybinding)->action, - keyboard->seat->server, - (*keyboard->repeat_keybinding)->data); + run_action((*cg_group->repeat_keybinding)->action, + cg_group->seat->server, + (*cg_group->repeat_keybinding)->data); } return 0; } static void -handle_modifier_event(struct cg_keyboard *keyboard) { - wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); - wlr_seat_keyboard_notify_modifiers(keyboard->seat->seat, - &keyboard->device->keyboard->modifiers); +handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat) { + wlr_seat_set_keyboard(seat->seat, device); + wlr_seat_keyboard_notify_modifiers(seat->seat, + &device->keyboard->modifiers); - wlr_idle_notify_activity(keyboard->seat->server->idle, - keyboard->seat->seat); + wlr_idle_notify_activity(seat->server->idle, seat->seat); } void -keyboard_disarm_key_repeat(struct cg_keyboard *keyboard) { - if(!keyboard) { +keyboard_disarm_key_repeat(struct cg_keyboard_group *group) { + if(!group) { return; } - keyboard->repeat_keybinding = NULL; - if(wl_event_source_timer_update(keyboard->key_repeat_timer, 0) < 0) { + group->repeat_keybinding = NULL; + if(wl_event_source_timer_update(group->key_repeat_timer, 0) < 0) { wlr_log(WLR_DEBUG, "failed to disarm key repeat timer"); } } @@ -258,7 +258,7 @@ keyboard_disarm_key_repeat(struct cg_keyboard *keyboard) { static bool handle_command_key_bindings(struct cg_server *server, xkb_keysym_t sym, uint32_t modifiers, uint32_t mode, - struct cg_keyboard *keyboard) { + struct cg_keyboard_group *group) { struct keybinding **keybinding = find_keybinding( server->keybindings, &(struct keybinding){.key = sym, .mode = mode, .modifiers = modifiers}); @@ -271,15 +271,16 @@ handle_command_key_bindings(struct cg_server *server, xkb_keysym_t sym, "Recognized keybinding pressed (key: %d, mode: %d, modifiers: %d)", sym, mode, modifiers); - if(keyboard->device->keyboard->repeat_info.delay > 0) { - keyboard->repeat_keybinding = keybinding; - if(wl_event_source_timer_update( - keyboard->key_repeat_timer, - keyboard->device->keyboard->repeat_info.delay) < 0) { + if(group->wlr_group->input_device->keyboard->repeat_info.delay > 0) { + group->repeat_keybinding = keybinding; + if(wl_event_source_timer_update(group->key_repeat_timer, + group->wlr_group->input_device + ->keyboard->repeat_info.delay) < + 0) { wlr_log(WLR_DEBUG, "failed to set key repeat timer"); } } - message_clear(keyboard->seat->server->curr_output); + message_clear(group->seat->server->curr_output); run_action((*keybinding)->action, server, (*keybinding)->data); wlr_idle_notify_activity(server->idle, server->seat->seat); return true; @@ -315,42 +316,42 @@ key_is_modifier(const xkb_keysym_t key) { } static void -handle_key_event(struct cg_keyboard *keyboard, void *data) { - struct cg_seat *seat = keyboard->seat; +handle_key_event(struct cg_keyboard_group *group, struct cg_seat *seat, + void *data) { struct wlr_event_keyboard_key *event = data; + struct wlr_input_device *device = group->wlr_group->input_device; /* Translate from libinput keycode to an xkbcommon keycode. */ xkb_keycode_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, - keycode, &syms); + int nsyms = + xkb_state_key_get_syms(device->keyboard->xkb_state, keycode, &syms); bool handled = false; for(int i = 0; i < nsyms; ++i) { if(event->state == WLR_KEY_PRESSED && !key_is_modifier(syms[i])) { - uint32_t modifiers = - wlr_keyboard_get_modifiers(keyboard->device->keyboard); + uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); /* Get the consumed_modifiers and remove them from the modifier list */ xkb_mod_mask_t consumed_modifiers = - xkb_state_key_get_consumed_mods2( - keyboard->device->keyboard->xkb_state, keycode, - XKB_CONSUMED_MODE_XKB); + xkb_state_key_get_consumed_mods2(device->keyboard->xkb_state, + keycode, + XKB_CONSUMED_MODE_GTK); if(handle_command_key_bindings(seat->server, syms[i], modifiers & ~consumed_modifiers, - seat->mode, keyboard)) { + seat->mode, group)) { handled = true; } - } else if(keyboard->repeat_keybinding != NULL && handled == false) { - keyboard_disarm_key_repeat(keyboard); + } else if(group->repeat_keybinding != NULL && handled == false) { + keyboard_disarm_key_repeat(group); } } if(!handled) { /* Otherwise, we pass it along to the client. */ - wlr_seat_set_keyboard(seat->seat, keyboard->device); + wlr_seat_set_keyboard(seat->seat, device); wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, event->keycode, event->state); } @@ -358,130 +359,28 @@ handle_key_event(struct cg_keyboard *keyboard, void *data) { wlr_idle_notify_activity(seat->server->idle, seat->seat); } -static void -cg_keyboard_group_remove(struct cg_keyboard *keyboard); - -static void -cg_keyboard_destroy(struct cg_keyboard *keyboard) { - struct cg_seat *seat = keyboard->seat; - - if(keyboard->device->keyboard->group != NULL) { - cg_keyboard_group_remove(keyboard); - } - - if(wlr_seat_get_keyboard(seat->seat) == keyboard->device->keyboard) { - wlr_seat_set_keyboard(seat->seat, NULL); - } - - keyboard_disarm_key_repeat(keyboard); - wl_event_source_remove(keyboard->key_repeat_timer); - - free(keyboard); -} - -static void -destroy_empty_wlr_keyboard_group(void *data) { - wlr_keyboard_group_destroy(data); -} - -static void -cg_keyboard_group_remove(struct cg_keyboard *keyboard) { - struct wlr_keyboard_group *wlr_group = keyboard->device->keyboard->group; - - wlr_keyboard_group_remove_keyboard(keyboard->device->keyboard->group, - keyboard->device->keyboard); - - if(wl_list_empty(&wlr_group->devices)) { - wlr_log(WLR_DEBUG, "Destroying empty keyboard group %p", - (void *)wlr_group); - struct cg_keyboard_group *cg_group = wlr_group->data; - wlr_group->data = NULL; - wl_list_remove(&cg_group->link); - wl_list_remove(&cg_group->key.link); - wl_list_remove(&cg_group->modifiers.link); - cg_keyboard_destroy(cg_group->keyboard); - free(cg_group); - - // To prevent use-after-free conditions when handling key events, defer - // freeing the wlr_keyboard_group until idle - if(keyboard->seat->server->running) { - wl_event_loop_add_idle(keyboard->seat->server->event_loop, - destroy_empty_wlr_keyboard_group, wlr_group); - } else { - destroy_empty_wlr_keyboard_group(wlr_group); - } - } -} - -static void -handle_keyboard_destroy(struct wl_listener *listener, void *_data) { - struct cg_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); - struct cg_seat *seat = keyboard->seat; - wl_list_remove(&keyboard->link); - wl_list_remove(&keyboard->destroy.link); - cg_keyboard_destroy(keyboard); - update_capabilities(seat); -} - static void handle_keyboard_group_key(struct wl_listener *listener, void *data) { struct cg_keyboard_group *cg_group = wl_container_of(listener, cg_group, key); - handle_key_event(cg_group->keyboard, data); + handle_key_event(cg_group, cg_group->seat, data); } static void handle_keyboard_group_modifiers(struct wl_listener *listener, void *_data) { struct cg_keyboard_group *group = wl_container_of(listener, group, modifiers); - handle_modifier_event(group->keyboard); -} - -static bool -keymaps_match(struct xkb_keymap *km1, struct xkb_keymap *km2) { - char *km1_str = xkb_keymap_get_as_string(km1, XKB_KEYMAP_FORMAT_TEXT_V1); - char *km2_str = xkb_keymap_get_as_string(km2, XKB_KEYMAP_FORMAT_TEXT_V1); - bool result = strcmp(km1_str, km2_str) == 0; - free(km1_str); - free(km2_str); - return result; -} - -static bool -repeat_info_match(const struct cg_keyboard *a, const struct wlr_keyboard *b) { - return a->device->keyboard->repeat_info.rate == b->repeat_info.rate && - a->device->keyboard->repeat_info.delay == b->repeat_info.delay; -} - -struct cg_keyboard * -cg_keyboard_from_seat(struct cg_seat *seat, struct wlr_input_device *device) { - struct cg_keyboard *keyboard = calloc(1, sizeof(struct cg_keyboard)); - if(keyboard == NULL) { - wlr_log(WLR_ERROR, "Could not allocate new cg_keyboard."); - return NULL; - } - - keyboard->seat = seat; - keyboard->device = device; - - keyboard->key_repeat_timer = wl_event_loop_add_timer( - seat->server->event_loop, handle_keyboard_repeat, keyboard); - - return keyboard; + handle_modifier_event(group->wlr_group->input_device, group->seat); } static void -keyboard_group_add(const struct cg_keyboard *keyboard) { - struct cg_seat *seat = keyboard->seat; - struct wlr_keyboard *wlr_keyboard = keyboard->device->keyboard; +cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) { + struct wlr_keyboard *wlr_keyboard = device->keyboard; struct cg_keyboard_group *group; wl_list_for_each(group, &seat->keyboard_groups, link) { struct wlr_keyboard_group *wlr_group = group->wlr_group; - if(keymaps_match(wlr_keyboard->keymap, wlr_group->keyboard.keymap) && - repeat_info_match(keyboard, &wlr_group->keyboard)) { - wlr_log(WLR_DEBUG, "Adding keyboard %p to group %p.", - (void *)keyboard, (void *)wlr_group); - wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard); + if(wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard)) { + wlr_log(WLR_DEBUG, "Adding keyboard to existing group."); return; } } @@ -493,6 +392,7 @@ keyboard_group_add(const struct cg_keyboard *keyboard) { wlr_log(WLR_ERROR, "Failed to allocate keyboard group."); return; } + cg_group->seat = seat; cg_group->wlr_group = wlr_keyboard_group_create(); if(cg_group->wlr_group == NULL) { wlr_log(WLR_ERROR, "Failed to create wlr keyboard group."); @@ -501,22 +401,12 @@ keyboard_group_add(const struct cg_keyboard *keyboard) { cg_group->wlr_group->data = cg_group; wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, - keyboard->device->keyboard->keymap); + device->keyboard->keymap); wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, - keyboard->device->keyboard->repeat_info.rate, - keyboard->device->keyboard->repeat_info.delay); - wlr_log(WLR_DEBUG, "Created keyboard group %p", - (void *)cg_group->wlr_group); + device->keyboard->repeat_info.rate, + device->keyboard->repeat_info.delay); + wlr_log(WLR_DEBUG, "Created keyboard group."); - cg_group->keyboard = - cg_keyboard_from_seat(seat, cg_group->wlr_group->input_device); - if(cg_group->keyboard == NULL) { - wlr_log(WLR_ERROR, "Failed to create keyboard from seat."); - goto cleanup; - } - - wlr_log(WLR_DEBUG, "Adding keyboard %p to group %p.", (void *)keyboard, - (void *)cg_group->wlr_group); wlr_keyboard_group_add_keyboard(cg_group->wlr_group, wlr_keyboard); wl_list_insert(&seat->keyboard_groups, &cg_group->link); @@ -525,6 +415,10 @@ keyboard_group_add(const struct cg_keyboard *keyboard) { wl_signal_add(&cg_group->wlr_group->keyboard.events.modifiers, &cg_group->modifiers); + + cg_group->key_repeat_timer = wl_event_loop_add_timer( + seat->server->event_loop, handle_keyboard_repeat, cg_group); + cg_group->modifiers.notify = handle_keyboard_group_modifiers; return; @@ -537,16 +431,9 @@ cleanup: static void handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) { - struct cg_keyboard *keyboard = calloc(1, sizeof(struct cg_keyboard)); - if(!keyboard) { - wlr_log(WLR_ERROR, "Cannot allocate keyboard"); - return; - } - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if(!context) { wlr_log(WLR_ERROR, "Unable to create XBK context"); - free(keyboard); return; } @@ -561,28 +448,19 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) { if(!keymap) { wlr_log(WLR_ERROR, "Unable to configure keyboard: keymap does not exist"); - free(keyboard); xkb_context_unref(context); return; } - keyboard->seat = seat; - keyboard->device = device; wlr_keyboard_set_keymap(device->keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); - keyboard_group_add(keyboard); + cg_keyboard_group_add(device, seat); - wlr_seat_set_keyboard(seat->seat, device->keyboard->group->input_device); - - wl_list_insert(&seat->keyboards, &keyboard->link); - keyboard->destroy.notify = handle_keyboard_destroy; - wl_signal_add(&device->events.destroy, &keyboard->destroy); - keyboard->key_repeat_timer = wl_event_loop_add_timer( - seat->server->event_loop, handle_keyboard_repeat, keyboard); + wlr_seat_set_keyboard(seat->seat, device); } static void @@ -914,9 +792,11 @@ handle_destroy(struct wl_listener *listener, void *_data) { struct cg_seat *seat = wl_container_of(listener, seat, destroy); wl_list_remove(&seat->destroy.link); - struct cg_keyboard *keyboard, *keyboard_tmp; - wl_list_for_each_safe(keyboard, keyboard_tmp, &seat->keyboards, link) { - handle_keyboard_destroy(&keyboard->destroy, NULL); + struct cg_keyboard_group *group, *group_tmp; + wl_list_for_each_safe(group, group_tmp, &seat->keyboard_groups, link) { + wlr_keyboard_group_destroy(group->wlr_group); + 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) { @@ -1014,7 +894,6 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) { wl_signal_add(&seat->seat->events.request_set_primary_selection, &seat->request_set_primary_selection); - wl_list_init(&seat->keyboards); wl_list_init(&seat->keyboard_groups); wl_list_init(&seat->pointers); wl_list_init(&seat->touch); diff --git a/seat.h b/seat.h index 7d1d7c7..a7632d7 100644 --- a/seat.h +++ b/seat.h @@ -14,22 +14,11 @@ struct wlr_backend; #define DEFAULT_XCURSOR "left_ptr" #define XCURSOR_SIZE 24 -struct cg_keyboard_group { - struct cg_keyboard *keyboard; - - struct wlr_keyboard_group *wlr_group; - struct cg_seat *seat; - struct wl_listener key; - struct wl_listener modifiers; - struct wl_list link; -}; - struct cg_seat { struct wlr_seat *seat; struct cg_server *server; struct wl_listener destroy; - struct wl_list keyboards; struct wl_list keyboard_groups; struct wl_list pointers; struct wl_list touch; @@ -66,14 +55,16 @@ struct cg_seat { struct cg_view *focused_view; }; -struct cg_keyboard { - struct wl_list link; // seat::keyboards +struct cg_keyboard_group { + struct wlr_keyboard_group *wlr_group; struct cg_seat *seat; - struct wlr_input_device *device; - struct wl_listener destroy; - struct keybinding **repeat_keybinding; + struct wl_listener key; + struct wl_listener modifiers; + struct wl_list link; + struct wl_event_source *key_repeat_timer; + struct keybinding **repeat_keybinding; }; struct cg_pointer { diff --git a/signatures/cagebreak.sig b/signatures/cagebreak.sig new file mode 100644 index 0000000000000000000000000000000000000000..3a641bee171da79f5d93fc627d5230d0786eb715 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$zY^*8mC$5XAX( z*9`0|Tc$z}|64$gG`MHKZ=AWaCuyalWsk4kO22O@Vk;D@>@jJuMc1+zpA&G+@{_qV zY9~dDUAwMOK2VHMa&iLO!uOvyglM zhBjpy;1P1#FHLT#7v>lpVVi6Z)1C)>q}@RqNpe^BE8D&&DY2=Mik-G~dS%Sl z0UXfHXw_6n^tAebKouvI4 z_=BR(cP)Ly>xoA^o*f2+Q=qp@z(YPty4N-AOu~Yv{8k&L$Lf7F?L)YbTwZlvADEF0 E$r~dTVE_OC literal 0 HcmV?d00001 diff --git a/view.c b/view.c index acd7603..6b0ed87 100644 --- a/view.c +++ b/view.c @@ -234,10 +234,14 @@ view_unmap(struct cg_view *view) { struct cg_tile *view_tile = view_get_tile(view); wlr_output_damage_add_box(view_tile->workspace->output->damage, &view_tile->tile); - if(view->workspace->server->seat->seat->keyboard_state - .focused_surface == NULL || - view->workspace->server->seat->seat->keyboard_state - .focused_surface == view->wlr_surface) { + if((view->workspace->server->seat->seat->keyboard_state + .focused_surface == NULL || + view->workspace->server->seat->seat->keyboard_state + .focused_surface == view->wlr_surface) && + view->workspace->server->curr_output + ->workspaces[view->workspace->server->curr_output + ->curr_workspace] + ->focused_tile == view_tile) { seat_set_focus(view->workspace->server->seat, prev); } else { view_tile->view = prev;