From 6a3c8a3edfed0a0fa81ec8e41cd1a1384e674325 Mon Sep 17 00:00:00 2001 From: zvon Date: Sun, 7 Aug 2022 11:44:13 +0200 Subject: [PATCH] Make shifting behave like I want to --- river-shifttags.c | 338 ++++++++++++++++++++++++---------------------- 1 file changed, 174 insertions(+), 164 deletions(-) diff --git a/river-shifttags.c b/river-shifttags.c index 2d74e1d..2f6f08c 100644 --- a/river-shifttags.c +++ b/river-shifttags.c @@ -7,215 +7,225 @@ #include "river-status-unstable-v1.h" #include "river-control-unstable-v1.h" +const char usage[] = + "Usage: river-shiftview [OPTIONS]\n" + " --shift VALUE value by which to rotate selected tag.\n" + " --num-tags VALUE number of tags to rotate\n" + " --start VALUE First tag to rotate from.\n" + " --help print this message and exit.\n" + "\n" + "\n"; + +int _shift = 1; +int _num_tags = 9; +int _start_tag = 1; +size_t outputs_size = 0; + int ret = EXIT_SUCCESS; +struct output { + struct wl_output *output; + size_t index; +}; + struct wl_display *wl_display = NULL; -struct wl_output *wl_output = NULL; +struct output *wl_outputs = NULL; struct wl_seat *seat = NULL; struct zriver_status_manager_v1 *river_status_manager = NULL; struct zriver_control_v1 *river_controller = NULL; -struct zriver_output_status_v1 *river_output_status = NULL; +struct zriver_output_status_v1 **river_output_statuses = NULL; -int shifts = 1; -int num_tags = 9; -int start_tag = 0; +unsigned int *new_tags = NULL; +size_t focused_output = 0; -unsigned int new_tags = 0; - -const char usage[] = -"Usage: river-shiftview [OPTIONS]\n" -" --shifts VALUE value by which to rotate selected tag.\n" -" --num-tags VALUE number of tags to rotate\n" -" --start VALUE First tag to rotate from.\n" -" --help print this message and exit.\n" -"\n" -"\n"; - -void -rotate ( - unsigned int tagmask, - int rotations, - int start_tag, - int num_tags) -{ - - rotations %= num_tags; - - const unsigned int mask = ~(~(0U) << num_tags) << start_tag; - unsigned int to_rotate = (tagmask & mask) >> start_tag; - - if (rotations < 1) - { - rotations = -rotations; - new_tags = (mask - & ((to_rotate >> rotations) - | (to_rotate << (num_tags - rotations)) << start_tag)) - + (~mask & tagmask); +void rotate(unsigned int tagmask, size_t index, int shift, int start_tag, + int num_tags) { + // if multiple tags, chose the lowest one + int current_tag = 1; + while (!(tagmask & 1)) { + tagmask = tagmask >> 1; + current_tag += 1; } - else - { - new_tags = (mask - & ((to_rotate << rotations) - | (to_rotate >> (num_tags - rotations)) << start_tag)) - + (~mask & tagmask); + + int new_tag = current_tag + shift; + while (new_tag > num_tags) { + new_tag = start_tag + (new_tag - num_tags) - + 1; // -1 because new_tag - num_tags is always at least 1 and + // if we overflow, we want to START at start_tag } + while (new_tag < start_tag) { + new_tag = num_tags + (new_tag - start_tag) + + 1; // +1 because num_tags is INCLUSIVE and new_tag - start_tag + // is always at least 1 + } + new_tags[index] = 1 << (new_tag - 1); +} + +static void print_tagmask(void *data, + struct zriver_output_status_v1 *output_status_v1, + unsigned int tagmask) { + rotate(tagmask, (size_t)data, _shift, _start_tag, _num_tags); } static void -print_tagmask ( - void *data, - struct zriver_output_status_v1 *output_status_v1, - unsigned int tagmask) -{ - rotate (tagmask, shifts, start_tag, num_tags); -} +river_status_handle_view_tags(void *data, + struct zriver_output_status_v1 *river_status, + struct wl_array *tags) {} -static void -river_status_handle_view_tags ( - void *data, - struct zriver_output_status_v1 *river_status, - struct wl_array *tags) -{ } +static void river_status_handle_urgent_tags( + void *data, struct zriver_output_status_v1 *river_status, uint32_t tags) {} -static void -river_status_handle_urgent_tags ( - void *data, - struct zriver_output_status_v1 *river_status, - uint32_t tags) -{ } - -static const struct zriver_output_status_v1_listener output_status_listener = { - .focused_tags = print_tagmask, - .view_tags = river_status_handle_view_tags, - .urgent_tags = river_status_handle_urgent_tags, +static const struct zriver_output_status_v1_listener tag_status_listener = { + .focused_tags = print_tagmask, + .view_tags = river_status_handle_view_tags, + .urgent_tags = river_status_handle_urgent_tags, }; -static void -global_registry_handler ( - void *data, - struct wl_registry *registry, - uint32_t id, - const char *interface, - uint32_t version) -{ - if (strcmp (interface, "wl_output") == 0) - { - wl_output = wl_registry_bind (registry, id, &wl_output_interface, 1); - } - else if ( strcmp( interface, "wl_seat" ) == 0 ) - { - seat = wl_registry_bind(registry, id, &wl_seat_interface, 3); - } - else if (strcmp (interface, zriver_status_manager_v1_interface.name) == 0) - { - river_status_manager = wl_registry_bind ( - registry, id, &zriver_status_manager_v1_interface, 2); - } - else if (strcmp (interface, zriver_control_v1_interface.name) == 0) - { - river_controller = wl_registry_bind( - registry, id, &zriver_control_v1_interface, 1); +void get_focused_output(void *data, + struct zriver_seat_status_v1 *zriver_seat_status_v1, + struct wl_output *output) { + for (size_t i = 0; i < outputs_size; i++) { + if (wl_outputs[i].output == output) { + focused_output = i; + } } } -static void -global_registry_remover ( - void *data, - struct wl_registry *registry, - uint32_t id) -{ } +void unfocused_output_empty(void *data, + struct zriver_seat_status_v1 *zriver_seat_status_v1, + struct wl_output *output) {} -static const struct wl_registry_listener registry_listener - = { global_registry_handler, global_registry_remover }; +void focused_view_empty(void *data, + struct zriver_seat_status_v1 *zriver_seat_status_v1, + const char *title) {} -int -main (int argc, char *argv[]) -{ - enum - { - HELP, - SHIFT_VALUE, - START_TAG, - NUM_TAGS - }; - static struct option opts[] = { - { "help", no_argument, NULL, HELP }, - { "shifts", required_argument, NULL, SHIFT_VALUE }, - { "num-tags", required_argument, NULL, NUM_TAGS }, - { "start", required_argument, NULL, START_TAG }, - { NULL, 0, NULL, 0 }, - }; +static const struct zriver_seat_status_v1_listener output_status_listener = { + .focused_output = get_focused_output, + .unfocused_output = unfocused_output_empty, + .focused_view = focused_view_empty, +}; - int opt; - while ((opt = getopt_long (argc, argv, "h", opts, NULL)) != -1) - { - switch (opt) - { +static void global_registry_handler(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, + uint32_t version) { + if (strcmp(interface, "wl_output") == 0) { + outputs_size++; + wl_outputs = realloc(wl_outputs, outputs_size * sizeof(struct output)); + if (wl_outputs == NULL) { + fputs("REALLOC ERROR", stderr); + exit(1); + } + wl_outputs[outputs_size - 1].output = + wl_registry_bind(registry, id, &wl_output_interface, 1); + wl_outputs[outputs_size - 1].index = outputs_size - 1; + } else if (strcmp(interface, "wl_seat") == 0) { + seat = wl_registry_bind(registry, id, &wl_seat_interface, 3); + } else if (strcmp(interface, zriver_status_manager_v1_interface.name) == + 0) { + river_status_manager = wl_registry_bind( + registry, id, &zriver_status_manager_v1_interface, 2); + } else if (strcmp(interface, zriver_control_v1_interface.name) == 0) { + river_controller = + wl_registry_bind(registry, id, &zriver_control_v1_interface, 1); + } +} + +static void global_registry_remover(void *data, struct wl_registry *registry, + uint32_t id) {} + +static const struct wl_registry_listener registry_listener = { + global_registry_handler, global_registry_remover +}; + +int main(int argc, char *argv[]) { + enum { HELP, SHIFT_VALUE, START_TAG, NUM_TAGS }; + static struct option opts[] = { + { "help", no_argument, NULL, HELP }, + { "shift", required_argument, NULL, SHIFT_VALUE }, + { "num-tags", required_argument, NULL, NUM_TAGS }, + { "start", required_argument, NULL, START_TAG }, + { NULL, 0, NULL, 0 }, + }; + + int opt; + while ((opt = getopt_long(argc, argv, "h", opts, NULL)) != -1) { + switch (opt) { case HELP: - fputs (usage, stderr); - return EXIT_SUCCESS; + fputs(usage, stderr); + return EXIT_SUCCESS; case SHIFT_VALUE: - shifts = atoi (optarg); - break; + _shift = atoi(optarg); + break; case START_TAG: - start_tag = atoi (optarg); - break; + _start_tag = atoi(optarg); + break; case NUM_TAGS: - num_tags = atoi (optarg); - break; + _num_tags = atoi(optarg); + break; default: - return EXIT_FAILURE; + return EXIT_FAILURE; } } - const char *display_name = getenv ("WAYLAND_DISPLAY"); - if (display_name == NULL) - { - fputs ("ERROR: WAYLAND_DISPLAY is not set.\n", stderr); - return EXIT_FAILURE; + const char *display_name = getenv("WAYLAND_DISPLAY"); + if (display_name == NULL) { + fputs("ERROR: WAYLAND_DISPLAY is not set.\n", stderr); + return EXIT_FAILURE; } - wl_display = wl_display_connect (display_name); - if (wl_display == NULL) - { - fputs ("ERROR: Can not connect to wayland display.\n", stderr); - return EXIT_FAILURE; + wl_display = wl_display_connect(display_name); + if (wl_display == NULL) { + fputs("ERROR: Can not connect to wayland display.\n", stderr); + return EXIT_FAILURE; } - struct wl_registry *registry = wl_display_get_registry (wl_display); - wl_registry_add_listener (registry, ®istry_listener, NULL); + struct wl_registry *registry = wl_display_get_registry(wl_display); + wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_roundtrip (wl_display); + wl_display_roundtrip(wl_display); - river_output_status = zriver_status_manager_v1_get_river_output_status ( - river_status_manager, wl_output); + river_output_statuses = + malloc(outputs_size * sizeof(struct zriver_output_status_v1 *)); + new_tags = malloc(outputs_size * sizeof(int *)); - zriver_output_status_v1_add_listener (river_output_status, - &output_status_listener, NULL); + struct zriver_seat_status_v1 *seat_status_manager = + zriver_status_manager_v1_get_river_seat_status(river_status_manager, + seat); + zriver_seat_status_v1_add_listener(seat_status_manager, + &output_status_listener, NULL); - /* Wait till new_tags is populated */ - wl_display_roundtrip (wl_display); + for (size_t i = 0; i < outputs_size; i++) { + river_output_statuses[i] = + zriver_status_manager_v1_get_river_output_status( + river_status_manager, wl_outputs[i].output); - /* Set the new focused tags */ - zriver_control_v1_add_argument( - river_controller, - "set-focused-tags" - ); + zriver_output_status_v1_add_listener(river_output_statuses[i], + &tag_status_listener, (void *)i); + new_tags[i] = 0; + } - char* tags_str = malloc( (size_t)snprintf( NULL, 0, "%d", new_tags )); - sprintf(tags_str, "%d", new_tags); + /* Wait till new_tags is populated */ + wl_display_roundtrip(wl_display); - zriver_control_v1_add_argument( - river_controller, tags_str); + /* Set the new focused tags */ + zriver_control_v1_add_argument(river_controller, "set-focused-tags"); - zriver_control_v1_run_command ( - river_controller, seat); + char *tags_str = + malloc((size_t)snprintf(NULL, 0, "%d", new_tags[focused_output])); + sprintf(tags_str, "%d", new_tags[focused_output]); - zriver_control_v1_destroy(river_controller); - wl_display_roundtrip (wl_display); + zriver_control_v1_add_argument(river_controller, tags_str); - return ret; + zriver_control_v1_run_command(river_controller, seat); + + zriver_control_v1_destroy(river_controller); + wl_display_roundtrip(wl_display); + + free(wl_outputs); + free(river_output_statuses); + free(new_tags); + + return ret; } -