From 375e4d5ea503cea950c12720b26e6e02acec55dc Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 22 Feb 2020 09:45:22 +0100 Subject: [PATCH 001/122] Completely switch to wlr_keyboard_group --- seat.c | 246 +++++++++++++++------------------------------------------ seat.h | 23 ++---- 2 files changed, 70 insertions(+), 199 deletions(-) diff --git a/seat.c b/seat.c index 75a6a78..0faacd5 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_XKB); 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); @@ -1095,7 +974,8 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) { #if CG_HAS_XWAYLAND if(view->type == CG_XWAYLAND_VIEW) { - const struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view); + const struct cg_xwayland_view *xwayland_view = + xwayland_view_from_view(view); if(!wlr_xwayland_or_surface_wants_focus( xwayland_view->xwayland_surface)) { return; 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 { From a2cc047132b31cbe4e7a87da4b033a827fad4087 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sun, 23 Feb 2020 16:53:47 +0100 Subject: [PATCH 002/122] Add support for output layout configuration --- cagebreak.c | 16 +++++++ fuzz/fuzz-parse.c | 10 +++++ output.c | 70 +++++++++++++++++++++++++++---- output.h | 11 ++++- parse.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ server.h | 2 + 6 files changed, 204 insertions(+), 8 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index 4a71480..1ba61fe 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -307,6 +307,8 @@ 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); @@ -506,6 +508,13 @@ main(int argc, char *argv[]) { free(config_file); } + { + struct cg_output *output; + wl_list_for_each(output, &server.outputs, link) { + output_configure(&server, output); + } + } + /* Place the cursor to the topl left of the output layout. */ wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); @@ -523,6 +532,13 @@ end: } free(server.modes); + struct cg_output_config *output_config, *output_config_tmp; + wl_list_for_each_safe(output_config, output_config_tmp, &server.output_config, link) { + wl_list_remove(&output_config->link); + free(output_config->output_name); + free(output_config); + } + keybinding_list_free(server.keybindings); wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 257f289..e159293 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -5,6 +5,7 @@ #include "../parse.h" #include "../seat.h" #include "../server.h" +#include "../output.h" #include #include #include @@ -58,6 +59,7 @@ LLVMFuzzerInitialize(int *argc, char ***argv) { /* new_xwayland_surface */ server.keybindings = keybinding_list_init(); server.output_transform = 0; + wl_list_init(&server.output_config); server.running = true; server.modes = malloc(sizeof(char *)); @@ -82,5 +84,13 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { free(str); keybinding_list_free(server.keybindings); server.keybindings = keybinding_list_init(); + + struct cg_output_config *output_config, *output_config_tmp; + wl_list_for_each_safe(output_config, output_config_tmp, &server.output_config, link) { + wl_list_remove(&output_config->link); + free(output_config->output_name); + free(output_config); + } + return 0; } diff --git a/output.c b/output.c index 4fd6960..c91f91b 100644 --- a/output.c +++ b/output.c @@ -480,6 +480,67 @@ handle_output_destroy(struct wl_listener *listener, void *data) { output_destroy(output); } +struct cg_output_config* +output_find_config(struct cg_server* server, struct wlr_output* output) { + struct cg_output_config *config; + wl_list_for_each(config, &server->output_config, link) { + if(strcmp(config->output_name, output->name) == 0) { + return config; + } + } + return NULL; +} + +static void output_set_mode(struct wlr_output *output, int width, int height, + float refresh_rate) { + int mhz = (int)(refresh_rate * 1000); + + if (wl_list_empty(&output->modes)) { + wlr_log(WLR_DEBUG, "Assigning custom mode to %s", output->name); + wlr_output_set_custom_mode(output, width, height, + refresh_rate > 0 ? mhz : 0); + return; + } + + struct wlr_output_mode *mode, *best = NULL; + wl_list_for_each(mode, &output->modes, link) { + if (mode->width == width && mode->height == height) { + if (mode->refresh == mhz) { + best = mode; + break; + } + if (best == NULL || mode->refresh > best->refresh) { + best = mode; + } + } + } + if (!best) { + wlr_log(WLR_ERROR, "Configured mode for %s not available", output->name); + wlr_log(WLR_INFO, "Picking preferred mode instead"); + best = wlr_output_preferred_mode(output); + } else { + wlr_log(WLR_DEBUG, "Assigning configured mode to %s", output->name); + } + wlr_output_set_mode(output, best); +} + +void +output_configure(struct cg_server* server, struct cg_output *output) { + struct wlr_output *wlr_output = output->wlr_output; + struct cg_output_config *config = output_find_config(server, wlr_output); + if(config == NULL) { + wlr_output_layout_add_auto(server->output_layout, wlr_output); + + struct wlr_output_mode *preferred_mode = + wlr_output_preferred_mode(wlr_output); + if(preferred_mode) { + wlr_output_set_mode(wlr_output, preferred_mode); + } + } else { + output_set_mode(wlr_output, config->pos.width, config->pos.height, config->refresh_rate); + } +} + void handle_new_output(struct wl_listener *listener, void *data) { struct cg_server *server = wl_container_of(listener, server, new_output); @@ -508,7 +569,8 @@ handle_new_output(struct wl_listener *listener, void *data) { wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); wlr_output_set_transform(wlr_output, server->output_transform); - wlr_output_layout_add_auto(server->output_layout, wlr_output); + + output_configure(server, output); output->workspaces = malloc(server->nws * sizeof(struct cg_workspace *)); for(unsigned int i = 0; i < server->nws; ++i) { @@ -520,12 +582,6 @@ handle_new_output(struct wl_listener *listener, void *data) { output->curr_workspace = 0; wl_list_init(&output->messages); - struct wlr_output_mode *preferred_mode = - wlr_output_preferred_mode(wlr_output); - if(preferred_mode) { - wlr_output_set_mode(wlr_output, preferred_mode); - } - if(wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, diff --git a/output.h b/output.h index ffca3e7..ba12ea6 100644 --- a/output.h +++ b/output.h @@ -2,13 +2,13 @@ #define CG_OUTPUT_H #include +#include struct cg_server; struct cg_view; struct wlr_output; struct wlr_output_damage; struct wlr_surface; -struct wlr_box; struct cg_output { struct cg_server *server; @@ -27,6 +27,13 @@ struct cg_output { struct wl_list link; // cg_server::outputs }; +struct cg_output_config { + struct wlr_box pos; + char* output_name; + float refresh_rate; + struct wl_list link;// cg_server::output_config +}; + typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, @@ -35,6 +42,8 @@ typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, void handle_new_output(struct wl_listener *listener, void *data); void +output_configure(struct cg_server* server, struct cg_output* output); +void output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *surface, double ox, double oy, cg_surface_iterator_func_t iterator, diff --git a/parse.c b/parse.c index e8c7b15..0b6e864 100644 --- a/parse.c +++ b/parse.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "keybinding.h" #include "output.h" @@ -343,6 +344,104 @@ parse_definemode(char ***modes, char **saveptr) { return 0; } +int +parse_uint(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 integer, got nothing"); + return -1; + } + long uint = strtol(uint_str, NULL, 10); + if(uint >= 0 && uint <= INT_MAX) { + return uint; + } else { + wlr_log(WLR_ERROR, "Error parsing non-negative integer. Must be a number larger or equal to 0 and less or equal to %d",INT_MAX); + return -1; + } +} + +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(struct wl_list *config_list, char **saveptr) { + struct cg_output_config* cfg = malloc(sizeof(struct cg_output_config)); + char *name = strtok_r(NULL, " ", saveptr); + if(name == NULL) { + wlr_log(WLR_ERROR, "Expected name of output to be configured, got none"); + goto error; + } + char *pos_str = strtok_r(NULL, " ", saveptr); + if(pos_str == NULL || strcmp(pos_str, "pos") != 0) { + wlr_log(WLR_ERROR, "Expected keyword \"pos\" in output configuration for output %s", name); + goto error; + } + + cfg->pos.x = parse_uint(saveptr, " "); + if(cfg->pos.x < 0) { + wlr_log(WLR_ERROR, "Error parsing x coordinate of output configuration for output %s", name); + goto error; + } + + cfg->pos.y = parse_uint(saveptr, " "); + if(cfg->pos.y < 0) { + wlr_log(WLR_ERROR, "Error parsing y coordinate of output configuration for output %s", name); + goto error; + } + + char *res_str = strtok_r(NULL, " ", saveptr); + if(res_str == NULL || strcmp(res_str, "res") != 0) { + wlr_log(WLR_ERROR, "Expected keyword \"res\" in output configuration for output %s", name); + goto error; + } + + cfg->pos.width = parse_uint(saveptr, "x"); + if(cfg->pos.width <= 0) { + wlr_log(WLR_ERROR, "Error parsing width of output configuration for output %s (hint: width must be larger than 0)", name); + goto error; + } + + cfg->pos.height = parse_uint(saveptr, " "); + if(cfg->pos.height <= 0) { + wlr_log(WLR_ERROR, "Error parsing height of output configuration for output %s (hint: height must e larger than 0)", name); + goto error; + } + + char *rate_str = strtok_r(NULL, " ", saveptr); + if(rate_str == NULL || strcmp(rate_str, "rate") != 0) { + wlr_log(WLR_ERROR, "Expected keyword \"rate\" in output configuration for output %s", name); + goto error; + } + + cfg->refresh_rate = parse_float(saveptr, " "); + if(cfg->refresh_rate <= 0.0) { + wlr_log(WLR_ERROR, "Error parsing refresh rate of output configuration for output %s", name); + goto error; + } + + cfg->output_name = strdup(name); + wl_list_insert(config_list, &cfg->link); + return 0; + +error: + free(cfg); + wlr_log(WLR_ERROR, "Output configuration must be of the form \"output pos res x rate "); + return -1; +} + int parse_rc_line(struct cg_server *server, char *line) { char *saveptr = NULL; // Used internally by strtok_r @@ -374,6 +473,10 @@ parse_rc_line(struct cg_server *server, char *line) { if(parse_and_run_exec(&saveptr) != 0) { return -1; } + } else if(strcmp(command, "output") == 0) { + if(parse_output_config(&server->output_config, &saveptr) != 0) { + return -1; + } } else if(strcmp(command, "workspaces") == 0) { char *nws_str = strtok_r(NULL, " ", &saveptr); if(nws_str == NULL) { diff --git a/server.h b/server.h index 92a9172..930cb56 100644 --- a/server.h +++ b/server.h @@ -11,6 +11,7 @@ struct cg_output; struct keybinding_list; struct wlr_output_layout; struct wlr_idle_inhibit_manager_v1; +struct cg_output_config; struct cg_server { struct wl_display *wl_display; @@ -35,6 +36,7 @@ struct cg_server { #endif struct keybinding_list *keybindings; + struct wl_list output_config; enum wl_output_transform output_transform; From 58746ee52fe49abf71d7ed528107c41e40230052 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Tue, 25 Feb 2020 12:57:49 +0000 Subject: [PATCH 003/122] Adjust version number for 1.0.3 release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6925b67..9fe4ce9 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.2', + version: '1.0.3', license: 'MIT', default_options: [ 'c_std=c11', From 0d4bb36068cf27854ba45423071111b285cee174 Mon Sep 17 00:00:00 2001 From: project-repo Date: Wed, 26 Feb 2020 07:55:25 +0100 Subject: [PATCH 004/122] Add documentation for "output" command --- man/cagebreak-config.5.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index bbf3096..6be7c60 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -182,6 +182,13 @@ by prepending a line with the # symbol. > Enter mode "``". After a keybinding is processed, return to default mode +**output pos res x rate ** + +> Configure the output "". and are the position of the monitor +> in pixels. The top-left monitor should have the coordinates 0 0. and +> specify the resolution in pixels and sets the refresh rate of +> the monitor (often this is 50 or 60). + **setmode ** > Set the default mode to `` From 33d245b60bfe86025d9244490bf144679af606f3 Mon Sep 17 00:00:00 2001 From: project-repo Date: Wed, 26 Feb 2020 07:56:28 +0100 Subject: [PATCH 005/122] Add example of "output" command usage --- examples/config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/config b/examples/config index cd7ee3c..0f0a5b0 100644 --- a/examples/config +++ b/examples/config @@ -70,3 +70,8 @@ definekey top XF86AudioLowerVolume exec pactl set-sink-mute 0 off&&amixer set Ma definekey top XF86AudioRaiseVolume exec pactl set-sink-mute 0 off&&amixer set Master 1%+ definekey top XF86MonBrightnessDown exec xbacklight -dec 1 definekey top XF86MonBrightnessUp exec xbacklight -inc 1 + +###################### +#Output configuration +###################### +#output eDP-1 pos 0 0 res 1366x768 rate 60 From 6fdc55c9a55edd187d63bf92f78365d4440fb845 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 28 Feb 2020 17:30:06 +0100 Subject: [PATCH 006/122] Add missing functionality to output configuration --- output.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/output.c b/output.c index c91f91b..7983983 100644 --- a/output.c +++ b/output.c @@ -528,6 +528,10 @@ void output_configure(struct cg_server* server, struct cg_output *output) { struct wlr_output *wlr_output = output->wlr_output; struct cg_output_config *config = output_find_config(server, wlr_output); + if(output->wlr_output->enabled) { + wlr_output_layout_remove(server->output_layout, wlr_output); + } + if(config == NULL) { wlr_output_layout_add_auto(server->output_layout, wlr_output); @@ -538,6 +542,7 @@ output_configure(struct cg_server* server, struct cg_output *output) { } } else { output_set_mode(wlr_output, config->pos.width, config->pos.height, config->refresh_rate); + wlr_output_layout_add(server->output_layout, wlr_output, config->pos.x, config->pos.y); } } From 6ff175b048ccdf44a8dc7249f6ef25b511f668dd Mon Sep 17 00:00:00 2001 From: project-repo Date: Sun, 1 Mar 2020 11:08:49 +0100 Subject: [PATCH 007/122] Fix bug in consumed modifier handling --- seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seat.c b/seat.c index 57c2b04..67f8e60 100644 --- a/seat.c +++ b/seat.c @@ -337,7 +337,7 @@ handle_key_event(struct cg_keyboard *keyboard, void *data) { xkb_mod_mask_t consumed_modifiers = xkb_state_key_get_consumed_mods2( keyboard->device->keyboard->xkb_state, keycode, - XKB_CONSUMED_MODE_XKB); + XKB_CONSUMED_MODE_GTK); if(handle_command_key_bindings(seat->server, syms[i], modifiers & ~consumed_modifiers, seat->mode, keyboard)) { From 8ebacb4a284f6e726584ae5ed2bb531a2f150897 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 2 Mar 2020 17:49:49 +0000 Subject: [PATCH 008/122] Improve README - Add working merge process specification --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8117d1f..2912c06 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 From f10395a16edf0e7a57d9a5c92f2df0ea1b80eea5 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 2 Mar 2020 18:17:25 +0000 Subject: [PATCH 009/122] Prepare 1.0.4 release --- Bugs.md | 7 +++++++ meson.build | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Bugs.md b/Bugs.md index 90758b8..5bea08a 100644 --- a/Bugs.md +++ b/Bugs.md @@ -26,3 +26,10 @@ 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. diff --git a/meson.build b/meson.build index 9fe4ce9..4387ce7 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.3', + version: '1.0.4', license: 'MIT', default_options: [ 'c_std=c11', From 54991cb6386a828aa721ab4d923285578f847b9d Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 6 Mar 2020 20:51:05 +0100 Subject: [PATCH 010/122] Unify parsing of config file --- keybinding.c | 80 +++++++- keybinding.h | 9 + parse.c | 537 +++++++++++++++++++++++++-------------------------- 3 files changed, 351 insertions(+), 275 deletions(-) diff --git a/keybinding.c b/keybinding.c index 2d5abdf..45a0021 100644 --- a/keybinding.c +++ b/keybinding.c @@ -54,12 +54,19 @@ find_keybinding(const struct keybinding_list *list, } void -keybinding_free(struct keybinding *keybinding) { +keybinding_free(struct keybinding *keybinding, bool recursive) { switch(keybinding->action) { + case KEYBINDING_DEFINEMODE: case KEYBINDING_RUN_COMMAND: if(keybinding->data.c != NULL) { free(keybinding->data.c); } + break; + case KEYBINDING_DEFINEKEY: + if(keybinding->data.kb != NULL && recursive) { + keybinding_free(keybinding->data.kb, true); + } + break; default: break; } @@ -79,7 +86,7 @@ keybinding_list_push(struct keybinding_list *list, * exist*/ struct keybinding **found_keybinding = find_keybinding(list, keybinding); if(found_keybinding != NULL) { - keybinding_free(*found_keybinding); + keybinding_free(*found_keybinding,true); *found_keybinding = keybinding; wlr_log(WLR_DEBUG, "A keybinding was found twice in the config file."); } else { @@ -101,7 +108,7 @@ keybinding_list_init() { void keybinding_list_free(struct keybinding_list *list) { for(unsigned int i = 0; i < list->length; ++i) { - keybinding_free(list->keybindings[i]); + keybinding_free(list->keybindings[i], true); } free(list->keybindings); free(list); @@ -634,6 +641,7 @@ keybinding_show_time(struct cg_server *server) { msg[strcspn(msg, "\n")] = '\0'; /* Remove the newline */ message_printf(server->curr_output, "%s", msg); + free(msg); } void @@ -670,6 +678,60 @@ keybinding_move_view_to_next_output(struct cg_server *server) { } } +void +keybinding_set_nws(struct cg_server *server, int nws) { + struct cg_output *output; + wl_list_for_each(output, &server->outputs, link) { + for(unsigned int i = nws; i < server->nws; ++i) { + workspace_free(output->workspaces[i]); + } + struct cg_workspace **new_workspaces = realloc( + output->workspaces, nws * sizeof(struct cg_workspace *)); + if(new_workspaces == NULL) { + wlr_log(WLR_ERROR, "Error reallocating memory for workspaces."); + return; + } + output->workspaces = new_workspaces; + for(int i = server->nws; i < nws; ++i) { + output->workspaces[i] = full_screen_workspace(output); + wl_list_init(&output->workspaces[i]->views); + wl_list_init(&output->workspaces[i]->unmanaged_views); + } + + if(output->curr_workspace >= nws) { + output->curr_workspace = nws-1; + } + } + server->nws = nws; +} + +void +keybinding_definemode(struct cg_server *server, char* mode) { + int length = 0; + while(server->modes[length++] != NULL); + char **tmp = realloc(server->modes, (length + 1) * sizeof(char *)); + if(tmp == NULL) { + wlr_log(WLR_ERROR, "Could not allocate memory for storing modes."); + return; + } + server->modes = tmp; + server->modes[length] = NULL; + + server->modes[length - 1] = strdup(mode); +} + +void +keybinding_definekey(struct cg_server *server, struct keybinding *kb) { + keybinding_list_push(server->keybindings,kb); +} + +void +keybinding_set_background(struct cg_server *server, float* bg) { + server->bg_color[0] = bg[0]; + server->bg_color[1] = bg[1]; + server->bg_color[2] = bg[2]; +} + void keybinding_move_view_to_workspace(struct cg_server *server, uint32_t ws) { struct cg_view *view = @@ -808,6 +870,18 @@ run_action(enum keybinding_action action, struct cg_server *server, keybinding_move_view_to_next_output(server); break; } + case KEYBINDING_DEFINEKEY: + keybinding_definekey(server,data.kb); + break; + case KEYBINDING_BACKGROUND: + keybinding_set_background(server, data.color); + break; + case KEYBINDING_DEFINEMODE: + keybinding_definemode(server, data.c); + break; + case KEYBINDING_WORKSPACES: + keybinding_set_nws(server, data.i); + break; default: { wlr_log(WLR_ERROR, "run_action was called with a value not present in \"enum " diff --git a/keybinding.h b/keybinding.h index d06bbbb..42ad114 100644 --- a/keybinding.h +++ b/keybinding.h @@ -43,6 +43,11 @@ enum keybinding_action { KEYBINDING_FOCUS_RIGHT, KEYBINDING_FOCUS_TOP, KEYBINDING_FOCUS_BOTTOM, + + KEYBINDING_DEFINEKEY, // data.kb is the keybinding definition + KEYBINDING_BACKGROUND, //data.color is the background color + KEYBINDING_DEFINEMODE, //data.c is the mode name + KEYBINDING_WORKSPACES, //data.i is the number of workspaces }; union keybinding_params { @@ -50,6 +55,8 @@ union keybinding_params { uint32_t u; int32_t i; bool b; + float color[3]; + struct keybinding* kb; }; struct keybinding { @@ -82,5 +89,7 @@ keybinding_list_init(); int run_action(enum keybinding_action action, struct cg_server *server, union keybinding_params data); +void +keybinding_free(struct keybinding *keybinding, bool recursive); #endif /* end of include guard KEYBINDINGS_H */ diff --git a/parse.c b/parse.c index e8c7b15..7e09fce 100644 --- a/parse.c +++ b/parse.c @@ -10,167 +10,6 @@ #include "server.h" #include "workspace.h" -int -parse_action(struct cg_server *server, struct keybinding *keybinding, - char **saveptr) { - char *action = strtok_r(NULL, " ", saveptr); - if(action == NULL) { - wlr_log( - WLR_ERROR, - "Not enough parameters to \"bind\". Expected action to execute"); - return -1; - } - keybinding->data = (union keybinding_params){.c = NULL}; - if(strcmp(action, "vsplit") == 0) { - keybinding->action = KEYBINDING_SPLIT_VERTICAL; - } else if(strcmp(action, "hsplit") == 0) { - keybinding->action = KEYBINDING_SPLIT_HORIZONTAL; - } else if(strcmp(action, "quit") == 0) { - keybinding->action = KEYBINDING_QUIT; - } else if(strcmp(action, "focus") == 0) { - keybinding->action = KEYBINDING_CYCLE_TILES; - keybinding->data.b = false; - } else if(strcmp(action, "focusprev") == 0) { - keybinding->action = KEYBINDING_CYCLE_TILES; - keybinding->data.b = true; - } else if(strcmp(action, "next") == 0) { - keybinding->action = KEYBINDING_CYCLE_VIEWS; - keybinding->data.b = false; - } else if(strcmp(action, "prev") == 0) { - keybinding->action = KEYBINDING_CYCLE_VIEWS; - keybinding->data.b = true; - } else if(strcmp(action, "only") == 0) { - keybinding->action = KEYBINDING_LAYOUT_FULLSCREEN; - } else if(strcmp(action, "abort") == 0) { - keybinding->action = KEYBINDING_NOOP; - } else if(strcmp(action, "time") == 0) { - keybinding->action = KEYBINDING_SHOW_TIME; - } else if(strcmp(action, "nextscreen") == 0) { - keybinding->action = KEYBINDING_CYCLE_OUTPUT; - keybinding->data.b = false; - } else if(strcmp(action, "prevscreen") == 0) { - keybinding->action = KEYBINDING_CYCLE_OUTPUT; - keybinding->data.b = true; - } else if(strcmp(action, "exec") == 0) { - keybinding->action = KEYBINDING_RUN_COMMAND; - if(*saveptr == NULL) { - wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected " - "string to execute."); - return -1; - } - keybinding->data.c = strdup(*saveptr); - } else if(strcmp(action, "resizeleft") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; - keybinding->data.i = -10; - } else if(strcmp(action, "resizeright") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; - keybinding->data.i = 10; - } else if(strcmp(action, "resizedown") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; - keybinding->data.i = 10; - } else if(strcmp(action, "resizeup") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; - keybinding->data.i = -10; - } else if(strcmp(action, "workspace") == 0) { - keybinding->action = KEYBINDING_SWITCH_WORKSPACE; - char *nws_str = strtok_r(NULL, " ", saveptr); - if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspace\" action, got none."); - return -1; - } - - long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { - wlr_log(WLR_ERROR, - "Requested binding for workspace %li, but have %u", ws, - server->nws); - return -1; - } - keybinding->data.u = ws - 1; - } else if(strcmp(action, "movetoworkspace") == 0) { - keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE; - char *nws_str = strtok_r(NULL, " ", saveptr); - if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspace\" action, got none."); - return -1; - } - - long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { - wlr_log( - WLR_ERROR, - "Requested binding for moving to workspace %li, but have %u", - ws, server->nws); - return -1; - } - keybinding->data.u = ws - 1; - } else if(strcmp(action, "exchangeleft") == 0) { - keybinding->action = KEYBINDING_SWAP_LEFT; - } else if(strcmp(action, "exchangeright") == 0) { - keybinding->action = KEYBINDING_SWAP_RIGHT; - } else if(strcmp(action, "exchangeup") == 0) { - keybinding->action = KEYBINDING_SWAP_TOP; - } else if(strcmp(action, "exchangedown") == 0) { - keybinding->action = KEYBINDING_SWAP_BOTTOM; - } else if(strcmp(action, "focusleft") == 0) { - keybinding->action = KEYBINDING_FOCUS_LEFT; - } else if(strcmp(action, "focusright") == 0) { - keybinding->action = KEYBINDING_FOCUS_RIGHT; - } else if(strcmp(action, "focusup") == 0) { - keybinding->action = KEYBINDING_FOCUS_TOP; - } else if(strcmp(action, "focusdown") == 0) { - keybinding->action = KEYBINDING_FOCUS_BOTTOM; - } else if(strcmp(action, "movetonextscreen") == 0) { - keybinding->action = KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT; - } else if(strcmp(action, "switchvt") == 0) { - keybinding->action = KEYBINDING_CHANGE_TTY; - char *ntty = strtok_r(NULL, " ", saveptr); - if(ntty == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"switchvt\" command, got none."); - return -1; - } - long tty = strtol(ntty, NULL, 10); - keybinding->data.u = tty; - } else if(strcmp(action, "mode") == 0) { - keybinding->action = KEYBINDING_SWITCH_MODE; - char *mode = strtok_r(NULL, " ", saveptr); - if(mode == NULL) { - wlr_log(WLR_ERROR, - "Expected mode after \"switch_mode\". Got nothing."); - return -1; - } - int mode_idx = get_mode_index_from_name(server->modes, mode); - if(mode_idx == -1) { - wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode); - return -1; - } - keybinding->data.u = (unsigned int)mode_idx; - } else if(strcmp(action, "setmode") == 0) { - keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE; - char *mode = strtok_r(NULL, " ", saveptr); - if(mode == NULL) { - wlr_log( - WLR_ERROR, - "Expected mode after \"switch_default_mode\". Got nothing."); - return -1; - } - int mode_idx = get_mode_index_from_name(server->modes, mode); - if(mode_idx == -1) { - wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode", - mode); - return -1; - } - keybinding->data.u = (unsigned int)mode_idx; - } else { - wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action); - return -1; - } - return 0; -} - /* parses a key definition (e.g. "S-Tab") and sets key and modifiers in * keybinding respectivly */ int @@ -218,6 +57,9 @@ parse_key(struct keybinding *keybinding, const char *key_def) { return 0; } +int +parse_command(struct cg_server *server, struct keybinding *keybinding, char *saveptr); + /* Parse a keybinding definition and return it if successful, else return NULL */ struct keybinding * @@ -229,188 +71,339 @@ parse_keybinding(struct cg_server *server, char **saveptr) { free(keybinding); return NULL; } - if(parse_action(server, keybinding, saveptr) != 0) { + if(parse_command(server, keybinding, *saveptr) != 0) { free(keybinding); return NULL; } return keybinding; } -int -parse_bind(struct cg_server *server, struct keybinding_list *list, - char **saveptr) { +struct keybinding * +parse_bind(struct cg_server *server, char **saveptr) { struct keybinding *keybinding = parse_keybinding(server, saveptr); if(keybinding == NULL) { wlr_log(WLR_ERROR, "Could not parse keybinding for \"bind\"."); - return -1; + return NULL; } keybinding->mode = 1; - keybinding_list_push(list, keybinding); - return 0; + return keybinding; } -int -parse_definekey(struct cg_server *server, struct keybinding_list *list, - char **saveptr) { +struct keybinding * +parse_definekey(struct cg_server *server, char **saveptr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { wlr_log(WLR_ERROR, "Too few arguments to \"definekey\". Expected mode"); - return -1; + return NULL; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { wlr_log(WLR_ERROR, "Unknown mode \"%s\"", mode); - return -1; + return NULL; } struct keybinding *keybinding = parse_keybinding(server, saveptr); if(keybinding == NULL) { wlr_log(WLR_ERROR, "Could not parse keybinding for \"definekey\""); - return -1; + return NULL; } keybinding->mode = mode_idx; - keybinding_list_push(list, keybinding); - return 0; + return keybinding; } int -parse_and_run_exec(char **saveptr) { - return run_action(KEYBINDING_RUN_COMMAND, NULL, - (union keybinding_params){.c = *saveptr}); -} - -int -parse_background(struct cg_server *server, char **saveptr) { +parse_background(struct cg_server *server, float *color, char **saveptr) { /* Read rgb numbers */ for(unsigned int i = 0; i < 3; ++i) { - char *nstr = strtok_r(NULL, " ", saveptr); - if(nstr == NULL) { + char *nstr = strtok_r(NULL, " \n", saveptr); + int nstrlen; + if(nstr == NULL||(nstrlen = strlen(nstr))== 0) { wlr_log(WLR_ERROR, "Expected three space-separated numbers (rgb) for " "background color setting. Got %d.", i); return -1; } + if(nstr[nstrlen-1] == '\n') { + nstr[nstrlen-1] = '\0'; + --nstrlen; + } char *endptr = NULL; float nval = strtof(nstr, &endptr); - if(endptr == nstr) { + if(endptr != nstr+nstrlen) { wlr_log( WLR_ERROR, - "Could not parse number \"%s\" für background color setting.", + "Could not parse number \"%s\" for background color setting.", nstr); return -1; } - server->bg_color[i] = nval; + if(nval<0||nval>1) { + wlr_log(WLR_ERROR, "Expected a number between 0 and 1 for setting of background color. Got %f.",nval); + return -1; + } + color[i] = nval; } return 0; } -int -parse_escape(struct keybinding_list *list, char **saveptr) { +struct keybinding * +parse_escape(char **saveptr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); char *key = strtok_r(NULL, " ", saveptr); if(parse_key(keybinding, key) != 0) { wlr_log(WLR_ERROR, "Could not parse key definition \"%s\" for \"escape\"", key); free(keybinding); - return -1; + return NULL; } keybinding->mode = 0; //"top" mode keybinding->action = KEYBINDING_SWITCH_MODE; keybinding->data.u = 1; //"root" mode - keybinding_list_push(list, keybinding); - return 0; + return keybinding; } -int -parse_definemode(char ***modes, char **saveptr) { - int length = 0; - while((*modes)[length++] != NULL) - ; - char **tmp = realloc(*modes, (length + 1) * sizeof(char *)); - if(tmp == NULL) { - wlr_log(WLR_ERROR, "Could not allocate memory for storing modes."); - return -1; - } - *modes = tmp; - (*modes)[length] = NULL; - +char* +parse_definemode(char **saveptr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { wlr_log(WLR_ERROR, "Expected mode to succeed \"definemode\" keyword."); + return NULL; + } + return strdup(mode); +} + +int +parse_workspaces(char **saveptr) { + char *nws_str = strtok_r(NULL, " ", saveptr); + if(nws_str == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"workspaces\" command, got none."); + return -1; + } + long nws = strtol(nws_str, NULL, 10); + if(!(1 <= nws && nws <= 30)) { + wlr_log(WLR_ERROR, + "More than 30 workspaces are not supported. Received %li", + nws); + return -1; + } + return nws; +} + +int +parse_command(struct cg_server *server, struct keybinding *keybinding, + char *saveptr) { + char *action = strtok_r(NULL, " ", &saveptr); + if(action == NULL) { + wlr_log( + WLR_ERROR, + "Expected an action to parse, got none."); + return -1; + } + keybinding->data = (union keybinding_params){.c = NULL}; + if(strcmp(action, "vsplit") == 0) { + keybinding->action = KEYBINDING_SPLIT_VERTICAL; + } else if(strcmp(action, "hsplit") == 0) { + keybinding->action = KEYBINDING_SPLIT_HORIZONTAL; + } else if(strcmp(action, "quit") == 0) { + keybinding->action = KEYBINDING_QUIT; + } else if(strcmp(action, "focus") == 0) { + keybinding->action = KEYBINDING_CYCLE_TILES; + keybinding->data.b = false; + } else if(strcmp(action, "focusprev") == 0) { + keybinding->action = KEYBINDING_CYCLE_TILES; + keybinding->data.b = true; + } else if(strcmp(action, "next") == 0) { + keybinding->action = KEYBINDING_CYCLE_VIEWS; + keybinding->data.b = false; + } else if(strcmp(action, "prev") == 0) { + keybinding->action = KEYBINDING_CYCLE_VIEWS; + keybinding->data.b = true; + } else if(strcmp(action, "only") == 0) { + keybinding->action = KEYBINDING_LAYOUT_FULLSCREEN; + } else if(strcmp(action, "abort") == 0) { + keybinding->action = KEYBINDING_NOOP; + } else if(strcmp(action, "time") == 0) { + keybinding->action = KEYBINDING_SHOW_TIME; + } else if(strcmp(action, "nextscreen") == 0) { + keybinding->action = KEYBINDING_CYCLE_OUTPUT; + keybinding->data.b = false; + } else if(strcmp(action, "prevscreen") == 0) { + keybinding->action = KEYBINDING_CYCLE_OUTPUT; + keybinding->data.b = true; + } else if(strcmp(action, "exec") == 0) { + keybinding->action = KEYBINDING_RUN_COMMAND; + if(saveptr == NULL) { + wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected " + "string to execute."); + return -1; + } + keybinding->data.c = strdup(saveptr); + } else if(strcmp(action, "resizeleft") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; + keybinding->data.i = -10; + } else if(strcmp(action, "resizeright") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; + keybinding->data.i = 10; + } else if(strcmp(action, "resizedown") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; + keybinding->data.i = 10; + } else if(strcmp(action, "resizeup") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; + keybinding->data.i = -10; + } else if(strcmp(action, "workspace") == 0) { + keybinding->action = KEYBINDING_SWITCH_WORKSPACE; + char *nws_str = strtok_r(NULL, " ", &saveptr); + if(nws_str == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"workspace\" action, got none."); + return -1; + } + + long ws = strtol(nws_str, NULL, 10); + if(!(1 <= ws && ws <= server->nws)) { + wlr_log(WLR_ERROR, + "Requested binding for workspace %li, but have %u", ws, + server->nws); + return -1; + } + keybinding->data.u = ws - 1; + } else if(strcmp(action, "movetoworkspace") == 0) { + keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE; + char *nws_str = strtok_r(NULL, " ", &saveptr); + if(nws_str == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"workspace\" action, got none."); + return -1; + } + + long ws = strtol(nws_str, NULL, 10); + if(!(1 <= ws && ws <= server->nws)) { + wlr_log( + WLR_ERROR, + "Requested binding for moving to workspace %li, but have %u", + ws, server->nws); + return -1; + } + keybinding->data.u = ws - 1; + } else if(strcmp(action, "exchangeleft") == 0) { + keybinding->action = KEYBINDING_SWAP_LEFT; + } else if(strcmp(action, "exchangeright") == 0) { + keybinding->action = KEYBINDING_SWAP_RIGHT; + } else if(strcmp(action, "exchangeup") == 0) { + keybinding->action = KEYBINDING_SWAP_TOP; + } else if(strcmp(action, "exchangedown") == 0) { + keybinding->action = KEYBINDING_SWAP_BOTTOM; + } else if(strcmp(action, "focusleft") == 0) { + keybinding->action = KEYBINDING_FOCUS_LEFT; + } else if(strcmp(action, "focusright") == 0) { + keybinding->action = KEYBINDING_FOCUS_RIGHT; + } else if(strcmp(action, "focusup") == 0) { + keybinding->action = KEYBINDING_FOCUS_TOP; + } else if(strcmp(action, "focusdown") == 0) { + keybinding->action = KEYBINDING_FOCUS_BOTTOM; + } else if(strcmp(action, "movetonextscreen") == 0) { + keybinding->action = KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT; + } else if(strcmp(action, "switchvt") == 0) { + keybinding->action = KEYBINDING_CHANGE_TTY; + char *ntty = strtok_r(NULL, " ", &saveptr); + if(ntty == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"switchvt\" command, got none."); + return -1; + } + long tty = strtol(ntty, NULL, 10); + keybinding->data.u = tty; + } else if(strcmp(action, "mode") == 0) { + keybinding->action = KEYBINDING_SWITCH_MODE; + char *mode = strtok_r(NULL, " ", &saveptr); + if(mode == NULL) { + wlr_log(WLR_ERROR, + "Expected mode after \"switch_mode\". Got nothing."); + return -1; + } + int mode_idx = get_mode_index_from_name(server->modes, mode); + if(mode_idx == -1) { + wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode); + return -1; + } + keybinding->data.u = (unsigned int)mode_idx; + } else if(strcmp(action, "setmode") == 0) { + keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE; + char *mode = strtok_r(NULL, " ", &saveptr); + if(mode == NULL) { + wlr_log( + WLR_ERROR, + "Expected mode after \"switch_default_mode\". Got nothing."); + return -1; + } + int mode_idx = get_mode_index_from_name(server->modes, mode); + if(mode_idx == -1) { + wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode", + mode); + return -1; + } + keybinding->data.u = (unsigned int)mode_idx; + } else if(strcmp(action, "bind") == 0) { + keybinding->action = KEYBINDING_DEFINEKEY; + keybinding->data.kb = parse_bind(server, &saveptr); + if(keybinding->data.kb == NULL) { + return -1; + } + } else if(strcmp(action, "definekey") == 0) { + keybinding->action = KEYBINDING_DEFINEKEY; + keybinding->data.kb = parse_definekey(server, &saveptr); + if(keybinding->data.kb == NULL) { + return -1; + } + } else if(strcmp(action, "background") == 0) { + keybinding->action = KEYBINDING_BACKGROUND; + if(parse_background(server, keybinding->data.color,&saveptr) != 0) { + return -1; + } + } else if(strcmp(action, "escape") == 0) { + keybinding->action = KEYBINDING_DEFINEKEY; + keybinding->data.kb = parse_escape(&saveptr); + if(keybinding->data.kb == NULL) { + return -1; + } + } else if(strcmp(action, "definemode") == 0) { + keybinding->action = KEYBINDING_DEFINEMODE; + keybinding->data.c = parse_definemode(&saveptr); + if(keybinding->data.c == NULL) { + return -1; + } + } else if(strcmp(action, "workspaces") == 0) { + keybinding->action = KEYBINDING_WORKSPACES; + keybinding->data.i=parse_workspaces(&saveptr); + if(keybinding->data.i<0) { + return -1; + } + } else { + wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action); return -1; } - (*modes)[length - 1] = strdup(mode); return 0; } int parse_rc_line(struct cg_server *server, char *line) { - char *saveptr = NULL; // Used internally by strtok_r - char *command = strtok_r(line, " ", &saveptr); - if(command == NULL) { - return 0; - } - if(strcmp(command, "bind") == 0) { - if(parse_bind(server, server->keybindings, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "definekey") == 0) { - if(parse_definekey(server, server->keybindings, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "background") == 0) { - if(parse_background(server, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "escape") == 0) { - if(parse_escape(server->keybindings, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "definemode") == 0) { - if(parse_definemode(&server->modes, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "exec") == 0) { - if(parse_and_run_exec(&saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "workspaces") == 0) { - char *nws_str = strtok_r(NULL, " ", &saveptr); - if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspaces\" command, got none."); - return -1; - } - long nws = strtol(nws_str, NULL, 10); - if(!(1 <= nws && nws <= 30)) { - wlr_log(WLR_ERROR, - "More than 30 workspaces are not supported. Received %li", - nws); - return -1; - } - struct cg_output *output; - wl_list_for_each(output, &server->outputs, link) { - for(unsigned int i = nws; i < server->nws; ++i) { - free(output->workspaces[i]); - } - struct cg_workspace **new_workspaces = realloc( - output->workspaces, nws * sizeof(struct cg_workspace *)); - if(new_workspaces == NULL) { - wlr_log(WLR_ERROR, "Error reallocating memory for workspaces."); - return -1; - } - output->workspaces = new_workspaces; - for(unsigned int i = server->nws; i < nws; ++i) { - output->workspaces[i] = full_screen_workspace(output); - wl_list_init(&output->workspaces[i]->views); - wl_list_init(&output->workspaces[i]->unmanaged_views); - } - } - server->nws = nws; - } else { - wlr_log(WLR_ERROR, "Unsupported command \"%s\" in config file", - command); + char *saveptr = strdup(line); // Used internally by strtok_r + + struct keybinding *keybinding = malloc(sizeof(struct keybinding)); + if(keybinding == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate memory for temporary keybinding struct."); + free(keybinding); + free(saveptr); return -1; } + if(parse_command(server, keybinding, saveptr) != 0) { + wlr_log(WLR_ERROR, "Error parsing config file."); + free(keybinding); + free(saveptr); + return -1; + } + run_action(keybinding->action, server, keybinding->data); + keybinding_free(keybinding, false); + free(saveptr); return 0; } From cb46e463a3f65b1a58086fc3ffbecc1bf494a9d6 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 6 Mar 2020 21:04:29 +0100 Subject: [PATCH 011/122] Fix memory leaks --- message.c | 1 + workspace.c | 1 + 2 files changed, 2 insertions(+) diff --git a/message.c b/message.c index 66e09dd..c7b6b96 100644 --- a/message.c +++ b/message.c @@ -147,6 +147,7 @@ message_printf(struct cg_output *output, const char *fmt, ...) { message_set_output(output, buffer, box, CG_MESSAGE_TOP_RIGHT); free(buffer); + free(box); alarm(output->server->message_timeout); } diff --git a/workspace.c b/workspace.c index 8ed010e..7027710 100644 --- a/workspace.c +++ b/workspace.c @@ -51,6 +51,7 @@ workspace_focus_tile(struct cg_workspace *ws, struct cg_tile *tile) { box->x = tile->tile.x + tile->tile.width / 2; box->y = tile->tile.y + tile->tile.height / 2; message_printf_pos(ws->output, box, CG_MESSAGE_CENTER, "Current frame"); + free(box); } void From e7ca6d693ffebb716445286a89d35e61a45ab9fb Mon Sep 17 00:00:00 2001 From: project-repo Date: Thu, 12 Mar 2020 22:08:52 +0100 Subject: [PATCH 012/122] Fix crash on view destroy --- view.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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; From bdfbc4cd32b7e3632ef659340a0bfd536b6583d5 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Fri, 13 Mar 2020 13:07:01 +0000 Subject: [PATCH 013/122] Prepare 1.0.5 release - Summaize bug - Increment version number --- Bugs.md | 22 ++++++++++++++++++++++ meson.build | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Bugs.md b/Bugs.md index 5bea08a..491d2c6 100644 --- a/Bugs.md +++ b/Bugs.md @@ -33,3 +33,25 @@ Steps to reproduce: * 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/meson.build b/meson.build index 4387ce7..46f2547 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.4', + version: '1.0.5', license: 'MIT', default_options: [ 'c_std=c11', From 56ee91d396ec181330008d6d3b0262ac503aae80 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:49:16 +0100 Subject: [PATCH 014/122] Cleanup cairo and pandoc structures on exit --- cagebreak.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cagebreak.c b/cagebreak.c index 4a71480..aeddf84 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -10,6 +10,9 @@ #include "config.h" +#include +#include +#include #include #include #include @@ -533,5 +536,10 @@ end: with a proper wl_display. */ wl_display_destroy(server.wl_display); wlr_output_layout_destroy(server.output_layout); + + pango_cairo_font_map_set_default(NULL); + cairo_debug_reset_static_data(); + FcFini(); + return ret; } From 0c7719011bf3db78be9545acb67c00ea118d8746 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:49:50 +0100 Subject: [PATCH 015/122] Add fontconfig as dependency --- meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meson.build b/meson.build index 6925b67..9904430 100644 --- a/meson.build +++ b/meson.build @@ -64,6 +64,7 @@ xkbcommon = dependency('xkbcommon') cairo = dependency('cairo') pango = dependency('pango') pangocairo = dependency('pangocairo') +fontconfig = dependency('fontconfig') math = cc.find_library('m') wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') @@ -180,6 +181,7 @@ cagebreak_dependencies = [ wayland_cursor, wlroots, xkbcommon, + fontconfig, pixman, math, pango, From 3035866d78fb165aed8143d56c67eeee2f1b4cf2 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:50:42 +0100 Subject: [PATCH 016/122] Fix parsing bugs --- parse.c | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/parse.c b/parse.c index 7e09fce..5b0ac6e 100644 --- a/parse.c +++ b/parse.c @@ -58,7 +58,8 @@ parse_key(struct keybinding *keybinding, const char *key_def) { } int -parse_command(struct cg_server *server, struct keybinding *keybinding, char *saveptr); +parse_command(struct cg_server *server, struct keybinding *keybinding, + char *saveptr); /* Parse a keybinding definition and return it if successful, else return NULL */ @@ -116,28 +117,31 @@ parse_background(struct cg_server *server, float *color, char **saveptr) { for(unsigned int i = 0; i < 3; ++i) { char *nstr = strtok_r(NULL, " \n", saveptr); int nstrlen; - if(nstr == NULL||(nstrlen = strlen(nstr))== 0) { + if(nstr == NULL || (nstrlen = strlen(nstr)) == 0) { wlr_log(WLR_ERROR, "Expected three space-separated numbers (rgb) for " "background color setting. Got %d.", i); return -1; } - if(nstr[nstrlen-1] == '\n') { - nstr[nstrlen-1] = '\0'; + if(nstr[nstrlen - 1] == '\n') { + nstr[nstrlen - 1] = '\0'; --nstrlen; } char *endptr = NULL; float nval = strtof(nstr, &endptr); - if(endptr != nstr+nstrlen) { + if(endptr != nstr + nstrlen) { wlr_log( WLR_ERROR, "Could not parse number \"%s\" for background color setting.", nstr); return -1; } - if(nval<0||nval>1) { - wlr_log(WLR_ERROR, "Expected a number between 0 and 1 for setting of background color. Got %f.",nval); + if(nval < 0 || nval > 1) { + wlr_log(WLR_ERROR, + "Expected a number between 0 and 1 for setting of " + "background color. Got %f.", + nval); return -1; } color[i] = nval; @@ -161,7 +165,7 @@ parse_escape(char **saveptr) { return keybinding; } -char* +char * parse_definemode(char **saveptr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { @@ -182,8 +186,7 @@ parse_workspaces(char **saveptr) { long nws = strtol(nws_str, NULL, 10); if(!(1 <= nws && nws <= 30)) { wlr_log(WLR_ERROR, - "More than 30 workspaces are not supported. Received %li", - nws); + "More than 30 workspaces are not supported. Received %li", nws); return -1; } return nws; @@ -191,12 +194,10 @@ parse_workspaces(char **saveptr) { int parse_command(struct cg_server *server, struct keybinding *keybinding, - char *saveptr) { + char *saveptr) { char *action = strtok_r(NULL, " ", &saveptr); if(action == NULL) { - wlr_log( - WLR_ERROR, - "Expected an action to parse, got none."); + wlr_log(WLR_ERROR, "Expected an action to parse, got none."); return -1; } keybinding->data = (union keybinding_params){.c = NULL}; @@ -260,10 +261,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { - wlr_log(WLR_ERROR, - "Requested binding for workspace %li, but have %u", ws, - server->nws); + if(ws < 1) { + wlr_log(WLR_ERROR, "Workspace number must be a integer number larger or equal to 1. Got %ld", ws); return -1; } keybinding->data.u = ws - 1; @@ -277,11 +276,9 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { + if(ws < 1) { wlr_log( - WLR_ERROR, - "Requested binding for moving to workspace %li, but have %u", - ws, server->nws); + WLR_ERROR, "Workspace number must be an integer larger or equal to 1. Got %ld", ws); return -1; } keybinding->data.u = ws - 1; @@ -357,7 +354,7 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } } else if(strcmp(action, "background") == 0) { keybinding->action = KEYBINDING_BACKGROUND; - if(parse_background(server, keybinding->data.color,&saveptr) != 0) { + if(parse_background(server, keybinding->data.color, &saveptr) != 0) { return -1; } } else if(strcmp(action, "escape") == 0) { @@ -374,8 +371,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } } else if(strcmp(action, "workspaces") == 0) { keybinding->action = KEYBINDING_WORKSPACES; - keybinding->data.i=parse_workspaces(&saveptr); - if(keybinding->data.i<0) { + keybinding->data.i = parse_workspaces(&saveptr); + if(keybinding->data.i < 0) { return -1; } } else { @@ -391,7 +388,8 @@ parse_rc_line(struct cg_server *server, char *line) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate memory for temporary keybinding struct."); + wlr_log(WLR_ERROR, + "Failed to allocate memory for temporary keybinding struct."); free(keybinding); free(saveptr); return -1; From f6240e9f687c2b101d4ae3754bd5ef9918995e9b Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:50:52 +0100 Subject: [PATCH 017/122] Fix potential double-free --- workspace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/workspace.c b/workspace.c index 7027710..8ed010e 100644 --- a/workspace.c +++ b/workspace.c @@ -51,7 +51,6 @@ workspace_focus_tile(struct cg_workspace *ws, struct cg_tile *tile) { box->x = tile->tile.x + tile->tile.width / 2; box->y = tile->tile.y + tile->tile.height / 2; message_printf_pos(ws->output, box, CG_MESSAGE_CENTER, "Current frame"); - free(box); } void From 8ffac22f1b4f175ccd9ff4b0f89c25e434bef829 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:51:05 +0100 Subject: [PATCH 018/122] Fix conventions for system include --- pango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pango.c b/pango.c index 035ac9b..ef3df10 100644 --- a/pango.c +++ b/pango.c @@ -1,4 +1,4 @@ -#include "cairo.h" +#include #include #include #include From b11e2409c6e7db5ca4fedd0392659b41e7f4f997 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:51:35 +0100 Subject: [PATCH 019/122] Add support for disabling messages when fuzzing --- message.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/message.c b/message.c index c7b6b96..c41e1a4 100644 --- a/message.c +++ b/message.c @@ -46,6 +46,12 @@ create_message_texture(const char *string, const struct cg_output *output) { cairo_surface_t *dummy_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); cairo_t *c = cairo_create(dummy_surface); + + // This occurs when we are fuzzing. In that case, do nothing + if(c == NULL) { + return NULL; + } + cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST); cairo_font_options_t *fo = cairo_font_options_create(); cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); @@ -147,7 +153,6 @@ message_printf(struct cg_output *output, const char *fmt, ...) { message_set_output(output, buffer, box, CG_MESSAGE_TOP_RIGHT); free(buffer); - free(box); alarm(output->server->message_timeout); } From 30bfa9b68928871b8a3f471d95f258ca27e1a27a Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:52:41 +0100 Subject: [PATCH 020/122] Fix bugs in keybinding execution --- keybinding.c | 111 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 33 deletions(-) diff --git a/keybinding.c b/keybinding.c index 45a0021..9bf5734 100644 --- a/keybinding.c +++ b/keybinding.c @@ -86,7 +86,7 @@ keybinding_list_push(struct keybinding_list *list, * exist*/ struct keybinding **found_keybinding = find_keybinding(list, keybinding); if(found_keybinding != NULL) { - keybinding_free(*found_keybinding,true); + keybinding_free(*found_keybinding, true); *found_keybinding = keybinding; wlr_log(WLR_DEBUG, "A keybinding was found twice in the config file."); } else { @@ -255,10 +255,27 @@ is_between_strict(int a, int b, int x) { return a < x && x < b; } +int +get_compl_coord(struct cg_tile *tile, int *(*get_coord)(struct cg_tile *tile)) { + return tile->tile.x + tile->tile.y - *get_coord(tile); +} + +int +get_compl_dim(struct cg_tile *tile, int *(*get_dim)(struct cg_tile *tile)) { + return tile->tile.width + tile->tile.height - *get_dim(tile); +} + bool -resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset, - int dim_offset, int *(*get_coord)(struct cg_tile *tile), - int *(*get_dim)(struct cg_tile *tile)) { +intervalls_intersect(int x1, int x2, int y1, int y2) { + return y2 > x1 && y1 < x2; +} + +bool +resize_allowed(struct cg_tile *tile, const struct cg_tile *parent, + int coord_offset, int dim_offset, + int *(*get_coord)(struct cg_tile *tile), + int *(*get_dim)(struct cg_tile *tile), struct cg_tile *orig) { + if(coord_offset == 0 && dim_offset == 0) { return true; } else if(*get_dim(tile) - coord_offset + dim_offset <= 0) { @@ -267,17 +284,25 @@ resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset, for(struct cg_tile *it = tile->next; it != tile && it != NULL; it = it->next) { - if(it == parent) { + if(it == parent || it == orig) { continue; } - if(it->tile.x == tile->tile.x + tile->tile.width) { - if(!resize_allowed(it, tile, dim_offset, -dim_offset, get_coord, - get_dim)) { - return false; - } - } else if(it->tile.x + it->tile.width == tile->tile.x) { - if(!resize_allowed(it, tile, 0, coord_offset, get_coord, get_dim)) { - return false; + if(intervalls_intersect( + get_compl_coord(tile, get_coord), + get_compl_coord(tile, get_coord) + get_compl_dim(tile, get_dim), + get_compl_coord(it, get_coord), + get_compl_coord(it, get_coord) + get_compl_dim(it, get_dim))) { + if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) { + if(!resize_allowed(it, tile, dim_offset + coord_offset, + -dim_offset - coord_offset, get_coord, + get_dim, orig)) { + return false; + } + } else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) { + if(!resize_allowed(it, tile, 0, coord_offset, get_coord, + get_dim, orig)) { + return false; + } } } } @@ -287,20 +312,27 @@ resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset, void resize(struct cg_tile *tile, const struct cg_tile *parent, int coord_offset, int dim_offset, int *(*get_coord)(struct cg_tile *tile), - int *(*get_dim)(struct cg_tile *tile)) { + int *(*get_dim)(struct cg_tile *tile), struct cg_tile *orig) { if(coord_offset == 0 && dim_offset == 0) { return; } for(struct cg_tile *it = tile->next; it != tile && it != NULL; it = it->next) { - if(it == parent) { + if(it == parent || it == orig) { continue; } - if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) { - resize(it, tile, dim_offset, -dim_offset, get_coord, get_dim); - } else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) { - resize(it, tile, 0, coord_offset, get_coord, get_dim); + if(intervalls_intersect( + get_compl_coord(tile, get_coord), + get_compl_coord(tile, get_coord) + get_compl_dim(tile, get_dim), + get_compl_coord(it, get_coord), + get_compl_coord(it, get_coord) + get_compl_dim(it, get_dim))) { + if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) { + resize(it, tile, dim_offset + coord_offset, + -dim_offset - coord_offset, get_coord, get_dim, orig); + } else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) { + resize(it, tile, 0, coord_offset, get_coord, get_dim, orig); + } } } @@ -342,26 +374,26 @@ bool resize_allowed_horizontal(struct cg_tile *tile, struct cg_tile *parent, int x_offset, int width_offset) { return resize_allowed(tile, parent, x_offset, width_offset, get_x, - get_width); + get_width, tile); } bool resize_allowed_vertical(struct cg_tile *tile, struct cg_tile *parent, int y_offset, int height_offset) { return resize_allowed(tile, parent, y_offset, height_offset, get_y, - get_height); + get_height, tile); } void resize_horizontal(struct cg_tile *tile, struct cg_tile *parent, int x_offset, int width_offset) { - resize(tile, parent, x_offset, width_offset, get_x, get_width); + resize(tile, parent, x_offset, width_offset, get_x, get_width, tile); } void resize_vertical(struct cg_tile *tile, struct cg_tile *parent, int y_offset, int height_offset) { - resize(tile, parent, y_offset, height_offset, get_y, get_height); + resize(tile, parent, y_offset, height_offset, get_y, get_height, tile); } /* hpixs: positiv -> right, negative -> left; vpixs: positiv -> down, negative @@ -615,9 +647,9 @@ keybinding_cycle_tiles(struct cg_server *server, bool reverse) { int keybinding_switch_ws(struct cg_server *server, uint32_t ws) { - if(ws > server->nws) { + if(ws >= server->nws) { wlr_log(WLR_ERROR, - "Requested workspace %u, but only have %u workspaces.", ws, + "Requested workspace %u, but only have %u workspaces.", ws+1, server->nws); return -1; } @@ -683,10 +715,21 @@ keybinding_set_nws(struct cg_server *server, int nws) { struct cg_output *output; wl_list_for_each(output, &server->outputs, link) { for(unsigned int i = nws; i < server->nws; ++i) { + struct cg_view *view, *tmp; + wl_list_for_each_safe(view,tmp, &output->workspaces[i]->views,link) { + wl_list_remove(&view->link); + wl_list_insert(&output->workspaces[nws-1]->views,&view->link); + view->workspace = output->workspaces[nws-1]; + } + wl_list_for_each_safe(view,tmp,&output->workspaces[i]->unmanaged_views,link) { + wl_list_remove(&view->link); + wl_list_insert(&output->workspaces[nws-1]->unmanaged_views,&view->link); + view->workspace = output->workspaces[nws-1]; + } workspace_free(output->workspaces[i]); } - struct cg_workspace **new_workspaces = realloc( - output->workspaces, nws * sizeof(struct cg_workspace *)); + struct cg_workspace **new_workspaces = + realloc(output->workspaces, nws * sizeof(struct cg_workspace *)); if(new_workspaces == NULL) { wlr_log(WLR_ERROR, "Error reallocating memory for workspaces."); return; @@ -699,16 +742,18 @@ keybinding_set_nws(struct cg_server *server, int nws) { } if(output->curr_workspace >= nws) { - output->curr_workspace = nws-1; + output->curr_workspace = nws - 1; } } server->nws = nws; + seat_set_focus(server->seat,server->curr_output->workspaces[server->curr_output->curr_workspace]->focused_tile->view); } void -keybinding_definemode(struct cg_server *server, char* mode) { +keybinding_definemode(struct cg_server *server, char *mode) { int length = 0; - while(server->modes[length++] != NULL); + while(server->modes[length++] != NULL) + ; char **tmp = realloc(server->modes, (length + 1) * sizeof(char *)); if(tmp == NULL) { wlr_log(WLR_ERROR, "Could not allocate memory for storing modes."); @@ -722,11 +767,11 @@ keybinding_definemode(struct cg_server *server, char* mode) { void keybinding_definekey(struct cg_server *server, struct keybinding *kb) { - keybinding_list_push(server->keybindings,kb); + keybinding_list_push(server->keybindings, kb); } void -keybinding_set_background(struct cg_server *server, float* bg) { +keybinding_set_background(struct cg_server *server, float *bg) { server->bg_color[0] = bg[0]; server->bg_color[1] = bg[1]; server->bg_color[2] = bg[2]; @@ -871,7 +916,7 @@ run_action(enum keybinding_action action, struct cg_server *server, break; } case KEYBINDING_DEFINEKEY: - keybinding_definekey(server,data.kb); + keybinding_definekey(server, data.kb); break; case KEYBINDING_BACKGROUND: keybinding_set_background(server, data.color); From 14a15feebbe676efd97c270597a91fabce2e108d Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 10:07:24 +0100 Subject: [PATCH 021/122] Ameliorate fuzzing process --- fuzz/execl_override.c | 28 ++- fuzz/fuzz-parse.c | 443 ++++++++++++++++++++++++++++++++++++++---- fuzz/meson.build | 1 + message.c | 6 +- 4 files changed, 428 insertions(+), 50 deletions(-) diff --git a/fuzz/execl_override.c b/fuzz/execl_override.c index 281282f..8ce707b 100644 --- a/fuzz/execl_override.c +++ b/fuzz/execl_override.c @@ -1,11 +1,29 @@ /* This file is used by the fuzzer in order to prevent executing shell commands. */ #define _GNU_SOURCE -#include - -struct tm *(*orig_localtime)(const time_t *timep); +#include +#include "../output.h" +#include +#include +#include int -execl(const char *pathname, const char *arg, ...) { - return 0; +fork() { + return 1; +} + +void wlr_texture_get_size(struct wlr_texture *texture, int *width, + int *height) { + if(width != NULL) { + *width=0; + } + + if(height != NULL) { + *height=0; + } +} + +cairo_surface_t* +cairo_image_surface_create(cairo_format_t fmt, int width, int height) { + return NULL; } diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 257f289..746e459 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -1,75 +1,410 @@ -#define _POSIX_C_SOURCE 200812L -#define FUZZING +/* + * Cagebreak: A Wayland tiling compositor. + * + * Copyright (C) 2018-2020 Jente Hidskes + * + * See the LICENSE file accompanying this file. + */ -#include "../keybinding.h" -#include "../parse.h" -#include "../seat.h" -#include "../server.h" -#include +#define _POSIX_C_SOURCE 200812L + +#include "config.h" + +#include +#include #include +#include #include #include #include #include + +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if CG_HAS_XWAYLAND +#include +#endif +#include +#include +#include +#include +#if CG_HAS_XWAYLAND +#include +#endif + +#include "idle_inhibit_v1.h" +#include "keybinding.h" +#include "message.h" +#include "output.h" +#include "workspace.h" +#include "parse.h" +#include "seat.h" +#include "server.h" +#include "view.h" +#include "xdg_shell.h" +#if CG_HAS_XWAYLAND +#include "xwayland.h" +#endif #ifndef WAIT_ANY #define WAIT_ANY -1 #endif -void -set_sig_handler(int sig) { - struct sigaction sa; - sa.sa_handler = SIG_IGN; // handle signal by ignoring - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if(sigaction(SIGCHLD, &sa, 0) == -1) { - perror(0); - exit(1); +static bool +drop_permissions(void) { + if(getuid() != geteuid() || getgid() != getegid()) { + if(setuid(getuid()) != 0 || setgid(getgid()) != 0) { + wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); + return false; + } } + + if(setuid(0) != -1) { + wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to " + "restore it after setuid), refusing to start"); + return false; + } + + return true; } -struct cg_server server; +static bool +parse_args(struct cg_server *server, int argc, char *argv[]) { + server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; + server->debug_damage_tracking = false; + return true; +} + +struct cg_server server = {0}; +struct wlr_xwayland *xwayland = NULL; +#if CG_HAS_XWAYLAND +struct wlr_xcursor_manager *xcursor_manager = NULL; +#endif + +void +cleanup() { + server.running = false; +#if CG_HAS_XWAYLAND + if(xwayland != NULL) { + wlr_xwayland_destroy(xwayland); + } + if(xcursor_manager != NULL) { + wlr_xcursor_manager_destroy(xcursor_manager); + } +#endif + wl_display_destroy_clients(server.wl_display); + + for(unsigned int i = 0; server.modes[i] != NULL; ++i) { + free(server.modes[i]); + } + free(server.modes); + + keybinding_list_free(server.keybindings); + + seat_destroy(server.seat); + /* This function is not null-safe, but we only ever get here + with a proper wl_display. */ + wl_display_destroy(server.wl_display); + wlr_output_layout_destroy(server.output_layout); +} int LLVMFuzzerInitialize(int *argc, char ***argv) { - set_sig_handler(SIGCHLD); + struct wl_event_loop *event_loop = NULL; + struct wlr_backend *backend = NULL; + struct wlr_renderer *renderer = NULL; + struct wlr_compositor *compositor = NULL; + struct wlr_data_device_manager *data_device_manager = NULL; + struct wlr_server_decoration_manager *server_decoration_manager = NULL; + 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_xdg_output_manager_v1 *output_manager = NULL; + struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + struct wlr_xdg_shell *xdg_shell = NULL; + int ret = 0; - server.wl_display = NULL; - server.event_loop = NULL; + if(!parse_args(&server, *argc, *argv)) { + return 1; + } - server.seat = malloc(sizeof(struct cg_seat)); - server.seat->mode = 0; - server.seat->default_mode = 0; +#ifdef DEBUG + wlr_log_init(WLR_DEBUG, NULL); +#else + wlr_log_init(WLR_ERROR, NULL); +#endif - server.idle = NULL; - server.idle_inhibit_v1 = NULL; - /* new_idle_inhibitor_v1 */ - wl_list_init(&server.inhibitors); + /* 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"); + return 1; + } - server.output_layout = NULL; - wl_list_init(&server.outputs); - server.curr_output = NULL; - - /* new_output */ - - /* xdg_toplevel_decoration */ - /* new_xdg_shell_surface */ - /* new_xwayland_surface */ - server.keybindings = keybinding_list_init(); - server.output_transform = 0; + server.wl_display = wl_display_create(); + if(!server.wl_display) { + wlr_log(WLR_ERROR, "Cannot allocate a Wayland display"); + return 1; + } server.running = true; - server.modes = malloc(sizeof(char *)); - server.modes[0] = NULL; + + server.modes = malloc(4 * sizeof(char *)); + server.modes[0] = strdup("top"); + server.modes[1] = strdup("root"); + server.modes[2] = strdup("resize"); + server.modes[3] = NULL; + server.nws = 1; - server.message_timeout = 0; + server.message_timeout = 2; + + event_loop = wl_display_get_event_loop(server.wl_display); + server.event_loop = event_loop; + + backend = wlr_backend_autocreate(server.wl_display, NULL); + if(!backend) { + wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); + ret = 1; + goto end; + } + server.backend = backend; + + if(!drop_permissions()) { + ret = 1; + goto end; + } + + server.keybindings = keybinding_list_init(); + if(server.keybindings == NULL || server.keybindings->keybindings == NULL) { + wlr_log(WLR_ERROR, "Unable to allocate keybindings"); + ret = 1; + goto end; + } + + renderer = wlr_backend_get_renderer(backend); + wlr_renderer_init_wl_display(renderer, server.wl_display); + server.bg_color = malloc(4 * sizeof(float)); server.bg_color[0] = 0; server.bg_color[1] = 0; server.bg_color[2] = 0; server.bg_color[3] = 1; + wl_list_init(&server.outputs); + server.output_layout = wlr_output_layout_create(); + if(!server.output_layout) { + wlr_log(WLR_ERROR, "Unable to create output layout"); + ret = 1; + goto end; + } + + compositor = wlr_compositor_create(server.wl_display, renderer); + if(!compositor) { + wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); + ret = 1; + goto end; + } + + data_device_manager = wlr_data_device_manager_create(server.wl_display); + if(!data_device_manager) { + wlr_log(WLR_ERROR, "Unable to create the data device 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. */ + server.new_output.notify = handle_new_output; + wl_signal_add(&backend->events.new_output, &server.new_output); + + server.seat = seat_create(&server, backend); + if(!server.seat) { + wlr_log(WLR_ERROR, "Unable to create the seat"); + ret = 1; + goto end; + } + + server.idle = wlr_idle_create(server.wl_display); + if(!server.idle) { + wlr_log(WLR_ERROR, "Unable to create the idle tracker"); + ret = 1; + goto end; + } + + server.idle_inhibit_v1 = wlr_idle_inhibit_v1_create(server.wl_display); + if(!server.idle_inhibit_v1) { + wlr_log(WLR_ERROR, "Cannot create the idle inhibitor"); + ret = 1; + goto end; + } + server.new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1_new; + wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, + &server.new_idle_inhibitor_v1); + wl_list_init(&server.inhibitors); + + xdg_shell = wlr_xdg_shell_create(server.wl_display); + if(!xdg_shell) { + wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); + ret = 1; + goto end; + } + server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new; + wl_signal_add(&xdg_shell->events.new_surface, + &server.new_xdg_shell_surface); + + xdg_decoration_manager = + wlr_xdg_decoration_manager_v1_create(server.wl_display); + if(!xdg_decoration_manager) { + wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager"); + ret = 1; + goto end; + } + wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration, + &server.xdg_toplevel_decoration); + server.xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; + + server_decoration_manager = + wlr_server_decoration_manager_create(server.wl_display); + if(!server_decoration_manager) { + wlr_log(WLR_ERROR, "Unable to create the server decoration manager"); + ret = 1; + goto end; + } + wlr_server_decoration_manager_set_default_mode( + server_decoration_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + + export_dmabuf_manager = + wlr_export_dmabuf_manager_v1_create(server.wl_display); + if(!export_dmabuf_manager) { + wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager"); + ret = 1; + goto end; + } + + screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display); + if(!screencopy_manager) { + wlr_log(WLR_ERROR, "Unable to create the screencopy manager"); + ret = 1; + goto end; + } + + output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, + server.output_layout); + if(!output_manager) { + wlr_log(WLR_ERROR, "Unable to create the output manager"); + ret = 1; + goto end; + } + + gamma_control_manager = + wlr_gamma_control_manager_v1_create(server.wl_display); + if(!gamma_control_manager) { + wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); + ret = 1; + goto end; + } + +#if CG_HAS_XWAYLAND + xwayland = wlr_xwayland_create(server.wl_display, compositor, true); + if(!xwayland) { + wlr_log(WLR_ERROR, "Cannot create XWayland server"); + ret = 1; + goto end; + } + server.new_xwayland_surface.notify = handle_xwayland_surface_new; + wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); + + xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); + if(!xcursor_manager) { + wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); + ret = 1; + goto end; + } + + if(setenv("DISPLAY", xwayland->display_name, true) < 0) { + wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland.", + "Clients may not be able to connect"); + } else { + wlr_log(WLR_DEBUG, "XWayland is running on display %s", + xwayland->display_name); + } + + if(wlr_xcursor_manager_load(xcursor_manager, 1)) { + wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); + } + struct wlr_xcursor *xcursor = + wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); + if(xcursor) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4, + image->width, image->height, image->hotspot_x, + image->hotspot_y); + } +#endif + + const char *socket = wl_display_add_socket_auto(server.wl_display); + if(!socket) { + wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket"); + ret = 1; + goto end; + } + + if(!wlr_backend_start(backend)) { + wlr_log(WLR_ERROR, "Unable to start the wlroots backend"); + ret = 1; + goto end; + } + + if(setenv("WAYLAND_DISPLAY", socket, true) < 0) { + wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.", + "Clients may not be able to connect"); + } else { + wlr_log(WLR_DEBUG, + "Cagebreak " CG_VERSION " is running on Wayland display %s", + socket); + } + +#if CG_HAS_XWAYLAND + wlr_xwayland_set_seat(xwayland, server.seat->seat); +#endif + + /* Place the cursor to the topl left of the output layout. */ + wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); + atexit(cleanup); + return 0; +end: + cleanup(); + return ret; +} + +/* Parse config file. Lines longer than "max_line_size" are ignored */ +int +set_configuration(struct cg_server *server, char *content) { + char *line; + for(unsigned int line_num = 1; + (line = strtok_r(NULL, "\n", &content)) != NULL; ++line_num) { + line[strcspn(line, "\n")] = '\0'; + if(*line != '\0' && *line != '#') { + if(parse_rc_line(server, line) != 0) { + return -1; + } + } + } return 0; } @@ -78,9 +413,33 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *str = malloc(size * sizeof(char) + 1); strncpy(str, (char *)data, size); str[size] = 0; - parse_rc_line(&server, str); + set_configuration(&server, str); free(str); keybinding_list_free(server.keybindings); server.keybindings = keybinding_list_init(); + run_action(KEYBINDING_WORKSPACES, &server, + (union keybinding_params){.i = 1}); + run_action(KEYBINDING_LAYOUT_FULLSCREEN, &server, + (union keybinding_params){.c = NULL}); + wl_display_flush_clients(server.wl_display); + wl_display_destroy_clients(server.wl_display); + struct cg_output* output; + wl_list_for_each(output, &server.outputs, link) { + message_clear(output); + struct cg_view *view; + wl_list_for_each(view, &(*output->workspaces)->views, link) { + view_unmap(view); + view_destroy(view); + } + wl_list_for_each(view, &(*output->workspaces)->unmanaged_views, link) { + view_unmap(view); + view_destroy(view); + } + } + for(unsigned int i = 3; server.modes[i] != NULL; ++i) { + free(server.modes[i]); + } + server.modes[3] = NULL; + server.modes = realloc(server.modes, 4 * sizeof(char *)); return 0; } diff --git a/fuzz/meson.build b/fuzz/meson.build index 0266717..8ff982a 100644 --- a/fuzz/meson.build +++ b/fuzz/meson.build @@ -17,6 +17,7 @@ endif override_lib = shared_library('execl_override', [ 'execl_override.c' ], + dependencies: [ pixman,cairo,pango,pangocairo ], install: false ) diff --git a/message.c b/message.c index c41e1a4..40ac033 100644 --- a/message.c +++ b/message.c @@ -45,13 +45,13 @@ create_message_texture(const char *string, const struct cg_output *output) { // Therefore, we cannot use cairo_create(NULL). cairo_surface_t *dummy_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); - cairo_t *c = cairo_create(dummy_surface); - // This occurs when we are fuzzing. In that case, do nothing - if(c == NULL) { + if(dummy_surface == NULL) { return NULL; } + cairo_t *c = cairo_create(dummy_surface); + cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST); cairo_font_options_t *fo = cairo_font_options_create(); cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); From 9363a59b95d2a97f8451fa5a061d5a082d7ffad4 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 14:31:06 +0100 Subject: [PATCH 022/122] Apply clang-format --- cagebreak.c | 4 ++-- fuzz/execl_override.c | 12 ++++++------ fuzz/fuzz-parse.c | 4 ++-- keybinding.c | 23 +++++++++++++++-------- keybinding.h | 10 +++++----- parse.c | 11 ++++++++--- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index aeddf84..ba359e5 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -10,11 +10,11 @@ #include "config.h" +#include #include +#include #include #include -#include -#include #include #include #include diff --git a/fuzz/execl_override.c b/fuzz/execl_override.c index 8ce707b..316cf1e 100644 --- a/fuzz/execl_override.c +++ b/fuzz/execl_override.c @@ -1,10 +1,10 @@ /* This file is used by the fuzzer in order to prevent executing shell commands. */ #define _GNU_SOURCE -#include #include "../output.h" #include #include +#include #include int @@ -12,18 +12,18 @@ fork() { return 1; } -void wlr_texture_get_size(struct wlr_texture *texture, int *width, - int *height) { +void +wlr_texture_get_size(struct wlr_texture *texture, int *width, int *height) { if(width != NULL) { - *width=0; + *width = 0; } if(height != NULL) { - *height=0; + *height = 0; } } -cairo_surface_t* +cairo_surface_t * cairo_image_surface_create(cairo_format_t fmt, int width, int height) { return NULL; } diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 746e459..24b15cf 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -51,11 +51,11 @@ #include "keybinding.h" #include "message.h" #include "output.h" -#include "workspace.h" #include "parse.h" #include "seat.h" #include "server.h" #include "view.h" +#include "workspace.h" #include "xdg_shell.h" #if CG_HAS_XWAYLAND #include "xwayland.h" @@ -423,7 +423,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { (union keybinding_params){.c = NULL}); wl_display_flush_clients(server.wl_display); wl_display_destroy_clients(server.wl_display); - struct cg_output* output; + struct cg_output *output; wl_list_for_each(output, &server.outputs, link) { message_clear(output); struct cg_view *view; diff --git a/keybinding.c b/keybinding.c index 9bf5734..f6f5eaf 100644 --- a/keybinding.c +++ b/keybinding.c @@ -649,7 +649,7 @@ int keybinding_switch_ws(struct cg_server *server, uint32_t ws) { if(ws >= server->nws) { wlr_log(WLR_ERROR, - "Requested workspace %u, but only have %u workspaces.", ws+1, + "Requested workspace %u, but only have %u workspaces.", ws + 1, server->nws); return -1; } @@ -716,15 +716,19 @@ keybinding_set_nws(struct cg_server *server, int nws) { wl_list_for_each(output, &server->outputs, link) { for(unsigned int i = nws; i < server->nws; ++i) { struct cg_view *view, *tmp; - wl_list_for_each_safe(view,tmp, &output->workspaces[i]->views,link) { + wl_list_for_each_safe(view, tmp, &output->workspaces[i]->views, + link) { wl_list_remove(&view->link); - wl_list_insert(&output->workspaces[nws-1]->views,&view->link); - view->workspace = output->workspaces[nws-1]; + wl_list_insert(&output->workspaces[nws - 1]->views, + &view->link); + view->workspace = output->workspaces[nws - 1]; } - wl_list_for_each_safe(view,tmp,&output->workspaces[i]->unmanaged_views,link) { + wl_list_for_each_safe( + view, tmp, &output->workspaces[i]->unmanaged_views, link) { wl_list_remove(&view->link); - wl_list_insert(&output->workspaces[nws-1]->unmanaged_views,&view->link); - view->workspace = output->workspaces[nws-1]; + wl_list_insert(&output->workspaces[nws - 1]->unmanaged_views, + &view->link); + view->workspace = output->workspaces[nws - 1]; } workspace_free(output->workspaces[i]); } @@ -746,7 +750,10 @@ keybinding_set_nws(struct cg_server *server, int nws) { } } server->nws = nws; - seat_set_focus(server->seat,server->curr_output->workspaces[server->curr_output->curr_workspace]->focused_tile->view); + seat_set_focus( + server->seat, + server->curr_output->workspaces[server->curr_output->curr_workspace] + ->focused_tile->view); } void diff --git a/keybinding.h b/keybinding.h index 42ad114..24f8af2 100644 --- a/keybinding.h +++ b/keybinding.h @@ -44,10 +44,10 @@ enum keybinding_action { KEYBINDING_FOCUS_TOP, KEYBINDING_FOCUS_BOTTOM, - KEYBINDING_DEFINEKEY, // data.kb is the keybinding definition - KEYBINDING_BACKGROUND, //data.color is the background color - KEYBINDING_DEFINEMODE, //data.c is the mode name - KEYBINDING_WORKSPACES, //data.i is the number of workspaces + KEYBINDING_DEFINEKEY, // data.kb is the keybinding definition + KEYBINDING_BACKGROUND, // data.color is the background color + KEYBINDING_DEFINEMODE, // data.c is the mode name + KEYBINDING_WORKSPACES, // data.i is the number of workspaces }; union keybinding_params { @@ -56,7 +56,7 @@ union keybinding_params { int32_t i; bool b; float color[3]; - struct keybinding* kb; + struct keybinding *kb; }; struct keybinding { diff --git a/parse.c b/parse.c index 5b0ac6e..cb6abe3 100644 --- a/parse.c +++ b/parse.c @@ -262,7 +262,10 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - wlr_log(WLR_ERROR, "Workspace number must be a integer number larger or equal to 1. Got %ld", ws); + wlr_log(WLR_ERROR, + "Workspace number must be a integer number larger or equal " + "to 1. Got %ld", + ws); return -1; } keybinding->data.u = ws - 1; @@ -277,8 +280,10 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - wlr_log( - WLR_ERROR, "Workspace number must be an integer larger or equal to 1. Got %ld", ws); + wlr_log(WLR_ERROR, + "Workspace number must be an integer larger or equal to 1. " + "Got %ld", + ws); return -1; } keybinding->data.u = ws - 1; From 741a0a4928eb4775074544d7159db69f4698e3bc Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 28 Mar 2020 09:09:24 +0100 Subject: [PATCH 023/122] Add warning message on version missmatch --- meson.build | 56 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index 46f2547..bec9dba 100644 --- a/meson.build +++ b/meson.build @@ -64,7 +64,7 @@ xkbcommon = dependency('xkbcommon') cairo = dependency('cairo') pango = dependency('pango') pangocairo = dependency('pangocairo') -math = cc.find_library('m') +fontconfig = dependency('fontconfig') wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') wayland_scanner = find_program('wayland-scanner') @@ -173,19 +173,47 @@ foreach header : cagebreak_header_strings cagebreak_headers += files(header) endforeach -cagebreak_dependencies = [ - server_protos, - wayland_server, - wayland_client, - wayland_cursor, - wlroots, - xkbcommon, - pixman, - math, - pango, - cairo, - pangocairo, -] +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, +} + +reproducible_build_versions = { + 'server_protos': '1.0.5', + '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', +} + +cagebreak_dependencies = [] + +foreach name, dep : cagebreak_dependencies_dict + cagebreak_dependencies += dep +endforeach + +foreach name, dep : cagebreak_dependencies_dict + if 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 hash specified in the "Reproducible Build" section of the manual (' + reproducible_build_versions[name] + '). There is therefore no guaranty that the hashes of the binaries match.' + ) + break + endif +endforeach executable( meson.project_name(), From d40db590f579c208c03ad72017640b41bc039487 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 28 Mar 2020 09:11:11 +0100 Subject: [PATCH 024/122] Reword warning message --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index bec9dba..3c6575c 100644 --- a/meson.build +++ b/meson.build @@ -209,7 +209,7 @@ endforeach foreach name, dep : cagebreak_dependencies_dict if 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 hash specified in the "Reproducible Build" section of the manual (' + reproducible_build_versions[name] + '). There is therefore no guaranty that the hashes of the binaries match.' + warning('The installed version of "' + name + '" on your machine (' + dep.version() + ') differs from the one used to generate the hash specified in the "Reproducible Build" section of the README (' + reproducible_build_versions[name] + '). There is therefore no guaranty that the hashes of the binaries match.' ) break endif From 82512a5b52be389b29707c3e6f351275a2bf914c Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 28 Mar 2020 21:14:33 +0100 Subject: [PATCH 025/122] Add missing dependency --- meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3c6575c..b4f6350 100644 --- a/meson.build +++ b/meson.build @@ -65,6 +65,7 @@ cairo = dependency('cairo') pango = dependency('pango') pangocairo = dependency('pangocairo') fontconfig = dependency('fontconfig') +math = cc.find_library('m') wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') wayland_scanner = find_program('wayland-scanner') @@ -185,6 +186,7 @@ cagebreak_dependencies_dict = { 'pango': pango, 'cairo': cairo, 'pangocairo': pangocairo, + 'math': math } reproducible_build_versions = { @@ -199,6 +201,7 @@ reproducible_build_versions = { 'pango': '1.44.7', 'cairo': '1.17.3', 'pangocairo': '1.44.7', + 'math': '-1' } cagebreak_dependencies = [] @@ -208,7 +211,7 @@ foreach name, dep : cagebreak_dependencies_dict endforeach foreach name, dep : cagebreak_dependencies_dict - if reproducible_build_versions[name] != dep.version() + 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 hash specified in the "Reproducible Build" section of the README (' + reproducible_build_versions[name] + '). There is therefore no guaranty that the hashes of the binaries match.' ) break From 78fc95e098d54501cab04be6d2ea97b5cd6af76f Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sat, 28 Mar 2020 21:33:54 +0000 Subject: [PATCH 026/122] Prepare cagebreak 1.0.6 for review - Make build reproducible accross commits - Document reproducibility regimen --- README.md | 36 ++++++++++++++++++++++++++++++++---- cagebreak.c | 2 +- meson.build | 4 ++-- signatures/cagebreak.sig | Bin 0 -> 566 bytes 4 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 signatures/cagebreak.sig diff --git a/README.md b/README.md index 2912c06..0e7093a 100644 --- a/README.md +++ b/README.md @@ -105,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 @@ -126,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 the versions not match, 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: 875d77ae0d1266ace899b143ca738e6adc514ea26b2dae58a0ce5989139149f2 + * sha 512: 066829ed30b299a21ef74d5d9c7f3ff8021b877ac18a141a0aa77aae1acf880305743eedf546cba0aa06acc53d26750bf989b7fb029f0ea5ac01b3804288ab88 + +#### 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/cagebreak.c b/cagebreak.c index 4a71480..1adc5a1 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -160,7 +160,7 @@ parse_args(struct cg_server *server, int argc, char *argv[]) { usage(stdout, argv[0]); return false; case 'v': - fprintf(stdout, "Cagebreak version " CG_VERSION "\n"); + fprintf(stdout, "Cagebreak version 1.0.6\n"); exit(0); default: usage(stderr, argv[0]); diff --git a/meson.build b/meson.build index b4f6350..419e625 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.5', + version: '1.0.6', license: 'MIT', default_options: [ 'c_std=c11', @@ -212,7 +212,7 @@ 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 hash specified in the "Reproducible Build" section of the README (' + reproducible_build_versions[name] + '). There is therefore no guaranty that the hashes of the binaries match.' + 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 diff --git a/signatures/cagebreak.sig b/signatures/cagebreak.sig new file mode 100644 index 0000000000000000000000000000000000000000..e742f265d2fbf6e489061218b890414e4e5037a9 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$zW>rT_{F5XAX( z*9`0|TZdy10G}F0tA5dHph^EPvbU}7ZX$N|Vy>@UXujVCSDrGj9@HHZp+xZij|C^B z_rB#LQ&^vSQJq=9{ih4&+?V{HIarH!^c>-6uig8NDrlOxseNzxrM^8v1;25mL!PYn zOvkj;V^+nK!K|X1c$hpi2_y1)ttqMr!b06hm$)nGelp4iEis58Kfx{j-gHWs5e{YW z*ogldyWE;DFk)+Po}<7S54vp-6s`4n&>paTU>E{<4l??ekA!!8bDaMa(SRt`KRmQJ zI44N>DrL2zJ~ozhqpjZ7fqW0nI^^DWHY*0^=Go)$>XT#0%S>CyIFuc%MbEn}#k_xP zb~Wws>IK5R$eia4zF?>#&b|XMc=i)_5(iT^13{fMkr+>9|A$yMgQKiUi2_sFo{Vqq zWC7#i5$FM0+Rf*ws&XX&g%HmHKfxhb7T=xp$V@l3O+_)K9R#4ldB>Tde~W1w^Uti= zNZ|;qFo4;y=}yBw&&1aA5tZt;#tb|I8{Aj6))Qe61SSYSv=*6r_fn8SdYGjb}0zdyJry^-|rO|cqVJ;PlGW2hLon-@%$Tqn%|5?rV_0>XmN E_hhge9{>OV literal 0 HcmV?d00001 From 1934b56fa144194a67690d5fa31f64ef6f288e42 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 28 Mar 2020 22:42:37 +0100 Subject: [PATCH 027/122] Reword readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e7093a..f2437aa 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ The full public keys can be found in `keys/` along with any revocation certifica ### Reproducible Builds Cagebreak offers reproducible builds given the exact library versions specified -in `meson.build`. Should the versions not match, a warning will be emitted. We have +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. From c794d3519bb67cbd6576be02ce508e7b7072171d Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 29 Mar 2020 10:33:28 +0200 Subject: [PATCH 028/122] Remove git hash from version --- cagebreak.c | 2 +- meson.build | 16 ++++------------ meson_options.txt | 1 + 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index 1adc5a1..4a71480 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -160,7 +160,7 @@ parse_args(struct cg_server *server, int argc, char *argv[]) { usage(stdout, argv[0]); return false; case 'v': - fprintf(stdout, "Cagebreak version 1.0.6\n"); + fprintf(stdout, "Cagebreak version " CG_VERSION "\n"); exit(0); default: usage(stderr, argv[0]); diff --git a/meson.build b/meson.build index 419e625..31a6611 100644 --- a/meson.build +++ b/meson.build @@ -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() 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.') From 8eb17bc54bb3db765e850aefd510a687bf4ecd19 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 29 Mar 2020 09:37:22 +0000 Subject: [PATCH 029/122] Update server_protos version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 31a6611..6b2e509 100644 --- a/meson.build +++ b/meson.build @@ -182,7 +182,7 @@ cagebreak_dependencies_dict = { } reproducible_build_versions = { - 'server_protos': '1.0.5', + 'server_protos': '1.0.6', 'wayland_server': '1.18.0', 'wayland_client': '1.18.0', 'wayland_cursor': '1.18.0', From 6a1266bc216991ad22a7165ea8237acf9713f782 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 29 Mar 2020 09:46:25 +0000 Subject: [PATCH 030/122] Add current hashes and signatures --- README.md | 4 ++-- signatures/cagebreak.sig | Bin 566 -> 566 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f2437aa..c793ac0 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,8 @@ For every release after 1.0.5, hashes will be provided. 1.0.6 - * sha 256: 875d77ae0d1266ace899b143ca738e6adc514ea26b2dae58a0ce5989139149f2 - * sha 512: 066829ed30b299a21ef74d5d9c7f3ff8021b877ac18a141a0aa77aae1acf880305743eedf546cba0aa06acc53d26750bf989b7fb029f0ea5ac01b3804288ab88 + * sha 256: 712ae9a8f17a9e589e108f0d503da203cc5eaf1c4a6ca6efb5b4c83b432ce0b8 + * sha 512: d574003023a00cfd6623aac986a5a7f397cfd0bc9114017629a8c72731b0df3977c4a31768502dfa8a6607be06930089b2ccf6ffca9b5bcd1096b7ca0aede226 #### GPG Signatures diff --git a/signatures/cagebreak.sig b/signatures/cagebreak.sig index e742f265d2fbf6e489061218b890414e4e5037a9..3a641bee171da79f5d93fc627d5230d0786eb715 100644 GIT binary patch delta 542 zcmV+(0^$9(1hxc_BY%Kx*8mC$5XAX(*9`0|Tc$z}|64$gG`MHKZ=AWaCuyalWsk4k zO22O@Vk;D@>@jJuMc1+zpA&G+@{_qVO`Y09k!O{I7iHTUnPT zkIYpcNNuceS3$Os?#EXLAyy`{?}uNjVHyd*;iJ~`1b>hBSmWUVf{UFQ>F9NW=K#IT@oo||J1{+Y@VaDU&9OEld zP{GeM)oL;krO_f@kyJ9bTNNg&f~=06r2QHAgQCuNEq%o6iAOx19R`F`ptnrGLq1Bn g*EQ@+!WV+4{8k&L$Lf7F?L)YbTwZlvADEF0$t#x(F8}}l delta 542 zcmV+(0^$9(1hxc_BY%IurT_{F5XAX(*9`0|TZdy10G}F0tA5dHph^EPvbU}7ZX$N| zVy>@UXujVCSDrGj9@HHZp+xZij|C^B_rB#LQ&^vSQJq=9{ih4&+?V{HIarH!^c>-6 zuig8NDrlOxseNzxrM^8v1;25mL!PYnOvkj;V^+nK!K|X1cz>8YGzlZ}daWs{3Bp3% zNSC-P>3%ZG1}!m&AwR(_{@!#-m=O+T@Ysm|8@t?^FEC@c@8rAmyd*Zd~=-t6w!bv)jvG6I5;Or_$p;sG&jCNdAy^jQ zo%F~|H?~bhF{K>@pu%~_nW2A+X&dv;tl3E62&^!G*?+O=PQyOW#Mbi>mFl*}3_JrH zk(u(J5L;8W>F4T{R$g>um%l9Ygi@Vs7>suu_Fl<&ClFVDfJZ0XhELhbjALn3{A zts2*A)?)S)q=uXs?%#clXEGLhjG&X_#XmN_k$4;?EnA( 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 031/122] 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; From 9c93e3d4e84bea2eb75591eb90dfe4c5d6bf63cf Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 29 Mar 2020 12:51:26 +0000 Subject: [PATCH 032/122] Prepare for merge --- Bugs.md | 24 ++++++++++++++++++++++++ meson.build | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Bugs.md b/Bugs.md index 491d2c6..835fc94 100644 --- a/Bugs.md +++ b/Bugs.md @@ -55,3 +55,27 @@ Steps to reproduce: ``` (EE) failed to read Wayland events: Broken pipe ``` + +### Issue 4 + + github issue number: #1 + Fixed: 1.0.7 + +This issue is code duplication in `parse.c`. + +Github issue text: + +``` +As of right now, the actions which can be run in the config file and the +actions which can be run as a keybinding are parsed separately in `parse.c`. +This leads to a lot of code duplication. Furthermore, unifying these +functionalities would enable a more versatile configuration. For instance, it +would enable the user to write `hsplit` into the configuration file to split +the output on startup and workspace 2 to set the default workspace to +workspace 2. Therefore, this change would simplify the code base, while at +the same time increasing the feature set. + +PS: As a side effect, this would allow quirky statements such as +`bind dbind r hsplit` which would bind the d key to binding the r key to +split the output... +``` diff --git a/meson.build b/meson.build index a65d0b6..e42700b 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.6', + version: '1.0.7', license: 'MIT', default_options: [ 'c_std=c11', From 3461b70baa38bc507362a90423a7d5c60c734432 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 29 Mar 2020 18:02:38 +0200 Subject: [PATCH 033/122] Fix missing ifdef guards --- fuzz/fuzz-parse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 24b15cf..e5b75cb 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -86,7 +86,9 @@ drop_permissions(void) { static bool parse_args(struct cg_server *server, int argc, char *argv[]) { server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; +#ifdef DEBUG server->debug_damage_tracking = false; +#endif return true; } From d54c2ecea9db31265d7c560dac74aaa5ff1bda24 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 29 Mar 2020 23:13:12 +0200 Subject: [PATCH 034/122] Fix version checking for server_protos --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e42700b..0bf6076 100644 --- a/meson.build +++ b/meson.build @@ -181,7 +181,7 @@ cagebreak_dependencies_dict = { } reproducible_build_versions = { - 'server_protos': '1.0.6', + 'server_protos': '-1', 'wayland_server': '1.18.0', 'wayland_client': '1.18.0', 'wayland_cursor': '1.18.0', From e0e980d8286cc3436861e83fc2e39fc4bd196db6 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 30 Mar 2020 09:33:28 +0000 Subject: [PATCH 035/122] Fix merging error --- meson.build | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/meson.build b/meson.build index f4b01d1..0bf6076 100644 --- a/meson.build +++ b/meson.build @@ -201,42 +201,6 @@ foreach name, dep : cagebreak_dependencies_dict cagebreak_dependencies += dep 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 -} - -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.' From f25e5d9ec3cd8a3f425385f4c2b0b8dc606f5ad1 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Wed, 1 Apr 2020 11:01:27 +0000 Subject: [PATCH 036/122] Prepare 1.1.0 release - adjust versions - adapt documentation --- Bugs.md | 2 +- README.md | 27 +++++++++++++++++++----- man/cagebreak-config.5.md | 20 ++++++++---------- man/cagebreak.1.md | 2 +- meson.build | 2 +- signatures/{cagebreak.sig => 1.0.6.sig} | Bin 6 files changed, 34 insertions(+), 19 deletions(-) rename signatures/{cagebreak.sig => 1.0.6.sig} (100%) diff --git a/Bugs.md b/Bugs.md index 835fc94..b34f4f6 100644 --- a/Bugs.md +++ b/Bugs.md @@ -59,7 +59,7 @@ Steps to reproduce: ### Issue 4 github issue number: #1 - Fixed: 1.0.7 + Fixed: 1.1.0 This issue is code duplication in `parse.c`. diff --git a/README.md b/README.md index c793ac0..953a7d5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Cagebreak: A Wayland Tiling Compositor Inspired by Ratpoison This is Cagebreak, a Wayland tiling compositor. The goal of this project is to -provide a successor to ratpoison for wayland users. However, this is +provide a successor to ratpoison for Wayland users. However, this is no reimplementation of ratpoison. Should you like to know if a feature will be implemented, open an issue or get in touch with the development team. @@ -83,7 +83,7 @@ git tag -v version git push --tags origin master ``` -and a log message roughly describing the features is added in the commit. +and a log message roughly describing the features added in the commit. In the past, our git history did not always reflect this scheme. @@ -94,8 +94,9 @@ Release checklist * [ ] Cursory testing * [ ] libfuzzer testing * [ ] Version Number - * [ ] -v flag + * [ ] meson.build * [ ] git tag + * [ ] man pages * [ ] Relevant Documentation * [ ] New features documented * [ ] man page @@ -131,7 +132,7 @@ The full public keys can be found in `keys/` along with any revocation certifica 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 +adapt the versions to the packages available under arch linux at the time of release. #### Reproducible Build Instructions @@ -163,12 +164,28 @@ will be named after their release version. Along with the project source code, a fuzzing framework based on `libfuzzer` is supplied. This allows for the testing of the parsing code responsible for reading -the `cagebreak` configuration file. When the `libfuzzer` is available (please +the `cagebreak` configuration file. When `libfuzzer` is available (please use the `clang` compiler to enable it), building the fuzz-testing software can be enabled by passing `-Dfuzz=true` to meson. This generates a `build/fuzz/fuzz-parse` binary according to the `libfuzzer` specifications. Further documentation on how to run this binary can be found [here](https://llvm.org/docs/LibFuzzer.html). +Here is an example workflow: + +``` +rm -rf build +CC=clang meson build -Dfuzz=true +ninja -C build/ +mkdir build/fuzz_corpus +cp examples/config build/fuzz_corpus/ +WLR_BACKENDS=headless ./build/fuzz/fuzz-parse -jobs=12 -max_len=50000 -close_fd_mask=3 build/fuzz_corpus/ +``` + +You may want to tweak `-jobs` or add other options depending on your own setup. +We have found code path discovery to increase rapidly when the fuzzer is supplied +with an initial config file. We are working on improving our fuzzing coverage to +find bugs in other areas of the code. + ## Bugs For any bug, please [create an diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index bbf3096..eebeda2 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -1,4 +1,4 @@ -% CAGEBREAK-CONFIG(1) Version 1.0 | Cagebreak Manual +% CAGEBREAK-CONFIG(1) Version 1.1 | Cagebreak Manual # NAME @@ -21,16 +21,16 @@ by prepending a line with the # symbol. **background - Set background color** > Set the background color. This command expects three floating point numbers -> between 0 and 1, specifying the r,g and b values respectively. +> between 0 and 1, specifying the r, g and b values respectively. > (e.g. "background 1.0 0.0 0.0" sets to background color to red) > There is no support for specifying a background image. -**bind - Bind key to action in command mode** +**bind - Bind key to command in root mode** -> This command requires a key (see **KEY DEFINITIONS**) and an action (see **ACTIONS**) as an argument. +> This command requires a key (see **KEY DEFINITIONS**) and a command (see **COMMANDS**) as an argument. > Subsequently, pressing this key while in command mode executes the -> supplied action. `bind ` is equivalent to -> `definekey root ` +> supplied action. `bind ` is equivalent to +>> `definekey root ` **definekey - Bind key to action in arbitrary mode** @@ -38,13 +38,13 @@ by prepending a line with the # symbol. > difference that the mode in which the keybinding is activated is > specified by the user. A call to this function is to be structured as follows: > ->> `definekey ` +>> `definekey ` **definemode** > This command requires a single argument; the name of the mode to be defined. > Subsequent to a call to this function, the defined mode may be used along with -> the definekey command to create a custom keymapping. Synopsis: +> the definekey command to create a custom key mapping. Synopsis: > >> `definemode ` @@ -64,8 +64,6 @@ by prepending a line with the # symbol. > Requires a single integer larger than 1 and less than 30 as an argument. Sets the number of > workspaces to the supplied number -# ACTIONS - **vsplit** > Split current tile vertically @@ -100,7 +98,7 @@ by prepending a line with the # symbol. **abort** -> Return to the default mode without running any action +> Return to the default mode without running any command **time** diff --git a/man/cagebreak.1.md b/man/cagebreak.1.md index 6d5b051..cacd1c2 100644 --- a/man/cagebreak.1.md +++ b/man/cagebreak.1.md @@ -1,4 +1,4 @@ -% CAGEBREAK(1) Version 1.0 | Cagebreak Manual +% CAGEBREAK(1) Version 1.1 | Cagebreak Manual # NAME diff --git a/meson.build b/meson.build index 0bf6076..959d35f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.7', + version: '1.1.0', license: 'MIT', default_options: [ 'c_std=c11', diff --git a/signatures/cagebreak.sig b/signatures/1.0.6.sig similarity index 100% rename from signatures/cagebreak.sig rename to signatures/1.0.6.sig From 9608770bc7f3c43aebc49074090693739ec9275f Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 1 Apr 2020 13:44:26 +0200 Subject: [PATCH 037/122] Add sanitizers to fuzzer workflow --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 953a7d5..980c786 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ Here is an example workflow: ``` rm -rf build -CC=clang meson build -Dfuzz=true +CC=clang meson build -Dfuzz=true -Db_sanitize=address,undefined -Db_lundef=false ninja -C build/ mkdir build/fuzz_corpus cp examples/config build/fuzz_corpus/ From ddae878c851dbdaf2039d10f5301ca22a1944476 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Wed, 1 Apr 2020 11:54:29 +0000 Subject: [PATCH 038/122] Update Hashes and release information --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 953a7d5..fbb6ea6 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,11 @@ ninja -C build For every release after 1.0.5, hashes will be provided. +1.1.0 + + * sha 256: fc393e225c549f893b9e21e8b904e546d5857bac1d905b3d26334c8f8a1cda11 + * sha 512: 8b94b1069e767202bcab087cb592eadc42f0453d17ee119d48760be00bc66278cf0fa60bb09308d30cb551df6a7a3e26e2ab8b29c04f0e953cc6906542cd2d6f + 1.0.6 * sha 256: 712ae9a8f17a9e589e108f0d503da203cc5eaf1c4a6ca6efb5b4c83b432ce0b8 @@ -201,6 +206,10 @@ independent of github, in case this service is unavailable. Adds basic tiling window manager functionality to cage. +### Release 1.1.0 + +Unifies commands and actions. See Issue 4 in Bugs.md. + ## License Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE) From e0e6fd50bd0a3e8871761018adc1e4b9fc77f71e Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Wed, 1 Apr 2020 11:57:26 +0000 Subject: [PATCH 039/122] Add release signature --- signatures/cagebreak.sig | Bin 0 -> 566 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 signatures/cagebreak.sig diff --git a/signatures/cagebreak.sig b/signatures/cagebreak.sig new file mode 100644 index 0000000000000000000000000000000000000000..ac5a0e800ff52d34973b17b4349461fee72fbd32 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$zl9z5ogd5XAX( z*9`0|TO2eH0JT8XB2TlbW_=Xa#kN@qTWL1V>FRsd$`XXjWfmfAwn0iW4MZ|YvHJeIWJfF7KYe&A8|sFKPdA1_Drb%haK7vulHRk zEMD~%b(50NLn5pw!`aLDjT(@M$UFDv2s--0L2nBQE)P{N*5~e{_vwv0$G0=EA=Bvn zZ8UxfiQ&n=5b7$KTxX|U0Lqfxe5cOlCH*kTg7Zy2T7{i0K(`ZryMgc_6sifgmu?YM zrz`#KXmh*1yEh9uWyl2>1}jRf>MDZOY%v)#J@hnSQguMrM@%jLr)bjhvCY3dP+X2!IIcI+tJ-9R-P+)!(96Nss%)jo$0`9L1W zzHaSL4fo5r)T7FcHo0nBw^&s~@EB=I(@Bb{-P Date: Wed, 1 Apr 2020 14:43:48 +0200 Subject: [PATCH 040/122] Reorder commands --- man/cagebreak-config.5.md | 186 +++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index eebeda2..dffc8b3 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -18,6 +18,10 @@ by prepending a line with the # symbol. ## COMMANDS +**abort** + +> Return to the default mode without running any command + **background - Set background color** > Set the background color. This command expects three floating point numbers @@ -53,88 +57,9 @@ by prepending a line with the # symbol. > Defines the key with which the current mode can be changed to "root". > `escape ` is equivalent to `definekey top switch_mode root` -**exec** +**exchangedown** -> Executes the supplied shell command using *`sh -c ""`*. Synopsis: -> ->> `exec ` - -**workspaces** - -> Requires a single integer larger than 1 and less than 30 as an argument. Sets the number of -> workspaces to the supplied number - -**vsplit** - -> Split current tile vertically - -**hsplit** - -> Split current tile horizontally - -**quit** - -> Exit cagebreak - -**focus** - -> Focus next tile - -**focusprev** - -> Focus previous tile - -**next** - -> Focus next window in current tile - -**prev** - -> Focus previous window in current tile - -**only** - -> Remove all splits and make the current window fill the entire screen - -**abort** - -> Return to the default mode without running any command - -**time** - -> Display time - -**nextscreen** - -> Focus the next screen - -**prevscreen** - -> Focus the previous screen - -**resizeleft** - -> Resize the current tile towards the left - -**resizeright** - -> Resize the current tile towards the right - -**resizedown** - -> Resize the current tile towards the bottom - -**resizeup** - -> Resize the current tile towards the top - -**workspace ** - -> Change to the n-th workspace - -**movetoworkspace ** - -> Move the currently focused window to the n-th workspace +> Exchange the current window with the window in the tile to the bottom **exchangeleft** @@ -148,14 +73,28 @@ by prepending a line with the # symbol. > Exchange the current window with the window in the tile to the top -**exchangedown** +**exec** -> Exchange the current window with the window in the tile to the bottom +> Executes the supplied shell command using *`sh -c ""`*. Synopsis: +> +>> `exec ` + +**focus** + +> Focus next tile + +**focusdown** + +> Focus the tile to the bottom **focusleft** > Focus the tile to the left +**focusprev** + +> Focus previous tile + **focusright** > Focus the tile to the right @@ -164,26 +103,87 @@ by prepending a line with the # symbol. > Focus the tile to the top -**focusdown** +**hsplit** -> Focus the tile to the bottom - -**movetonextscreen** - -> Move the current window to the next screen - -**switchvt ** - -> Switch to tty n +> Split current tile horizontally **mode ** > Enter mode "``". After a keybinding is processed, return to default mode +**movetonextscreen** + +> Move the current window to the next screen + +**movetoworkspace ** + +> Move the currently focused window to the n-th workspace + +**next** + +> Focus next window in current tile + +**nextscreen** + +> Focus the next screen + +**only** + +> Remove all splits and make the current window fill the entire screen + +**prev** + +> Focus previous window in current tile + +**prevscreen** + +> Focus the previous screen + +**quit** + +> Exit cagebreak + +**resizedown** + +> Resize the current tile towards the bottom + +**resizeleft** + +> Resize the current tile towards the left + +**resizeright** + +> Resize the current tile towards the right + +**resizeup** + +> Resize the current tile towards the top + **setmode ** > Set the default mode to `` +**switchvt ** + +> Switch to tty n + +**time** + +> Display time + +**vsplit** + +> Split current tile vertically + +**workspace ** + +> Change to the n-th workspace + +**workspaces** + +> Requires a single integer larger than 1 and less than 30 as an argument. Sets the number of +> workspaces to the supplied number + # MODES By default, three modes are defined: From 484ad8280e144258652f17a1ea5292572a705780 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 4 Apr 2020 09:26:00 +0200 Subject: [PATCH 041/122] Make include paths more intuitive --- fuzz/fuzz-parse.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index e5b75cb..e4dcd06 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -47,18 +47,18 @@ #include #endif -#include "idle_inhibit_v1.h" -#include "keybinding.h" -#include "message.h" -#include "output.h" -#include "parse.h" -#include "seat.h" -#include "server.h" -#include "view.h" -#include "workspace.h" -#include "xdg_shell.h" +#include "../idle_inhibit_v1.h" +#include "../keybinding.h" +#include "../message.h" +#include "../output.h" +#include "../parse.h" +#include "../seat.h" +#include "../server.h" +#include "../view.h" +#include "../workspace.h" +#include "../xdg_shell.h" #if CG_HAS_XWAYLAND -#include "xwayland.h" +#include "../xwayland.h" #endif #ifndef WAIT_ANY From ce9b68d44834ae3cd258447d5495bcc1051d693b Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 4 Apr 2020 21:33:54 +0200 Subject: [PATCH 042/122] Squashed commit of the following: commit 27fa2b70b9d45a41860bf5332ba80f8d6b11bc8e Merge: 1a87477 6fdc55c Author: Cagebreak Signing Key 1 Date: Mon Mar 2 18:45:11 2020 +0000 Merge branch 'output_config' of https://github.com/project-repo/cagebreak into output_config commit 6fdc55c9a55edd187d63bf92f78365d4440fb845 Author: project-repo Date: Fri Feb 28 17:30:06 2020 +0100 Add missing functionality to output configuration commit 33d245b60bfe86025d9244490bf144679af606f3 Author: project-repo Date: Wed Feb 26 07:56:28 2020 +0100 Add example of "output" command usage commit 0d4bb36068cf27854ba45423071111b285cee174 Author: project-repo Date: Wed Feb 26 07:55:25 2020 +0100 Add documentation for "output" command commit a2cc047132b31cbe4e7a87da4b033a827fad4087 Author: project-repo Date: Sun Feb 23 16:53:47 2020 +0100 Add support for output layout configuration --- cagebreak.c | 16 ++++++ examples/config | 5 ++ fuzz/fuzz-parse.c | 17 +++++-- man/cagebreak-config.5.md | 7 +++ output.c | 75 ++++++++++++++++++++++++--- output.h | 11 +++- parse.c | 103 ++++++++++++++++++++++++++++++++++++++ server.h | 2 + 8 files changed, 225 insertions(+), 11 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index ba359e5..03cd5b9 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -310,6 +310,8 @@ 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); @@ -509,6 +511,13 @@ main(int argc, char *argv[]) { free(config_file); } + { + struct cg_output *output; + wl_list_for_each(output, &server.outputs, link) { + output_configure(&server, output); + } + } + /* Place the cursor to the topl left of the output layout. */ wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); @@ -526,6 +535,13 @@ end: } free(server.modes); + struct cg_output_config *output_config, *output_config_tmp; + wl_list_for_each_safe(output_config, output_config_tmp, &server.output_config, link) { + wl_list_remove(&output_config->link); + free(output_config->output_name); + free(output_config); + } + keybinding_list_free(server.keybindings); wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); diff --git a/examples/config b/examples/config index cd7ee3c..0f0a5b0 100644 --- a/examples/config +++ b/examples/config @@ -70,3 +70,8 @@ definekey top XF86AudioLowerVolume exec pactl set-sink-mute 0 off&&amixer set Ma definekey top XF86AudioRaiseVolume exec pactl set-sink-mute 0 off&&amixer set Master 1%+ definekey top XF86MonBrightnessDown exec xbacklight -dec 1 definekey top XF86MonBrightnessUp exec xbacklight -inc 1 + +###################### +#Output configuration +###################### +#output eDP-1 pos 0 0 res 1366x768 rate 60 diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index e4dcd06..ff13a15 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -8,10 +8,13 @@ #define _POSIX_C_SOURCE 200812L -#include "config.h" -#include -#include +#include "../keybinding.h" +#include "../parse.h" +#include "../seat.h" +#include "../server.h" +#include "../output.h" +#include #include #include #include @@ -443,5 +446,13 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { } server.modes[3] = NULL; server.modes = realloc(server.modes, 4 * sizeof(char *)); + + struct cg_output_config *output_config, *output_config_tmp; + wl_list_for_each_safe(output_config, output_config_tmp, &server.output_config, link) { + wl_list_remove(&output_config->link); + free(output_config->output_name); + free(output_config); + } + return 0; } diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index dffc8b3..cdcf229 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -131,6 +131,13 @@ by prepending a line with the # symbol. > Remove all splits and make the current window fill the entire screen +**output pos res x rate ** + +> Configure the output "". and are the position of the monitor +> in pixels. The top-left monitor should have the coordinates 0 0. and +> specify the resolution in pixels and sets the refresh rate of +> the monitor (often this is 50 or 60). + **prev** > Focus previous window in current tile diff --git a/output.c b/output.c index 4fd6960..7983983 100644 --- a/output.c +++ b/output.c @@ -480,6 +480,72 @@ handle_output_destroy(struct wl_listener *listener, void *data) { output_destroy(output); } +struct cg_output_config* +output_find_config(struct cg_server* server, struct wlr_output* output) { + struct cg_output_config *config; + wl_list_for_each(config, &server->output_config, link) { + if(strcmp(config->output_name, output->name) == 0) { + return config; + } + } + return NULL; +} + +static void output_set_mode(struct wlr_output *output, int width, int height, + float refresh_rate) { + int mhz = (int)(refresh_rate * 1000); + + if (wl_list_empty(&output->modes)) { + wlr_log(WLR_DEBUG, "Assigning custom mode to %s", output->name); + wlr_output_set_custom_mode(output, width, height, + refresh_rate > 0 ? mhz : 0); + return; + } + + struct wlr_output_mode *mode, *best = NULL; + wl_list_for_each(mode, &output->modes, link) { + if (mode->width == width && mode->height == height) { + if (mode->refresh == mhz) { + best = mode; + break; + } + if (best == NULL || mode->refresh > best->refresh) { + best = mode; + } + } + } + if (!best) { + wlr_log(WLR_ERROR, "Configured mode for %s not available", output->name); + wlr_log(WLR_INFO, "Picking preferred mode instead"); + best = wlr_output_preferred_mode(output); + } else { + wlr_log(WLR_DEBUG, "Assigning configured mode to %s", output->name); + } + wlr_output_set_mode(output, best); +} + +void +output_configure(struct cg_server* server, struct cg_output *output) { + struct wlr_output *wlr_output = output->wlr_output; + struct cg_output_config *config = output_find_config(server, wlr_output); + if(output->wlr_output->enabled) { + wlr_output_layout_remove(server->output_layout, wlr_output); + } + + if(config == NULL) { + wlr_output_layout_add_auto(server->output_layout, wlr_output); + + struct wlr_output_mode *preferred_mode = + wlr_output_preferred_mode(wlr_output); + if(preferred_mode) { + wlr_output_set_mode(wlr_output, preferred_mode); + } + } else { + output_set_mode(wlr_output, config->pos.width, config->pos.height, config->refresh_rate); + wlr_output_layout_add(server->output_layout, wlr_output, config->pos.x, config->pos.y); + } +} + void handle_new_output(struct wl_listener *listener, void *data) { struct cg_server *server = wl_container_of(listener, server, new_output); @@ -508,7 +574,8 @@ handle_new_output(struct wl_listener *listener, void *data) { wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); wlr_output_set_transform(wlr_output, server->output_transform); - wlr_output_layout_add_auto(server->output_layout, wlr_output); + + output_configure(server, output); output->workspaces = malloc(server->nws * sizeof(struct cg_workspace *)); for(unsigned int i = 0; i < server->nws; ++i) { @@ -520,12 +587,6 @@ handle_new_output(struct wl_listener *listener, void *data) { output->curr_workspace = 0; wl_list_init(&output->messages); - struct wlr_output_mode *preferred_mode = - wlr_output_preferred_mode(wlr_output); - if(preferred_mode) { - wlr_output_set_mode(wlr_output, preferred_mode); - } - if(wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, diff --git a/output.h b/output.h index ffca3e7..ba12ea6 100644 --- a/output.h +++ b/output.h @@ -2,13 +2,13 @@ #define CG_OUTPUT_H #include +#include struct cg_server; struct cg_view; struct wlr_output; struct wlr_output_damage; struct wlr_surface; -struct wlr_box; struct cg_output { struct cg_server *server; @@ -27,6 +27,13 @@ struct cg_output { struct wl_list link; // cg_server::outputs }; +struct cg_output_config { + struct wlr_box pos; + char* output_name; + float refresh_rate; + struct wl_list link;// cg_server::output_config +}; + typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, @@ -35,6 +42,8 @@ typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, void handle_new_output(struct wl_listener *listener, void *data); void +output_configure(struct cg_server* server, struct cg_output* output); +void output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *surface, double ox, double oy, cg_surface_iterator_func_t iterator, diff --git a/parse.c b/parse.c index cb6abe3..dae5164 100644 --- a/parse.c +++ b/parse.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "keybinding.h" #include "output.h" @@ -192,6 +193,104 @@ parse_workspaces(char **saveptr) { return nws; } +int +parse_uint(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 integer, got nothing"); + return -1; + } + long uint = strtol(uint_str, NULL, 10); + if(uint >= 0 && uint <= INT_MAX) { + return uint; + } else { + wlr_log(WLR_ERROR, "Error parsing non-negative integer. Must be a number larger or equal to 0 and less or equal to %d",INT_MAX); + return -1; + } +} + +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(struct wl_list *config_list, char **saveptr) { + struct cg_output_config* cfg = malloc(sizeof(struct cg_output_config)); + char *name = strtok_r(NULL, " ", saveptr); + if(name == NULL) { + wlr_log(WLR_ERROR, "Expected name of output to be configured, got none"); + goto error; + } + char *pos_str = strtok_r(NULL, " ", saveptr); + if(pos_str == NULL || strcmp(pos_str, "pos") != 0) { + wlr_log(WLR_ERROR, "Expected keyword \"pos\" in output configuration for output %s", name); + goto error; + } + + cfg->pos.x = parse_uint(saveptr, " "); + if(cfg->pos.x < 0) { + wlr_log(WLR_ERROR, "Error parsing x coordinate of output configuration for output %s", name); + goto error; + } + + cfg->pos.y = parse_uint(saveptr, " "); + if(cfg->pos.y < 0) { + wlr_log(WLR_ERROR, "Error parsing y coordinate of output configuration for output %s", name); + goto error; + } + + char *res_str = strtok_r(NULL, " ", saveptr); + if(res_str == NULL || strcmp(res_str, "res") != 0) { + wlr_log(WLR_ERROR, "Expected keyword \"res\" in output configuration for output %s", name); + goto error; + } + + cfg->pos.width = parse_uint(saveptr, "x"); + if(cfg->pos.width <= 0) { + wlr_log(WLR_ERROR, "Error parsing width of output configuration for output %s (hint: width must be larger than 0)", name); + goto error; + } + + cfg->pos.height = parse_uint(saveptr, " "); + if(cfg->pos.height <= 0) { + wlr_log(WLR_ERROR, "Error parsing height of output configuration for output %s (hint: height must e larger than 0)", name); + goto error; + } + + char *rate_str = strtok_r(NULL, " ", saveptr); + if(rate_str == NULL || strcmp(rate_str, "rate") != 0) { + wlr_log(WLR_ERROR, "Expected keyword \"rate\" in output configuration for output %s", name); + goto error; + } + + cfg->refresh_rate = parse_float(saveptr, " "); + if(cfg->refresh_rate <= 0.0) { + wlr_log(WLR_ERROR, "Error parsing refresh rate of output configuration for output %s", name); + goto error; + } + + cfg->output_name = strdup(name); + wl_list_insert(config_list, &cfg->link); + return 0; + +error: + free(cfg); + wlr_log(WLR_ERROR, "Output configuration must be of the form \"output pos res x rate "); + return -1; +} + int parse_command(struct cg_server *server, struct keybinding *keybinding, char *saveptr) { @@ -380,6 +479,10 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, if(keybinding->data.i < 0) { return -1; } + } else if(strcmp(action, "output") == 0) { + if(parse_output_config(&server->output_config, &saveptr) != 0) { + return -1; + } } else { wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action); return -1; diff --git a/server.h b/server.h index 92a9172..930cb56 100644 --- a/server.h +++ b/server.h @@ -11,6 +11,7 @@ struct cg_output; struct keybinding_list; struct wlr_output_layout; struct wlr_idle_inhibit_manager_v1; +struct cg_output_config; struct cg_server { struct wl_display *wl_display; @@ -35,6 +36,7 @@ struct cg_server { #endif struct keybinding_list *keybindings; + struct wl_list output_config; enum wl_output_transform output_transform; From 50be52b7fc2d19eecba2836f3575bb8392668920 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 4 Apr 2020 21:47:07 +0200 Subject: [PATCH 043/122] Fix bug in fuzzer --- fuzz/fuzz-parse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index ff13a15..2103a20 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -200,6 +200,8 @@ LLVMFuzzerInitialize(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); From 3f277d2b7f13e955fa27b23d60decf303963664d Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 9 Apr 2020 17:31:35 +0000 Subject: [PATCH 044/122] Prepare new release - Update version numbers --- README.md | 4 ++++ man/cagebreak-config.5.md | 2 +- man/cagebreak.1.md | 2 +- meson.build | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 619fd75..33e0e35 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,10 @@ Adds basic tiling window manager functionality to cage. Unifies commands and actions. See Issue 4 in Bugs.md. +### Release 1.2.0 + +Adds output configuration as described in the man pages. + ## License Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE) diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index cdcf229..8f9cb72 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -1,4 +1,4 @@ -% CAGEBREAK-CONFIG(1) Version 1.1 | Cagebreak Manual +% CAGEBREAK-CONFIG(1) Version 1.2 | Cagebreak Manual # NAME diff --git a/man/cagebreak.1.md b/man/cagebreak.1.md index cacd1c2..07c0058 100644 --- a/man/cagebreak.1.md +++ b/man/cagebreak.1.md @@ -1,4 +1,4 @@ -% CAGEBREAK(1) Version 1.1 | Cagebreak Manual +% CAGEBREAK(1) Version 1.2 | Cagebreak Manual # NAME diff --git a/meson.build b/meson.build index 959d35f..148a3e2 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.1.0', + version: '1.2.0', license: 'MIT', default_options: [ 'c_std=c11', From da8d0304a61a4c508e4c6661ec0aa787978f1d6f Mon Sep 17 00:00:00 2001 From: project-repo Date: Sun, 12 Apr 2020 09:07:54 +0200 Subject: [PATCH 045/122] Remove keyboard group from list on destroy --- seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/seat.c b/seat.c index 7567586..ae8e52f 100644 --- a/seat.c +++ b/seat.c @@ -794,6 +794,7 @@ handle_destroy(struct wl_listener *listener, void *_data) { struct cg_keyboard_group *group, *group_tmp; wl_list_for_each_safe(group, group_tmp, &seat->keyboard_groups, link) { + wl_list_remove(&group->link); wlr_keyboard_group_destroy(group->wlr_group); wl_event_source_remove(group->key_repeat_timer); free(group); From 91bf4913b20e50e18d699fda6100813d45c1f688 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 14 May 2020 13:26:34 +0000 Subject: [PATCH 046/122] Update dependency version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 148a3e2..38b46f7 100644 --- a/meson.build +++ b/meson.build @@ -188,7 +188,7 @@ reproducible_build_versions = { 'wlroots': '0.10.1', 'xkbcommon': '0.10.0', 'fontconfig': '2.13.91', - 'pixman': '0.38.4', + 'pixman': '0.40.0', 'pango': '1.44.7', 'cairo': '1.17.3', 'pangocairo': '1.44.7', From 9a5b26716f8eba0023f8c048ecb69606187a4f36 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 14 May 2020 14:21:00 +0000 Subject: [PATCH 047/122] Remove -Wall because warning_level=3 includes it --- meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/meson.build b/meson.build index 38b46f7..40c09d7 100644 --- a/meson.build +++ b/meson.build @@ -10,7 +10,6 @@ project('cagebreak', 'c', add_project_arguments( [ '-DWLR_USE_UNSTABLE', - '-Wall', '-Wundef', '-Wno-unused-parameter', ], From 212da7a3454de94e0ce2763ed9e88514b7311faa Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 14 May 2020 14:42:09 +0000 Subject: [PATCH 048/122] Add binary hashes --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 33e0e35..0eb113b 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,11 @@ ninja -C build For every release after 1.0.5, hashes will be provided. +1.2.0 + + * sha 256: b3c6135833001a0ef600ea9628cca11f4130a524ebe748929d8f7bad034f2bf0 + * sha 512: c044a086a9f65b0d27d05e2f12a20fe5d77386fc5682991c13a1894a84804bcd337c9167235869661d6e6581133521bd710ef2330066a5d2e2703d1630042f3f + 1.1.0 * sha 256: fc393e225c549f893b9e21e8b904e546d5857bac1d905b3d26334c8f8a1cda11 From a0a6b2625da8371a852e854d123a27c768dc6027 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 14 May 2020 14:52:40 +0000 Subject: [PATCH 049/122] Add release signature --- signatures/1.1.0.sig | Bin 0 -> 566 bytes signatures/cagebreak.sig | Bin 566 -> 566 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 signatures/1.1.0.sig diff --git a/signatures/1.1.0.sig b/signatures/1.1.0.sig new file mode 100644 index 0000000000000000000000000000000000000000..ac5a0e800ff52d34973b17b4349461fee72fbd32 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$zl9z5ogd5XAX( z*9`0|TO2eH0JT8XB2TlbW_=Xa#kN@qTWL1V>FRsd$`XXjWfmfAwn0iW4MZ|YvHJeIWJfF7KYe&A8|sFKPdA1_Drb%haK7vulHRk zEMD~%b(50NLn5pw!`aLDjT(@M$UFDv2s--0L2nBQE)P{N*5~e{_vwv0$G0=EA=Bvn zZ8UxfiQ&n=5b7$KTxX|U0Lqfxe5cOlCH*kTg7Zy2T7{i0K(`ZryMgc_6sifgmu?YM zrz`#KXmh*1yEh9uWyl2>1}jRf>MDZOY%v)#J@hnSQguMrM@%jLr)bjhvCY3dP+X2!IIcI+tJ-9R-P+)!(96Nss%)jo$0`9L1W zzHaSL4fo5r)T7FcHo0nBw^&s~@EB=I(@Bb{-P;=&|eqh z+5NTd^Vmn-Yf;hi9?v`un2@!jWj@ zpD7oQnvI3QO^SRPx;FLXS9Rlm>Dx)uj8~KZ>RgVL!w5-k+kZM))aP;Pbmou%1JxGZ zR{zN*1;o~TVdW3#Uhb`Q;<~fz(B5R11P_n7GbgxufMMH|;&cYcrf0+lhUl*@Sn_Z7 zO^Hac&@>)&^p^SdC0LWmvXnu%7haaK-Fv!OoG4^HWi=?$-!mjgX1lla;a$<^S$QFa zrqH=c&T|}&y?;NqT;}DaOMfUBH!W2p>k75}i_PWNVG8!F z49YIZ#D`M?vELRP?_B3u2=nW$b!Y_giac^m@a9zxO_FsRRuDV~RxC_}!#stghbW|4 zj`6TbAd4Q@>kHq)$ delta 542 zcmV+(0^$9(1hxc_BY%W>z5ogd5XAX(*9`0|TO2eH0JT8XB2TlbW_=Xa#kN@qTWL1V z>FRsd$`XXjWfmfAwn0iW4MZ|YvHCHnh{!wl=LkCb z!a;8f2`&#+FV^Soqxb2JJIA*(up!gv{cSXU35ns!zYyvwnOtY5T>#3G-F&Cc<|X|w z$%6AuK3avHEq_3_6Mwsb@F5hc3AdMS5mcuu{q1OTyS}?O3p!=U1sDb^O0DWDg4Jv> z88bcfG+>0J?N1H&%YV7lqsomoxoTVEqR{@|j?eq+ zf_Wszus)TC);~$H9CeLJWCm>7Ssiobp&>ao;G33i?%Kke3Sv?%2suKd!K7J+77HoU z&jO)2-!K8RgC50dKWg-iA^OEiO}_fo5 Date: Wed, 20 May 2020 11:53:46 +0200 Subject: [PATCH 050/122] Apply fixes suggested by -fanalyze --- cagebreak.c | 17 ++++++++++++++++- keybinding.c | 15 +++++++++++++-- message.c | 15 +++++++++++++++ output.c | 8 ++++++++ parse.c | 14 +++++++++++++- workspace.c | 26 ++++++++++++++++++++------ workspace.h | 4 ++-- 7 files changed, 87 insertions(+), 12 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index 03cd5b9..28ba139 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -198,10 +198,12 @@ set_configuration(struct cg_server *server, if(parse_rc_line(server, line) != 0) { wlr_log(WLR_ERROR, "Error in config file \"%s\", line %d\n", config_file_path, line_num); + fclose(config_file); return -1; } } } + fclose(config_file); return 0; } @@ -218,6 +220,10 @@ get_config_file() { } char *config_path = malloc( (strlen(config_home_path) + strlen(addition) + 1) * sizeof(char)); + if(!config_path) { + wlr_log(WLR_ERROR, "Failed to allocate space for configuration path"); + return NULL; + } sprintf(config_path, "%s%s", config_home_path, addition); return config_path; } @@ -256,6 +262,12 @@ main(int argc, char *argv[]) { wlr_log_init(WLR_ERROR, NULL); #endif + server.modes = malloc(4 * sizeof(char *)); + if(!server.modes) { + wlr_log(WLR_ERROR,"Error allocating mode array"); + return -1; + } + /* 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"); @@ -270,11 +282,14 @@ main(int argc, char *argv[]) { server.running = true; - server.modes = malloc(4 * sizeof(char *)); server.modes[0] = strdup("top"); server.modes[1] = strdup("root"); server.modes[2] = strdup("resize"); server.modes[3] = NULL; + if(!server.modes[0]||!server.modes[1]||server.modes[2]) { + wlr_log(WLR_ERROR,"Error allocating default modes"); + goto end; + } server.nws = 1; server.message_timeout = 2; diff --git a/keybinding.c b/keybinding.c index f6f5eaf..c9fe665 100644 --- a/keybinding.c +++ b/keybinding.c @@ -453,8 +453,10 @@ keybinding_workspace_fullscreen(struct cg_server *server) { } workspace_free_tiles(output->workspaces[output->curr_workspace]); - full_screen_workspace_tiles(output, - output->workspaces[output->curr_workspace]); + if(full_screen_workspace_tiles(server->output_layout,output->wlr_output, output->workspaces[output->curr_workspace])!=0) { + wlr_log(WLR_ERROR, "Failed to allocate space for fullscreen workspace"); + return; + } seat_set_focus(server->seat, current_view); } @@ -517,6 +519,10 @@ keybinding_split_output(struct cg_output *output, bool vertical) { } struct cg_tile *new_tile = calloc(1, sizeof(struct cg_tile)); + if(!new_tile) { + wlr_log(WLR_ERROR, "Failed to allocate new tile for splitting"); + return; + } new_tile->tile.x = new_x; new_tile->tile.y = new_y; new_tile->tile.width = x + width - new_x; @@ -741,6 +747,11 @@ keybinding_set_nws(struct cg_server *server, int nws) { output->workspaces = new_workspaces; for(int i = server->nws; i < nws; ++i) { output->workspaces[i] = full_screen_workspace(output); + if(!output->workspaces[i]) { + wlr_log(WLR_ERROR, "Failed to allocate additional workspaces"); + return; + } + wl_list_init(&output->workspaces[i]->views); wl_list_init(&output->workspaces[i]->unmanaged_views); } diff --git a/message.c b/message.c index 40ac033..bc24928 100644 --- a/message.c +++ b/message.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "cairo.h" #include "message.h" @@ -98,6 +99,11 @@ void message_set_output(struct cg_output *output, const char *string, struct wlr_box *box, enum cg_message_align align) { struct cg_message *message = malloc(sizeof(struct cg_message)); + if(!message) { + wlr_log(WLR_ERROR, "Error allocating message structure"); + free(box); + return; + } message->message = create_message_texture(string, output); message->position = box; wl_list_insert(&output->messages, &message->link); @@ -136,6 +142,10 @@ void message_printf(struct cg_output *output, const char *fmt, ...) { uint16_t buf_len = 256; char *buffer = (char *)malloc(buf_len * sizeof(char)); + if(buffer == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate buffer in message_printf"); + return; + } va_list ap; va_start(ap, fmt); @@ -143,6 +153,11 @@ message_printf(struct cg_output *output, const char *fmt, ...) { va_end(ap); struct wlr_box *box = malloc(sizeof(struct wlr_box)); + if(box == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate box in message_printf"); + free(buffer); + return; + } struct wlr_box *output_box = wlr_output_layout_get_box( output->server->output_layout, output->wlr_output); diff --git a/output.c b/output.c index 7983983..dbf75b5 100644 --- a/output.c +++ b/output.c @@ -580,6 +580,10 @@ handle_new_output(struct wl_listener *listener, void *data) { output->workspaces = malloc(server->nws * sizeof(struct cg_workspace *)); for(unsigned int i = 0; i < server->nws; ++i) { output->workspaces[i] = full_screen_workspace(output); + if(!output->workspaces[i]) { + wlr_log(WLR_ERROR, "Failed to allocate workspaces for output"); + return; + } wl_list_init(&output->workspaces[i]->views); wl_list_init(&output->workspaces[i]->unmanaged_views); } @@ -603,6 +607,10 @@ handle_new_output(struct wl_listener *listener, void *data) { for(unsigned int i = 0; i < server->nws; ++i) { workspace_free(output->workspaces[i]); output->workspaces[i] = full_screen_workspace(output); + if(!output->workspaces[i]) { + wlr_log(WLR_ERROR, "Failed to allocate workspaces for output"); + return; + } wl_list_init(&output->workspaces[i]->views); wl_list_init(&output->workspaces[i]->unmanaged_views); } diff --git a/parse.c b/parse.c index dae5164..33082c8 100644 --- a/parse.c +++ b/parse.c @@ -67,7 +67,11 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, struct keybinding * parse_keybinding(struct cg_server *server, char **saveptr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); - char *key = strtok_r(NULL, " ", saveptr); + if(keybinding == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate memory for keybinding in parse_keybinding"); + return NULL; + } +char *key = strtok_r(NULL, " ", saveptr); if(parse_key(keybinding, key) != 0) { wlr_log(WLR_ERROR, "Could not parse key definition \"%s\"", key); free(keybinding); @@ -153,6 +157,10 @@ parse_background(struct cg_server *server, float *color, char **saveptr) { struct keybinding * parse_escape(char **saveptr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); + if(keybinding == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate memory for keybinding in parse_escape"); + return NULL; + } char *key = strtok_r(NULL, " ", saveptr); if(parse_key(keybinding, key) != 0) { wlr_log(WLR_ERROR, @@ -228,6 +236,10 @@ parse_float(char **saveptr, const char* delim) { int parse_output_config(struct wl_list *config_list, char **saveptr) { struct cg_output_config* cfg = malloc(sizeof(struct cg_output_config)); + if(cfg == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate memory for output configuration"); + goto error; + } char *name = strtok_r(NULL, " ", saveptr); if(name == NULL) { wlr_log(WLR_ERROR, "Expected name of output to be configured, got none"); diff --git a/workspace.c b/workspace.c index 8ed010e..10a476d 100644 --- a/workspace.c +++ b/workspace.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "message.h" #include "output.h" @@ -19,27 +20,36 @@ #include "view.h" #include "workspace.h" -void -full_screen_workspace_tiles(const struct cg_output *output, +int +full_screen_workspace_tiles(struct wlr_output_layout *layout,struct wlr_output *output, struct cg_workspace *workspace) { - workspace->server = output->server; workspace->focused_tile = calloc(1, sizeof(struct cg_tile)); + if(!workspace->focused_tile) { + return -1; + } workspace->focused_tile->workspace = workspace; workspace->focused_tile->next = workspace->focused_tile; workspace->focused_tile->prev = workspace->focused_tile; workspace->focused_tile->tile.x = 0; workspace->focused_tile->tile.y = 0; - struct wlr_box *output_box = wlr_output_layout_get_box( - output->server->output_layout, output->wlr_output); + struct wlr_box *output_box = wlr_output_layout_get_box(layout, output); workspace->focused_tile->tile.width = output_box->width; workspace->focused_tile->tile.height = output_box->height; workspace->focused_tile->view = NULL; + return 0; } struct cg_workspace * full_screen_workspace(struct cg_output *output) { struct cg_workspace *workspace = calloc(1, sizeof(struct cg_workspace)); - full_screen_workspace_tiles(output, workspace); + if(!workspace) { + return NULL; + } + workspace->server=output->server; + if(full_screen_workspace_tiles(output->server->output_layout, output->wlr_output, workspace)!=0) { + free(workspace); + return NULL; + } workspace->output = output; return workspace; } @@ -48,6 +58,10 @@ void workspace_focus_tile(struct cg_workspace *ws, struct cg_tile *tile) { ws->focused_tile = tile; struct wlr_box *box = malloc(sizeof(struct wlr_box)); + if(!box) { + wlr_log(WLR_ERROR, "Failed to allocate box required to focus tile"); + return; + } box->x = tile->tile.x + tile->tile.width / 2; box->y = tile->tile.y + tile->tile.height / 2; message_printf_pos(ws->output, box, CG_MESSAGE_CENTER, "Current frame"); diff --git a/workspace.h b/workspace.h index 069d036..34586f7 100644 --- a/workspace.h +++ b/workspace.h @@ -25,8 +25,8 @@ struct cg_workspace { struct cg_workspace * full_screen_workspace(struct cg_output *output); -void -full_screen_workspace_tiles(const struct cg_output *output, +int +full_screen_workspace_tiles(struct wlr_output_layout *layout,struct wlr_output *output, struct cg_workspace *workspace); void workspace_free_tiles(struct cg_workspace *workspace); From 9ac95ce69c7faf7b9be1fb0dbb10436a1556a702 Mon Sep 17 00:00:00 2001 From: project-repo Date: Wed, 20 May 2020 19:35:16 +0200 Subject: [PATCH 051/122] Apply clang-format --- cagebreak.c | 9 +++--- fuzz/fuzz-parse.c | 6 ++-- keybinding.c | 4 ++- output.c | 32 +++++++++++--------- output.h | 6 ++-- parse.c | 74 ++++++++++++++++++++++++++++++++++------------- workspace.c | 8 +++-- workspace.h | 3 +- 8 files changed, 93 insertions(+), 49 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index 28ba139..8f5c01d 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -264,7 +264,7 @@ main(int argc, char *argv[]) { server.modes = malloc(4 * sizeof(char *)); if(!server.modes) { - wlr_log(WLR_ERROR,"Error allocating mode array"); + wlr_log(WLR_ERROR, "Error allocating mode array"); return -1; } @@ -286,8 +286,8 @@ main(int argc, char *argv[]) { server.modes[1] = strdup("root"); server.modes[2] = strdup("resize"); server.modes[3] = NULL; - if(!server.modes[0]||!server.modes[1]||server.modes[2]) { - wlr_log(WLR_ERROR,"Error allocating default modes"); + if(!server.modes[0] || !server.modes[1] || server.modes[2]) { + wlr_log(WLR_ERROR, "Error allocating default modes"); goto end; } @@ -551,7 +551,8 @@ end: free(server.modes); struct cg_output_config *output_config, *output_config_tmp; - wl_list_for_each_safe(output_config, output_config_tmp, &server.output_config, link) { + wl_list_for_each_safe(output_config, output_config_tmp, + &server.output_config, link) { wl_list_remove(&output_config->link); free(output_config->output_name); free(output_config); diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 2103a20..bcfb701 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -8,12 +8,11 @@ #define _POSIX_C_SOURCE 200812L - #include "../keybinding.h" +#include "../output.h" #include "../parse.h" #include "../seat.h" #include "../server.h" -#include "../output.h" #include #include #include @@ -450,7 +449,8 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { server.modes = realloc(server.modes, 4 * sizeof(char *)); struct cg_output_config *output_config, *output_config_tmp; - wl_list_for_each_safe(output_config, output_config_tmp, &server.output_config, link) { + wl_list_for_each_safe(output_config, output_config_tmp, + &server.output_config, link) { wl_list_remove(&output_config->link); free(output_config->output_name); free(output_config); diff --git a/keybinding.c b/keybinding.c index c9fe665..752a434 100644 --- a/keybinding.c +++ b/keybinding.c @@ -453,7 +453,9 @@ keybinding_workspace_fullscreen(struct cg_server *server) { } workspace_free_tiles(output->workspaces[output->curr_workspace]); - if(full_screen_workspace_tiles(server->output_layout,output->wlr_output, output->workspaces[output->curr_workspace])!=0) { + if(full_screen_workspace_tiles( + server->output_layout, output->wlr_output, + output->workspaces[output->curr_workspace]) != 0) { wlr_log(WLR_ERROR, "Failed to allocate space for fullscreen workspace"); return; } diff --git a/output.c b/output.c index dbf75b5..7c23ad8 100644 --- a/output.c +++ b/output.c @@ -480,8 +480,8 @@ handle_output_destroy(struct wl_listener *listener, void *data) { output_destroy(output); } -struct cg_output_config* -output_find_config(struct cg_server* server, struct wlr_output* output) { +struct cg_output_config * +output_find_config(struct cg_server *server, struct wlr_output *output) { struct cg_output_config *config; wl_list_for_each(config, &server->output_config, link) { if(strcmp(config->output_name, output->name) == 0) { @@ -491,31 +491,33 @@ output_find_config(struct cg_server* server, struct wlr_output* output) { return NULL; } -static void output_set_mode(struct wlr_output *output, int width, int height, - float refresh_rate) { +static void +output_set_mode(struct wlr_output *output, int width, int height, + float refresh_rate) { int mhz = (int)(refresh_rate * 1000); - if (wl_list_empty(&output->modes)) { + if(wl_list_empty(&output->modes)) { wlr_log(WLR_DEBUG, "Assigning custom mode to %s", output->name); wlr_output_set_custom_mode(output, width, height, - refresh_rate > 0 ? mhz : 0); + refresh_rate > 0 ? mhz : 0); return; } struct wlr_output_mode *mode, *best = NULL; wl_list_for_each(mode, &output->modes, link) { - if (mode->width == width && mode->height == height) { - if (mode->refresh == mhz) { + if(mode->width == width && mode->height == height) { + if(mode->refresh == mhz) { best = mode; break; } - if (best == NULL || mode->refresh > best->refresh) { + if(best == NULL || mode->refresh > best->refresh) { best = mode; } } } - if (!best) { - wlr_log(WLR_ERROR, "Configured mode for %s not available", output->name); + if(!best) { + wlr_log(WLR_ERROR, "Configured mode for %s not available", + output->name); wlr_log(WLR_INFO, "Picking preferred mode instead"); best = wlr_output_preferred_mode(output); } else { @@ -525,7 +527,7 @@ static void output_set_mode(struct wlr_output *output, int width, int height, } void -output_configure(struct cg_server* server, struct cg_output *output) { +output_configure(struct cg_server *server, struct cg_output *output) { struct wlr_output *wlr_output = output->wlr_output; struct cg_output_config *config = output_find_config(server, wlr_output); if(output->wlr_output->enabled) { @@ -541,8 +543,10 @@ output_configure(struct cg_server* server, struct cg_output *output) { wlr_output_set_mode(wlr_output, preferred_mode); } } else { - output_set_mode(wlr_output, config->pos.width, config->pos.height, config->refresh_rate); - wlr_output_layout_add(server->output_layout, wlr_output, config->pos.x, config->pos.y); + output_set_mode(wlr_output, config->pos.width, config->pos.height, + config->refresh_rate); + wlr_output_layout_add(server->output_layout, wlr_output, config->pos.x, + config->pos.y); } } diff --git a/output.h b/output.h index ba12ea6..bf9abb4 100644 --- a/output.h +++ b/output.h @@ -29,9 +29,9 @@ struct cg_output { struct cg_output_config { struct wlr_box pos; - char* output_name; + char *output_name; float refresh_rate; - struct wl_list link;// cg_server::output_config + struct wl_list link; // cg_server::output_config }; typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, @@ -42,7 +42,7 @@ typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, void handle_new_output(struct wl_listener *listener, void *data); void -output_configure(struct cg_server* server, struct cg_output* output); +output_configure(struct cg_server *server, struct cg_output *output); void output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *surface, double ox, diff --git a/parse.c b/parse.c index 33082c8..f08b59d 100644 --- a/parse.c +++ b/parse.c @@ -1,9 +1,9 @@ #define _POSIX_C_SOURCE 200812L +#include #include #include #include -#include #include "keybinding.h" #include "output.h" @@ -68,10 +68,11 @@ struct keybinding * parse_keybinding(struct cg_server *server, char **saveptr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate memory for keybinding in parse_keybinding"); + wlr_log(WLR_ERROR, + "Failed to allocate memory for keybinding in parse_keybinding"); return NULL; } -char *key = strtok_r(NULL, " ", saveptr); + char *key = strtok_r(NULL, " ", saveptr); if(parse_key(keybinding, key) != 0) { wlr_log(WLR_ERROR, "Could not parse key definition \"%s\"", key); free(keybinding); @@ -158,7 +159,8 @@ struct keybinding * parse_escape(char **saveptr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate memory for keybinding in parse_escape"); + wlr_log(WLR_ERROR, + "Failed to allocate memory for keybinding in parse_escape"); return NULL; } char *key = strtok_r(NULL, " ", saveptr); @@ -202,7 +204,7 @@ parse_workspaces(char **saveptr) { } int -parse_uint(char **saveptr, const char* delim) { +parse_uint(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 integer, got nothing"); @@ -212,13 +214,16 @@ parse_uint(char **saveptr, const char* delim) { if(uint >= 0 && uint <= INT_MAX) { return uint; } else { - wlr_log(WLR_ERROR, "Error parsing non-negative integer. Must be a number larger or equal to 0 and less or equal to %d",INT_MAX); + wlr_log(WLR_ERROR, + "Error parsing non-negative integer. Must be a number larger " + "or equal to 0 and less or equal to %d", + INT_MAX); return -1; } } float -parse_float(char **saveptr, const char* delim) { +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"); @@ -228,68 +233,95 @@ parse_float(char **saveptr, const char* delim) { if(ufloat >= 0) { return ufloat; } else { - wlr_log(WLR_ERROR, "Error parsing non-negative float. Must be a number larger or equal to 0"); + wlr_log(WLR_ERROR, "Error parsing non-negative float. Must be a number " + "larger or equal to 0"); return -1; } } int parse_output_config(struct wl_list *config_list, char **saveptr) { - struct cg_output_config* cfg = malloc(sizeof(struct cg_output_config)); + struct cg_output_config *cfg = malloc(sizeof(struct cg_output_config)); if(cfg == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate memory for output configuration"); + wlr_log(WLR_ERROR, + "Failed to allocate memory for output configuration"); goto error; } char *name = strtok_r(NULL, " ", saveptr); if(name == NULL) { - wlr_log(WLR_ERROR, "Expected name of output to be configured, got none"); + wlr_log(WLR_ERROR, + "Expected name of output to be configured, got none"); goto error; } char *pos_str = strtok_r(NULL, " ", saveptr); if(pos_str == NULL || strcmp(pos_str, "pos") != 0) { - wlr_log(WLR_ERROR, "Expected keyword \"pos\" in output configuration for output %s", name); + wlr_log( + WLR_ERROR, + "Expected keyword \"pos\" in output configuration for output %s", + name); goto error; } cfg->pos.x = parse_uint(saveptr, " "); if(cfg->pos.x < 0) { - wlr_log(WLR_ERROR, "Error parsing x coordinate of output configuration for output %s", name); + wlr_log( + WLR_ERROR, + "Error parsing x coordinate of output configuration for output %s", + name); goto error; } cfg->pos.y = parse_uint(saveptr, " "); if(cfg->pos.y < 0) { - wlr_log(WLR_ERROR, "Error parsing y coordinate of output configuration for output %s", name); + wlr_log( + WLR_ERROR, + "Error parsing y coordinate of output configuration for output %s", + name); goto error; } char *res_str = strtok_r(NULL, " ", saveptr); if(res_str == NULL || strcmp(res_str, "res") != 0) { - wlr_log(WLR_ERROR, "Expected keyword \"res\" in output configuration for output %s", name); + wlr_log( + WLR_ERROR, + "Expected keyword \"res\" in output configuration for output %s", + name); goto error; } cfg->pos.width = parse_uint(saveptr, "x"); if(cfg->pos.width <= 0) { - wlr_log(WLR_ERROR, "Error parsing width of output configuration for output %s (hint: width must be larger than 0)", name); + wlr_log(WLR_ERROR, + "Error parsing width of output configuration for output %s " + "(hint: width must be larger than 0)", + name); goto error; } cfg->pos.height = parse_uint(saveptr, " "); if(cfg->pos.height <= 0) { - wlr_log(WLR_ERROR, "Error parsing height of output configuration for output %s (hint: height must e larger than 0)", name); + wlr_log(WLR_ERROR, + "Error parsing height of output configuration for output %s " + "(hint: height must e larger than 0)", + name); goto error; } char *rate_str = strtok_r(NULL, " ", saveptr); if(rate_str == NULL || strcmp(rate_str, "rate") != 0) { - wlr_log(WLR_ERROR, "Expected keyword \"rate\" in output configuration for output %s", name); + wlr_log( + WLR_ERROR, + "Expected keyword \"rate\" in output configuration for output %s", + name); goto error; } cfg->refresh_rate = parse_float(saveptr, " "); if(cfg->refresh_rate <= 0.0) { - wlr_log(WLR_ERROR, "Error parsing refresh rate of output configuration for output %s", name); + wlr_log( + WLR_ERROR, + "Error parsing refresh rate of output configuration for output %s", + name); goto error; } @@ -299,7 +331,9 @@ parse_output_config(struct wl_list *config_list, char **saveptr) { error: free(cfg); - wlr_log(WLR_ERROR, "Output configuration must be of the form \"output pos res x rate "); + wlr_log(WLR_ERROR, + "Output configuration must be of the form \"output pos " + " res x rate "); return -1; } diff --git a/workspace.c b/workspace.c index 10a476d..265010e 100644 --- a/workspace.c +++ b/workspace.c @@ -21,7 +21,8 @@ #include "workspace.h" int -full_screen_workspace_tiles(struct wlr_output_layout *layout,struct wlr_output *output, +full_screen_workspace_tiles(struct wlr_output_layout *layout, + struct wlr_output *output, struct cg_workspace *workspace) { workspace->focused_tile = calloc(1, sizeof(struct cg_tile)); if(!workspace->focused_tile) { @@ -45,8 +46,9 @@ full_screen_workspace(struct cg_output *output) { if(!workspace) { return NULL; } - workspace->server=output->server; - if(full_screen_workspace_tiles(output->server->output_layout, output->wlr_output, workspace)!=0) { + workspace->server = output->server; + if(full_screen_workspace_tiles(output->server->output_layout, + output->wlr_output, workspace) != 0) { free(workspace); return NULL; } diff --git a/workspace.h b/workspace.h index 34586f7..a5da674 100644 --- a/workspace.h +++ b/workspace.h @@ -26,7 +26,8 @@ struct cg_workspace { struct cg_workspace * full_screen_workspace(struct cg_output *output); int -full_screen_workspace_tiles(struct wlr_output_layout *layout,struct wlr_output *output, +full_screen_workspace_tiles(struct wlr_output_layout *layout, + struct wlr_output *output, struct cg_workspace *workspace); void workspace_free_tiles(struct cg_workspace *workspace); From 3367d8e0bac480f9a431552fb5c5810764020601 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Wed, 20 May 2020 19:12:00 +0000 Subject: [PATCH 052/122] Add formatting to release checklist --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0eb113b..e278804 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Release checklist * [ ] Cursory testing * [ ] libfuzzer testing + * [ ] ninja -C build clang-format * [ ] Version Number * [ ] meson.build * [ ] git tag From d7970326940684175273f066d9c2d6d96d50ad28 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 21 May 2020 08:27:07 +0000 Subject: [PATCH 053/122] Manage fanalyzer warnings with pragmas --- idle_inhibit_v1.c | 3 +++ message.c | 3 +++ xdg_shell.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/idle_inhibit_v1.c b/idle_inhibit_v1.c index ee7ca82..e73915d 100644 --- a/idle_inhibit_v1.c +++ b/idle_inhibit_v1.c @@ -22,6 +22,8 @@ struct cg_idle_inhibitor_v1 { struct wl_listener destroy; }; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" static void idle_inhibit_v1_check_active(struct cg_server *server) { /* As of right now, this does not check whether the inhibitor @@ -29,6 +31,7 @@ idle_inhibit_v1_check_active(struct cg_server *server) { bool inhibited = !wl_list_empty(&server->inhibitors); wlr_idle_set_enabled(server->idle, NULL, !inhibited); } +#pragma GCC diagnostic pop static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/message.c b/message.c index bc24928..07dd0b6 100644 --- a/message.c +++ b/message.c @@ -95,6 +95,8 @@ create_message_texture(const char *string, const struct cg_output *output) { return texture; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" void message_set_output(struct cg_output *output, const char *string, struct wlr_box *box, enum cg_message_align align) { @@ -137,6 +139,7 @@ message_set_output(struct cg_output *output, const char *string, } wlr_output_damage_add_box(output->damage, message->position); } +#pragma GCC diagnostic pop void message_printf(struct cg_output *output, const char *fmt, ...) { diff --git a/xdg_shell.c b/xdg_shell.c index b420795..00af384 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -32,6 +32,8 @@ xdg_decoration_handle_destroy(struct wl_listener *listener, void *_data) { free(xdg_decoration); } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" static void xdg_decoration_handle_request_mode(struct wl_listener *listener, void *_data) { struct cg_xdg_decoration *xdg_decoration = @@ -42,6 +44,7 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *_data) { wlr_xdg_toplevel_decoration_v1_set_mode(xdg_decoration->wlr_decoration, mode); } +#pragma GCC diagnostic pop static void xdg_popup_destroy(struct cg_view_child *child) { From 19e1407983fe3e9149c8bd66dc03024578667a62 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 21 May 2020 13:33:32 +0000 Subject: [PATCH 054/122] Fix remaining fanalyzer errors --- cagebreak.c | 3 +++ meson.build | 1 + view.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/cagebreak.c b/cagebreak.c index 8f5c01d..63bb000 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -545,6 +545,8 @@ main(int argc, char *argv[]) { wl_display_destroy_clients(server.wl_display); end: +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-double-free" for(unsigned int i = 0; server.modes[i] != NULL; ++i) { free(server.modes[i]); } @@ -575,3 +577,4 @@ end: return ret; } +#pragma GCC diagnostic pop diff --git a/meson.build b/meson.build index 40c09d7..f562b3f 100644 --- a/meson.build +++ b/meson.build @@ -11,6 +11,7 @@ add_project_arguments( [ '-DWLR_USE_UNSTABLE', '-Wundef', + '-fanalyzer', '-Wno-unused-parameter', ], language: 'c', diff --git a/view.c b/view.c index 6b0ed87..f90baaf 100644 --- a/view.c +++ b/view.c @@ -223,6 +223,8 @@ view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, view->impl->for_each_popup(view, iterator, data); } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" void view_unmap(struct cg_view *view) { #if CG_HAS_XWAYLAND @@ -263,6 +265,7 @@ view_unmap(struct cg_view *view) { } } #endif +#pragma GCC diagnostic pop wl_list_remove(&view->link); From af6adcc9730d18d94b263253a9b12ecbd9d6469c Mon Sep 17 00:00:00 2001 From: project-repo Date: Thu, 21 May 2020 17:17:11 +0200 Subject: [PATCH 055/122] Fix null pointer dereference warning --- view.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/view.c b/view.c index f90baaf..609b01e 100644 --- a/view.c +++ b/view.c @@ -223,17 +223,15 @@ view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, view->impl->for_each_popup(view, iterator, data); } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" void view_unmap(struct cg_view *view) { #if CG_HAS_XWAYLAND if((view->type != CG_XWAYLAND_VIEW || xwayland_view_should_manage(view))) #endif { - if(view_is_visible(view)) { + struct cg_tile *view_tile = view_get_tile(view); + if(view_tile != NULL) { struct cg_view *prev = view_get_prev_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 @@ -265,7 +263,6 @@ view_unmap(struct cg_view *view) { } } #endif -#pragma GCC diagnostic pop wl_list_remove(&view->link); From 7b83f7a31935713303bde40e4b933dc639801bc4 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 21 May 2020 15:36:28 +0000 Subject: [PATCH 056/122] Remove fanalyzer from meson.build --- meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/meson.build b/meson.build index f562b3f..40c09d7 100644 --- a/meson.build +++ b/meson.build @@ -11,7 +11,6 @@ add_project_arguments( [ '-DWLR_USE_UNSTABLE', '-Wundef', - '-fanalyzer', '-Wno-unused-parameter', ], language: 'c', From 4b383b55747b0e0b32f5c898de212551c89457fd Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 21 May 2020 15:57:25 +0000 Subject: [PATCH 057/122] Fix debug build fanalyzer warnings --- message.c | 2 +- output.c | 3 +++ parse.c | 3 +++ workspace.c | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/message.c b/message.c index 07dd0b6..bd6eed0 100644 --- a/message.c +++ b/message.c @@ -139,7 +139,6 @@ message_set_output(struct cg_output *output, const char *string, } wlr_output_damage_add_box(output->damage, message->position); } -#pragma GCC diagnostic pop void message_printf(struct cg_output *output, const char *fmt, ...) { @@ -173,6 +172,7 @@ message_printf(struct cg_output *output, const char *fmt, ...) { free(buffer); alarm(output->server->message_timeout); } +#pragma GCC diagnostic pop void message_printf_pos(struct cg_output *output, struct wlr_box *position, diff --git a/output.c b/output.c index 7c23ad8..388471d 100644 --- a/output.c +++ b/output.c @@ -550,6 +550,8 @@ output_configure(struct cg_server *server, struct cg_output *output) { } } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" void handle_new_output(struct wl_listener *listener, void *data) { struct cg_server *server = wl_container_of(listener, server, new_output); @@ -627,6 +629,7 @@ handle_new_output(struct wl_listener *listener, void *data) { DEFAULT_XCURSOR, server->seat->cursor); wlr_cursor_warp(server->seat->cursor, NULL, 0, 0); } +#pragma GCC diagnostic pop void output_set_window_title(struct cg_output *output, const char *title) { diff --git a/parse.c b/parse.c index f08b59d..043f843 100644 --- a/parse.c +++ b/parse.c @@ -325,9 +325,12 @@ parse_output_config(struct wl_list *config_list, char **saveptr) { goto error; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" cfg->output_name = strdup(name); wl_list_insert(config_list, &cfg->link); return 0; +#pragma GCC diagnostic pop error: free(cfg); diff --git a/workspace.c b/workspace.c index 265010e..440a83e 100644 --- a/workspace.c +++ b/workspace.c @@ -20,6 +20,8 @@ #include "view.h" #include "workspace.h" +#pragma GCC diagnostic push +#pragma GCC ignored "-Wanalyzer-malloc-leak" int full_screen_workspace_tiles(struct wlr_output_layout *layout, struct wlr_output *output, @@ -39,6 +41,7 @@ full_screen_workspace_tiles(struct wlr_output_layout *layout, workspace->focused_tile->view = NULL; return 0; } +#pragma GCC diagnostic pop struct cg_workspace * full_screen_workspace(struct cg_output *output) { From 8e7f954b329f864a22ce6997ca0c1e18b258edd7 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Thu, 21 May 2020 16:00:53 +0000 Subject: [PATCH 058/122] Fix typo --- workspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspace.c b/workspace.c index 440a83e..c7688ab 100644 --- a/workspace.c +++ b/workspace.c @@ -21,7 +21,7 @@ #include "workspace.h" #pragma GCC diagnostic push -#pragma GCC ignored "-Wanalyzer-malloc-leak" +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" int full_screen_workspace_tiles(struct wlr_output_layout *layout, struct wlr_output *output, From 989438a1cbb2b4d013a2a1daab25858e455b07be Mon Sep 17 00:00:00 2001 From: project-repo Date: Thu, 21 May 2020 19:36:35 +0200 Subject: [PATCH 059/122] Fix compilation under clang --- cagebreak.c | 4 ++++ config.h.in | 1 + idle_inhibit_v1.c | 4 ++++ meson.build | 7 +++++++ message.c | 4 ++++ output.c | 4 ++++ parse.c | 4 ++++ workspace.c | 4 ++++ xdg_shell.c | 4 ++++ 9 files changed, 36 insertions(+) diff --git a/cagebreak.c b/cagebreak.c index 63bb000..e9690a1 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -545,8 +545,10 @@ main(int argc, char *argv[]) { wl_display_destroy_clients(server.wl_display); end: +#if CG_HAS_FANALYZE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-double-free" +#endif for(unsigned int i = 0; server.modes[i] != NULL; ++i) { free(server.modes[i]); } @@ -577,4 +579,6 @@ end: return ret; } +#if CG_HAS_FANALYZE #pragma GCC diagnostic pop +#endif diff --git a/config.h.in b/config.h.in index cf6bcbc..8495284 100644 --- a/config.h.in +++ b/config.h.in @@ -2,6 +2,7 @@ #define CG_CONFIG_H #mesondefine CG_HAS_XWAYLAND +#mesondefine CG_HAS_FANALYZE #mesondefine CG_VERSION diff --git a/idle_inhibit_v1.c b/idle_inhibit_v1.c index e73915d..17c0041 100644 --- a/idle_inhibit_v1.c +++ b/idle_inhibit_v1.c @@ -22,8 +22,10 @@ struct cg_idle_inhibitor_v1 { struct wl_listener destroy; }; +#if CG_HAS_FANALYZE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif static void idle_inhibit_v1_check_active(struct cg_server *server) { /* As of right now, this does not check whether the inhibitor @@ -31,7 +33,9 @@ idle_inhibit_v1_check_active(struct cg_server *server) { bool inhibited = !wl_list_empty(&server->inhibitors); wlr_idle_set_enabled(server->idle, NULL, !inhibited); } +#if CG_HAS_FANALYZE #pragma GCC diagnostic pop +#endif static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/meson.build b/meson.build index 40c09d7..b9ff4ed 100644 --- a/meson.build +++ b/meson.build @@ -100,6 +100,12 @@ else have_xwayland = false endif +if cc.get_id() == 'gcc' and cc.version().version_compare('>=10') + have_fanalyze=true +else + have_fanalyze=false +endif + if get_option('version_override') != '' version = '@0@'.format(get_option('version_override')) else @@ -108,6 +114,7 @@ endif conf_data = configuration_data() conf_data.set10('CG_HAS_XWAYLAND', have_xwayland) +conf_data.set10('CG_HAS_FANALYZE', have_fanalyze) conf_data.set_quoted('CG_VERSION', version) diff --git a/message.c b/message.c index bd6eed0..8ada1f8 100644 --- a/message.c +++ b/message.c @@ -95,8 +95,10 @@ create_message_texture(const char *string, const struct cg_output *output) { return texture; } +#if CG_HAS_FANALYZE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif void message_set_output(struct cg_output *output, const char *string, struct wlr_box *box, enum cg_message_align align) { @@ -172,7 +174,9 @@ message_printf(struct cg_output *output, const char *fmt, ...) { free(buffer); alarm(output->server->message_timeout); } +#if CG_HAS_FANALYZE #pragma GCC diagnostic pop +#endif void message_printf_pos(struct cg_output *output, struct wlr_box *position, diff --git a/output.c b/output.c index 388471d..4f40050 100644 --- a/output.c +++ b/output.c @@ -550,8 +550,10 @@ output_configure(struct cg_server *server, struct cg_output *output) { } } +#if CG_HAS_FANALYZE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif void handle_new_output(struct wl_listener *listener, void *data) { struct cg_server *server = wl_container_of(listener, server, new_output); @@ -629,7 +631,9 @@ handle_new_output(struct wl_listener *listener, void *data) { DEFAULT_XCURSOR, server->seat->cursor); wlr_cursor_warp(server->seat->cursor, NULL, 0, 0); } +#if CG_HAS_FANALYZE #pragma GCC diagnostic pop +#endif void output_set_window_title(struct cg_output *output, const char *title) { diff --git a/parse.c b/parse.c index 043f843..82cc0f2 100644 --- a/parse.c +++ b/parse.c @@ -325,12 +325,16 @@ parse_output_config(struct wl_list *config_list, char **saveptr) { goto error; } +#if CG_HAS_FANALYZE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif cfg->output_name = strdup(name); wl_list_insert(config_list, &cfg->link); return 0; +#if CG_HAS_FANALYZE #pragma GCC diagnostic pop +#endif error: free(cfg); diff --git a/workspace.c b/workspace.c index c7688ab..fcc7650 100644 --- a/workspace.c +++ b/workspace.c @@ -20,8 +20,10 @@ #include "view.h" #include "workspace.h" +#if CG_HAS_FANALYZE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif int full_screen_workspace_tiles(struct wlr_output_layout *layout, struct wlr_output *output, @@ -41,7 +43,9 @@ full_screen_workspace_tiles(struct wlr_output_layout *layout, workspace->focused_tile->view = NULL; return 0; } +#if CG_HAS_FANALYZE #pragma GCC diagnostic pop +#endif struct cg_workspace * full_screen_workspace(struct cg_output *output) { diff --git a/xdg_shell.c b/xdg_shell.c index 00af384..fd9ef3d 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -32,8 +32,10 @@ xdg_decoration_handle_destroy(struct wl_listener *listener, void *_data) { free(xdg_decoration); } +#if CG_HAS_FANALYZE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif static void xdg_decoration_handle_request_mode(struct wl_listener *listener, void *_data) { struct cg_xdg_decoration *xdg_decoration = @@ -44,7 +46,9 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *_data) { wlr_xdg_toplevel_decoration_v1_set_mode(xdg_decoration->wlr_decoration, mode); } +#if CG_HAS_FANALYZE #pragma GCC diagnostic pop +#endif static void xdg_popup_destroy(struct cg_view_child *child) { From 0017ad48c5bfc3a8d52306e03df05760b356bcba Mon Sep 17 00:00:00 2001 From: project-repo Date: Thu, 21 May 2020 23:04:45 +0200 Subject: [PATCH 060/122] Add ipc capability --- cagebreak.c | 14 +-- ipc_server.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++ ipc_server.h | 44 +++++++++ meson.build | 2 + parse.h | 2 + server.h | 3 + 6 files changed, 307 insertions(+), 6 deletions(-) create mode 100644 ipc_server.c create mode 100644 ipc_server.h diff --git a/cagebreak.c b/cagebreak.c index e9690a1..0f0a539 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -55,6 +55,7 @@ #include "server.h" #include "view.h" #include "xdg_shell.h" +#include "ipc_server.h" #if CG_HAS_XWAYLAND #include "xwayland.h" #endif @@ -189,10 +190,9 @@ set_configuration(struct cg_server *server, config_file_path); return -1; } - size_t max_line_size = 256; - char line[max_line_size * sizeof(char)]; + char line[MAX_LINE_SIZE * sizeof(char)]; for(unsigned int line_num = 1; - fgets(line, max_line_size, config_file) != NULL; ++line_num) { + fgets(line, MAX_LINE_SIZE, config_file) != NULL; ++line_num) { line[strcspn(line, "\n")] = '\0'; if(*line != '\0' && *line != '#') { if(parse_rc_line(server, line) != 0) { @@ -286,9 +286,9 @@ main(int argc, char *argv[]) { server.modes[1] = strdup("root"); server.modes[2] = strdup("resize"); server.modes[3] = NULL; - if(!server.modes[0] || !server.modes[1] || server.modes[2]) { + if(server.modes[0] == NULL || server.modes[1] == NULL || server.modes[2] == NULL) { wlr_log(WLR_ERROR, "Error allocating default modes"); - goto end; + return 1; } server.nws = 1; @@ -533,7 +533,9 @@ main(int argc, char *argv[]) { } } - /* Place the cursor to the topl left of the output layout. */ + ipc_init(&server); + + /* Place the cursor to the top left of the output layout. */ wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); wl_display_run(server.wl_display); diff --git a/ipc_server.c b/ipc_server.c new file mode 100644 index 0000000..2c415c1 --- /dev/null +++ b/ipc_server.c @@ -0,0 +1,248 @@ +/* + * 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 200112L + +#include "ipc_server.h" +#include "server.h" +#include "parse.h" +#include "message.h" + +#include +#include +#include +#include +#include +#include +#include + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct cg_ipc_handle *ipc = wl_container_of(listener, ipc,display_destroy); + if (ipc->event_source != NULL) { + wl_event_source_remove(ipc->event_source); + } + close(ipc->socket); + unlink(ipc->sockaddr->sun_path); + + struct cg_ipc_client *tmp_client, *client; + wl_list_for_each_safe(client, tmp_client, &ipc->client_list, link) { + ipc_client_disconnect(client); + } + + free(ipc->sockaddr); + + wl_list_remove(&ipc->display_destroy.link); +} + +int ipc_init(struct cg_server *server) { + struct cg_ipc_handle *ipc = &server->ipc; + ipc->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (ipc->socket == -1) { + wlr_log(WLR_ERROR, "Unable to create IPC socket"); + return -1; + } + if (fcntl(ipc->socket, F_SETFD, FD_CLOEXEC) == -1) { + wlr_log(WLR_ERROR,"Unable to set CLOEXEC on IPC socket"); + return -1; + } + if (fcntl(ipc->socket, F_SETFL, O_NONBLOCK) == -1) { + wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC socket"); + return -1; + } + + ipc->sockaddr = malloc(sizeof(struct sockaddr_un)); + + if(ipc->sockaddr == NULL) { + wlr_log(WLR_ERROR, "Unable to allocate socket address"); + return -1; + } + + ipc->sockaddr->sun_family=AF_UNIX; + int max_path_size = sizeof(ipc->sockaddr->sun_path); + const char *sockdir=getenv("XDG_RUNTIME_DIR"); + if(sockdir == NULL) { + sockdir = "/tmp"; + } + + if (max_path_size <= snprintf(ipc->sockaddr->sun_path, max_path_size, + "%s/cagebreak-ipc.%i.%i.sock", sockdir, getuid(), getpid())) { + wlr_log(WLR_ERROR,"Unable to write socket path to ipc->sockaddr->sun_path. Path too long"); + return -1; + } + + unlink(ipc->sockaddr->sun_path); + + if (bind(ipc->socket, (struct sockaddr *)ipc->sockaddr, sizeof(*ipc->sockaddr)) == -1) { + wlr_log(WLR_ERROR, "Unable to bind IPC socket"); + return -1; + } + + if (listen(ipc->socket, 3) == -1) { + wlr_log(WLR_ERROR, "Unable to listen on IPC socket"); + } + + setenv("CAGEBREAK_SOCKET", ipc->sockaddr->sun_path, 1); + + wl_list_init(&ipc->client_list); + + ipc->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(server->wl_display, &ipc->display_destroy); + + ipc->event_source = wl_event_loop_add_fd(server->event_loop, ipc->socket, + WL_EVENT_READABLE, ipc_handle_connection, server); + return 0; +} + +int ipc_handle_connection(int fd, uint32_t mask, void *data) { + (void) fd; + struct cg_server *server = data; + struct cg_ipc_handle *ipc = &server->ipc; + if(mask != WL_EVENT_READABLE) { + wlr_log(WLR_ERROR, "Expected to receive a WL_EVENT_READABLE"); + return 0; + } + + int client_fd = accept(ipc->socket, NULL, NULL); + if (client_fd == -1) { + wlr_log(WLR_ERROR, "Unable to accept IPC client connection"); + return 0; + } + + int flags; + if ((flags = fcntl(client_fd, F_GETFD)) == -1 + || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { + wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket"); + close(client_fd); + return 0; + } + if ((flags = fcntl(client_fd, F_GETFL)) == -1 + || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { + wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket"); + close(client_fd); + return 0; + } + + struct cg_ipc_client *client = malloc(sizeof(struct cg_ipc_client)); + if (!client) { + wlr_log(WLR_ERROR, "Unable to allocate ipc client"); + close(client_fd); + return 0; + } + // +1 for \n and +1 for \0 + client->read_buffer = malloc(sizeof(char)*(MAX_LINE_SIZE+2)); + client->read_buf_len = 0; + client->read_discard = 0; + client->server = server; + client->fd = client_fd; + client->event_source = wl_event_loop_add_fd(server->event_loop, + client_fd, WL_EVENT_READABLE, ipc_client_handle_readable, client); + client->writable_event_source = NULL; + + client->write_buffer_size = 128; + client->write_buffer_len = 0; + client->write_buffer = malloc(client->write_buffer_size); + if (!client->write_buffer) { + wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer"); + close(client_fd); + return 0; + } + + wl_list_insert(&ipc->client_list, &client->link); + return 0; +} + +int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { + struct cg_ipc_client *client = data; + + if (mask & WL_EVENT_ERROR) { + wlr_log(WLR_ERROR, "IPC Client socket error, removing client"); + ipc_client_disconnect(client); + return 0; + } + + if (mask & WL_EVENT_HANGUP) { + ipc_client_disconnect(client); + return 0; + } + + int read_available; + if (ioctl(client_fd, FIONREAD, &read_available) == -1) { + wlr_log(WLR_ERROR, "Unable to read IPC socket buffer size"); + ipc_client_disconnect(client); + return 0; + } + + int read_size = read_available < MAX_LINE_SIZE+1-client->read_buf_len ? read_available:MAX_LINE_SIZE+1-client->read_buf_len; + // Append to buffer + ssize_t received = recv(client_fd, client->read_buffer+client->read_buf_len, read_size, 0); + if (received == -1) { + wlr_log(WLR_ERROR, "Unable to receive data from IPC client"); + ipc_client_disconnect(client); + return 0; + } + client->read_buf_len+=received; + + ipc_client_handle_command(client); + + return 0; +} + +void ipc_client_disconnect(struct cg_ipc_client *client) { + if (client == NULL) { + wlr_log(WLR_ERROR, "Client \"NULL\" was passed to ipc_client_disconnect"); + return; + } + + shutdown(client->fd, SHUT_RDWR); + + wl_event_source_remove(client->event_source); + if (client->writable_event_source) { + wl_event_source_remove(client->writable_event_source); + } + wl_list_remove(&client->link); + free(client->write_buffer); + free(client->read_buffer); + close(client->fd); + free(client); +} + +void ipc_client_handle_command(struct cg_ipc_client *client) { + if (client == NULL) { + wlr_log(WLR_ERROR, "Client \"NULL\" was passed to ipc_client_handle_command"); + return; + } + client->read_buffer[client->read_buf_len]='\0'; + char *nl_pos; + int offset=0; + while((nl_pos = strchr(client->read_buffer+offset,'\n')) != NULL){ + if(client->read_discard) { + client->read_discard = 0; + } else { + *nl_pos='\0'; + char *line=client->read_buffer+offset; + if(*line != '\0' && *line != '#') { + message_clear(client->server->curr_output); + if(parse_rc_line(client->server, line) != 0) { + wlr_log(WLR_ERROR, "Error parsing input from IPC socket."); + } + } + } + offset+=(nl_pos-client->read_buffer)+1; + } + if(client->read_buf_len-offset == MAX_LINE_SIZE+1) { + wlr_log(WLR_ERROR, "Line received was longer that %d, discarding it",MAX_LINE_SIZE); + client->read_buf_len =0; + client->read_discard = 1; + return; + } + if(offsetread_buf_len) { + memmove(client->read_buffer, client->read_buffer+offset, client->read_buf_len-offset); + } + client->read_buf_len-=offset; +} diff --git a/ipc_server.h b/ipc_server.h new file mode 100644 index 0000000..0e5aadd --- /dev/null +++ b/ipc_server.h @@ -0,0 +1,44 @@ +#ifndef CG_IPC_SERVER_H +#define CG_IPC_SERVER_H + +#include "config.h" + +#include +#include +#include + +struct cg_server; + +struct cg_ipc_client { + struct wl_event_source *event_source; + struct wl_event_source *writable_event_source; + struct cg_server *server; + struct wl_list link; + int fd; + uint32_t security_policy; + size_t write_buffer_len; + size_t write_buffer_size; + char *write_buffer; + // The following is for storing data between event_loop calls + uint8_t read_buf_len; + uint8_t read_discard;// 1 if the current line is to be discarded + char *read_buffer; +}; + +struct cg_ipc_handle { + int socket; + struct wl_event_source *event_source; + struct wl_list client_list; + struct wl_listener display_destroy; + struct sockaddr_un *sockaddr; +}; + +int ipc_init(struct cg_server *server); +int ipc_handle_connection(int fd, uint32_t mask, void *data); +int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); +//int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data); +void ipc_client_disconnect(struct cg_ipc_client *client); +void ipc_client_handle_command(struct cg_ipc_client *client); +//bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); + +#endif diff --git a/meson.build b/meson.build index b9ff4ed..23e6367 100644 --- a/meson.build +++ b/meson.build @@ -121,6 +121,7 @@ conf_data.set_quoted('CG_VERSION', version) cagebreak_main_file = [ 'cagebreak.c', ] cagebreak_source_strings = [ 'idle_inhibit_v1.c', + 'ipc_server.c', 'keybinding.c', 'workspace.c', 'output.c', @@ -137,6 +138,7 @@ cagebreak_source_strings = [ cagebreak_header_strings = [ 'idle_inhibit_v1.h', + 'ipc_server.h', 'keybinding.h', 'workspace.h', 'output.h', diff --git a/parse.h b/parse.h index 622697f..f170b0d 100644 --- a/parse.h +++ b/parse.h @@ -2,6 +2,8 @@ #define PARSE_H +# define MAX_LINE_SIZE 256 + struct cg_server; int diff --git a/server.h b/server.h index 930cb56..24c2fb1 100644 --- a/server.h +++ b/server.h @@ -2,6 +2,7 @@ #define CG_SERVER_H #include "config.h" +#include "ipc_server.h" #include #include @@ -40,6 +41,8 @@ struct cg_server { enum wl_output_transform output_transform; + struct cg_ipc_handle ipc; + bool running; char **modes; uint16_t nws; From 4482bb495cde9fba2b7a1dd1857802fbc452d405 Mon Sep 17 00:00:00 2001 From: project-repo Date: Thu, 21 May 2020 23:16:57 +0200 Subject: [PATCH 061/122] Fix ordering of ipc --- cagebreak.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index 0f0a539..3a2c3e7 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -511,6 +511,8 @@ main(int argc, char *argv[]) { wlr_xwayland_set_seat(xwayland, server.seat->seat); #endif + ipc_init(&server); + { // config_file should only be visible as long as it is valid char *config_file = get_config_file(); if(config_file == NULL) { @@ -533,8 +535,6 @@ main(int argc, char *argv[]) { } } - ipc_init(&server); - /* Place the cursor to the top left of the output layout. */ wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); From fd9c301c4d28292ccd2c57d98a5e222a05a389a1 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 22 May 2020 00:22:28 +0200 Subject: [PATCH 062/122] Fix bug on startup --- cagebreak.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cagebreak.c b/cagebreak.c index e9690a1..42fef88 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -286,7 +286,7 @@ main(int argc, char *argv[]) { server.modes[1] = strdup("root"); server.modes[2] = strdup("resize"); server.modes[3] = NULL; - if(!server.modes[0] || !server.modes[1] || server.modes[2]) { + if(server.modes[0] == NULL || server.modes[1] == NULL || server.modes[2] == NULL) { wlr_log(WLR_ERROR, "Error allocating default modes"); goto end; } From 5c0d68e2e50d86ff09363a994898175a06508c50 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 22 May 2020 09:05:41 +0200 Subject: [PATCH 063/122] Ameliorate ipc --- ipc_server.c | 10 +++++----- ipc_server.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ipc_server.c b/ipc_server.c index 2c415c1..f0b1e08 100644 --- a/ipc_server.c +++ b/ipc_server.c @@ -172,7 +172,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { } int read_available; - if (ioctl(client_fd, FIONREAD, &read_available) == -1) { + if (ioctl(client_fd, FIONREAD, &read_available) < 0) { wlr_log(WLR_ERROR, "Unable to read IPC socket buffer size"); ipc_client_disconnect(client); return 0; @@ -219,7 +219,7 @@ void ipc_client_handle_command(struct cg_ipc_client *client) { } client->read_buffer[client->read_buf_len]='\0'; char *nl_pos; - int offset=0; + uint32_t offset=0; while((nl_pos = strchr(client->read_buffer+offset,'\n')) != NULL){ if(client->read_discard) { client->read_discard = 0; @@ -233,11 +233,11 @@ void ipc_client_handle_command(struct cg_ipc_client *client) { } } } - offset+=(nl_pos-client->read_buffer)+1; + offset=(nl_pos-client->read_buffer)+1; } - if(client->read_buf_len-offset == MAX_LINE_SIZE+1) { + if(offset == 0) { wlr_log(WLR_ERROR, "Line received was longer that %d, discarding it",MAX_LINE_SIZE); - client->read_buf_len =0; + client->read_buf_len = 0; client->read_discard = 1; return; } diff --git a/ipc_server.h b/ipc_server.h index 0e5aadd..91d09b2 100644 --- a/ipc_server.h +++ b/ipc_server.h @@ -20,7 +20,7 @@ struct cg_ipc_client { size_t write_buffer_size; char *write_buffer; // The following is for storing data between event_loop calls - uint8_t read_buf_len; + uint16_t read_buf_len; uint8_t read_discard;// 1 if the current line is to be discarded char *read_buffer; }; From 4bae00f5933e39dbd8196e7e13697d2213845c72 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 22 May 2020 15:40:15 +0200 Subject: [PATCH 064/122] Add fanalyzer flag by default if supported --- meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index b9ff4ed..eeef2e0 100644 --- a/meson.build +++ b/meson.build @@ -100,8 +100,10 @@ else have_xwayland = false endif -if cc.get_id() == 'gcc' and cc.version().version_compare('>=10') +fanalyzer_compile_flag=[] +if cc.has_argument('-fanalyzer') have_fanalyze=true + fanalyzer_compile_flag=[ '-fanalyzer' ] else have_fanalyze=false endif @@ -220,7 +222,7 @@ executable( cagebreak_main_file + cagebreak_sources + cagebreak_headers, dependencies: cagebreak_dependencies, install: true, - link_args: fuzz_link_args, + link_args: fuzz_link_args+fanalyzer_compile_flag, c_args: fuzz_compile_args, ) From 07ec19e45e3323c492a315ac05703e17649ea05c Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Fri, 22 May 2020 17:04:21 +0000 Subject: [PATCH 065/122] Add fanalyzer development documentation --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index e278804..b6672e5 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,35 @@ Nonetheless, don't be intimidated by the (slightly lengthy) release checklist or part of this file. Do what you can, open an issue and we will collaborate toward a solution. +### GCC and -fanalyzer + +Cagebreak should be buildable with any reasonably new gcc or clang. Consider +a gcc version of at least [10.1](https://gcc.gnu.org/gcc-10/changes.html) if +you want to get the benefit of the brand-new +[-fanalyzer](https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html) +flag. However, this new flag sometimes produces false-postives and we +selectively disable warnings for affected code segments as described below. + +Meson is configured to set 'CG_HAS_FANALYZE' if '-fanalyzer' is available. +Because we also compile with clang for fuzzing, please use the following +preprocessor statements before + +``` +#if CG_HAS_FANALYZE +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "WARNING OPTION" +#endif +``` +and after + +``` +#if CG_HAS_FANALYZE +#pragma GCC diagnostic pop +#endif +``` + +the offending part of the code iff the warning is a false positive. + ### Branching strategy All features are to be developed on feature branches, named after the feature. From 66683293b565278acd5ac85f555f9b0102c8ef36 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Fri, 22 May 2020 17:04:39 +0000 Subject: [PATCH 066/122] Prepare 1.2.1 release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index eeef2e0..4a06c92 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.2.0', + version: '1.2.1', license: 'MIT', default_options: [ 'c_std=c11', From 64a305cd4c1a01e5f4555d928780f6e6e57be15c Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Fri, 22 May 2020 17:23:20 +0000 Subject: [PATCH 067/122] Fix highlighting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b6672e5..2df3e90 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ you want to get the benefit of the brand-new flag. However, this new flag sometimes produces false-postives and we selectively disable warnings for affected code segments as described below. -Meson is configured to set 'CG_HAS_FANALYZE' if '-fanalyzer' is available. +Meson is configured to set `CG_HAS_FANALYZE` if `-fanalyzer` is available. Because we also compile with clang for fuzzing, please use the following preprocessor statements before From 68950664e343c9dd4e8822aa03973343a3957d9e Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 22 May 2020 20:24:35 +0200 Subject: [PATCH 068/122] Ameliorate README --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2df3e90..6938686 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ toward a solution. ### GCC and -fanalyzer -Cagebreak should be buildable with any reasonably new gcc or clang. Consider +Cagebreak should compile with any reasonably new gcc or clang. Consider a gcc version of at least [10.1](https://gcc.gnu.org/gcc-10/changes.html) if you want to get the benefit of the brand-new [-fanalyzer](https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html) @@ -71,8 +71,8 @@ flag. However, this new flag sometimes produces false-postives and we selectively disable warnings for affected code segments as described below. Meson is configured to set `CG_HAS_FANALYZE` if `-fanalyzer` is available. -Because we also compile with clang for fuzzing, please use the following -preprocessor statements before +Therefore, to maintain portability, false-positive fanalyzer warnings are to be +disabled using the following syntax: ``` #if CG_HAS_FANALYZE @@ -88,8 +88,6 @@ and after #endif ``` -the offending part of the code iff the warning is a false positive. - ### Branching strategy All features are to be developed on feature branches, named after the feature. @@ -112,7 +110,8 @@ git tag -v version git push --tags origin master ``` -and a log message roughly describing the features added in the commit. +and a log message roughly describing the features added in the commit is +included. In the past, our git history did not always reflect this scheme. From f568f5379e0f47f6d807744580dd45bf0469aff7 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 23 May 2020 09:16:18 +0200 Subject: [PATCH 069/122] Add error messaging to ipc --- cagebreak.c | 6 +- fuzz/fuzz-parse.c | 6 +- ipc_server.c | 10 ++- parse.c | 200 +++++++++++++++++++--------------------------- parse.h | 2 +- 5 files changed, 103 insertions(+), 121 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index 3a2c3e7..ccbbc7d 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -195,10 +195,14 @@ set_configuration(struct cg_server *server, fgets(line, MAX_LINE_SIZE, config_file) != NULL; ++line_num) { line[strcspn(line, "\n")] = '\0'; if(*line != '\0' && *line != '#') { - if(parse_rc_line(server, line) != 0) { + char *errstr; + if(parse_rc_line(server, line, &errstr) != 0) { wlr_log(WLR_ERROR, "Error in config file \"%s\", line %d\n", config_file_path, line_num); fclose(config_file); + if(errstr != NULL) { + free(errstr); + } return -1; } } diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index bcfb701..70602fe 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -406,7 +406,11 @@ set_configuration(struct cg_server *server, char *content) { (line = strtok_r(NULL, "\n", &content)) != NULL; ++line_num) { line[strcspn(line, "\n")] = '\0'; if(*line != '\0' && *line != '#') { - if(parse_rc_line(server, line) != 0) { + char *errstr; + if(parse_rc_line(server, line, &errstr) != 0) { + if(errstr != NULL) { + free(errstr); + } return -1; } } diff --git a/ipc_server.c b/ipc_server.c index f0b1e08..8a7b083 100644 --- a/ipc_server.c +++ b/ipc_server.c @@ -228,8 +228,14 @@ void ipc_client_handle_command(struct cg_ipc_client *client) { char *line=client->read_buffer+offset; if(*line != '\0' && *line != '#') { message_clear(client->server->curr_output); - if(parse_rc_line(client->server, line) != 0) { - wlr_log(WLR_ERROR, "Error parsing input from IPC socket."); + char *errstr; + if(parse_rc_line(client->server, line, &errstr) != 0) { + if(errstr != NULL) { + message_printf(client->server->curr_output, "%s", errstr); + wlr_log(WLR_ERROR, "%s",errstr); + free(errstr); + } + wlr_log(WLR_ERROR, "Error parsing input from IPC socket"); } } } diff --git a/parse.c b/parse.c index 82cc0f2..12f7ee5 100644 --- a/parse.c +++ b/parse.c @@ -11,12 +11,34 @@ #include "server.h" #include "workspace.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; +} + +char *log_error(const char *fmt, ...) { + va_list args; + va_start(args,fmt); + char *ret=malloc_vsprintf(fmt, args); + if(ret != NULL) { + wlr_log(WLR_ERROR, "%s", ret); + } + va_end(args); + return ret; + +} + /* parses a key definition (e.g. "S-Tab") and sets key and modifiers in * keybinding respectivly */ int -parse_key(struct keybinding *keybinding, const char *key_def) { +parse_key(struct keybinding *keybinding, const char *key_def,char **errstr) { if(key_def == NULL) { - wlr_log(WLR_ERROR, "Expected key definition, got nothing."); + *errstr=log_error("Expected key definition, got nothing."); return -1; } keybinding->modifiers = 0; @@ -44,14 +66,14 @@ parse_key(struct keybinding *keybinding, const char *key_def) { keybinding->modifiers |= WLR_MODIFIER_MOD5; break; default: - wlr_log(WLR_ERROR, "Unknown modifier \"%c\"", key_def[0]); + *errstr=log_error("Unknown modifier \"%c\"", key_def[0]); return -1; } key_def += 2; } xkb_keysym_t keysym = xkb_keysym_from_name(key_def, XKB_KEYSYM_NO_FLAGS); if(keysym == XKB_KEY_NoSymbol) { - wlr_log(WLR_ERROR, "Could not convert key \"%s\" to keysym.", key_def); + *errstr=log_error("Could not convert key \"%s\" to keysym.", key_def); return -1; } keybinding->key = keysym; @@ -60,25 +82,24 @@ parse_key(struct keybinding *keybinding, const char *key_def) { int parse_command(struct cg_server *server, struct keybinding *keybinding, - char *saveptr); + char *saveptr, char **errstr); /* Parse a keybinding definition and return it if successful, else return NULL */ struct keybinding * -parse_keybinding(struct cg_server *server, char **saveptr) { +parse_keybinding(struct cg_server *server, char **saveptr, char **errstr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - wlr_log(WLR_ERROR, - "Failed to allocate memory for keybinding in parse_keybinding"); + *errstr=log_error("Failed to allocate memory for keybinding in parse_keybinding"); return NULL; } char *key = strtok_r(NULL, " ", saveptr); - if(parse_key(keybinding, key) != 0) { + if(parse_key(keybinding, key, errstr) != 0) { wlr_log(WLR_ERROR, "Could not parse key definition \"%s\"", key); free(keybinding); return NULL; } - if(parse_command(server, keybinding, *saveptr) != 0) { + if(parse_command(server, keybinding, *saveptr, errstr) != 0) { free(keybinding); return NULL; } @@ -86,8 +107,8 @@ parse_keybinding(struct cg_server *server, char **saveptr) { } struct keybinding * -parse_bind(struct cg_server *server, char **saveptr) { - struct keybinding *keybinding = parse_keybinding(server, saveptr); +parse_bind(struct cg_server *server, char **saveptr, char **errstr) { + struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr); if(keybinding == NULL) { wlr_log(WLR_ERROR, "Could not parse keybinding for \"bind\"."); return NULL; @@ -97,18 +118,18 @@ parse_bind(struct cg_server *server, char **saveptr) { } struct keybinding * -parse_definekey(struct cg_server *server, char **saveptr) { +parse_definekey(struct cg_server *server, char **saveptr, char **errstr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { - wlr_log(WLR_ERROR, "Too few arguments to \"definekey\". Expected mode"); + *errstr=log_error("Too few arguments to \"definekey\". Expected mode"); return NULL; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { - wlr_log(WLR_ERROR, "Unknown mode \"%s\"", mode); + *errstr=log_error("Unknown mode \"%s\"", mode); return NULL; } - struct keybinding *keybinding = parse_keybinding(server, saveptr); + struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr); if(keybinding == NULL) { wlr_log(WLR_ERROR, "Could not parse keybinding for \"definekey\""); return NULL; @@ -118,16 +139,13 @@ parse_definekey(struct cg_server *server, char **saveptr) { } int -parse_background(struct cg_server *server, float *color, char **saveptr) { +parse_background(struct cg_server *server, float *color, char **saveptr, char **errstr) { /* Read rgb numbers */ for(unsigned int i = 0; i < 3; ++i) { char *nstr = strtok_r(NULL, " \n", saveptr); int nstrlen; if(nstr == NULL || (nstrlen = strlen(nstr)) == 0) { - wlr_log(WLR_ERROR, - "Expected three space-separated numbers (rgb) for " - "background color setting. Got %d.", - i); + *errstr=log_error("Expected three space-separated numbers (rgb) for background color setting. Got %d.", i); return -1; } if(nstr[nstrlen - 1] == '\n') { @@ -137,17 +155,11 @@ parse_background(struct cg_server *server, float *color, char **saveptr) { char *endptr = NULL; float nval = strtof(nstr, &endptr); if(endptr != nstr + nstrlen) { - wlr_log( - WLR_ERROR, - "Could not parse number \"%s\" for background color setting.", - nstr); + *errstr=log_error("Could not parse number \"%s\" for background color setting.", nstr); return -1; } if(nval < 0 || nval > 1) { - wlr_log(WLR_ERROR, - "Expected a number between 0 and 1 for setting of " - "background color. Got %f.", - nval); + *errstr=log_error("Expected a number between 0 and 1 for setting of background color. Got %f.", nval); return -1; } color[i] = nval; @@ -156,15 +168,14 @@ parse_background(struct cg_server *server, float *color, char **saveptr) { } struct keybinding * -parse_escape(char **saveptr) { +parse_escape(char **saveptr, char **errstr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - wlr_log(WLR_ERROR, - "Failed to allocate memory for keybinding in parse_escape"); + *errstr=log_error("Failed to allocate memory for keybinding in parse_escape"); return NULL; } char *key = strtok_r(NULL, " ", saveptr); - if(parse_key(keybinding, key) != 0) { + if(parse_key(keybinding, key, errstr) != 0) { wlr_log(WLR_ERROR, "Could not parse key definition \"%s\" for \"escape\"", key); free(keybinding); @@ -177,27 +188,25 @@ parse_escape(char **saveptr) { } char * -parse_definemode(char **saveptr) { +parse_definemode(char **saveptr, char **errstr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { - wlr_log(WLR_ERROR, "Expected mode to succeed \"definemode\" keyword."); + *errstr=log_error("Expected mode to succeed \"definemode\" keyword."); return NULL; } return strdup(mode); } int -parse_workspaces(char **saveptr) { +parse_workspaces(char **saveptr, char **errstr) { char *nws_str = strtok_r(NULL, " ", saveptr); if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspaces\" command, got none."); + *errstr=log_error("Expected argument for \"workspaces\" command, got none."); return -1; } long nws = strtol(nws_str, NULL, 10); if(!(1 <= nws && nws <= 30)) { - wlr_log(WLR_ERROR, - "More than 30 workspaces are not supported. Received %li", nws); + *errstr=log_error("More than 30 workspaces are not supported. Received %li", nws); return -1; } return nws; @@ -240,88 +249,62 @@ parse_float(char **saveptr, const char *delim) { } int -parse_output_config(struct wl_list *config_list, char **saveptr) { +parse_output_config(struct wl_list *config_list, char **saveptr, char **errstr) { struct cg_output_config *cfg = malloc(sizeof(struct cg_output_config)); if(cfg == NULL) { - wlr_log(WLR_ERROR, - "Failed to allocate memory for output configuration"); + *errstr=log_error("Failed to allocate memory for output configuration"); goto error; } char *name = strtok_r(NULL, " ", saveptr); if(name == NULL) { - wlr_log(WLR_ERROR, - "Expected name of output to be configured, got none"); + *errstr=log_error("Expected name of output to be configured, got none"); goto error; } char *pos_str = strtok_r(NULL, " ", saveptr); if(pos_str == NULL || strcmp(pos_str, "pos") != 0) { - wlr_log( - WLR_ERROR, - "Expected keyword \"pos\" in output configuration for output %s", - name); + *errstr=log_error("Expected keyword \"pos\" in output configuration for output %s", name); goto error; } cfg->pos.x = parse_uint(saveptr, " "); if(cfg->pos.x < 0) { - wlr_log( - WLR_ERROR, - "Error parsing x coordinate of output configuration for output %s", - name); + *errstr=log_error("Error parsing x coordinate of output configuration for output %s", name); goto error; } cfg->pos.y = parse_uint(saveptr, " "); if(cfg->pos.y < 0) { - wlr_log( - WLR_ERROR, - "Error parsing y coordinate of output configuration for output %s", - name); + *errstr=log_error("Error parsing y coordinate of output configuration for output %s", name); goto error; } char *res_str = strtok_r(NULL, " ", saveptr); if(res_str == NULL || strcmp(res_str, "res") != 0) { - wlr_log( - WLR_ERROR, - "Expected keyword \"res\" in output configuration for output %s", - name); + *errstr=log_error("Expected keyword \"res\" in output configuration for output %s", name); goto error; } cfg->pos.width = parse_uint(saveptr, "x"); if(cfg->pos.width <= 0) { - wlr_log(WLR_ERROR, - "Error parsing width of output configuration for output %s " - "(hint: width must be larger than 0)", - name); + *errstr=log_error("Error parsing width of output configuration for output %s (hint: width must be larger than 0)", name); goto error; } cfg->pos.height = parse_uint(saveptr, " "); if(cfg->pos.height <= 0) { - wlr_log(WLR_ERROR, - "Error parsing height of output configuration for output %s " - "(hint: height must e larger than 0)", - name); + *errstr=log_error("Error parsing height of output configuration for output %s (hint: height must e larger than 0)", name); goto error; } char *rate_str = strtok_r(NULL, " ", saveptr); if(rate_str == NULL || strcmp(rate_str, "rate") != 0) { - wlr_log( - WLR_ERROR, - "Expected keyword \"rate\" in output configuration for output %s", - name); + *errstr=log_error("Expected keyword \"rate\" in output configuration for output %s", name); goto error; } cfg->refresh_rate = parse_float(saveptr, " "); if(cfg->refresh_rate <= 0.0) { - wlr_log( - WLR_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", name); goto error; } @@ -346,10 +329,10 @@ error: int parse_command(struct cg_server *server, struct keybinding *keybinding, - char *saveptr) { + char *saveptr, char** errstr) { char *action = strtok_r(NULL, " ", &saveptr); if(action == NULL) { - wlr_log(WLR_ERROR, "Expected an action to parse, got none."); + *errstr=log_error("Expexted an action to parse, got none."); return -1; } keybinding->data = (union keybinding_params){.c = NULL}; @@ -386,8 +369,7 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } else if(strcmp(action, "exec") == 0) { keybinding->action = KEYBINDING_RUN_COMMAND; if(saveptr == NULL) { - wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected " - "string to execute."); + *errstr=log_error("Not enough paramaters to \"exec\". Expected " "string to execute."); return -1; } keybinding->data.c = strdup(saveptr); @@ -407,17 +389,13 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_SWITCH_WORKSPACE; char *nws_str = strtok_r(NULL, " ", &saveptr); if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspace\" action, got none."); + *errstr=log_error("Expected argument for \"workspace\" action, got none."); return -1; } long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - wlr_log(WLR_ERROR, - "Workspace number must be a integer number larger or equal " - "to 1. Got %ld", - ws); + *errstr=log_error("Workspace number must be an integer number larger or equal to 1. Got %ld", ws); return -1; } keybinding->data.u = ws - 1; @@ -425,17 +403,13 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE; char *nws_str = strtok_r(NULL, " ", &saveptr); if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspace\" action, got none."); + *errstr=log_error("Expected argument for \"workspace\" action, got none."); return -1; } long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - wlr_log(WLR_ERROR, - "Workspace number must be an integer larger or equal to 1. " - "Got %ld", - ws); + *errstr=log_error("Workspace number must be an integer larger or equal to 1. Got %ld", ws); return -1; } keybinding->data.u = ws - 1; @@ -461,8 +435,7 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_CHANGE_TTY; char *ntty = strtok_r(NULL, " ", &saveptr); if(ntty == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"switchvt\" command, got none."); + *errstr=log_error("Expected argument for \"switchvt\" command, got none."); return -1; } long tty = strtol(ntty, NULL, 10); @@ -471,13 +444,12 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_SWITCH_MODE; char *mode = strtok_r(NULL, " ", &saveptr); if(mode == NULL) { - wlr_log(WLR_ERROR, - "Expected mode after \"switch_mode\". Got nothing."); + *errstr=log_error("Expected mode after \"switch_mode\". Got nothing."); return -1; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { - wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode); + *errstr=log_error("Unknown mode \"%s\" for switch_mode", mode); return -1; } keybinding->data.u = (unsigned int)mode_idx; @@ -485,78 +457,74 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE; char *mode = strtok_r(NULL, " ", &saveptr); if(mode == NULL) { - wlr_log( - WLR_ERROR, - "Expected mode after \"switch_default_mode\". Got nothing."); + *errstr=log_error("Expected mode after \"switch_default_mode\". Got nothing."); return -1; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { - wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode", - mode); + *errstr=log_error("Unknown mode \"%s\" for switch_default_mode", mode); return -1; } keybinding->data.u = (unsigned int)mode_idx; } else if(strcmp(action, "bind") == 0) { keybinding->action = KEYBINDING_DEFINEKEY; - keybinding->data.kb = parse_bind(server, &saveptr); + keybinding->data.kb = parse_bind(server, &saveptr, errstr); if(keybinding->data.kb == NULL) { return -1; } } else if(strcmp(action, "definekey") == 0) { keybinding->action = KEYBINDING_DEFINEKEY; - keybinding->data.kb = parse_definekey(server, &saveptr); + keybinding->data.kb = parse_definekey(server, &saveptr, errstr); if(keybinding->data.kb == NULL) { return -1; } } else if(strcmp(action, "background") == 0) { keybinding->action = KEYBINDING_BACKGROUND; - if(parse_background(server, keybinding->data.color, &saveptr) != 0) { + if(parse_background(server, keybinding->data.color, &saveptr, errstr) != 0) { return -1; } } else if(strcmp(action, "escape") == 0) { keybinding->action = KEYBINDING_DEFINEKEY; - keybinding->data.kb = parse_escape(&saveptr); + keybinding->data.kb = parse_escape(&saveptr, errstr); if(keybinding->data.kb == NULL) { return -1; } } else if(strcmp(action, "definemode") == 0) { keybinding->action = KEYBINDING_DEFINEMODE; - keybinding->data.c = parse_definemode(&saveptr); + keybinding->data.c = parse_definemode(&saveptr, errstr); if(keybinding->data.c == NULL) { return -1; } } else if(strcmp(action, "workspaces") == 0) { keybinding->action = KEYBINDING_WORKSPACES; - keybinding->data.i = parse_workspaces(&saveptr); + keybinding->data.i = parse_workspaces(&saveptr, errstr); if(keybinding->data.i < 0) { return -1; } } else if(strcmp(action, "output") == 0) { - if(parse_output_config(&server->output_config, &saveptr) != 0) { + if(parse_output_config(&server->output_config, &saveptr, errstr) != 0) { return -1; } } else { - wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action); + *errstr=log_error("Error, unsupported action \"%s\".", action); return -1; } return 0; } int -parse_rc_line(struct cg_server *server, char *line) { +parse_rc_line(struct cg_server *server, char *line, char **errstr) { char *saveptr = strdup(line); // Used internally by strtok_r struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - wlr_log(WLR_ERROR, - "Failed to allocate memory for temporary keybinding struct."); + *errstr=log_error("Failed to allocate memory for temporary keybinding struct."); free(keybinding); free(saveptr); return -1; } - if(parse_command(server, keybinding, saveptr) != 0) { - wlr_log(WLR_ERROR, "Error parsing config file."); + if(parse_command(server, keybinding, saveptr, errstr) != 0) { + wlr_log(WLR_ERROR, "Error parsing command."); free(keybinding); free(saveptr); return -1; diff --git a/parse.h b/parse.h index f170b0d..2a5da8d 100644 --- a/parse.h +++ b/parse.h @@ -7,6 +7,6 @@ struct cg_server; int -parse_rc_line(struct cg_server *server, char *line); +parse_rc_line(struct cg_server *server, char *line, char **errstr); #endif /* end of include guard PARSE_H */ From f55f70e86717cc73aaf957c954a50901780679f4 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sat, 23 May 2020 17:27:34 +0200 Subject: [PATCH 070/122] Update version number --- man/cagebreak-config.5.md | 2 +- man/cagebreak.1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index 8f9cb72..ed82205 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -1,4 +1,4 @@ -% CAGEBREAK-CONFIG(1) Version 1.2 | Cagebreak Manual +% CAGEBREAK-CONFIG(1) Version 1.2.1 | Cagebreak Manual # NAME diff --git a/man/cagebreak.1.md b/man/cagebreak.1.md index 07c0058..a2731d3 100644 --- a/man/cagebreak.1.md +++ b/man/cagebreak.1.md @@ -1,4 +1,4 @@ -% CAGEBREAK(1) Version 1.2 | Cagebreak Manual +% CAGEBREAK(1) Version 1.2.1 | Cagebreak Manual # NAME From 82398c777b70738741abe2353efae5235144bbe2 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sat, 23 May 2020 17:53:41 +0200 Subject: [PATCH 071/122] Apply clang-format --- cagebreak.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cagebreak.c b/cagebreak.c index 42fef88..223beae 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -286,7 +286,8 @@ main(int argc, char *argv[]) { server.modes[1] = strdup("root"); server.modes[2] = strdup("resize"); server.modes[3] = NULL; - if(server.modes[0] == NULL || server.modes[1] == NULL || server.modes[2] == NULL) { + if(server.modes[0] == NULL || server.modes[1] == NULL || + server.modes[2] == NULL) { wlr_log(WLR_ERROR, "Error allocating default modes"); goto end; } From eb86303e841d20c0166c7c3ec1b32b2f3a8ee414 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 24 May 2020 17:50:52 +0200 Subject: [PATCH 072/122] Fix reproducibility - See Issue 5 in Bugs.md --- Bugs.md | 14 ++++++++++++-- README.md | 3 +++ meson.build | 11 +++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Bugs.md b/Bugs.md index b34f4f6..b4c2277 100644 --- a/Bugs.md +++ b/Bugs.md @@ -58,8 +58,8 @@ Steps to reproduce: ### Issue 4 - github issue number: #1 - Fixed: 1.1.0 + * github issue number: #1 + * Fixed: 1.1.0 This issue is code duplication in `parse.c`. @@ -79,3 +79,13 @@ PS: As a side effect, this would allow quirky statements such as `bind dbind r hsplit` which would bind the d key to binding the r key to split the output... ``` + +### Issue 5 + + * github issue number : N/A + * Fixed: 1.2.1 + +Cagebreak up to and including release 1.2.0 does not warn of irreproducibility +if a different compiler or compiler version is used. This makes cagebreak +difficult to reproduce. + diff --git a/README.md b/README.md index 6938686..8f54992 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,9 @@ decided on this compromise to allow flexibility and security. In general we will adapt the versions to the packages available under arch linux at the time of release. +There are reproducibility issues up to and including release `1.2.0`. See +`Issue 5` in [Bugs.md](Bugs.md). + #### Reproducible Build Instructions All hashes and signatures are provided for the following build instructions. diff --git a/meson.build b/meson.build index 4a06c92..4c8643b 100644 --- a/meson.build +++ b/meson.build @@ -217,6 +217,17 @@ foreach name, dep : cagebreak_dependencies_dict endif endforeach +reproducible_build_compiler = 'gcc' +reproducible_build_compiler_version = '10.1.0' + +if cc.get_id() != reproducible_build_compiler + warning('The compiler "' + cc.get_id() + '" differs from the one used to generate to binary specified in the README section "Reproducible Builds" (' + reproducible_build_compiler + ').') +endif + +if cc.version() != reproducible_build_compiler_version + warning('The version of ' + cc.get_id() + ' (' + cc.version() + ') differs from the one used to generate the binary specified in the README section "Reproducible Builds" ' + reproducible_build_compiler_version + '.') +endif + executable( meson.project_name(), cagebreak_main_file + cagebreak_sources + cagebreak_headers, From 8c3821c75efdb27ef8e052cc2f0279c5651d2a9a Mon Sep 17 00:00:00 2001 From: project-repo Date: Sun, 24 May 2020 18:14:38 +0200 Subject: [PATCH 073/122] Add line length check to fuzzing infrastructure --- fuzz/fuzz-parse.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index bcfb701..a53883d 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -416,9 +416,13 @@ set_configuration(struct cg_server *server, char *content) { int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - char *str = malloc(size * sizeof(char) + 1); - strncpy(str, (char *)data, size); - str[size] = 0; + if(size == 0) { + return 0; + } + int max_line_size=256>size?size:256; + char *str = malloc(sizeof(char)*max_line_size); + strncpy(str, (char *)data, max_line_size); + str[max_line_size-1] = 0; set_configuration(&server, str); free(str); keybinding_list_free(server.keybindings); From c3db5393b027743ce69e47f5ff0b25d830a84a46 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 24 May 2020 18:27:20 +0200 Subject: [PATCH 074/122] Add Issue 6 documentation --- Bugs.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Bugs.md b/Bugs.md index b4c2277..7845cca 100644 --- a/Bugs.md +++ b/Bugs.md @@ -89,3 +89,11 @@ Cagebreak up to and including release 1.2.0 does not warn of irreproducibility if a different compiler or compiler version is used. This makes cagebreak difficult to reproduce. +### Issue 6 + + * github issue number : N/A + * Fixed: 1.2.1 + +Our fuzzing framework up to and including release 1.2.0 does not the limit line +lengths. This can crash the fuzzing framework with a segfault due to running +out of memory. From 66d3f51e687f145337ae0bba505f04cb6db2835e Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 24 May 2020 18:31:24 +0200 Subject: [PATCH 075/122] Apply clang-format --- fuzz/fuzz-parse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index a53883d..2434feb 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -419,10 +419,10 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if(size == 0) { return 0; } - int max_line_size=256>size?size:256; - char *str = malloc(sizeof(char)*max_line_size); + int max_line_size = 256 > size ? size : 256; + char *str = malloc(sizeof(char) * max_line_size); strncpy(str, (char *)data, max_line_size); - str[max_line_size-1] = 0; + str[max_line_size - 1] = 0; set_configuration(&server, str); free(str); keybinding_list_free(server.keybindings); From ab33d5c230b504c0b7b015d285ac9c2de5efb52c Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 24 May 2020 18:38:27 +0200 Subject: [PATCH 076/122] Add signatures for 1.2.1 release --- signatures/1.2.0.sig | Bin 0 -> 566 bytes signatures/cagebreak.sig | Bin 566 -> 566 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 signatures/1.2.0.sig diff --git a/signatures/1.2.0.sig b/signatures/1.2.0.sig new file mode 100644 index 0000000000000000000000000000000000000000..18255c989a5f248014471ca87d0e34d33d1565fb GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$#mZGyn<-5XAX( z*9`0|Td=GU0IR~cjMr-vzp4+Q%y>;=&|eqh+5NTd^Vmn-Yf;hi9?v`un2@!jWj@pD7oQnvI3QO^SRPx;FLXS9Rlm>Dx)u zj8~KZ>RgVL!w5-k+d5g)=W*(E=8ymb)fV1X|H&l<#MXRaN{|lJwd zd6Zn{<)up~7&k3dB*#A0=>Tk*iOZLIMt~y zFR_Ir{^)C8U08LeU6zITA1u^p-y14+)m+CI!*eP`gncOXgP4|!1mZ<5lNnU~kZ*p4 E?97)K8~^|S literal 0 HcmV?d00001 diff --git a/signatures/cagebreak.sig b/signatures/cagebreak.sig index 18255c989a5f248014471ca87d0e34d33d1565fb..a37d71e32647647a7bb002a6190182802402fd72 100644 GIT binary patch delta 542 zcmV+(0^$9(1hxc_BY(=Gx&R6Z5XAX(*9`0|TOcnG0FlIP=RBx_{a+33HaD1>)MaI`0crcBBFt0RJ5mVd|$aT!!ycLAjp6G_vT)Dj*E6CmG@w12!N6`*#-BR(+P8Ku=O zpP_EmJ16aa@##xv=$M`QU(IrV2|+ecF!C0AB8-W4f|}6Kn`*0s#z2`aWN_sq&$*D= zAy0s_iW1%wV#{0WCIBxSmUm-MFF++2XdBq{uFRHd6b+wtGZ+B{(hhk`0B5XX}vcMHnp5tHFArxrbtI_bet&1)c`d^>U6{Urcfn znNlE2PNzIknI~H(O7F+vvi#z}h*i~Gus`USQ7_yKw110s+l#iIzNLSlH5m=HkBmFq z%mvfmJ5K_fiEzK>0{3(7P$QfWQUo&lY74TGXZpU(Rm=IyN{&A92fzR4fSrjtJ;G9T_7bX9&#v?qpmM$ gL#YvZY!@CXqi%JK8<7W@8be!l_nW9?uxjX=MbQ2HJ^%m! delta 542 zcmV+(0^$9(1hxc_BY(YGGyn<-5XAX(*9`0|Td=GU0IR~cjMr-vzp4+Q%y>;=&|eqh z+5NTd^Vmn-Yf;hi9?v`un2@!jWj@ zpD7oQnvI3QO^SRPx;FLXS9Rlm>Dx)uj8~KZ>RgVL!w5-k+kZM))aP;Pbmou%1JxGZ zR{zN*1;o~TVdW3#Uhb`Q;<~fz(B5R11P_n7GbgxufMMH|;&cYcrf0+lhUl*@Sn_Z7 zO^Hac&@>)&^p^SdC0LWmvXnu%7haaK-Fv!OoG4^HWi=?$-!mjgX1lla;a$<^S$QFa zrqH=c&T|}&y?;NqT;}DaOMfUBH!W2p>k75}i_PWNVG8!F z49YIZ#D`M?vELRP?_B3u2=nW$b!Y_giac^m@a9zxO_FsRRuDV~RxC_}!#stghbW|4 zj`6TbAd4Q@>kHq)$ From 08dc40376db812594bf7eefcccdd8df5b99027d8 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 24 May 2020 18:40:53 +0200 Subject: [PATCH 077/122] Add hashes for 1.2.1 release --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 8f54992..9e47706 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,11 @@ ninja -C build For every release after 1.0.5, hashes will be provided. +1.2.1 + + * sha 256: 803f7667dc4997062f9ec95afcdca0cac68c82a7cf057cef83fe1ccfee33b8bc + * sha 512: 4d6b7efea10d190a153f893123b1715f290f4b131b490f3d23f489e2dd8edbb886001282849aad9575ad2f40375bbbded59c1cb6157115fcc14dd6a2a061b103 + 1.2.0 * sha 256: b3c6135833001a0ef600ea9628cca11f4130a524ebe748929d8f7bad034f2bf0 From d11e744bc3020daccc34f0560daf5543ff65a04b Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 13:59:55 +0200 Subject: [PATCH 078/122] Add asset generation to release checklist --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9e47706..aa091d4 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,9 @@ Release checklist * [ ] Update signature of the binary * [ ] Signature * [ ] Branching Strategy + * [ ] git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version . + * [ ] gpg --detach-sign -u keyid release_version.tar.gz + * [ ] upload build assets ### Signing Key From 8f9ed7220159e97135e794b942d225e925d5ce22 Mon Sep 17 00:00:00 2001 From: project-repo Date: Mon, 25 May 2020 17:45:19 +0200 Subject: [PATCH 079/122] Improve error handling --- cagebreak.c | 6 +++++- ipc_server.c | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cagebreak.c b/cagebreak.c index ccbbc7d..c99bd95 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -515,7 +515,11 @@ main(int argc, char *argv[]) { wlr_xwayland_set_seat(xwayland, server.seat->seat); #endif - ipc_init(&server); + if(ipc_init(&server) != 0) { + wlr_log(WLR_ERROR, "Failed to initialize IPC"); + ret = 1; + goto end; + } { // config_file should only be visible as long as it is valid char *config_file = get_config_file(); diff --git a/ipc_server.c b/ipc_server.c index 8a7b083..35eea2d 100644 --- a/ipc_server.c +++ b/ipc_server.c @@ -73,6 +73,7 @@ int ipc_init(struct cg_server *server) { if (max_path_size <= snprintf(ipc->sockaddr->sun_path, max_path_size, "%s/cagebreak-ipc.%i.%i.sock", sockdir, getuid(), getpid())) { wlr_log(WLR_ERROR,"Unable to write socket path to ipc->sockaddr->sun_path. Path too long"); + free(ipc->sockaddr); return -1; } @@ -80,11 +81,14 @@ int ipc_init(struct cg_server *server) { if (bind(ipc->socket, (struct sockaddr *)ipc->sockaddr, sizeof(*ipc->sockaddr)) == -1) { wlr_log(WLR_ERROR, "Unable to bind IPC socket"); + free(ipc->sockaddr); return -1; } if (listen(ipc->socket, 3) == -1) { wlr_log(WLR_ERROR, "Unable to listen on IPC socket"); + free(ipc->sockaddr); + return -1; } setenv("CAGEBREAK_SOCKET", ipc->sockaddr->sun_path, 1); From b8ba8186ece3e4f8b4cdb7334d3d1e33604223aa Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 18:34:24 +0200 Subject: [PATCH 080/122] Update version number --- man/cagebreak-config.5.md | 2 +- man/cagebreak.1.md | 2 +- meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index ed82205..96aff5f 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -1,4 +1,4 @@ -% CAGEBREAK-CONFIG(1) Version 1.2.1 | Cagebreak Manual +% CAGEBREAK-CONFIG(1) Version 1.3.0 | Cagebreak Manual # NAME diff --git a/man/cagebreak.1.md b/man/cagebreak.1.md index a2731d3..de820a1 100644 --- a/man/cagebreak.1.md +++ b/man/cagebreak.1.md @@ -1,4 +1,4 @@ -% CAGEBREAK(1) Version 1.2.1 | Cagebreak Manual +% CAGEBREAK(1) Version 1.3.0 | Cagebreak Manual # NAME diff --git a/meson.build b/meson.build index fb52671..c7aef6e 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.2.1', + version: '1.3.03.03.0 license: 'MIT', default_options: [ 'c_std=c11', From e98378bffd805fd74fc469c029b42080dc15d172 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 20:04:29 +0200 Subject: [PATCH 081/122] Fix quotation error --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index c7aef6e..2a2d0ba 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.3.03.03.0 + version: '1.3.0', license: 'MIT', default_options: [ 'c_std=c11', From 816283cdb15c40b0ba30e0bac41babe2f49388a0 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 20:13:33 +0200 Subject: [PATCH 082/122] Apply clang-format --- cagebreak.c | 5 +- ipc_server.c | 141 ++++++++++++++++++++++++++++---------------------- ipc_server.h | 24 +++++---- parse.c | 143 +++++++++++++++++++++++++++++++++------------------ parse.h | 2 +- 5 files changed, 193 insertions(+), 122 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index c99bd95..f908117 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -47,6 +47,7 @@ #endif #include "idle_inhibit_v1.h" +#include "ipc_server.h" #include "keybinding.h" #include "message.h" #include "output.h" @@ -55,7 +56,6 @@ #include "server.h" #include "view.h" #include "xdg_shell.h" -#include "ipc_server.h" #if CG_HAS_XWAYLAND #include "xwayland.h" #endif @@ -290,7 +290,8 @@ main(int argc, char *argv[]) { server.modes[1] = strdup("root"); server.modes[2] = strdup("resize"); server.modes[3] = NULL; - if(server.modes[0] == NULL || server.modes[1] == NULL || server.modes[2] == NULL) { + if(server.modes[0] == NULL || server.modes[1] == NULL || + server.modes[2] == NULL) { wlr_log(WLR_ERROR, "Error allocating default modes"); return 1; } diff --git a/ipc_server.c b/ipc_server.c index 35eea2d..a7c6f21 100644 --- a/ipc_server.c +++ b/ipc_server.c @@ -10,21 +10,22 @@ #define _POSIX_C_SOURCE 200112L #include "ipc_server.h" -#include "server.h" -#include "parse.h" #include "message.h" +#include "parse.h" +#include "server.h" +#include +#include +#include #include #include -#include #include -#include #include -#include -static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct cg_ipc_handle *ipc = wl_container_of(listener, ipc,display_destroy); - if (ipc->event_source != NULL) { +static void +handle_display_destroy(struct wl_listener *listener, void *data) { + struct cg_ipc_handle *ipc = wl_container_of(listener, ipc, display_destroy); + if(ipc->event_source != NULL) { wl_event_source_remove(ipc->event_source); } close(ipc->socket); @@ -40,18 +41,19 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&ipc->display_destroy.link); } -int ipc_init(struct cg_server *server) { +int +ipc_init(struct cg_server *server) { struct cg_ipc_handle *ipc = &server->ipc; ipc->socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (ipc->socket == -1) { + if(ipc->socket == -1) { wlr_log(WLR_ERROR, "Unable to create IPC socket"); return -1; } - if (fcntl(ipc->socket, F_SETFD, FD_CLOEXEC) == -1) { - wlr_log(WLR_ERROR,"Unable to set CLOEXEC on IPC socket"); + if(fcntl(ipc->socket, F_SETFD, FD_CLOEXEC) == -1) { + wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC socket"); return -1; } - if (fcntl(ipc->socket, F_SETFL, O_NONBLOCK) == -1) { + if(fcntl(ipc->socket, F_SETFL, O_NONBLOCK) == -1) { wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC socket"); return -1; } @@ -63,29 +65,32 @@ int ipc_init(struct cg_server *server) { return -1; } - ipc->sockaddr->sun_family=AF_UNIX; + ipc->sockaddr->sun_family = AF_UNIX; int max_path_size = sizeof(ipc->sockaddr->sun_path); - const char *sockdir=getenv("XDG_RUNTIME_DIR"); + const char *sockdir = getenv("XDG_RUNTIME_DIR"); if(sockdir == NULL) { sockdir = "/tmp"; } - if (max_path_size <= snprintf(ipc->sockaddr->sun_path, max_path_size, - "%s/cagebreak-ipc.%i.%i.sock", sockdir, getuid(), getpid())) { - wlr_log(WLR_ERROR,"Unable to write socket path to ipc->sockaddr->sun_path. Path too long"); + if(max_path_size <= snprintf(ipc->sockaddr->sun_path, max_path_size, + "%s/cagebreak-ipc.%i.%i.sock", sockdir, + getuid(), getpid())) { + wlr_log(WLR_ERROR, "Unable to write socket path to " + "ipc->sockaddr->sun_path. Path too long"); free(ipc->sockaddr); return -1; } unlink(ipc->sockaddr->sun_path); - if (bind(ipc->socket, (struct sockaddr *)ipc->sockaddr, sizeof(*ipc->sockaddr)) == -1) { + if(bind(ipc->socket, (struct sockaddr *)ipc->sockaddr, + sizeof(*ipc->sockaddr)) == -1) { wlr_log(WLR_ERROR, "Unable to bind IPC socket"); free(ipc->sockaddr); return -1; } - if (listen(ipc->socket, 3) == -1) { + if(listen(ipc->socket, 3) == -1) { wlr_log(WLR_ERROR, "Unable to listen on IPC socket"); free(ipc->sockaddr); return -1; @@ -98,13 +103,15 @@ int ipc_init(struct cg_server *server) { ipc->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(server->wl_display, &ipc->display_destroy); - ipc->event_source = wl_event_loop_add_fd(server->event_loop, ipc->socket, - WL_EVENT_READABLE, ipc_handle_connection, server); + ipc->event_source = + wl_event_loop_add_fd(server->event_loop, ipc->socket, WL_EVENT_READABLE, + ipc_handle_connection, server); return 0; } -int ipc_handle_connection(int fd, uint32_t mask, void *data) { - (void) fd; +int +ipc_handle_connection(int fd, uint32_t mask, void *data) { + (void)fd; struct cg_server *server = data; struct cg_ipc_handle *ipc = &server->ipc; if(mask != WL_EVENT_READABLE) { @@ -113,45 +120,46 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { } int client_fd = accept(ipc->socket, NULL, NULL); - if (client_fd == -1) { + if(client_fd == -1) { wlr_log(WLR_ERROR, "Unable to accept IPC client connection"); return 0; } int flags; - if ((flags = fcntl(client_fd, F_GETFD)) == -1 - || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { + if((flags = fcntl(client_fd, F_GETFD)) == -1 || + fcntl(client_fd, F_SETFD, flags | FD_CLOEXEC) == -1) { wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket"); close(client_fd); return 0; } - if ((flags = fcntl(client_fd, F_GETFL)) == -1 - || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { + if((flags = fcntl(client_fd, F_GETFL)) == -1 || + fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) == -1) { wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket"); close(client_fd); return 0; } struct cg_ipc_client *client = malloc(sizeof(struct cg_ipc_client)); - if (!client) { + if(!client) { wlr_log(WLR_ERROR, "Unable to allocate ipc client"); close(client_fd); return 0; } // +1 for \n and +1 for \0 - client->read_buffer = malloc(sizeof(char)*(MAX_LINE_SIZE+2)); + client->read_buffer = malloc(sizeof(char) * (MAX_LINE_SIZE + 2)); client->read_buf_len = 0; client->read_discard = 0; client->server = server; client->fd = client_fd; - client->event_source = wl_event_loop_add_fd(server->event_loop, - client_fd, WL_EVENT_READABLE, ipc_client_handle_readable, client); + client->event_source = + wl_event_loop_add_fd(server->event_loop, client_fd, WL_EVENT_READABLE, + ipc_client_handle_readable, client); client->writable_event_source = NULL; client->write_buffer_size = 128; client->write_buffer_len = 0; client->write_buffer = malloc(client->write_buffer_size); - if (!client->write_buffer) { + if(!client->write_buffer) { wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer"); close(client_fd); return 0; @@ -161,52 +169,58 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { return 0; } -int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { +int +ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { struct cg_ipc_client *client = data; - if (mask & WL_EVENT_ERROR) { + if(mask & WL_EVENT_ERROR) { wlr_log(WLR_ERROR, "IPC Client socket error, removing client"); ipc_client_disconnect(client); return 0; } - if (mask & WL_EVENT_HANGUP) { + if(mask & WL_EVENT_HANGUP) { ipc_client_disconnect(client); return 0; } int read_available; - if (ioctl(client_fd, FIONREAD, &read_available) < 0) { + if(ioctl(client_fd, FIONREAD, &read_available) < 0) { wlr_log(WLR_ERROR, "Unable to read IPC socket buffer size"); ipc_client_disconnect(client); return 0; } - int read_size = read_available < MAX_LINE_SIZE+1-client->read_buf_len ? read_available:MAX_LINE_SIZE+1-client->read_buf_len; + int read_size = read_available < MAX_LINE_SIZE + 1 - client->read_buf_len + ? read_available + : MAX_LINE_SIZE + 1 - client->read_buf_len; // Append to buffer - ssize_t received = recv(client_fd, client->read_buffer+client->read_buf_len, read_size, 0); - if (received == -1) { + ssize_t received = recv( + client_fd, client->read_buffer + client->read_buf_len, read_size, 0); + if(received == -1) { wlr_log(WLR_ERROR, "Unable to receive data from IPC client"); ipc_client_disconnect(client); return 0; } - client->read_buf_len+=received; + client->read_buf_len += received; ipc_client_handle_command(client); return 0; } -void ipc_client_disconnect(struct cg_ipc_client *client) { - if (client == NULL) { - wlr_log(WLR_ERROR, "Client \"NULL\" was passed to ipc_client_disconnect"); +void +ipc_client_disconnect(struct cg_ipc_client *client) { + if(client == NULL) { + wlr_log(WLR_ERROR, + "Client \"NULL\" was passed to ipc_client_disconnect"); return; } shutdown(client->fd, SHUT_RDWR); wl_event_source_remove(client->event_source); - if (client->writable_event_source) { + if(client->writable_event_source) { wl_event_source_remove(client->writable_event_source); } wl_list_remove(&client->link); @@ -216,43 +230,48 @@ void ipc_client_disconnect(struct cg_ipc_client *client) { free(client); } -void ipc_client_handle_command(struct cg_ipc_client *client) { - if (client == NULL) { - wlr_log(WLR_ERROR, "Client \"NULL\" was passed to ipc_client_handle_command"); +void +ipc_client_handle_command(struct cg_ipc_client *client) { + if(client == NULL) { + wlr_log(WLR_ERROR, + "Client \"NULL\" was passed to ipc_client_handle_command"); return; } - client->read_buffer[client->read_buf_len]='\0'; + client->read_buffer[client->read_buf_len] = '\0'; char *nl_pos; - uint32_t offset=0; - while((nl_pos = strchr(client->read_buffer+offset,'\n')) != NULL){ + uint32_t offset = 0; + while((nl_pos = strchr(client->read_buffer + offset, '\n')) != NULL) { if(client->read_discard) { client->read_discard = 0; } else { - *nl_pos='\0'; - char *line=client->read_buffer+offset; + *nl_pos = '\0'; + char *line = client->read_buffer + offset; if(*line != '\0' && *line != '#') { message_clear(client->server->curr_output); char *errstr; if(parse_rc_line(client->server, line, &errstr) != 0) { if(errstr != NULL) { - message_printf(client->server->curr_output, "%s", errstr); - wlr_log(WLR_ERROR, "%s",errstr); + message_printf(client->server->curr_output, "%s", + errstr); + wlr_log(WLR_ERROR, "%s", errstr); free(errstr); } wlr_log(WLR_ERROR, "Error parsing input from IPC socket"); } } } - offset=(nl_pos-client->read_buffer)+1; + offset = (nl_pos - client->read_buffer) + 1; } if(offset == 0) { - wlr_log(WLR_ERROR, "Line received was longer that %d, discarding it",MAX_LINE_SIZE); + wlr_log(WLR_ERROR, "Line received was longer that %d, discarding it", + MAX_LINE_SIZE); client->read_buf_len = 0; client->read_discard = 1; return; } - if(offsetread_buf_len) { - memmove(client->read_buffer, client->read_buffer+offset, client->read_buf_len-offset); + if(offset < client->read_buf_len) { + memmove(client->read_buffer, client->read_buffer + offset, + client->read_buf_len - offset); } - client->read_buf_len-=offset; + client->read_buf_len -= offset; } diff --git a/ipc_server.h b/ipc_server.h index 91d09b2..5e66ea4 100644 --- a/ipc_server.h +++ b/ipc_server.h @@ -3,8 +3,8 @@ #include "config.h" -#include #include +#include #include struct cg_server; @@ -21,7 +21,7 @@ struct cg_ipc_client { char *write_buffer; // The following is for storing data between event_loop calls uint16_t read_buf_len; - uint8_t read_discard;// 1 if the current line is to be discarded + uint8_t read_discard; // 1 if the current line is to be discarded char *read_buffer; }; @@ -33,12 +33,18 @@ struct cg_ipc_handle { struct sockaddr_un *sockaddr; }; -int ipc_init(struct cg_server *server); -int ipc_handle_connection(int fd, uint32_t mask, void *data); -int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); -//int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data); -void ipc_client_disconnect(struct cg_ipc_client *client); -void ipc_client_handle_command(struct cg_ipc_client *client); -//bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); +int +ipc_init(struct cg_server *server); +int +ipc_handle_connection(int fd, uint32_t mask, void *data); +int +ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); +// int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data); +void +ipc_client_disconnect(struct cg_ipc_client *client); +void +ipc_client_handle_command(struct cg_ipc_client *client); +// bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t +// payload_length); #endif diff --git a/parse.c b/parse.c index 12f7ee5..1cdcd0c 100644 --- a/parse.c +++ b/parse.c @@ -11,34 +11,35 @@ #include "server.h" #include "workspace.h" -char *malloc_vsprintf(const char *fmt, va_list ap) { +char * +malloc_vsprintf(const char *fmt, va_list ap) { va_list ap2; - va_copy(ap2,ap); + va_copy(ap2, ap); int len = vsnprintf(NULL, 0, fmt, ap); - char *ret=malloc(sizeof(char)*(len+1)); - vsnprintf(ret, len+1, fmt, ap2); + char *ret = malloc(sizeof(char) * (len + 1)); + vsnprintf(ret, len + 1, fmt, ap2); va_end(ap2); return ret; } -char *log_error(const char *fmt, ...) { +char * +log_error(const char *fmt, ...) { va_list args; - va_start(args,fmt); - char *ret=malloc_vsprintf(fmt, args); + va_start(args, fmt); + char *ret = malloc_vsprintf(fmt, args); if(ret != NULL) { wlr_log(WLR_ERROR, "%s", ret); } va_end(args); return ret; - } /* parses a key definition (e.g. "S-Tab") and sets key and modifiers in * keybinding respectivly */ int -parse_key(struct keybinding *keybinding, const char *key_def,char **errstr) { +parse_key(struct keybinding *keybinding, const char *key_def, char **errstr) { if(key_def == NULL) { - *errstr=log_error("Expected key definition, got nothing."); + *errstr = log_error("Expected key definition, got nothing."); return -1; } keybinding->modifiers = 0; @@ -66,14 +67,14 @@ parse_key(struct keybinding *keybinding, const char *key_def,char **errstr) { keybinding->modifiers |= WLR_MODIFIER_MOD5; break; default: - *errstr=log_error("Unknown modifier \"%c\"", key_def[0]); + *errstr = log_error("Unknown modifier \"%c\"", key_def[0]); return -1; } key_def += 2; } xkb_keysym_t keysym = xkb_keysym_from_name(key_def, XKB_KEYSYM_NO_FLAGS); if(keysym == XKB_KEY_NoSymbol) { - *errstr=log_error("Could not convert key \"%s\" to keysym.", key_def); + *errstr = log_error("Could not convert key \"%s\" to keysym.", key_def); return -1; } keybinding->key = keysym; @@ -90,7 +91,8 @@ struct keybinding * parse_keybinding(struct cg_server *server, char **saveptr, char **errstr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - *errstr=log_error("Failed to allocate memory for keybinding in parse_keybinding"); + *errstr = log_error( + "Failed to allocate memory for keybinding in parse_keybinding"); return NULL; } char *key = strtok_r(NULL, " ", saveptr); @@ -121,12 +123,13 @@ struct keybinding * parse_definekey(struct cg_server *server, char **saveptr, char **errstr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { - *errstr=log_error("Too few arguments to \"definekey\". Expected mode"); + *errstr = + log_error("Too few arguments to \"definekey\". Expected mode"); return NULL; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { - *errstr=log_error("Unknown mode \"%s\"", mode); + *errstr = log_error("Unknown mode \"%s\"", mode); return NULL; } struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr); @@ -139,13 +142,16 @@ parse_definekey(struct cg_server *server, char **saveptr, char **errstr) { } int -parse_background(struct cg_server *server, float *color, char **saveptr, char **errstr) { +parse_background(struct cg_server *server, float *color, char **saveptr, + char **errstr) { /* Read rgb numbers */ for(unsigned int i = 0; i < 3; ++i) { char *nstr = strtok_r(NULL, " \n", saveptr); int nstrlen; if(nstr == NULL || (nstrlen = strlen(nstr)) == 0) { - *errstr=log_error("Expected three space-separated numbers (rgb) for background color setting. Got %d.", i); + *errstr = log_error("Expected three space-separated numbers (rgb) " + "for background color setting. Got %d.", + i); return -1; } if(nstr[nstrlen - 1] == '\n') { @@ -155,11 +161,15 @@ parse_background(struct cg_server *server, float *color, char **saveptr, char ** char *endptr = NULL; float nval = strtof(nstr, &endptr); if(endptr != nstr + nstrlen) { - *errstr=log_error("Could not parse number \"%s\" for background color setting.", nstr); + *errstr = log_error( + "Could not parse number \"%s\" for background color setting.", + nstr); return -1; } if(nval < 0 || nval > 1) { - *errstr=log_error("Expected a number between 0 and 1 for setting of background color. Got %f.", nval); + *errstr = log_error("Expected a number between 0 and 1 for setting " + "of background color. Got %f.", + nval); return -1; } color[i] = nval; @@ -171,7 +181,8 @@ struct keybinding * parse_escape(char **saveptr, char **errstr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - *errstr=log_error("Failed to allocate memory for keybinding in parse_escape"); + *errstr = log_error( + "Failed to allocate memory for keybinding in parse_escape"); return NULL; } char *key = strtok_r(NULL, " ", saveptr); @@ -191,7 +202,7 @@ char * parse_definemode(char **saveptr, char **errstr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { - *errstr=log_error("Expected mode to succeed \"definemode\" keyword."); + *errstr = log_error("Expected mode to succeed \"definemode\" keyword."); return NULL; } return strdup(mode); @@ -201,12 +212,14 @@ int parse_workspaces(char **saveptr, char **errstr) { char *nws_str = strtok_r(NULL, " ", saveptr); if(nws_str == NULL) { - *errstr=log_error("Expected argument for \"workspaces\" command, got none."); + *errstr = log_error( + "Expected argument for \"workspaces\" command, got none."); return -1; } long nws = strtol(nws_str, NULL, 10); if(!(1 <= nws && nws <= 30)) { - *errstr=log_error("More than 30 workspaces are not supported. Received %li", nws); + *errstr = log_error( + "More than 30 workspaces are not supported. Received %li", nws); return -1; } return nws; @@ -249,62 +262,81 @@ parse_float(char **saveptr, const char *delim) { } int -parse_output_config(struct wl_list *config_list, char **saveptr, char **errstr) { +parse_output_config(struct wl_list *config_list, char **saveptr, + char **errstr) { struct cg_output_config *cfg = malloc(sizeof(struct cg_output_config)); if(cfg == NULL) { - *errstr=log_error("Failed to allocate memory for output configuration"); + *errstr = + log_error("Failed to allocate memory for output configuration"); goto error; } char *name = strtok_r(NULL, " ", saveptr); if(name == NULL) { - *errstr=log_error("Expected name of output to be configured, got none"); + *errstr = + log_error("Expected name of output to be configured, got none"); goto error; } char *pos_str = strtok_r(NULL, " ", saveptr); if(pos_str == NULL || strcmp(pos_str, "pos") != 0) { - *errstr=log_error("Expected keyword \"pos\" in output configuration for output %s", name); + *errstr = log_error( + "Expected keyword \"pos\" in output configuration for output %s", + name); goto error; } cfg->pos.x = parse_uint(saveptr, " "); if(cfg->pos.x < 0) { - *errstr=log_error("Error parsing x coordinate of output configuration for output %s", name); + *errstr = log_error( + "Error parsing x coordinate of output configuration for output %s", + name); goto error; } cfg->pos.y = parse_uint(saveptr, " "); if(cfg->pos.y < 0) { - *errstr=log_error("Error parsing y coordinate of output configuration for output %s", name); + *errstr = log_error( + "Error parsing y coordinate of output configuration for output %s", + name); goto error; } char *res_str = strtok_r(NULL, " ", saveptr); if(res_str == NULL || strcmp(res_str, "res") != 0) { - *errstr=log_error("Expected keyword \"res\" in output configuration for output %s", name); + *errstr = log_error( + "Expected keyword \"res\" in output configuration for output %s", + name); goto error; } cfg->pos.width = parse_uint(saveptr, "x"); if(cfg->pos.width <= 0) { - *errstr=log_error("Error parsing width of output configuration for output %s (hint: width must be larger than 0)", name); + *errstr = log_error("Error parsing width of output configuration for " + "output %s (hint: width must be larger than 0)", + name); goto error; } cfg->pos.height = parse_uint(saveptr, " "); if(cfg->pos.height <= 0) { - *errstr=log_error("Error parsing height of output configuration for output %s (hint: height must e larger than 0)", name); + *errstr = log_error("Error parsing height of output configuration for " + "output %s (hint: height must e larger than 0)", + name); goto error; } char *rate_str = strtok_r(NULL, " ", saveptr); if(rate_str == NULL || strcmp(rate_str, "rate") != 0) { - *errstr=log_error("Expected keyword \"rate\" in output configuration for output %s", name); + *errstr = log_error( + "Expected keyword \"rate\" in output configuration for output %s", + name); goto error; } 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", + name); goto error; } @@ -329,10 +361,10 @@ error: int parse_command(struct cg_server *server, struct keybinding *keybinding, - char *saveptr, char** errstr) { + char *saveptr, char **errstr) { char *action = strtok_r(NULL, " ", &saveptr); if(action == NULL) { - *errstr=log_error("Expexted an action to parse, got none."); + *errstr = log_error("Expexted an action to parse, got none."); return -1; } keybinding->data = (union keybinding_params){.c = NULL}; @@ -369,7 +401,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } else if(strcmp(action, "exec") == 0) { keybinding->action = KEYBINDING_RUN_COMMAND; if(saveptr == NULL) { - *errstr=log_error("Not enough paramaters to \"exec\". Expected " "string to execute."); + *errstr = log_error("Not enough paramaters to \"exec\". Expected " + "string to execute."); return -1; } keybinding->data.c = strdup(saveptr); @@ -389,13 +422,16 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_SWITCH_WORKSPACE; char *nws_str = strtok_r(NULL, " ", &saveptr); if(nws_str == NULL) { - *errstr=log_error("Expected argument for \"workspace\" action, got none."); + *errstr = log_error( + "Expected argument for \"workspace\" action, got none."); return -1; } long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - *errstr=log_error("Workspace number must be an integer number larger or equal to 1. Got %ld", ws); + *errstr = log_error("Workspace number must be an integer number " + "larger or equal to 1. Got %ld", + ws); return -1; } keybinding->data.u = ws - 1; @@ -403,13 +439,16 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE; char *nws_str = strtok_r(NULL, " ", &saveptr); if(nws_str == NULL) { - *errstr=log_error("Expected argument for \"workspace\" action, got none."); + *errstr = log_error( + "Expected argument for \"workspace\" action, got none."); return -1; } long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - *errstr=log_error("Workspace number must be an integer larger or equal to 1. Got %ld", ws); + *errstr = log_error("Workspace number must be an integer larger or " + "equal to 1. Got %ld", + ws); return -1; } keybinding->data.u = ws - 1; @@ -435,7 +474,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_CHANGE_TTY; char *ntty = strtok_r(NULL, " ", &saveptr); if(ntty == NULL) { - *errstr=log_error("Expected argument for \"switchvt\" command, got none."); + *errstr = log_error( + "Expected argument for \"switchvt\" command, got none."); return -1; } long tty = strtol(ntty, NULL, 10); @@ -444,12 +484,13 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_SWITCH_MODE; char *mode = strtok_r(NULL, " ", &saveptr); if(mode == NULL) { - *errstr=log_error("Expected mode after \"switch_mode\". Got nothing."); + *errstr = + log_error("Expected mode after \"switch_mode\". Got nothing."); return -1; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { - *errstr=log_error("Unknown mode \"%s\" for switch_mode", mode); + *errstr = log_error("Unknown mode \"%s\" for switch_mode", mode); return -1; } keybinding->data.u = (unsigned int)mode_idx; @@ -457,12 +498,14 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE; char *mode = strtok_r(NULL, " ", &saveptr); if(mode == NULL) { - *errstr=log_error("Expected mode after \"switch_default_mode\". Got nothing."); + *errstr = log_error( + "Expected mode after \"switch_default_mode\". Got nothing."); return -1; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { - *errstr=log_error("Unknown mode \"%s\" for switch_default_mode", mode); + *errstr = + log_error("Unknown mode \"%s\" for switch_default_mode", mode); return -1; } keybinding->data.u = (unsigned int)mode_idx; @@ -480,7 +523,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } } else if(strcmp(action, "background") == 0) { keybinding->action = KEYBINDING_BACKGROUND; - if(parse_background(server, keybinding->data.color, &saveptr, errstr) != 0) { + if(parse_background(server, keybinding->data.color, &saveptr, errstr) != + 0) { return -1; } } else if(strcmp(action, "escape") == 0) { @@ -506,7 +550,7 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, return -1; } } else { - *errstr=log_error("Error, unsupported action \"%s\".", action); + *errstr = log_error("Error, unsupported action \"%s\".", action); return -1; } return 0; @@ -518,7 +562,8 @@ parse_rc_line(struct cg_server *server, char *line, char **errstr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - *errstr=log_error("Failed to allocate memory for temporary keybinding struct."); + *errstr = log_error( + "Failed to allocate memory for temporary keybinding struct."); free(keybinding); free(saveptr); return -1; diff --git a/parse.h b/parse.h index 2a5da8d..ba1b2e8 100644 --- a/parse.h +++ b/parse.h @@ -2,7 +2,7 @@ #define PARSE_H -# define MAX_LINE_SIZE 256 +#define MAX_LINE_SIZE 256 struct cg_server; From 43b06932d75aee64e8392a9d871a81998fbc2845 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 21:01:27 +0200 Subject: [PATCH 083/122] Add ipc documentation --- man/cagebreak.1.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/man/cagebreak.1.md b/man/cagebreak.1.md index de820a1..4150ad4 100644 --- a/man/cagebreak.1.md +++ b/man/cagebreak.1.md @@ -18,10 +18,16 @@ in contrast to the original `ratpoison`, has native support for multi-workspace operation. All interactions between the user and `cagebreak` are done via -the keyboard. Configuration of this behaviour is specified -in the **\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**). +the keyboard. -## OPTIONS +Configuration of this behaviour is specified in the +**\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**). + +Scripting support is provided through the inter process communication +socket **\$CAGEBREAK_SOCKET**. +Errors are displayed in the top right corner of the screen. + +# OPTIONS -h @@ -37,6 +43,11 @@ in the **\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**) # ENVIRONMENT +`CAGEBREAK_SOCKET` + +: The inter process communication unix domain socket address accepting +everything specified in **cagebreak-config(5)** + `XKB_DEFAULT_LAYOUT` : The keyboard layout to be used (See **xkeyboard-config(7)**) From d8f801bb064151b894a660a586a4d0089f5f1777 Mon Sep 17 00:00:00 2001 From: project-repo Date: Mon, 25 May 2020 21:16:59 +0200 Subject: [PATCH 084/122] Reword manpage --- man/cagebreak.1.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/man/cagebreak.1.md b/man/cagebreak.1.md index 4150ad4..c72323f 100644 --- a/man/cagebreak.1.md +++ b/man/cagebreak.1.md @@ -23,9 +23,12 @@ the keyboard. Configuration of this behaviour is specified in the **\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**). -Scripting support is provided through the inter process communication -socket **\$CAGEBREAK_SOCKET**. -Errors are displayed in the top right corner of the screen. +Scripting support is provided through the IPC +socket specified in the environment variable **\$CAGEBREAK_SOCKET**. +The syntax accepted through this socket is identical to +that of the configuration file (see **cagebreak-config(5)**). +Errors which occur during interaction over IPC channel +are displayed in a message box at the top right of the screen. # OPTIONS @@ -45,8 +48,8 @@ Errors are displayed in the top right corner of the screen. `CAGEBREAK_SOCKET` -: The inter process communication unix domain socket address accepting -everything specified in **cagebreak-config(5)** +: The IPC unix domain socket address accepting +commands as specified in **cagebreak-config(5)** `XKB_DEFAULT_LAYOUT` From 2f366fb4ca47b57cb97dbde53d2406004998d04d Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 21:49:18 +0200 Subject: [PATCH 085/122] Add 1.3.0 Changelog --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index aa091d4..bfa20a3 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,10 @@ Unifies commands and actions. See Issue 4 in Bugs.md. Adds output configuration as described in the man pages. +### Release 1.3.0 + +Adds IPC as described in the man pages. + ## License Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE) From f9babbe52205e7ae60286fb9c83e116c0d167e66 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 22:57:56 +0200 Subject: [PATCH 086/122] Fix typo --- Bugs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugs.md b/Bugs.md index 7845cca..f39de1c 100644 --- a/Bugs.md +++ b/Bugs.md @@ -94,6 +94,6 @@ difficult to reproduce. * github issue number : N/A * Fixed: 1.2.1 -Our fuzzing framework up to and including release 1.2.0 does not the limit line +Our fuzzing framework up to and including release 1.2.0 does not limit line lengths. This can crash the fuzzing framework with a segfault due to running out of memory. From 9605d7c243bd4b5dcdc486c24b76f996c11af3d7 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 22:59:25 +0200 Subject: [PATCH 087/122] Update hashes --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index bfa20a3..19a1f02 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,11 @@ ninja -C build For every release after 1.0.5, hashes will be provided. +1.3.0 + + * sha 256: aecc5292f56f7250d777110cee1f11a92018a9eb2117d7d37cd51d7d3a5cbae0 + * sha 512: 1d2d220f44787a97359a32f305e33185f0369551e61a9d7066023bfa43de50849eba5bcbb0083d2dc563ac993b8d51dd733afa0adb2a823ef50ecfee5624bbc0 + 1.2.1 * sha 256: 803f7667dc4997062f9ec95afcdca0cac68c82a7cf057cef83fe1ccfee33b8bc From b10dfb287d3619cc42bc913b3d1e1eed93991c94 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 25 May 2020 23:01:42 +0200 Subject: [PATCH 088/122] Update signatures --- signatures/1.2.1.sig | Bin 0 -> 566 bytes signatures/cagebreak.sig | Bin 566 -> 566 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 signatures/1.2.1.sig diff --git a/signatures/1.2.1.sig b/signatures/1.2.1.sig new file mode 100644 index 0000000000000000000000000000000000000000..a37d71e32647647a7bb002a6190182802402fd72 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$$3Zx&R6Z5XAX( z*9`0|TOcnG0FlIP=RBx_{a+33HaD1>)MaI`0crcBBFt0RJ5mVd|$aT!!ycLAjp z6G_vT)Dj*E6CmG@w7e!2pmxP0J}}%FrPVH

EYXC+&Xm=}Twmn4S7x&2oPUK{ik@ z@)mm{jEQ!Fn$XajYO93CK$$LNaOEV=xsci+Pk^(E65bSI%UkOv052StcVka4KqVMx z8`$)&%$8~t4WD*17y$*+4tYxeXRKo7UPc*j6|u?;M4tmV)YY~dU87{}NNshUPVs7^=CQSvN2GaF%j#^(#aub%1y&Bvi;V#HYus2~z6?VA(evWumTk&VE(Lvitm>LVRWku}b2yQ|uQ|6L#@DIRhtlcTOLX+x-2e&+5XAX(*9`0|TaZ-`|8B19v8nWt+`yQRe_>?zV9R$K zNOZ;Ao6nXhbU1&)=v=`5F>DZu{#kbT6{L}V-K$1hB}cOf3-I#7y8ey(rb(#xaKdnF zJw~ z8`fdv%)~Z_(|<4L#TiH=Ny}^&kAR=rb;~L{@JAa$My;n&b>9`oK*kX3BOp>H8@eZ# zbU)__h%*`N3}{$BBEl;tzu^qD(b*2&(|}8VO5{o)FM^hjH-UX=^?;TB%|a3~F9^;o zKfu6<&~OnzlOr+eB)@;cVVqMb;7Ph)tYRB;tvoWzF@N_#6J%u5aEWgA%%3IIiWbNH z;7~)MaI`0crcBBFt0RJ5mVd|$aT!!ycLAjp6G_vT)Dj*E6CmG@w12!N6`*#-BR(+P8Ku=O zpP_EmJ16aa@##xv=$M`QU(IrV2|+ecF!C0AB8-W4f|}6Kn`*0s#z2`aWN_sq&$*D= zAy0s_iW1%wV#{0WCIBxSmUm-MFF++2XdBq{uFRHd6b+wtGZ+B{(hhk`0B5XX}vcMHnp5tHFArxrbtI_bet&1)c`d^>U6{Urcfn znNlE2PNzIknI~H(O7F+vvi#z}h*i~Gus`USQ7_yKw110s+l#iIzNLSlH5m=HkBmFq z%mvfmJ5K_fiEzK>0{3(7P$QfWQUo&lY74TGXZpU(Rm=IyN{&A92fzR4fSrjtJ;G9T_7bX9&#v?qpmM$ gL#YvZY!@CXqi%JK8<7W@8be!l_nW9?uxjX=MbQ2HJ^%m! From a277f06224d709f78d190c212459fbecbf86b89e Mon Sep 17 00:00:00 2001 From: project-repo Date: Tue, 26 May 2020 14:16:58 +0200 Subject: [PATCH 089/122] Ameliorate meson.build - Only warn about compiler version missmatch in the case that the compilers are the same --- meson.build | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 2a2d0ba..de94fda 100644 --- a/meson.build +++ b/meson.build @@ -224,9 +224,7 @@ reproducible_build_compiler_version = '10.1.0' if cc.get_id() != reproducible_build_compiler warning('The compiler "' + cc.get_id() + '" differs from the one used to generate to binary specified in the README section "Reproducible Builds" (' + reproducible_build_compiler + ').') -endif - -if cc.version() != reproducible_build_compiler_version +elif cc.version() != reproducible_build_compiler_version warning('The version of ' + cc.get_id() + ' (' + cc.version() + ') differs from the one used to generate the binary specified in the README section "Reproducible Builds" ' + reproducible_build_compiler_version + '.') endif From 5bd9164c3b1450bb83519cefd35a3e8de92e48fd Mon Sep 17 00:00:00 2001 From: project-repo Date: Thu, 28 May 2020 15:03:59 +0200 Subject: [PATCH 090/122] Fix indentiing issues --- view.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/view.c b/view.c index 609b01e..0bc6dfc 100644 --- a/view.c +++ b/view.c @@ -238,10 +238,10 @@ view_unmap(struct cg_view *view) { .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) { + 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; From 32dc8c3717e10b079c3c6da0b31e10d2099a5bf3 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 29 May 2020 14:42:01 +0200 Subject: [PATCH 091/122] Restructure fuzzer --- fuzz/fuzz-lib.c | 554 ++++++++++++++++++++++++++++++++++++++++++++++ fuzz/fuzz-lib.h | 42 ++++ fuzz/fuzz-parse.c | 413 ++++------------------------------ fuzz/meson.build | 2 + 4 files changed, 642 insertions(+), 369 deletions(-) create mode 100644 fuzz/fuzz-lib.c create mode 100644 fuzz/fuzz-lib.h diff --git a/fuzz/fuzz-lib.c b/fuzz/fuzz-lib.c new file mode 100644 index 0000000..aad54b3 --- /dev/null +++ b/fuzz/fuzz-lib.c @@ -0,0 +1,554 @@ +/* + * Cagebreak: A Wayland tiling compositor. + * + * Copyright (C) 2018-2020 Jente Hidskes + * + * See the LICENSE file accompanying this file. + */ + +#define _POSIX_C_SOURCE 200812L + +#include "../keybinding.h" +#include "../output.h" +#include "../parse.h" +#include "../seat.h" +#include "../server.h" +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if CG_HAS_XWAYLAND +#include +#endif +#include +#include +#include +#include +#if CG_HAS_XWAYLAND +#include +#endif + +#include "../idle_inhibit_v1.h" +#include "../xdg_shell.h" +#if CG_HAS_XWAYLAND +#include "../xwayland.h" +#endif + +#include "fuzz-lib.h" + +static bool +drop_permissions(void) { + if(getuid() != geteuid() || getgid() != getegid()) { + if(setuid(getuid()) != 0 || setgid(getgid()) != 0) { + wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); + return false; + } + } + + if(setuid(0) != -1) { + wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to " + "restore it after setuid), refusing to start"); + return false; + } + + return true; +} + +static bool +parse_args(struct cg_server *server, int argc, char *argv[]) { + server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; +#ifdef DEBUG + server->debug_damage_tracking = false; +#endif + return true; +} + +void +cleanup() { + server.running = false; +#if CG_HAS_XWAYLAND + if(xwayland != NULL) { + wlr_xwayland_destroy(xwayland); + } + if(xcursor_manager != NULL) { + wlr_xcursor_manager_destroy(xcursor_manager); + } +#endif + wl_display_destroy_clients(server.wl_display); + + for(unsigned int i = 0; server.modes[i] != NULL; ++i) { + free(server.modes[i]); + } + free(server.modes); + + keybinding_list_free(server.keybindings); + + seat_destroy(server.seat); + /* This function is not null-safe, but we only ever get here + with a proper wl_display. */ + wl_display_destroy(server.wl_display); + wlr_output_layout_destroy(server.output_layout); +} + +int +LLVMFuzzerInitialize(int *argc, char ***argv) { + struct wl_event_loop *event_loop = NULL; + struct wlr_backend *backend = NULL; + struct wlr_renderer *renderer = NULL; + struct wlr_compositor *compositor = NULL; + struct wlr_data_device_manager *data_device_manager = NULL; + struct wlr_server_decoration_manager *server_decoration_manager = NULL; + 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_xdg_output_manager_v1 *output_manager = NULL; + struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + int ret = 0; + + if(!parse_args(&server, *argc, *argv)) { + return 1; + } + +#ifdef DEBUG + wlr_log_init(WLR_DEBUG, NULL); +#else + wlr_log_init(WLR_ERROR, NULL); +#endif + + /* 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"); + return 1; + } + + server.wl_display = wl_display_create(); + if(!server.wl_display) { + wlr_log(WLR_ERROR, "Cannot allocate a Wayland display"); + return 1; + } + + server.running = true; + + server.modes = malloc(4 * sizeof(char *)); + server.modes[0] = strdup("top"); + server.modes[1] = strdup("root"); + server.modes[2] = strdup("resize"); + server.modes[3] = NULL; + + server.nws = 1; + server.message_timeout = 2; + + event_loop = wl_display_get_event_loop(server.wl_display); + server.event_loop = event_loop; + + backend = wlr_multi_backend_create(server.wl_display); + if(!backend) { + wlr_log(WLR_ERROR, "Unable to create the wlroots multi backend"); + ret = 1; + goto end; + } + server.backend = backend; + + struct wlr_backend *headless_backend=wlr_headless_backend_create(server.wl_display, NULL); + if(!headless_backend) { + wlr_log(WLR_ERROR, "Unable to create the wlroots headless backend"); + ret = 1; + goto end; + } + wlr_headless_add_output(headless_backend,600,300); + + + if(!wlr_multi_backend_add(backend, headless_backend)) { + wlr_log(WLR_ERROR, "Unable to insert headless backend into multi backend"); + ret = 1; + goto end; + }; + + if(!drop_permissions()) { + ret = 1; + goto end; + } + + server.keybindings = keybinding_list_init(); + if(server.keybindings == NULL || server.keybindings->keybindings == NULL) { + wlr_log(WLR_ERROR, "Unable to allocate keybindings"); + ret = 1; + goto end; + } + + wl_list_init(&server.output_config); + + renderer = wlr_backend_get_renderer(backend); + wlr_renderer_init_wl_display(renderer, server.wl_display); + + server.bg_color = malloc(4 * sizeof(float)); + server.bg_color[0] = 0; + server.bg_color[1] = 0; + server.bg_color[2] = 0; + server.bg_color[3] = 1; + wl_list_init(&server.outputs); + + server.output_layout = wlr_output_layout_create(); + if(!server.output_layout) { + wlr_log(WLR_ERROR, "Unable to create output layout"); + ret = 1; + goto end; + } + + data_device_manager = wlr_data_device_manager_create(server.wl_display); + if(!data_device_manager) { + wlr_log(WLR_ERROR, "Unable to create the data device 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. */ + server.new_output.notify = handle_new_output; + wl_signal_add(&backend->events.new_output, &server.new_output); + + server.seat = seat_create(&server, backend); + if(!server.seat) { + wlr_log(WLR_ERROR, "Unable to create the seat"); + ret = 1; + goto end; + } + + server.idle = wlr_idle_create(server.wl_display); + if(!server.idle) { + wlr_log(WLR_ERROR, "Unable to create the idle tracker"); + ret = 1; + goto end; + } + + server.idle_inhibit_v1 = wlr_idle_inhibit_v1_create(server.wl_display); + if(!server.idle_inhibit_v1) { + wlr_log(WLR_ERROR, "Cannot create the idle inhibitor"); + ret = 1; + goto end; + } + server.new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1_new; + wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, + &server.new_idle_inhibitor_v1); + wl_list_init(&server.inhibitors); + + xdg_shell = wlr_xdg_shell_create(server.wl_display); + if(!xdg_shell) { + wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); + ret = 1; + goto end; + } + server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new; + wl_signal_add(&xdg_shell->events.new_surface, + &server.new_xdg_shell_surface); + + xdg_decoration_manager = + wlr_xdg_decoration_manager_v1_create(server.wl_display); + if(!xdg_decoration_manager) { + wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager"); + ret = 1; + goto end; + } + wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration, + &server.xdg_toplevel_decoration); + server.xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; + + server_decoration_manager = + wlr_server_decoration_manager_create(server.wl_display); + if(!server_decoration_manager) { + wlr_log(WLR_ERROR, "Unable to create the server decoration manager"); + ret = 1; + goto end; + } + wlr_server_decoration_manager_set_default_mode( + server_decoration_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + + export_dmabuf_manager = + wlr_export_dmabuf_manager_v1_create(server.wl_display); + if(!export_dmabuf_manager) { + wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager"); + ret = 1; + goto end; + } + + screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display); + if(!screencopy_manager) { + wlr_log(WLR_ERROR, "Unable to create the screencopy manager"); + ret = 1; + goto end; + } + + output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, + server.output_layout); + if(!output_manager) { + wlr_log(WLR_ERROR, "Unable to create the output manager"); + ret = 1; + goto end; + } + + gamma_control_manager = + wlr_gamma_control_manager_v1_create(server.wl_display); + if(!gamma_control_manager) { + wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); + ret = 1; + goto end; + } + + if(!compositor) { + wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); + ret = 1; + goto end; + } + + compositor = wlr_compositor_create(server.wl_display, renderer); + if(!compositor) { + wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); + ret = 1; + goto end; + } + +#if CG_HAS_XWAYLAND + xwayland = wlr_xwayland_create(server.wl_display, compositor, true); + if(!xwayland) { + wlr_log(WLR_ERROR, "Cannot create XWayland server"); + ret = 1; + goto end; + } + server.new_xwayland_surface.notify = handle_xwayland_surface_new; + wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); + + xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); + if(!xcursor_manager) { + wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); + ret = 1; + goto end; + } + + if(setenv("DISPLAY", xwayland->display_name, true) < 0) { + wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland.", + "Clients may not be able to connect"); + } else { + wlr_log(WLR_DEBUG, "XWayland is running on display %s", + xwayland->display_name); + } + + if(wlr_xcursor_manager_load(xcursor_manager, 1)) { + wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); + } + struct wlr_xcursor *xcursor = + wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); + if(xcursor) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4, + image->width, image->height, image->hotspot_x, + image->hotspot_y); + } + +#endif + + const char *socket = wl_display_add_socket_auto(server.wl_display); + if(!socket) { + wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket"); + ret = 1; + goto end; + } + + if(!wlr_backend_start(backend)) { + wlr_log(WLR_ERROR, "Unable to start the wlroots backend"); + ret = 1; + goto end; + } + + if(setenv("WAYLAND_DISPLAY", socket, true) < 0) { + wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.", + "Clients may not be able to connect"); + } else { + wlr_log(WLR_DEBUG, + "Cagebreak " CG_VERSION " is running on Wayland display %s", + socket); + } + + /* Place the cursor to the topl left of the output layout. */ + wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); + atexit(cleanup); + //server.wl_display->run = 1; + return 0; +end: + cleanup(); + return ret; +} + +void +move_cursor(char *line, struct cg_server *server) { + return;//TODO + long del=0; + char *delstr = strtok_r(NULL, ";", &line); + enum wlr_axis_orientation orientation = (*(line++)=='0')? WLR_AXIS_ORIENTATION_VERTICAL:WLR_AXIS_ORIENTATION_HORIZONTAL; + if(delstr == NULL) { + return; + } + del=strtol(delstr,NULL,10); + struct wlr_event_pointer_axis event = { + .device = NULL, + .time_msec = 0, + .source = WLR_AXIS_SOURCE_WHEEL, + .orientation = orientation, + .delta = del * 15, + .delta_discrete = del + }; + //TODO dispatch_cursor_axis(server->seat->cursor, &event); +} + +void add_output_callback(struct wlr_backend *backend, void *data) { + long *dims=data; + wlr_headless_add_output(backend, dims[0], dims[1]); +} + +void +create_output(char *line, struct cg_server *server) { + char *widthstr = strtok_r(NULL, ";", &line); + long dims[2]= {600, 200}; + if(widthstr != NULL) { + dims[0]=strtol(widthstr,NULL,10); + if(line[0] != '\0') { + ++line; + } + } + char *heightstr = strtok_r(NULL, ";", &line); + if(heightstr != NULL) { + dims[1]=strtol(heightstr,NULL,10); + } + long max_dim = 10000; + if (dims[0] > max_dim || dims[0] <= 0 ) { + wlr_log(WLR_ERROR, "height out of range."); + return; + } else if (dims[1] > max_dim || dims[1] <= 0) { + wlr_log(WLR_ERROR, "width out of range."); + return; + } + wlr_multi_for_each_backend(server->backend, add_output_callback, dims); +} + +void add_input_device_callback(struct wlr_backend *backend, void *data) { + enum wlr_input_device_type *type=data; + wlr_headless_add_input_device(backend, *type); +} + +void +create_input_device(char *line, struct cg_server *server) { + enum wlr_input_device_type type; + if(*line != '\0') { + if(strncmp(line,"kbd",3) == 0) { + type = WLR_INPUT_DEVICE_KEYBOARD; + wlr_multi_for_each_backend(server->backend, add_input_device_callback, &type); + } else if(strncmp(line,"ptr",3) == 0) { + type = WLR_INPUT_DEVICE_POINTER; + wlr_multi_for_each_backend(server->backend, add_input_device_callback, &type); + } else if(strncmp(line,"tch",3) == 0) { + type = WLR_INPUT_DEVICE_TOUCH; + wlr_multi_for_each_backend(server->backend, add_input_device_callback, &type); + } + } +} + +void +destroy_input_device(char *line, struct cg_server *server) { + long devn=0; + if(line[0] != '\0') { + devn = strtol(line+1,NULL,10); + } + if(line != NULL) { + if(strncmp(line,"k",1) == 0) { + if(wl_list_empty(&server->seat->keyboard_groups)) { + return; + } + devn = devn % wl_list_length(&server->seat->keyboard_groups); + struct cg_keyboard_group *group, *group_tmp; + wl_list_for_each_safe(group, group_tmp, &server->seat->keyboard_groups, link) { + if(devn == 0) { + wl_list_remove(&group->link); + wlr_keyboard_group_destroy(group->wlr_group); + wl_event_source_remove(group->key_repeat_timer); + free(group); + break; + } + --devn; + } + } else if(strncmp(line,"p",1) == 0) { + if(wl_list_empty(&server->seat->pointers)) { + 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) { + 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); + break; + } + --devn; + } + + } + } +} + +void +destroy_output(char *line, struct cg_server *server) { + if(wl_list_length(&server->outputs)<2) { + return; + } + char *outpnstr = strtok_r(NULL, ";", &line); + long outpn = 0; + if(outpnstr != NULL) { + outpn=strtol(outpnstr,NULL,10); + } + outpn=outpn%wl_list_length(&server->outputs); + struct cg_output *it; + wl_list_for_each(it,&server->outputs,link) { + if(outpn == 0) { + break; + } else { + --outpn; + } + } + it->damage_destroy.notify(&it->damage_destroy,NULL); +} diff --git a/fuzz/fuzz-lib.h b/fuzz/fuzz-lib.h new file mode 100644 index 0000000..95007b3 --- /dev/null +++ b/fuzz/fuzz-lib.h @@ -0,0 +1,42 @@ +/* + * Cagebreak: A Wayland tiling compositor. + * + * Copyright (C) 2018-2020 Jente Hidskes + * + * See the LICENSE file accompanying this file. + */ + +#ifndef CG_FUZZ_LIB_H +#define CG_FUZZ_LIB_H + +#define _POSIX_C_SOURCE 200812L + +#include "../server.h" + +#ifndef WAIT_ANY +#define WAIT_ANY -1 +#endif + +struct cg_server server; +struct wlr_xdg_shell *xdg_shell; + +struct wlr_xwayland *xwayland; +#if CG_HAS_XWAYLAND +struct wlr_xcursor_manager *xcursor_manager; +#endif + +void cleanup(); + +int LLVMFuzzerInitialize(int *argc, char ***argv); + +void move_cursor(char *line, struct cg_server *server); + +void create_output(char *line, struct cg_server *server); + +void create_input_device(char *line, struct cg_server *server); + +void destroy_input_device(char *line, struct cg_server *server); + +void destroy_output(char *line, struct cg_server *server); + +#endif diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 45e74da..09ce0c0 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -8,394 +8,46 @@ #define _POSIX_C_SOURCE 200812L -#include "../keybinding.h" -#include "../output.h" -#include "../parse.h" -#include "../seat.h" -#include "../server.h" -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if CG_HAS_XWAYLAND -#include -#endif -#include -#include +#include #include #include -#if CG_HAS_XWAYLAND -#include -#endif -#include "../idle_inhibit_v1.h" +#include "config.h" #include "../keybinding.h" #include "../message.h" #include "../output.h" #include "../parse.h" #include "../seat.h" #include "../server.h" -#include "../view.h" #include "../workspace.h" -#include "../xdg_shell.h" #if CG_HAS_XWAYLAND #include "../xwayland.h" #endif -#ifndef WAIT_ANY -#define WAIT_ANY -1 -#endif - -static bool -drop_permissions(void) { - if(getuid() != geteuid() || getgid() != getegid()) { - if(setuid(getuid()) != 0 || setgid(getgid()) != 0) { - wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); - return false; - } - } - - if(setuid(0) != -1) { - wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to " - "restore it after setuid), refusing to start"); - return false; - } - - return true; -} - -static bool -parse_args(struct cg_server *server, int argc, char *argv[]) { - server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; -#ifdef DEBUG - server->debug_damage_tracking = false; -#endif - return true; -} - -struct cg_server server = {0}; -struct wlr_xwayland *xwayland = NULL; -#if CG_HAS_XWAYLAND -struct wlr_xcursor_manager *xcursor_manager = NULL; -#endif - -void -cleanup() { - server.running = false; -#if CG_HAS_XWAYLAND - if(xwayland != NULL) { - wlr_xwayland_destroy(xwayland); - } - if(xcursor_manager != NULL) { - wlr_xcursor_manager_destroy(xcursor_manager); - } -#endif - wl_display_destroy_clients(server.wl_display); - - for(unsigned int i = 0; server.modes[i] != NULL; ++i) { - free(server.modes[i]); - } - free(server.modes); - - keybinding_list_free(server.keybindings); - - seat_destroy(server.seat); - /* This function is not null-safe, but we only ever get here - with a proper wl_display. */ - wl_display_destroy(server.wl_display); - wlr_output_layout_destroy(server.output_layout); -} +#include "fuzz-lib.h" int -LLVMFuzzerInitialize(int *argc, char ***argv) { - struct wl_event_loop *event_loop = NULL; - struct wlr_backend *backend = NULL; - struct wlr_renderer *renderer = NULL; - struct wlr_compositor *compositor = NULL; - struct wlr_data_device_manager *data_device_manager = NULL; - struct wlr_server_decoration_manager *server_decoration_manager = NULL; - 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_xdg_output_manager_v1 *output_manager = NULL; - struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; - struct wlr_xdg_shell *xdg_shell = NULL; - int ret = 0; - - if(!parse_args(&server, *argc, *argv)) { - return 1; +fuzz_cmds(struct cg_server *server, char *line) { + if(strncmp(line, "mcurs",5) == 0) { + move_cursor(&line[5], server); + return 0; + } else if(strncmp(line, "noutp",5) == 0) { + create_output(&line[5], server); + return 0; + } else if(strncmp(line, "doutp",5) == 0) { + destroy_output(&line[5], server); + return 0; + } else if(strncmp(line, "crdev",5) == 0) { + return -1; + create_input_device(&line[5], server); + return 0; + } else if(strncmp(line, "ddev",5) == 0) { + destroy_input_device(&line[5], server); + return 0; } - -#ifdef DEBUG - wlr_log_init(WLR_DEBUG, NULL); -#else - wlr_log_init(WLR_ERROR, NULL); -#endif - - /* 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"); - return 1; - } - - server.wl_display = wl_display_create(); - if(!server.wl_display) { - wlr_log(WLR_ERROR, "Cannot allocate a Wayland display"); - return 1; - } - - server.running = true; - - server.modes = malloc(4 * sizeof(char *)); - server.modes[0] = strdup("top"); - server.modes[1] = strdup("root"); - server.modes[2] = strdup("resize"); - server.modes[3] = NULL; - - server.nws = 1; - server.message_timeout = 2; - - event_loop = wl_display_get_event_loop(server.wl_display); - server.event_loop = event_loop; - - backend = wlr_backend_autocreate(server.wl_display, NULL); - if(!backend) { - wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); - ret = 1; - goto end; - } - server.backend = backend; - - if(!drop_permissions()) { - ret = 1; - goto end; - } - - server.keybindings = keybinding_list_init(); - if(server.keybindings == NULL || server.keybindings->keybindings == NULL) { - wlr_log(WLR_ERROR, "Unable to allocate keybindings"); - ret = 1; - goto end; - } - - wl_list_init(&server.output_config); - - renderer = wlr_backend_get_renderer(backend); - wlr_renderer_init_wl_display(renderer, server.wl_display); - - server.bg_color = malloc(4 * sizeof(float)); - server.bg_color[0] = 0; - server.bg_color[1] = 0; - server.bg_color[2] = 0; - server.bg_color[3] = 1; - wl_list_init(&server.outputs); - - server.output_layout = wlr_output_layout_create(); - if(!server.output_layout) { - wlr_log(WLR_ERROR, "Unable to create output layout"); - ret = 1; - goto end; - } - - compositor = wlr_compositor_create(server.wl_display, renderer); - if(!compositor) { - wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); - ret = 1; - goto end; - } - - data_device_manager = wlr_data_device_manager_create(server.wl_display); - if(!data_device_manager) { - wlr_log(WLR_ERROR, "Unable to create the data device 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. */ - server.new_output.notify = handle_new_output; - wl_signal_add(&backend->events.new_output, &server.new_output); - - server.seat = seat_create(&server, backend); - if(!server.seat) { - wlr_log(WLR_ERROR, "Unable to create the seat"); - ret = 1; - goto end; - } - - server.idle = wlr_idle_create(server.wl_display); - if(!server.idle) { - wlr_log(WLR_ERROR, "Unable to create the idle tracker"); - ret = 1; - goto end; - } - - server.idle_inhibit_v1 = wlr_idle_inhibit_v1_create(server.wl_display); - if(!server.idle_inhibit_v1) { - wlr_log(WLR_ERROR, "Cannot create the idle inhibitor"); - ret = 1; - goto end; - } - server.new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1_new; - wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, - &server.new_idle_inhibitor_v1); - wl_list_init(&server.inhibitors); - - xdg_shell = wlr_xdg_shell_create(server.wl_display); - if(!xdg_shell) { - wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); - ret = 1; - goto end; - } - server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new; - wl_signal_add(&xdg_shell->events.new_surface, - &server.new_xdg_shell_surface); - - xdg_decoration_manager = - wlr_xdg_decoration_manager_v1_create(server.wl_display); - if(!xdg_decoration_manager) { - wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager"); - ret = 1; - goto end; - } - wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration, - &server.xdg_toplevel_decoration); - server.xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; - - server_decoration_manager = - wlr_server_decoration_manager_create(server.wl_display); - if(!server_decoration_manager) { - wlr_log(WLR_ERROR, "Unable to create the server decoration manager"); - ret = 1; - goto end; - } - wlr_server_decoration_manager_set_default_mode( - server_decoration_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - - export_dmabuf_manager = - wlr_export_dmabuf_manager_v1_create(server.wl_display); - if(!export_dmabuf_manager) { - wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager"); - ret = 1; - goto end; - } - - screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display); - if(!screencopy_manager) { - wlr_log(WLR_ERROR, "Unable to create the screencopy manager"); - ret = 1; - goto end; - } - - output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, - server.output_layout); - if(!output_manager) { - wlr_log(WLR_ERROR, "Unable to create the output manager"); - ret = 1; - goto end; - } - - gamma_control_manager = - wlr_gamma_control_manager_v1_create(server.wl_display); - if(!gamma_control_manager) { - wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); - ret = 1; - goto end; - } - -#if CG_HAS_XWAYLAND - xwayland = wlr_xwayland_create(server.wl_display, compositor, true); - if(!xwayland) { - wlr_log(WLR_ERROR, "Cannot create XWayland server"); - ret = 1; - goto end; - } - server.new_xwayland_surface.notify = handle_xwayland_surface_new; - wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); - - xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); - if(!xcursor_manager) { - wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); - ret = 1; - goto end; - } - - if(setenv("DISPLAY", xwayland->display_name, true) < 0) { - wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland.", - "Clients may not be able to connect"); - } else { - wlr_log(WLR_DEBUG, "XWayland is running on display %s", - xwayland->display_name); - } - - if(wlr_xcursor_manager_load(xcursor_manager, 1)) { - wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); - } - struct wlr_xcursor *xcursor = - wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); - if(xcursor) { - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4, - image->width, image->height, image->hotspot_x, - image->hotspot_y); - } -#endif - - const char *socket = wl_display_add_socket_auto(server.wl_display); - if(!socket) { - wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket"); - ret = 1; - goto end; - } - - if(!wlr_backend_start(backend)) { - wlr_log(WLR_ERROR, "Unable to start the wlroots backend"); - ret = 1; - goto end; - } - - if(setenv("WAYLAND_DISPLAY", socket, true) < 0) { - wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.", - "Clients may not be able to connect"); - } else { - wlr_log(WLR_DEBUG, - "Cagebreak " CG_VERSION " is running on Wayland display %s", - socket); - } - -#if CG_HAS_XWAYLAND - wlr_xwayland_set_seat(xwayland, server.seat->seat); -#endif - - /* Place the cursor to the topl left of the output layout. */ - wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); - atexit(cleanup); - return 0; -end: - cleanup(); - return ret; + return -1; } /* Parse config file. Lines longer than "max_line_size" are ignored */ @@ -407,6 +59,10 @@ set_configuration(struct cg_server *server, char *content) { line[strcspn(line, "\n")] = '\0'; if(*line != '\0' && *line != '#') { char *errstr; + server->running=true; + if(fuzz_cmds(server, line) == 0) { + continue; + } if(parse_rc_line(server, line, &errstr) != 0) { if(errstr != NULL) { free(errstr); @@ -463,6 +119,25 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { free(output_config->output_name); free(output_config); } + struct cg_keyboard_group *group, *group_tmp; + wl_list_for_each_safe(group, group_tmp, &server.seat->keyboard_groups, link) { + wl_list_remove(&group->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, &server.seat->pointers, link) { + pointer->destroy.notify(&pointer->destroy, NULL); + } + struct cg_touch *touch, *touch_tmp; + wl_list_for_each_safe(touch, touch_tmp, &server.seat->touch, link) { + touch->destroy.notify(&touch->destroy, NULL); + } + + while(wl_list_length(&server.outputs) != 1) { + server.curr_output->damage_destroy.notify(&server.curr_output->damage_destroy,NULL); + } return 0; } diff --git a/fuzz/meson.build b/fuzz/meson.build index 8ff982a..b5ba1be 100644 --- a/fuzz/meson.build +++ b/fuzz/meson.build @@ -1,9 +1,11 @@ fuzz_sources = [ 'fuzz-parse.c', + 'fuzz-lib.c', ] fuzz_headers = [ '../parse.h', + 'fuzz-lib.h', ] inc = include_directories(['..','../build/']) From 9a8b6fa600c36635bec0493dbffccfeeee80bd89 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 29 May 2020 14:47:32 +0200 Subject: [PATCH 092/122] Fix fuzzer includes --- fuzz/fuzz-lib.c | 15 ++++++--------- fuzz/fuzz-parse.c | 3 +++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fuzz/fuzz-lib.c b/fuzz/fuzz-lib.c index aad54b3..e5fc2a3 100644 --- a/fuzz/fuzz-lib.c +++ b/fuzz/fuzz-lib.c @@ -8,12 +8,8 @@ #define _POSIX_C_SOURCE 200812L -#include "../keybinding.h" -#include "../output.h" -#include "../parse.h" -#include "../seat.h" -#include "../server.h" #include "config.h" + #include #include #include @@ -22,11 +18,7 @@ #include #include -#include -#include -#include #include -#include #include #include #include @@ -53,6 +45,11 @@ #include #endif +#include "../keybinding.h" +#include "../output.h" +#include "../parse.h" +#include "../seat.h" +#include "../server.h" #include "../idle_inhibit_v1.h" #include "../xdg_shell.h" #if CG_HAS_XWAYLAND diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 09ce0c0..5dcf837 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -9,10 +9,12 @@ #define _POSIX_C_SOURCE 200812L #include +#include #include #include #include +#include #include "config.h" #include "../keybinding.h" @@ -22,6 +24,7 @@ #include "../seat.h" #include "../server.h" #include "../workspace.h" +#include "../view.h" #if CG_HAS_XWAYLAND #include "../xwayland.h" #endif From c84e2c994e8b124ac5e020ae2ade643513ce49d3 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 29 May 2020 14:57:33 +0200 Subject: [PATCH 093/122] Remove erroneous comment --- fuzz/fuzz-parse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 5dcf837..d3870a1 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -53,7 +53,6 @@ fuzz_cmds(struct cg_server *server, char *line) { return -1; } -/* Parse config file. Lines longer than "max_line_size" are ignored */ int set_configuration(struct cg_server *server, char *content) { char *line; From 29da70746303a086b9fae3096e2e3e9d44d5d20b Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 29 May 2020 15:10:30 +0200 Subject: [PATCH 094/122] Fix error in fuzz-lib --- fuzz/fuzz-lib.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fuzz/fuzz-lib.c b/fuzz/fuzz-lib.c index e5fc2a3..b5376e5 100644 --- a/fuzz/fuzz-lib.c +++ b/fuzz/fuzz-lib.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -317,12 +318,6 @@ LLVMFuzzerInitialize(int *argc, char ***argv) { goto end; } - if(!compositor) { - wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); - ret = 1; - goto end; - } - compositor = wlr_compositor_create(server.wl_display, renderer); if(!compositor) { wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); From 4de82c076fde42094ab6c5752bd555d86f62ef77 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 29 May 2020 15:10:45 +0200 Subject: [PATCH 095/122] Remove input device creation from fuzz-parse.c --- fuzz/fuzz-parse.c | 56 ----------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index d3870a1..1403eda 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -31,28 +31,6 @@ #include "fuzz-lib.h" -int -fuzz_cmds(struct cg_server *server, char *line) { - if(strncmp(line, "mcurs",5) == 0) { - move_cursor(&line[5], server); - return 0; - } else if(strncmp(line, "noutp",5) == 0) { - create_output(&line[5], server); - return 0; - } else if(strncmp(line, "doutp",5) == 0) { - destroy_output(&line[5], server); - return 0; - } else if(strncmp(line, "crdev",5) == 0) { - return -1; - create_input_device(&line[5], server); - return 0; - } else if(strncmp(line, "ddev",5) == 0) { - destroy_input_device(&line[5], server); - return 0; - } - return -1; -} - int set_configuration(struct cg_server *server, char *content) { char *line; @@ -62,9 +40,6 @@ set_configuration(struct cg_server *server, char *content) { if(*line != '\0' && *line != '#') { char *errstr; server->running=true; - if(fuzz_cmds(server, line) == 0) { - continue; - } if(parse_rc_line(server, line, &errstr) != 0) { if(errstr != NULL) { free(errstr); @@ -93,20 +68,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { (union keybinding_params){.i = 1}); run_action(KEYBINDING_LAYOUT_FULLSCREEN, &server, (union keybinding_params){.c = NULL}); - wl_display_flush_clients(server.wl_display); - wl_display_destroy_clients(server.wl_display); struct cg_output *output; wl_list_for_each(output, &server.outputs, link) { message_clear(output); - struct cg_view *view; - wl_list_for_each(view, &(*output->workspaces)->views, link) { - view_unmap(view); - view_destroy(view); - } - wl_list_for_each(view, &(*output->workspaces)->unmanaged_views, link) { - view_unmap(view); - view_destroy(view); - } } for(unsigned int i = 3; server.modes[i] != NULL; ++i) { free(server.modes[i]); @@ -121,25 +85,5 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { free(output_config->output_name); free(output_config); } - struct cg_keyboard_group *group, *group_tmp; - wl_list_for_each_safe(group, group_tmp, &server.seat->keyboard_groups, link) { - wl_list_remove(&group->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, &server.seat->pointers, link) { - pointer->destroy.notify(&pointer->destroy, NULL); - } - struct cg_touch *touch, *touch_tmp; - wl_list_for_each_safe(touch, touch_tmp, &server.seat->touch, link) { - touch->destroy.notify(&touch->destroy, NULL); - } - - while(wl_list_length(&server.outputs) != 1) { - server.curr_output->damage_destroy.notify(&server.curr_output->damage_destroy,NULL); - } - return 0; } From 35a15670eaa512dd3ea64179d8e89df128d69db4 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 29 May 2020 16:13:52 +0200 Subject: [PATCH 096/122] Fix permission dropping --- cagebreak.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index f908117..0591591 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -88,13 +88,14 @@ sig_chld_handler(int signal) { static bool drop_permissions(void) { if(getuid() != geteuid() || getgid() != getegid()) { - if(setuid(getuid()) != 0 || setgid(getgid()) != 0) { + // Set gid before uid + if(setgid(getgid()) != 0 || setuid(getuid()) != 0) { wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); return false; } } - if(setuid(0) != -1) { + if(setgid(0) != -1 || setuid(0) != -1) { wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to " "restore it after setuid), refusing to start"); return false; From 82093b28436f11f9fc7f2fce5c1cc1933d97d34f Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Fri, 29 May 2020 17:36:38 +0200 Subject: [PATCH 097/122] Improve release documentation --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 19a1f02..eec991b 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,9 @@ git merge --squash development git tag -u keyid version HEAD git tag -v version git push --tags origin master +git checkout development +git merge master +git push --tags origin development ``` and a log message roughly describing the features added in the commit is @@ -119,6 +122,7 @@ In the past, our git history did not always reflect this scheme. Release checklist + * [ ] Check cage for possible code merges * [ ] Cursory testing * [ ] libfuzzer testing * [ ] ninja -C build clang-format @@ -140,8 +144,9 @@ Release checklist * [ ] Signature * [ ] Branching Strategy * [ ] git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version . + * [ ] Extract, build and verify reproducibility of archive * [ ] gpg --detach-sign -u keyid release_version.tar.gz - * [ ] upload build assets + * [ ] Upload archive and signature as build assets ### Signing Key From 95944340258883a91c0cfd1cacc927c859ba1821 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 17:14:57 +0200 Subject: [PATCH 098/122] Move fanalyzer section in README --- README.md | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index eec991b..7c5bb8d 100644 --- a/README.md +++ b/README.md @@ -61,33 +61,6 @@ Nonetheless, don't be intimidated by the (slightly lengthy) release checklist or part of this file. Do what you can, open an issue and we will collaborate toward a solution. -### GCC and -fanalyzer - -Cagebreak should compile with any reasonably new gcc or clang. Consider -a gcc version of at least [10.1](https://gcc.gnu.org/gcc-10/changes.html) if -you want to get the benefit of the brand-new -[-fanalyzer](https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html) -flag. However, this new flag sometimes produces false-postives and we -selectively disable warnings for affected code segments as described below. - -Meson is configured to set `CG_HAS_FANALYZE` if `-fanalyzer` is available. -Therefore, to maintain portability, false-positive fanalyzer warnings are to be -disabled using the following syntax: - -``` -#if CG_HAS_FANALYZE -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "WARNING OPTION" -#endif -``` -and after - -``` -#if CG_HAS_FANALYZE -#pragma GCC diagnostic pop -#endif -``` - ### Branching strategy All features are to be developed on feature branches, named after the feature. @@ -220,6 +193,33 @@ 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. +### GCC and -fanalyzer + +Cagebreak should compile with any reasonably new gcc or clang. Consider +a gcc version of at least [10.1](https://gcc.gnu.org/gcc-10/changes.html) if +you want to get the benefit of the brand-new +[-fanalyzer](https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html) +flag. However, this new flag sometimes produces false-postives and we +selectively disable warnings for affected code segments as described below. + +Meson is configured to set `CG_HAS_FANALYZE` if `-fanalyzer` is available. +Therefore, to maintain portability, false-positive fanalyzer warnings are to be +disabled using the following syntax: + +``` +#if CG_HAS_FANALYZE +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "WARNING OPTION" +#endif +``` +and after + +``` +#if CG_HAS_FANALYZE +#pragma GCC diagnostic pop +#endif +``` + ### Fuzzing Along with the project source code, a fuzzing framework based on `libfuzzer` is From bd43989987c1a62ebc58f6251c4dcb27eee6c4e6 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 17:55:13 +0200 Subject: [PATCH 099/122] Add more convenient link to man pages --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c5bb8d..a396293 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ will be implemented, open an issue or get in touch with the development team. This README is only relevant for development resources and instructions. For a description of Cagebreak and installation instructions for end-users, please see -the man page supplied in the `man/` directory and the [Wiki](https://github.com/project-repo/cagebreak/wiki/). +the man pages for [cagebreak](man/cagebreak.1.md) and cagebreak +[configuration](man/cagebreak-config.5.md) and the +[Wiki](https://github.com/project-repo/cagebreak/wiki/). Cagebreak is based on [Cage](https://github.com/Hjdskes/cage), a Wayland kiosk compositor. From 98e57c534139aa6841718c2ce492558c6f0c91a1 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 17:57:06 +0200 Subject: [PATCH 100/122] Clarify branching strategy and versioning --- README.md | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index a396293..bf30d62 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Nonetheless, don't be intimidated by the (slightly lengthy) release checklist or part of this file. Do what you can, open an issue and we will collaborate toward a solution. -### Branching strategy +### Branching Strategy and Versioning All features are to be developed on feature branches, named after the feature. @@ -73,25 +73,9 @@ are merged for final testing. Once `development` is ready for a release, meaning that the release checklist is fulfilled, it is merged into `master`, creating a new release, which is tagged and signed. -Merging into master is always done by +All releases are tagged according to [semantic versioning](https://semver.org) guidelines. -``` -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 -git checkout development -git merge master -git push --tags origin development -``` - -and a log message roughly describing the features added in the commit is -included. - -In the past, our git history did not always reflect this scheme. +In the past, our git history did not perfectly reflect this scheme. ### Releases From f14261d4554c3e72463d78c31c73cbb894ec8058 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 17:58:26 +0200 Subject: [PATCH 101/122] Move signing key section --- README.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index bf30d62..98b65ee 100644 --- a/README.md +++ b/README.md @@ -107,21 +107,6 @@ Release checklist * [ ] gpg --detach-sign -u keyid release_version.tar.gz * [ ] Upload archive and signature as build assets -### Signing Key - -All releases are signed by at least one of the following collection of -keys. - - * E79F6D9E113529F4B1FFE4D5C4F974D70CEC2C5B - * 4739D329C9187A1C2795C20A02ABFDEC3A40545F - -Should we at any point retire a key, we will only replace it with keys signed -by at least one of the above collection. - -Should we at any point have official mail addresses, their keys will be signed by -a valid key noted above. - -The full public keys can be found in `keys/` along with any revocation certificates. ### Reproducible Builds @@ -179,6 +164,22 @@ 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. +#### Signing Key + +All releases are signed by at least one of the following collection of +keys. + + * E79F6D9E113529F4B1FFE4D5C4F974D70CEC2C5B + * 4739D329C9187A1C2795C20A02ABFDEC3A40545F + +Should we at any point retire a key, we will only replace it with keys signed +by at least one of the above collection. + +Should we at any point have official mail addresses, their keys will be signed by +a valid key noted above. + +The full public keys can be found in `keys/` along with any revocation certificates. + ### GCC and -fanalyzer Cagebreak should compile with any reasonably new gcc or clang. Consider From 5374b3728e9ca9cd3a7566c819962583237464b2 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 17:59:46 +0200 Subject: [PATCH 102/122] Combine release checklist with branching strategy --- README.md | 67 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 98b65ee..ab177d9 100644 --- a/README.md +++ b/README.md @@ -79,34 +79,59 @@ In the past, our git history did not perfectly reflect this scheme. ### Releases -Release checklist +The release checklist has to be completely fullfilled in one run for a release to +occur. Once any failure occurs the entire checklist has to be completed again. + * [ ] `git checkout development` + * [ ] `git pull origin development` + * [ ] `git push origin development` * [ ] Check cage for possible code merges - * [ ] Cursory testing - * [ ] libfuzzer testing * [ ] ninja -C build clang-format + * [ ] Determine new version number according to [semantic versioning](https://semver.org) guidelines + * [ ] Relevant Documentation + * [ ] New features documented + * [ ] man pages + * [ ] man/cagebreak + * [ ] man/cagebreak-config + * [ ] wiki + * [ ] README.md Changelog + * [ ] Document fixed bugs in Bugs.md + * [ ] Testing + * [ ] Manual testing + * [ ] Libfuzzer testing * [ ] Version Number * [ ] meson.build * [ ] git tag * [ ] man pages - * [ ] Relevant Documentation - * [ ] New features documented - * [ ] man page - * [ ] wiki - * [ ] New configuration documented - * [ ] man page - * [ ] wiki - * [ ] Changelog in README - * [ ] Document fixed bugs in Bugs.md - * [ ] Update hashes of the binary - * [ ] Update signature of the binary - * [ ] Signature - * [ ] Branching Strategy - * [ ] git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version . - * [ ] Extract, build and verify reproducibility of archive - * [ ] gpg --detach-sign -u keyid release_version.tar.gz - * [ ] Upload archive and signature as build assets - + * [ ] `git add` relevant files + * [ ] `git commit` + * [ ] `git push origin development` + * [ ] Check reproducibility on multiple machines + * [ ] Document Reproducible Builds Artefacts + * [ ] Add hashes of the binary + * [ ] Rename cagebreak.sig to previous_signature.sig + * [ ] Add signature of the binary as cagebreak.sig + * [ ] Determine commit and tag message (Start with "Release version_number\n\n") + * [ ] `git checkout master` + * [ ] `git merge --squash development` + * [ ] `git commit` and insert message + * [ ] `git tag -u keyid version HEAD` and insert message + * [ ] `git tag -v version` and check signing key + * [ ] `git push --tags origin master` + * [ ] `git checkout development` + * [ ] `git merge master` + * [ ] `git push --tags origin development` + * [ ] `git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version .` + * [ ] Check archive + * [ ] tar -xvf release_version.tar.gz + * [ ] cd cagebreak + * [ ] meson build --buildtype=release + * [ ] ninja -C build + * [ ] gpg --verify ../signatures/cagebreak.sig build/cagebreak + * [ ] cd .. + * [ ] rm -rf cagebreak + * [ ] `gpg --detach-sign -u keyid release_version.tar.gz` + * [ ] Upload archive and signature as release assets ### Reproducible Builds From 78c5b30e81aebfc45771d2c1f5d0bb0c41cf657d Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 18:31:12 +0200 Subject: [PATCH 103/122] Add more detailed installation instructions --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ab177d9..eab64c5 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ provide a successor to ratpoison for Wayland users. However, this is no reimplementation of ratpoison. Should you like to know if a feature will be implemented, open an issue or get in touch with the development team. -This README is only relevant for development resources and instructions. For a -description of Cagebreak and installation instructions for end-users, please see +This README is only relevant for development resources and instructions. For +documentation of Cagebreak, please see the man pages for [cagebreak](man/cagebreak.1.md) and cagebreak [configuration](man/cagebreak-config.5.md) and the [Wiki](https://github.com/project-repo/cagebreak/wiki/). @@ -14,16 +14,23 @@ the man pages for [cagebreak](man/cagebreak.1.md) and cagebreak Cagebreak is based on [Cage](https://github.com/Hjdskes/cage), a Wayland kiosk compositor. -## Experimenting with Cagebreak +## Installation -Cagebreak is currently being developed under arch linux and uses the libraries -as they are obtained through pacman. However, cagebreak should also work on -other distributions given the proper library versions. +### Obtaining Source Code -You can build Cagebreak with the [meson](https://mesonbuild.com/) build system. It -requires wayland, wlroots and xkbcommon to be installed. Note that Cagebreak is -developed against the latest tag of wlroots, in order not to constantly chase -breaking changes as soon as they occur. +There are different ways to obtain cagebreak source: + + * git clone (for all releases) + * download release asset tarballs (starting at release 1.2.1) + +### Verifying Source Code + +There are corresponding methods of verifying you obtained the correct code: + + * our git history includes signed tags for releases + * release assets starting at release 1.2.1 contain a signature for the tarball + +### Building Cagebreak Simply execute the following steps to build Cagebreak: From a7c51888e1bcfc88ac6ea3c17733448a1f2fbd74 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 18:32:06 +0200 Subject: [PATCH 104/122] Add missing section --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index eab64c5..a1d5630 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,17 @@ within an existing X11 or Wayland session, it will open in a virtual output as a window in your existing session. If you run it in a TTY, it'll run with the KMS+DRM backend. For more configuration options, see the man pages. +## Experimenting with Cagebreak + +Cagebreak is currently being developed under arch linux and uses the libraries +as they are obtained through pacman. However, cagebreak should also work on +other distributions given the proper library versions. + +You can build Cagebreak with the [meson](https://mesonbuild.com/) build system. It +requires wayland, wlroots and xkbcommon to be installed. Note that Cagebreak is +developed against the latest tag of wlroots, in order not to constantly chase +breaking changes as soon as they occur. + ## Contributing to Cagebreak Cagebreak is currently developed to fit the needs of its creators. Should you desire From e40fcaf737d11e556a8b887fbce924f427358a17 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 31 May 2020 18:39:22 +0200 Subject: [PATCH 105/122] Dissolve README section --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a1d5630..76e5718 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ the man pages for [cagebreak](man/cagebreak.1.md) and cagebreak Cagebreak is based on [Cage](https://github.com/Hjdskes/cage), a Wayland kiosk compositor. +Cagebreak is currently being developed under arch linux and uses the libraries +as they are obtained through pacman. However, cagebreak should also work on +other distributions given the proper library versions. + ## Installation ### Obtaining Source Code @@ -32,6 +36,11 @@ There are corresponding methods of verifying you obtained the correct code: ### Building Cagebreak +You can build Cagebreak with the [meson](https://mesonbuild.com/) build system. It +requires wayland, wlroots and xkbcommon to be installed. Note that Cagebreak is +developed against the latest tag of wlroots, in order not to constantly chase +breaking changes as soon as they occur. + Simply execute the following steps to build Cagebreak: ``` @@ -59,17 +68,6 @@ within an existing X11 or Wayland session, it will open in a virtual output as a window in your existing session. If you run it in a TTY, it'll run with the KMS+DRM backend. For more configuration options, see the man pages. -## Experimenting with Cagebreak - -Cagebreak is currently being developed under arch linux and uses the libraries -as they are obtained through pacman. However, cagebreak should also work on -other distributions given the proper library versions. - -You can build Cagebreak with the [meson](https://mesonbuild.com/) build system. It -requires wayland, wlroots and xkbcommon to be installed. Note that Cagebreak is -developed against the latest tag of wlroots, in order not to constantly chase -breaking changes as soon as they occur. - ## Contributing to Cagebreak Cagebreak is currently developed to fit the needs of its creators. Should you desire From cc0a97649b4409033a49500b07df31802f207c0b Mon Sep 17 00:00:00 2001 From: project-repo Date: Sun, 31 May 2020 21:20:59 +0200 Subject: [PATCH 106/122] Improve README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 76e5718..d31f066 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ the man pages for [cagebreak](man/cagebreak.1.md) and cagebreak Cagebreak is based on [Cage](https://github.com/Hjdskes/cage), a Wayland kiosk compositor. -Cagebreak is currently being developed under arch linux and uses the libraries +Cagebreak is currently being developed under Arch Linux and uses the libraries as they are obtained through pacman. However, cagebreak should also work on other distributions given the proper library versions. @@ -29,7 +29,7 @@ There are different ways to obtain cagebreak source: ### Verifying Source Code -There are corresponding methods of verifying you obtained the correct code: +There are corresponding methods of verifying that you obtained the correct code: * our git history includes signed tags for releases * release assets starting at release 1.2.1 contain a signature for the tarball @@ -95,8 +95,8 @@ In the past, our git history did not perfectly reflect this scheme. ### Releases -The release checklist has to be completely fullfilled in one run for a release to -occur. Once any failure occurs the entire checklist has to be completed again. +The release checklist must be completely fulfilled in one run for a release to +occur. Once any failure occurs the entire checklist must be completed from scratch. * [ ] `git checkout development` * [ ] `git pull origin development` @@ -154,7 +154,7 @@ occur. Once any failure occurs the entire checklist has to be completed again. 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 arch linux at the time of +adapt the versions to the packages available under Arch Linux at the time of release. There are reproducibility issues up to and including release `1.2.0`. See From 7bbf2f330aa0ffe85584f711ab66187e5c156b5b Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 1 Jun 2020 12:51:26 +0200 Subject: [PATCH 107/122] Improve section hierarchy --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d31f066..50d7ba9 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,12 @@ $ meson build $ ninja -C build ``` -### Release Build +#### Release Build By default, this builds a debug build. To build a release build, use `meson build --buildtype=release`. -### Xwayland Support +#### Xwayland Support Cagebreak comes with compile-time support for XWayland. To enable this, first make sure that your version of wlroots is compiled with this From a68462cb95eb7100e0713b000812f5736a82436d Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 1 Jun 2020 13:51:04 +0200 Subject: [PATCH 108/122] Add new keys with signatures --- README.md | 28 +++++- keys/cagebreak@project-repo.co.pub | 75 ++++++++++++++++ keys/cagebreak_signing_key_1.asc | 65 -------------- keys/cagebreak_signing_key_1@cagebreak.pub | 88 +++++++++++++++++++ ... => cagebreak_signing_key_2@cagebreak.pub} | 0 ...agebreak_signing_key_3@project-repo.co.pub | 76 ++++++++++++++++ ...agebreak_signing_key_4@project-repo.co.pub | 64 ++++++++++++++ 7 files changed, 328 insertions(+), 68 deletions(-) create mode 100644 keys/cagebreak@project-repo.co.pub delete mode 100644 keys/cagebreak_signing_key_1.asc create mode 100644 keys/cagebreak_signing_key_1@cagebreak.pub rename keys/{cagebreak_signing_key_2.asc => cagebreak_signing_key_2@cagebreak.pub} (100%) create mode 100644 keys/cagebreak_signing_key_3@project-repo.co.pub create mode 100644 keys/cagebreak_signing_key_4@project-repo.co.pub diff --git a/README.md b/README.md index 50d7ba9..9356ad2 100644 --- a/README.md +++ b/README.md @@ -205,19 +205,24 @@ 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. -#### Signing Key +#### Signing Keys All releases are signed by at least one of the following collection of keys. * E79F6D9E113529F4B1FFE4D5C4F974D70CEC2C5B * 4739D329C9187A1C2795C20A02ABFDEC3A40545F + * 7535AB89220A5C15A728B75F74104CC7DCA5D7A8 + * 827BC2320D535AEAD0540E6E2E66F65D99761A6F Should we at any point retire a key, we will only replace it with keys signed by at least one of the above collection. -Should we at any point have official mail addresses, their keys will be signed by -a valid key noted above. +We registered project-repo.co and added mail addresses after release `1.3.0`. +This allows for verified releases. + +We now have a mail address and its key is signed by signing keys. See Security +Bugs for details. The full public keys can be found in `keys/` along with any revocation certificates. @@ -283,6 +288,23 @@ issue](https://github.com/project-repo/cagebreak/issues/new) on Fixed bugs are to be assigned a number and summarized inside Bugs.md for future reference independent of github, in case this service is unavailable. +### Security Bugs + +Should you want to get in touch with the developers of cagebreak to report a +security vulnerability or a different issue confidentially, contact +`cagebreak @ project-repo . co`. + +We will try to respond to everything that is not obvious spam. + +Please encrypt your email with the appropriate [GPG key](keys/cagebreak@project-repo.co.pub). + + * B15B92642760E11FE002DE168708D42451A94AB5 + +Note that the key is signed by cagebreak signing keys. + +If you want us to answer by GPG-encrypted mail, please include your own +public key or provide the fingerprint and directions to obtain the key. + ## Changelog ### Release 1.0.0 diff --git a/keys/cagebreak@project-repo.co.pub b/keys/cagebreak@project-repo.co.pub new file mode 100644 index 0000000..2642c1e --- /dev/null +++ b/keys/cagebreak@project-repo.co.pub @@ -0,0 +1,75 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=QlUC +-----END PGP PUBLIC KEY BLOCK----- diff --git a/keys/cagebreak_signing_key_1.asc b/keys/cagebreak_signing_key_1.asc deleted file mode 100644 index 835d485..0000000 --- a/keys/cagebreak_signing_key_1.asc +++ /dev/null @@ -1,65 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -Rw== -=IZJF ------END PGP PUBLIC KEY BLOCK----- diff --git a/keys/cagebreak_signing_key_1@cagebreak.pub b/keys/cagebreak_signing_key_1@cagebreak.pub new file mode 100644 index 0000000..b6ff569 --- /dev/null +++ b/keys/cagebreak_signing_key_1@cagebreak.pub @@ -0,0 +1,88 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=Z3hL +-----END PGP PUBLIC KEY BLOCK----- diff --git a/keys/cagebreak_signing_key_2.asc b/keys/cagebreak_signing_key_2@cagebreak.pub similarity index 100% rename from keys/cagebreak_signing_key_2.asc rename to keys/cagebreak_signing_key_2@cagebreak.pub diff --git a/keys/cagebreak_signing_key_3@project-repo.co.pub b/keys/cagebreak_signing_key_3@project-repo.co.pub new file mode 100644 index 0000000..855c32f --- /dev/null +++ b/keys/cagebreak_signing_key_3@project-repo.co.pub @@ -0,0 +1,76 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +vOQMlRsEbbSw+T2OA2gGXUPK7yzF +=kqmE +-----END PGP PUBLIC KEY BLOCK----- diff --git a/keys/cagebreak_signing_key_4@project-repo.co.pub b/keys/cagebreak_signing_key_4@project-repo.co.pub new file mode 100644 index 0000000..50b92c4 --- /dev/null +++ b/keys/cagebreak_signing_key_4@project-repo.co.pub @@ -0,0 +1,64 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +/qf52E0= +=zGAB +-----END PGP PUBLIC KEY BLOCK----- From 46a9bf9e39c7860522bfa40645e050c5bd517136 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 1 Jun 2020 16:12:43 +0200 Subject: [PATCH 109/122] Improve README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9356ad2..ca79218 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ other distributions given the proper library versions. ## Installation +If you are using archlinux, just use the [PKGBUILD](https://aur.archlinux.org/cagebreak.git) from the aur. + +See [cagebreak-pkgbuild](https://github.com/project-repo/cagebreak-pkgbuild) for details. + ### Obtaining Source Code There are different ways to obtain cagebreak source: @@ -219,7 +223,6 @@ Should we at any point retire a key, we will only replace it with keys signed by at least one of the above collection. We registered project-repo.co and added mail addresses after release `1.3.0`. -This allows for verified releases. We now have a mail address and its key is signed by signing keys. See Security Bugs for details. From 65dfd151779262a2b9a06e636c0086da079ea936 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Mon, 1 Jun 2020 16:22:18 +0200 Subject: [PATCH 110/122] Fix README wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca79218..70f5a75 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ other distributions given the proper library versions. ## Installation -If you are using archlinux, just use the [PKGBUILD](https://aur.archlinux.org/cagebreak.git) from the aur. +If you are using archlinux, just clone the [PKGBUILD](https://aur.archlinux.org/cagebreak.git) from the aur. See [cagebreak-pkgbuild](https://github.com/project-repo/cagebreak-pkgbuild) for details. From d71230cdfeb003eb38cddfbf1f9dcbd39d3d787f Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Wed, 3 Jun 2020 15:27:38 +0200 Subject: [PATCH 111/122] Improve release checklist --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 70f5a75..e3eb415 100644 --- a/README.md +++ b/README.md @@ -105,17 +105,17 @@ occur. Once any failure occurs the entire checklist must be completed from scrat * [ ] `git checkout development` * [ ] `git pull origin development` * [ ] `git push origin development` - * [ ] Check cage for possible code merges - * [ ] ninja -C build clang-format - * [ ] Determine new version number according to [semantic versioning](https://semver.org) guidelines - * [ ] Relevant Documentation - * [ ] New features documented + * [ ] Cage has no reasonable code merges + * [ ] `ninja -C build clang-format` makes no changes + * [ ] New version number determined according to [semantic versioning](https://semver.org) guidelines + * [ ] Relevant Documentation completed + * [ ] New features * [ ] man pages * [ ] man/cagebreak * [ ] man/cagebreak-config * [ ] wiki - * [ ] README.md Changelog - * [ ] Document fixed bugs in Bugs.md + * [ ] README.md Changelog for major and minor releases but not patches + * [ ] Fixed bugs documented in Bugs.md * [ ] Testing * [ ] Manual testing * [ ] Libfuzzer testing @@ -126,12 +126,13 @@ occur. Once any failure occurs the entire checklist must be completed from scrat * [ ] `git add` relevant files * [ ] `git commit` * [ ] `git push origin development` - * [ ] Check reproducibility on multiple machines - * [ ] Document Reproducible Builds Artefacts - * [ ] Add hashes of the binary - * [ ] Rename cagebreak.sig to previous_signature.sig - * [ ] Add signature of the binary as cagebreak.sig - * [ ] Determine commit and tag message (Start with "Release version_number\n\n") + * [ ] meson.build reproducible build versions are current archlinux libraries and gcc + * [ ] Cagebreak is reproducible on multiple machines + * [ ] Documented reproducible build artefacts + * [ ] Hashes of the binary + * [ ] Renamed cagebreak.sig to previous_release_tag.sig + * [ ] Signature of the binary as cagebreak.sig with appropriate signing key + * [ ] Determined commit and tag message (Start with "Release version_number\n\n") * [ ] `git checkout master` * [ ] `git merge --squash development` * [ ] `git commit` and insert message @@ -142,7 +143,7 @@ occur. Once any failure occurs the entire checklist must be completed from scrat * [ ] `git merge master` * [ ] `git push --tags origin development` * [ ] `git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version .` - * [ ] Check archive + * [ ] Checked archive * [ ] tar -xvf release_version.tar.gz * [ ] cd cagebreak * [ ] meson build --buildtype=release From b08ec3692fbcc6386bfa1566a35a5eed5a7ced56 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Wed, 3 Jun 2020 15:28:33 +0200 Subject: [PATCH 112/122] Improve README wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3eb415..d348e25 100644 --- a/README.md +++ b/README.md @@ -306,7 +306,7 @@ Please encrypt your email with the appropriate [GPG key](keys/cagebreak@project- Note that the key is signed by cagebreak signing keys. -If you want us to answer by GPG-encrypted mail, please include your own +If you want us to respond via GPG-encrypted mail, please include your own public key or provide the fingerprint and directions to obtain the key. ## Changelog From 1661c449fb1e68654c626151b718f6866be7f142 Mon Sep 17 00:00:00 2001 From: project-repo Date: Wed, 3 Jun 2020 15:50:38 +0200 Subject: [PATCH 113/122] Fix rendering bugs --- render.c | 22 ++++++++++++++++++++++ view.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- view.h | 1 + xdg_shell.c | 24 +++++++++++++++++++++++- 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/render.c b/render.c index 43da1da..649f9bc 100644 --- a/render.c +++ b/render.c @@ -51,6 +51,7 @@ scissor_output(struct wlr_output *output, pixman_box32_t *rect) { struct render_data { pixman_region32_t *damage; + int tile_width, tile_height; }; static void @@ -101,6 +102,12 @@ render_surface_iterator(struct cg_output *output, struct wlr_surface *surface, wlr_matrix_project_box(matrix, box, transform, 0.0F, wlr_output->transform_matrix); + if(data->tile_width != 0) { + box->width = box->width > data->tile_width ? data->tile_width:box->width; + } + if(data->tile_height != 0) { + box->height = box->height > data->tile_height ? data->tile_height:box->height; + } render_texture(wlr_output, output_damage, texture, box, matrix); } @@ -109,6 +116,8 @@ render_drag_icons(struct cg_output *output, pixman_region32_t *damage, struct wl_list *drag_icons) { struct render_data data = { .damage = damage, + .tile_width = 0, + .tile_height = 0, }; output_drag_icons_for_each_surface(output, drag_icons, render_surface_iterator, &data); @@ -122,7 +131,18 @@ render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage) { struct render_data data = { .damage = damage, + .tile_width = 0, + .tile_height = 0, }; + //TODO: improve run time behaviour of view_get_tile + struct cg_tile *view_tile=view_get_tile(view); + if(view_tile != NULL) { + if(view_tile->tile.width != view->wlr_surface->current.width || view_tile->tile.height != view->wlr_surface->current.height) { + view_damage_whole(view); + } + data.tile_width=view_tile->tile.width; + data.tile_height=view_tile->tile.height; + } double ox, oy; ox = view->ox; @@ -147,6 +167,8 @@ render_view_popups(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage) { struct render_data data = { .damage = damage, + .tile_width = 0, + .tile_height = 0, }; output_view_for_each_popup(output, view, render_popup_iterator, &data); } diff --git a/view.c b/view.c index 0bc6dfc..1329e57 100644 --- a/view.c +++ b/view.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "output.h" #include "seat.h" @@ -44,10 +45,15 @@ view_get_prev_view(struct cg_view *view) { return prev; } +void +view_damage_child(struct cg_view_child *child, int x, int y,bool whole); + static void view_child_handle_commit(struct wl_listener *listener, void *_data) { struct cg_view_child *child = wl_container_of(listener, child, commit); - view_damage_part(child->view); + int x,y; + child->get_coords(child, &x, &y); + view_damage_child(child,child->view->ox+x,child->view->oy+y,false); } static void @@ -67,7 +73,9 @@ view_child_finish(struct cg_view_child *child) { return; } - view_damage_whole(child->view); + int x,y; + child->get_coords(child, &x, &y); + view_damage_child(child,child->view->ox+x,child->view->oy+y,true); wl_list_remove(&child->link); wl_list_remove(&child->commit.link); @@ -108,6 +116,28 @@ subsurface_handle_destroy(struct wl_listener *listener, void *_data) { subsurface_destroy(view_child); } +static void +subsurface_get_coords(struct cg_view_child *child, int *x, int *y) { + + struct wlr_surface *surface = child->wlr_surface; + *x = 0; + *y = 0; + + if(!(child->view && child->view->impl)) { + while (surface && wlr_surface_is_subsurface(surface)) { + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(surface); + if (subsurface == NULL) { + break; + } + *x += subsurface->current.x; + *y += subsurface->current.y; + surface = subsurface->parent; + } + } + +} + static void subsurface_create(struct cg_view *view, struct wlr_subsurface *wlr_subsurface) { struct cg_subsurface *subsurface = calloc(1, sizeof(struct cg_subsurface)); @@ -117,6 +147,7 @@ subsurface_create(struct cg_view *view, struct wlr_subsurface *wlr_subsurface) { view_child_init(&subsurface->view_child, view, wlr_subsurface->surface); subsurface->view_child.destroy = subsurface_destroy; + subsurface->view_child.get_coords = subsurface_get_coords; subsurface->wlr_subsurface = wlr_subsurface; subsurface->destroy.notify = subsurface_handle_destroy; @@ -170,10 +201,20 @@ view_is_visible(const struct cg_view *view) { void view_damage(struct cg_view *view, bool whole) { + struct cg_tile *view_tile = view_get_tile(view); + if(view_tile != NULL&&(view->wlr_surface->current.width != view_tile->tile.width || view->wlr_surface->current.height != view_tile->tile.height)) { + view_maximize(view, &view_tile->tile); + } output_damage_surface(view->workspace->output, view->wlr_surface, view->ox, view->oy, whole); } +void +view_damage_child(struct cg_view_child *child, int x, int y,bool whole) { + output_damage_surface(child->view->workspace->output, child->wlr_surface, x, + y, whole); +} + void view_damage_part(struct cg_view *view) { view_damage(view, false); diff --git a/view.h b/view.h index 150e79b..8b405da 100644 --- a/view.h +++ b/view.h @@ -59,6 +59,7 @@ struct cg_view_child { struct wl_listener new_subsurface; void (*destroy)(struct cg_view_child *child); + void (*get_coords)(struct cg_view_child *child, int *x, int *y); }; struct cg_subsurface { diff --git a/xdg_shell.c b/xdg_shell.c index fd9ef3d..ce6d93b 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -7,6 +7,8 @@ * See the LICENSE file accompanying this file. */ +#define _POSIX_C_SOURCE 200809L + #include #include #include @@ -15,6 +17,7 @@ #include #include #include +#include #include "output.h" #include "server.h" @@ -117,6 +120,23 @@ popup_unconstrain(struct cg_xdg_popup *popup) { wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box); } +static void xdg_popup_get_coords(struct cg_view_child *child, int *x, int *y) { + if(!child) { + return; + } + struct cg_xdg_popup *popup = (struct cg_xdg_popup *)child; + struct wlr_xdg_surface *surface = popup->wlr_popup->base; + + int x_offset = -surface->geometry.x; + int y_offset = -surface->geometry.y; + + wlr_xdg_popup_get_toplevel_coords(surface->popup, + x_offset + surface->popup->geometry.x, + y_offset + surface->popup->geometry.y, + x, y); + +} + static void xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup) { struct cg_xdg_popup *popup = calloc(1, sizeof(struct cg_xdg_popup)); @@ -125,6 +145,7 @@ xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup) { } popup->wlr_popup = wlr_popup; + popup->view_child.get_coords = xdg_popup_get_coords; view_child_init(&popup->view_child, view, wlr_popup->base->surface); popup->view_child.destroy = xdg_popup_destroy; popup->destroy.notify = handle_xdg_popup_destroy; @@ -195,7 +216,8 @@ static void maximize(struct cg_view *view, int width, int height) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_surface, width, height); - wlr_xdg_toplevel_set_maximized(xdg_shell_view->xdg_surface, true); + enum wlr_edges edges = WLR_EDGE_LEFT|WLR_EDGE_RIGHT|WLR_EDGE_TOP|WLR_EDGE_BOTTOM; + wlr_xdg_toplevel_set_tiled(xdg_shell_view->xdg_surface, edges); } static void From 50c1268f5ebf97df7172e70a304928974e0823ae Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Wed, 3 Jun 2020 16:20:02 +0200 Subject: [PATCH 114/122] Apply clang-format --- fuzz/fuzz-lib.c | 112 +++++++++++++++++++++++++--------------------- fuzz/fuzz-lib.h | 21 ++++++--- fuzz/fuzz-parse.c | 12 +++-- render.c | 29 ++++++------ view.c | 33 +++++++------- xdg_shell.c | 16 +++---- 6 files changed, 120 insertions(+), 103 deletions(-) diff --git a/fuzz/fuzz-lib.c b/fuzz/fuzz-lib.c index b5376e5..e99a21f 100644 --- a/fuzz/fuzz-lib.c +++ b/fuzz/fuzz-lib.c @@ -20,21 +20,21 @@ #include #include -#include -#include +#include +#include #include +#include #include #include #include #include #include #include +#include #include #include #include #include -#include -#include #if CG_HAS_XWAYLAND #include #endif @@ -46,12 +46,12 @@ #include #endif +#include "../idle_inhibit_v1.h" #include "../keybinding.h" #include "../output.h" #include "../parse.h" #include "../seat.h" #include "../server.h" -#include "../idle_inhibit_v1.h" #include "../xdg_shell.h" #if CG_HAS_XWAYLAND #include "../xwayland.h" @@ -172,17 +172,18 @@ LLVMFuzzerInitialize(int *argc, char ***argv) { } server.backend = backend; - struct wlr_backend *headless_backend=wlr_headless_backend_create(server.wl_display, NULL); + struct wlr_backend *headless_backend = + wlr_headless_backend_create(server.wl_display, NULL); if(!headless_backend) { wlr_log(WLR_ERROR, "Unable to create the wlroots headless backend"); ret = 1; goto end; } - wlr_headless_add_output(headless_backend,600,300); - + wlr_headless_add_output(headless_backend, 600, 300); if(!wlr_multi_backend_add(backend, headless_backend)) { - wlr_log(WLR_ERROR, "Unable to insert headless backend into multi backend"); + wlr_log(WLR_ERROR, + "Unable to insert headless backend into multi backend"); ret = 1; goto end; }; @@ -389,7 +390,7 @@ LLVMFuzzerInitialize(int *argc, char ***argv) { /* Place the cursor to the topl left of the output layout. */ wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); atexit(cleanup); - //server.wl_display->run = 1; + // server.wl_display->run = 1; return 0; end: cleanup(); @@ -398,57 +399,59 @@ end: void move_cursor(char *line, struct cg_server *server) { - return;//TODO - long del=0; + return; // TODO + long del = 0; char *delstr = strtok_r(NULL, ";", &line); - enum wlr_axis_orientation orientation = (*(line++)=='0')? WLR_AXIS_ORIENTATION_VERTICAL:WLR_AXIS_ORIENTATION_HORIZONTAL; + enum wlr_axis_orientation orientation = + (*(line++) == '0') ? WLR_AXIS_ORIENTATION_VERTICAL + : WLR_AXIS_ORIENTATION_HORIZONTAL; if(delstr == NULL) { return; } - del=strtol(delstr,NULL,10); - struct wlr_event_pointer_axis event = { - .device = NULL, - .time_msec = 0, - .source = WLR_AXIS_SOURCE_WHEEL, - .orientation = orientation, - .delta = del * 15, - .delta_discrete = del - }; - //TODO dispatch_cursor_axis(server->seat->cursor, &event); + del = strtol(delstr, NULL, 10); + struct wlr_event_pointer_axis event = {.device = NULL, + .time_msec = 0, + .source = WLR_AXIS_SOURCE_WHEEL, + .orientation = orientation, + .delta = del * 15, + .delta_discrete = del}; + // TODO dispatch_cursor_axis(server->seat->cursor, &event); } -void add_output_callback(struct wlr_backend *backend, void *data) { - long *dims=data; +void +add_output_callback(struct wlr_backend *backend, void *data) { + long *dims = data; wlr_headless_add_output(backend, dims[0], dims[1]); } void create_output(char *line, struct cg_server *server) { char *widthstr = strtok_r(NULL, ";", &line); - long dims[2]= {600, 200}; + long dims[2] = {600, 200}; if(widthstr != NULL) { - dims[0]=strtol(widthstr,NULL,10); + dims[0] = strtol(widthstr, NULL, 10); if(line[0] != '\0') { ++line; } } char *heightstr = strtok_r(NULL, ";", &line); if(heightstr != NULL) { - dims[1]=strtol(heightstr,NULL,10); + dims[1] = strtol(heightstr, NULL, 10); } long max_dim = 10000; - if (dims[0] > max_dim || dims[0] <= 0 ) { + if(dims[0] > max_dim || dims[0] <= 0) { wlr_log(WLR_ERROR, "height out of range."); return; - } else if (dims[1] > max_dim || dims[1] <= 0) { + } else if(dims[1] > max_dim || dims[1] <= 0) { wlr_log(WLR_ERROR, "width out of range."); return; } wlr_multi_for_each_backend(server->backend, add_output_callback, dims); } -void add_input_device_callback(struct wlr_backend *backend, void *data) { - enum wlr_input_device_type *type=data; +void +add_input_device_callback(struct wlr_backend *backend, void *data) { + enum wlr_input_device_type *type = data; wlr_headless_add_input_device(backend, *type); } @@ -456,33 +459,37 @@ void create_input_device(char *line, struct cg_server *server) { enum wlr_input_device_type type; if(*line != '\0') { - if(strncmp(line,"kbd",3) == 0) { + if(strncmp(line, "kbd", 3) == 0) { type = WLR_INPUT_DEVICE_KEYBOARD; - wlr_multi_for_each_backend(server->backend, add_input_device_callback, &type); - } else if(strncmp(line,"ptr",3) == 0) { + wlr_multi_for_each_backend(server->backend, + add_input_device_callback, &type); + } else if(strncmp(line, "ptr", 3) == 0) { type = WLR_INPUT_DEVICE_POINTER; - wlr_multi_for_each_backend(server->backend, add_input_device_callback, &type); - } else if(strncmp(line,"tch",3) == 0) { + wlr_multi_for_each_backend(server->backend, + add_input_device_callback, &type); + } else if(strncmp(line, "tch", 3) == 0) { type = WLR_INPUT_DEVICE_TOUCH; - wlr_multi_for_each_backend(server->backend, add_input_device_callback, &type); + wlr_multi_for_each_backend(server->backend, + add_input_device_callback, &type); } } } void destroy_input_device(char *line, struct cg_server *server) { - long devn=0; + long devn = 0; if(line[0] != '\0') { - devn = strtol(line+1,NULL,10); + devn = strtol(line + 1, NULL, 10); } if(line != NULL) { - if(strncmp(line,"k",1) == 0) { + if(strncmp(line, "k", 1) == 0) { if(wl_list_empty(&server->seat->keyboard_groups)) { return; } devn = devn % wl_list_length(&server->seat->keyboard_groups); struct cg_keyboard_group *group, *group_tmp; - wl_list_for_each_safe(group, group_tmp, &server->seat->keyboard_groups, link) { + wl_list_for_each_safe(group, group_tmp, + &server->seat->keyboard_groups, link) { if(devn == 0) { wl_list_remove(&group->link); wlr_keyboard_group_destroy(group->wlr_group); @@ -492,55 +499,56 @@ destroy_input_device(char *line, struct cg_server *server) { } --devn; } - } else if(strncmp(line,"p",1) == 0) { + } else if(strncmp(line, "p", 1) == 0) { if(wl_list_empty(&server->seat->pointers)) { 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) { + wl_list_for_each_safe(pointer, pointer_tmp, &server->seat->pointers, + link) { if(devn == 0) { pointer->destroy.notify(&pointer->destroy, NULL); break; } --devn; } - } else if(strncmp(line,"t",1) == 0) { + } 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) { + wl_list_for_each_safe(touch, touch_tmp, &server->seat->touch, + link) { if(devn == 0) { touch->destroy.notify(&touch->destroy, NULL); break; } --devn; } - } } } void destroy_output(char *line, struct cg_server *server) { - if(wl_list_length(&server->outputs)<2) { + if(wl_list_length(&server->outputs) < 2) { return; } char *outpnstr = strtok_r(NULL, ";", &line); long outpn = 0; if(outpnstr != NULL) { - outpn=strtol(outpnstr,NULL,10); + outpn = strtol(outpnstr, NULL, 10); } - outpn=outpn%wl_list_length(&server->outputs); + outpn = outpn % wl_list_length(&server->outputs); struct cg_output *it; - wl_list_for_each(it,&server->outputs,link) { + wl_list_for_each(it, &server->outputs, link) { if(outpn == 0) { break; } else { --outpn; } } - it->damage_destroy.notify(&it->damage_destroy,NULL); + it->damage_destroy.notify(&it->damage_destroy, NULL); } diff --git a/fuzz/fuzz-lib.h b/fuzz/fuzz-lib.h index 95007b3..0ea499b 100644 --- a/fuzz/fuzz-lib.h +++ b/fuzz/fuzz-lib.h @@ -25,18 +25,25 @@ struct wlr_xwayland *xwayland; struct wlr_xcursor_manager *xcursor_manager; #endif -void cleanup(); +void +cleanup(); -int LLVMFuzzerInitialize(int *argc, char ***argv); +int +LLVMFuzzerInitialize(int *argc, char ***argv); -void move_cursor(char *line, struct cg_server *server); +void +move_cursor(char *line, struct cg_server *server); -void create_output(char *line, struct cg_server *server); +void +create_output(char *line, struct cg_server *server); -void create_input_device(char *line, struct cg_server *server); +void +create_input_device(char *line, struct cg_server *server); -void destroy_input_device(char *line, struct cg_server *server); +void +destroy_input_device(char *line, struct cg_server *server); -void destroy_output(char *line, struct cg_server *server); +void +destroy_output(char *line, struct cg_server *server); #endif diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 1403eda..8aded78 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -11,20 +11,20 @@ #include #include +#include #include #include #include -#include -#include "config.h" #include "../keybinding.h" #include "../message.h" #include "../output.h" #include "../parse.h" #include "../seat.h" #include "../server.h" -#include "../workspace.h" #include "../view.h" +#include "../workspace.h" +#include "config.h" #if CG_HAS_XWAYLAND #include "../xwayland.h" #endif @@ -39,7 +39,7 @@ set_configuration(struct cg_server *server, char *content) { line[strcspn(line, "\n")] = '\0'; if(*line != '\0' && *line != '#') { char *errstr; - server->running=true; + server->running = true; if(parse_rc_line(server, line, &errstr) != 0) { if(errstr != NULL) { free(errstr); @@ -69,9 +69,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { run_action(KEYBINDING_LAYOUT_FULLSCREEN, &server, (union keybinding_params){.c = NULL}); struct cg_output *output; - wl_list_for_each(output, &server.outputs, link) { - message_clear(output); - } + wl_list_for_each(output, &server.outputs, link) { message_clear(output); } for(unsigned int i = 3; server.modes[i] != NULL; ++i) { free(server.modes[i]); } diff --git a/render.c b/render.c index 649f9bc..e1ca1c1 100644 --- a/render.c +++ b/render.c @@ -103,10 +103,12 @@ render_surface_iterator(struct cg_output *output, struct wlr_surface *surface, wlr_output->transform_matrix); if(data->tile_width != 0) { - box->width = box->width > data->tile_width ? data->tile_width:box->width; + box->width = + box->width > data->tile_width ? data->tile_width : box->width; } if(data->tile_height != 0) { - box->height = box->height > data->tile_height ? data->tile_height:box->height; + box->height = + box->height > data->tile_height ? data->tile_height : box->height; } render_texture(wlr_output, output_damage, texture, box, matrix); } @@ -116,8 +118,8 @@ render_drag_icons(struct cg_output *output, pixman_region32_t *damage, struct wl_list *drag_icons) { struct render_data data = { .damage = damage, - .tile_width = 0, - .tile_height = 0, + .tile_width = 0, + .tile_height = 0, }; output_drag_icons_for_each_surface(output, drag_icons, render_surface_iterator, &data); @@ -131,17 +133,18 @@ render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage) { struct render_data data = { .damage = damage, - .tile_width = 0, - .tile_height = 0, + .tile_width = 0, + .tile_height = 0, }; - //TODO: improve run time behaviour of view_get_tile - struct cg_tile *view_tile=view_get_tile(view); + // TODO: improve run time behaviour of view_get_tile + struct cg_tile *view_tile = view_get_tile(view); if(view_tile != NULL) { - if(view_tile->tile.width != view->wlr_surface->current.width || view_tile->tile.height != view->wlr_surface->current.height) { + if(view_tile->tile.width != view->wlr_surface->current.width || + view_tile->tile.height != view->wlr_surface->current.height) { view_damage_whole(view); } - data.tile_width=view_tile->tile.width; - data.tile_height=view_tile->tile.height; + data.tile_width = view_tile->tile.width; + data.tile_height = view_tile->tile.height; } double ox, oy; @@ -167,8 +170,8 @@ render_view_popups(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage) { struct render_data data = { .damage = damage, - .tile_width = 0, - .tile_height = 0, + .tile_width = 0, + .tile_height = 0, }; output_view_for_each_popup(output, view, render_popup_iterator, &data); } diff --git a/view.c b/view.c index 1329e57..142ac36 100644 --- a/view.c +++ b/view.c @@ -14,11 +14,11 @@ #include #include #include +#include #include #include #include #include -#include #include "output.h" #include "seat.h" @@ -46,14 +46,14 @@ view_get_prev_view(struct cg_view *view) { } void -view_damage_child(struct cg_view_child *child, int x, int y,bool whole); +view_damage_child(struct cg_view_child *child, int x, int y, bool whole); static void view_child_handle_commit(struct wl_listener *listener, void *_data) { struct cg_view_child *child = wl_container_of(listener, child, commit); - int x,y; + int x, y; child->get_coords(child, &x, &y); - view_damage_child(child,child->view->ox+x,child->view->oy+y,false); + view_damage_child(child, child->view->ox + x, child->view->oy + y, false); } static void @@ -73,9 +73,9 @@ view_child_finish(struct cg_view_child *child) { return; } - int x,y; + int x, y; child->get_coords(child, &x, &y); - view_damage_child(child,child->view->ox+x,child->view->oy+y,true); + view_damage_child(child, child->view->ox + x, child->view->oy + y, true); wl_list_remove(&child->link); wl_list_remove(&child->commit.link); @@ -124,10 +124,10 @@ subsurface_get_coords(struct cg_view_child *child, int *x, int *y) { *y = 0; if(!(child->view && child->view->impl)) { - while (surface && wlr_surface_is_subsurface(surface)) { + while(surface && wlr_surface_is_subsurface(surface)) { struct wlr_subsurface *subsurface = - wlr_subsurface_from_wlr_surface(surface); - if (subsurface == NULL) { + wlr_subsurface_from_wlr_surface(surface); + if(subsurface == NULL) { break; } *x += subsurface->current.x; @@ -135,7 +135,6 @@ subsurface_get_coords(struct cg_view_child *child, int *x, int *y) { surface = subsurface->parent; } } - } static void @@ -202,7 +201,9 @@ view_is_visible(const struct cg_view *view) { void view_damage(struct cg_view *view, bool whole) { struct cg_tile *view_tile = view_get_tile(view); - if(view_tile != NULL&&(view->wlr_surface->current.width != view_tile->tile.width || view->wlr_surface->current.height != view_tile->tile.height)) { + if(view_tile != NULL && + (view->wlr_surface->current.width != view_tile->tile.width || + view->wlr_surface->current.height != view_tile->tile.height)) { view_maximize(view, &view_tile->tile); } output_damage_surface(view->workspace->output, view->wlr_surface, view->ox, @@ -210,7 +211,7 @@ view_damage(struct cg_view *view, bool whole) { } void -view_damage_child(struct cg_view_child *child, int x, int y,bool whole) { +view_damage_child(struct cg_view_child *child, int x, int y, bool whole) { output_damage_surface(child->view->workspace->output, child->wlr_surface, x, y, whole); } @@ -279,10 +280,10 @@ view_unmap(struct cg_view *view) { .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) { + 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; diff --git a/xdg_shell.c b/xdg_shell.c index ce6d93b..59b3334 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -16,8 +16,8 @@ #include #include #include -#include #include +#include #include "output.h" #include "server.h" @@ -120,7 +120,8 @@ popup_unconstrain(struct cg_xdg_popup *popup) { wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box); } -static void xdg_popup_get_coords(struct cg_view_child *child, int *x, int *y) { +static void +xdg_popup_get_coords(struct cg_view_child *child, int *x, int *y) { if(!child) { return; } @@ -130,11 +131,9 @@ static void xdg_popup_get_coords(struct cg_view_child *child, int *x, int *y) { int x_offset = -surface->geometry.x; int y_offset = -surface->geometry.y; - wlr_xdg_popup_get_toplevel_coords(surface->popup, - x_offset + surface->popup->geometry.x, - y_offset + surface->popup->geometry.y, - x, y); - + wlr_xdg_popup_get_toplevel_coords( + surface->popup, x_offset + surface->popup->geometry.x, + y_offset + surface->popup->geometry.y, x, y); } static void @@ -216,7 +215,8 @@ static void maximize(struct cg_view *view, int width, int height) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_surface, width, height); - enum wlr_edges edges = WLR_EDGE_LEFT|WLR_EDGE_RIGHT|WLR_EDGE_TOP|WLR_EDGE_BOTTOM; + enum wlr_edges edges = + WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM; wlr_xdg_toplevel_set_tiled(xdg_shell_view->xdg_surface, edges); } From 8c1c317d48442aae9262e028c174b34d77acc850 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Wed, 3 Jun 2020 16:21:05 +0200 Subject: [PATCH 115/122] Increment version number --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index de94fda..c6676ea 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.3.0', + version: '1.3.1', license: 'MIT', default_options: [ 'c_std=c11', From 8756f4eab35ee0b4a9009f125b2845c16a8b7020 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Wed, 3 Jun 2020 16:26:09 +0200 Subject: [PATCH 116/122] Add fixed bugs --- Bugs.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Bugs.md b/Bugs.md index f39de1c..dc238c4 100644 --- a/Bugs.md +++ b/Bugs.md @@ -97,3 +97,25 @@ difficult to reproduce. Our fuzzing framework up to and including release 1.2.0 does not limit line lengths. This can crash the fuzzing framework with a segfault due to running out of memory. + +### Issue 7 + + * github issue number: N/A + * Fixed: 1.3.1 + +Cagebreak up to and including release 1.3.0 does not ensure that windows +are resized correctly. The download save dialog in firefox +demonstrates this issue, as it may be rendered larger than the current +monitor. As of release 1.3.1 the size of every window is checked on +rendering and adjusted if necessary. + +### Issue 8 + + * github issue number: N/A + * Fixed: 1.3.1 + +Cagebreak up to and including release 1.3.0 does not force windows +to resize to the appropriate size. Calling `vsplit` on inkscape +demonstrates this issue, since it causes adjacent tiles to overlap +(contrary to the idea of a tiling compositor). + From fa10639ec077a9176e78646c723a3a4fb4485b93 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Wed, 3 Jun 2020 16:44:14 +0200 Subject: [PATCH 117/122] Increment man version numbers --- man/cagebreak-config.5.md | 2 +- man/cagebreak.1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index 96aff5f..4e8f542 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -1,4 +1,4 @@ -% CAGEBREAK-CONFIG(1) Version 1.3.0 | Cagebreak Manual +% CAGEBREAK-CONFIG(1) Version 1.3.1 | Cagebreak Manual # NAME diff --git a/man/cagebreak.1.md b/man/cagebreak.1.md index c72323f..6777cd7 100644 --- a/man/cagebreak.1.md +++ b/man/cagebreak.1.md @@ -1,4 +1,4 @@ -% CAGEBREAK(1) Version 1.3.0 | Cagebreak Manual +% CAGEBREAK(1) Version 1.3.1 | Cagebreak Manual # NAME From e98a5318ea81e4217dd732f9bc177d5fa639ccdf Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Wed, 3 Jun 2020 18:05:02 +0200 Subject: [PATCH 118/122] Update hashes and signature --- README.md | 5 +++++ signatures/1.3.0.sig | Bin 0 -> 566 bytes signatures/cagebreak.sig | Bin 566 -> 566 bytes 3 files changed, 5 insertions(+) create mode 100644 signatures/1.3.0.sig diff --git a/README.md b/README.md index d348e25..f4da22e 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,11 @@ ninja -C build For every release after 1.0.5, hashes will be provided. +1.3.1 + + * sha 256: 71be224cd99d20da4f039675ec5c48213dd14ef027b804501fa3241886b2b08b + * sha 512: d094b786e5a74b01699997a85747943e6de3544cc903dd1c5dba449c66bd925b6378de800d3734969dabf8a20c7004dc3402e3c59577db09ce107b68a1f7bd21 + 1.3.0 * sha 256: aecc5292f56f7250d777110cee1f11a92018a9eb2117d7d37cd51d7d3a5cbae0 diff --git a/signatures/1.3.0.sig b/signatures/1.3.0.sig new file mode 100644 index 0000000000000000000000000000000000000000..3c5c35930506e97301e9cae291cc396d25a231cf GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$$89-2e&+5XAX( z*9`0|TaZ-`|8B19v8nWt+`yQRe_>?zV9R$KNOZ;Ao6nXhbU1&)=v=`5F>DZu{#kbT z6{L}V-K$1hB}cOf3-I#7y8ey(rb(#xaKdnFJwit<~c5^ zy(6d3S7kaKru_arzzNe&FI^df3y^)W4(q7)ut|E4Yd@8gL#=G+%RJ4oYzqQo!Ca*| zYTG657GHJfgsvX1G-WMAdsBmmg5k{0syR#>)?ww$#5RZ1FXzP>NFzzhY!;7zpW1cH zDm(B;8$w2{r%`p^6~{ov5bGl#QYIU^Czo_T=Lv{28SD&bSUw`cD<{9<47AbN4&Bp$ zOMgn_N+2(SmX9}qeQEW8mHy2_5;89c&MZH`z=+Ur5kQk8G3q40f5Ks$Qz_s{x?ikf z8*{BZGRradK@((T({PDy_ROCp)ruC!{oqhVTpQ`xX|kCjE3+XlgG=J~)v{FNR}4FC zt12}>Gi^x`e%zrAdC=4$!aNrj0HVVw&dO13pbKTvHRI^88+Vvtd@{6I5z#EMncg+c zG^gK2^REW3ovSE;Qc01T(ybNn=b(_NwQn1X$z}>-Zi;OjKXZLyfD60pAnR?4bH@OG EH)i?|)&Kwi literal 0 HcmV?d00001 diff --git a/signatures/cagebreak.sig b/signatures/cagebreak.sig index 3c5c35930506e97301e9cae291cc396d25a231cf..288094e0abe6c0c0c5f8f02f02e4b23453297d07 100644 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j+6HLHmt3S1SZD7Rm95KPD1rPrth0$$h31po>O5Ofes z$K0jYsDzyl|7~X-L$LyQ?Cxv9MrwnDpN7!^p^iuQrsJ(88|V@D3~kLFc}6NeoA9e6 zXW#~a-j?!2tQX)>{Bqlf&!xMiXccM**s^axv7>-p%vdrlDOltSYBe1h5A@GSV#Zj9 zU7X|i|6c0ILEZsxlD@<|GOJfbV!~O^_AF1NJLz(Lj`O?&UNX9_&ZnC_Q3`f{XdT|G zkE*6#Py>LNs1v5|t2w>cIei|%8aP2j4v_-?#=R;LLTA99%}3&U;2{v! zS}{(`TdKe;h!3pno3keDIz@I;NPbSnVVKEPUXVA22pc=(`1kic*<=oR7h+9=1Qam( z(^f(rCukN0@FWpA(2Dg<;usl{;=qMIi=g}Vrz>|XBlUd}&dQ>JUQ>Jis|Y{%Sdp43 EWwj;=*Z=?k literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$$89-2e&+5XAX( z*9`0|TaZ-`|8B19v8nWt+`yQRe_>?zV9R$KNOZ;Ao6nXhbU1&)=v=`5F>DZu{#kbT z6{L}V-K$1hB}cOf3-I#7y8ey(rb(#xaKdnFJwit<~c5^ zy(6d3S7kaKru_arzzNe&FI^df3y^)W4(q7)ut|E4Yd@8gL#=G+%RJ4oYzqQo!Ca*| zYTG657GHJfgsvX1G-WMAdsBmmg5k{0syR#>)?ww$#5RZ1FXzP>NFzzhY!;7zpW1cH zDm(B;8$w2{r%`p^6~{ov5bGl#QYIU^Czo_T=Lv{28SD&bSUw`cD<{9<47AbN4&Bp$ zOMgn_N+2(SmX9}qeQEW8mHy2_5;89c&MZH`z=+Ur5kQk8G3q40f5Ks$Qz_s{x?ikf z8*{BZGRradK@((T({PDy_ROCp)ruC!{oqhVTpQ`xX|kCjE3+XlgG=J~)v{FNR}4FC zt12}>Gi^x`e%zrAdC=4$!aNrj0HVVw&dO13pbKTvHRI^88+Vvtd@{6I5z#EMncg+c zG^gK2^REW3ovSE;Qc01T(ybNn=b(_NwQn1X$z}>-Zi;OjKXZLyfD60pAnR?4bH@OG EH)i?|)&Kwi From aa80c2032231e68fce167be127b002ef25552064 Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 3 Date: Fri, 5 Jun 2020 17:03:29 +0200 Subject: [PATCH 119/122] Add doxygen config file draft --- doxygen_config | 2553 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2553 insertions(+) create mode 100644 doxygen_config diff --git a/doxygen_config b/doxygen_config new file mode 100644 index 0000000..c4d1525 --- /dev/null +++ b/doxygen_config @@ -0,0 +1,2553 @@ +# Doxyfile 1.8.18 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Cagebreak" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.3.1 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Tiling wayland compositor" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.doc \ + *.txt \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png The default and svg Looks nicer but requires the +# pdf2svg tool. +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /