From 55ed2736b5a8d69e69ebf6a77fffe684309fd4ac Mon Sep 17 00:00:00 2001 From: Bruno Pinto Date: Fri, 20 Apr 2018 01:25:51 +0100 Subject: [PATCH 01/17] [swaylock] Install pam module --- swaylock/meson.build | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/swaylock/meson.build b/swaylock/meson.build index 3cde47a44..63f694b94 100644 --- a/swaylock/meson.build +++ b/swaylock/meson.build @@ -1,3 +1,5 @@ +sysconfdir = get_option('sysconfdir') + executable( 'swaylock', [ 'main.c', @@ -21,3 +23,8 @@ executable( link_with: [lib_sway_common, lib_sway_client], install: true ) + +install_data( + 'pam/swaylock', + install_dir: sysconfdir + '/pam.d/' +) From 34429a3605888b2d67af6e4489d8ceaa64bbd25a Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 20 Apr 2018 09:01:52 +1000 Subject: [PATCH 02/17] Keep view fullscreened when moving to another workspace. container_handle_fullscreen_reparent() must be called *after* setting the container's new parent. --- sway/tree/layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 7ffc24844..12af71729 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -150,8 +150,8 @@ void container_add_child(struct sway_container *parent, parent, parent->type, parent->width, parent->height); struct sway_container *old_parent = child->parent; list_add(parent->children, child); - container_handle_fullscreen_reparent(child, old_parent); child->parent = parent; + container_handle_fullscreen_reparent(child, old_parent); } struct sway_container *container_remove_child(struct sway_container *child) { From 17bee33fc9497448f7d3f4121ecf9821bf7b5956 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 20 Apr 2018 16:24:34 +0100 Subject: [PATCH 03/17] Don't unmap on destroy, this is already guaranteed by wlroots --- sway/desktop/xwayland.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 46eaa84ce..cad9156d8 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -257,11 +257,6 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, destroy); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->mapped) { - handle_unmap(&xwayland_view->unmap, xsurface); - } view_destroy(&xwayland_view->view); } From e0107c4dd7baec5845d16fa151b18f33159c3729 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 21 Apr 2018 13:44:32 +1200 Subject: [PATCH 04/17] Always send POLLHUP and POLLERR with event loop --- swaybar/event_loop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c index 748372edf..1e0d426b8 100644 --- a/swaybar/event_loop.c +++ b/swaybar/event_loop.c @@ -118,7 +118,10 @@ void event_loop_poll() { struct pollfd pfd = event_loop.fds.items[i]; struct event_item *item = (struct event_item *)event_loop.items->items[i]; - if (pfd.revents & pfd.events) { + // Always send these events + unsigned events = pfd.events | POLLHUP | POLLERR; + + if (pfd.revents & events) { item->cb(pfd.fd, pfd.revents, item->data); } } From 9a3fb33e33b2503809d9d3a1b0d10c21bc112a80 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 21 Apr 2018 14:38:34 +1200 Subject: [PATCH 05/17] Change remove_event logic We defer the removal of entries until after the poll loop has finished. Otherwise we may end up adjusting the poll array while we're still reading from it, causing us to skip events. --- swaybar/event_loop.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c index 1e0d426b8..bc4053beb 100644 --- a/swaybar/event_loop.c +++ b/swaybar/event_loop.c @@ -72,24 +72,18 @@ void add_event(int fd, short mask, } bool remove_event(int fd) { - int index = -1; + /* + * Instead of removing events immediately, we mark them for deletion + * and clean them up later. This is so we can call remove_event inside + * an event callback safely. + */ for (int i = 0; i < event_loop.fds.length; ++i) { if (event_loop.fds.items[i].fd == fd) { - index = i; + event_loop.fds.items[i].fd = -1; + return true; } } - if (index != -1) { - free(event_loop.items->items[index]); - - --event_loop.fds.length; - memmove(&event_loop.fds.items[index], &event_loop.fds.items[index + 1], - sizeof(struct pollfd) * event_loop.fds.length - index); - - list_del(event_loop.items, index); - return true; - } else { - return false; - } + return false; } static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { @@ -126,6 +120,21 @@ void event_loop_poll() { } } + // Cleanup removed events + int end = 0; + int length = event_loop.fds.length; + for (int i = 0; i < length; ++i) { + if (event_loop.fds.items[i].fd == -1) { + free(event_loop.items->items[i]); + list_del(event_loop.items, i); + --event_loop.fds.length; + } else if (end != i) { + event_loop.fds.items[end++] = event_loop.fds.items[i]; + } else { + end = i + 1; + } + } + // check timers // not tested, but seems to work for (int i = 0; i < event_loop.timers->length; ++i) { From 2ebb6073b7eb052984008110e3df4469d2d9c596 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 21 Apr 2018 14:39:46 +1200 Subject: [PATCH 06/17] Remove status command event on error This prevents very high CPU load when the status command dies, and poll continuously awoken with POLLHUP. --- swaybar/bar.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/swaybar/bar.c b/swaybar/bar.c index d51c4ec71..10a840cc0 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -418,7 +418,11 @@ static void ipc_in(int fd, short mask, void *_bar) { static void status_in(int fd, short mask, void *_bar) { struct swaybar *bar = (struct swaybar *)_bar; - if (status_handle_readable(bar->status)) { + if (mask & (POLLHUP | POLLERR)) { + status_error(bar->status, "[error reading from status command]"); + render_all_frames(bar); + remove_event(fd); + } else if (status_handle_readable(bar->status)) { render_all_frames(bar); } } From c63554885e4aae4e1c8f97ffbd53160f3eb99510 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 21 Apr 2018 14:45:34 +1200 Subject: [PATCH 07/17] Remove void * casts They're pointless. --- swaybar/bar.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/swaybar/bar.c b/swaybar/bar.c index 10a840cc0..669cb11ac 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -401,23 +401,23 @@ void bar_setup(struct swaybar *bar, render_all_frames(bar); } -static void display_in(int fd, short mask, void *_bar) { - struct swaybar *bar = (struct swaybar *)_bar; +static void display_in(int fd, short mask, void *data) { + struct swaybar *bar = data; if (wl_display_dispatch(bar->display) == -1) { bar_teardown(bar); exit(0); } } -static void ipc_in(int fd, short mask, void *_bar) { - struct swaybar *bar = (struct swaybar *)_bar; +static void ipc_in(int fd, short mask, void *data) { + struct swaybar *bar = data; if (handle_ipc_readable(bar)) { render_all_frames(bar); } } -static void status_in(int fd, short mask, void *_bar) { - struct swaybar *bar = (struct swaybar *)_bar; +static void status_in(int fd, short mask, void *data) { + struct swaybar *bar = data; if (mask & (POLLHUP | POLLERR)) { status_error(bar->status, "[error reading from status command]"); render_all_frames(bar); From 33ed279494e7f95d74d494523afe8949091da8cd Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 21 Apr 2018 12:46:48 +0100 Subject: [PATCH 08/17] Update cursor when workspace focus changes --- sway/input/cursor.c | 5 ++--- sway/input/seat.c | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index a19f0752a..5ed4f1f7a 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -59,9 +59,8 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor, // find the output the cursor is on struct wlr_output_layout *output_layout = root_container.sway_root->output_layout; - struct wlr_output *wlr_output = - wlr_output_layout_output_at(output_layout, - cursor->cursor->x, cursor->cursor->y); + struct wlr_output *wlr_output = wlr_output_layout_output_at(output_layout, + cursor->cursor->x, cursor->cursor->y); if (wlr_output == NULL) { return NULL; } diff --git a/sway/input/seat.c b/sway/input/seat.c index 8bba7d8fc..631a273f2 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -564,6 +564,12 @@ void seat_set_focus_warp(struct sway_seat *seat, view_set_activated(view, false); } + if (last_workspace && last_workspace != new_workspace) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + cursor_send_pointer_motion(seat->cursor, now.tv_nsec / 1000); + } + seat->has_focus = (container != NULL); update_debug_tree(); From 4cf77e1de4b0be8b7d9374f04ff0e191ce22610a Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 21 Apr 2018 14:07:22 +0100 Subject: [PATCH 09/17] Default to current time when triggering cursor events --- include/sway/input/cursor.h | 2 +- sway/commands/seat/cursor.c | 16 ++++++---------- sway/input/cursor.c | 18 ++++++++++++++++-- sway/input/seat.c | 8 ++------ 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index fcd94437c..20c1c9038 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -29,7 +29,7 @@ struct sway_cursor { void sway_cursor_destroy(struct sway_cursor *cursor); struct sway_cursor *sway_cursor_create(struct sway_seat *seat); -void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time); +void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec); void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state); diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 5dad97f1a..929384b03 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -11,7 +11,7 @@ #include "sway/input/cursor.h" static struct cmd_results *press_or_release(struct sway_cursor *cursor, - char *action, char *button_str, uint32_t time); + char *action, char *button_str); static const char *expected_syntax = "Expected 'cursor ' or " "'cursor ' or " @@ -29,10 +29,6 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { struct sway_cursor *cursor = seat->cursor; - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t time = now.tv_nsec / 1000; - if (strcasecmp(argv[0], "move") == 0) { if (argc < 3) { return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); @@ -40,7 +36,7 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { int delta_x = strtol(argv[1], NULL, 10); int delta_y = strtol(argv[2], NULL, 10); wlr_cursor_move(cursor->cursor, NULL, delta_x, delta_y); - cursor_send_pointer_motion(cursor, time); + cursor_send_pointer_motion(cursor, 0); } else if (strcasecmp(argv[0], "set") == 0) { if (argc < 3) { return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); @@ -49,12 +45,12 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { float x = strtof(argv[1], NULL) / root_container.width; float y = strtof(argv[2], NULL) / root_container.height; wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); - cursor_send_pointer_motion(cursor, time); + cursor_send_pointer_motion(cursor, 0); } else { if (argc < 2) { return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); } - if ((error = press_or_release(cursor, argv[0], argv[1], time))) { + if ((error = press_or_release(cursor, argv[0], argv[1]))) { return error; } } @@ -63,7 +59,7 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { } static struct cmd_results *press_or_release(struct sway_cursor *cursor, - char *action, char *button_str, uint32_t time) { + char *action, char *button_str) { enum wlr_button_state state; uint32_t button; if (strcasecmp(action, "press") == 0) { @@ -84,6 +80,6 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor, return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); } } - dispatch_cursor_button(cursor, time, button, state); + dispatch_cursor_button(cursor, 0, button, state); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 5ed4f1f7a..831109dc7 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -15,6 +15,12 @@ #include "sway/tree/workspace.h" #include "wlr-layer-shell-unstable-v1-protocol.h" +static uint32_t get_current_time_msec() { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return now.tv_nsec / 1000; +} + static struct wlr_surface *layer_surface_at(struct sway_output *output, struct wl_list *layer, double ox, double oy, double *sx, double *sy) { struct sway_layer_surface *sway_layer; @@ -128,7 +134,11 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor, return output->swayc; } -void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time) { +void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec) { + if (time_msec == 0) { + time_msec = get_current_time_msec(); + } + struct wlr_seat *seat = cursor->seat->wlr_seat; struct wlr_surface *surface = NULL; double sx, sy; @@ -152,7 +162,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time) { if (surface != NULL) { if (seat_is_input_allowed(cursor->seat, surface)) { wlr_seat_pointer_notify_enter(seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat, time, sx, sy); + wlr_seat_pointer_notify_motion(seat, time_msec, sx, sy); } } else { wlr_seat_pointer_clear_focus(seat); @@ -178,6 +188,10 @@ static void handle_cursor_motion_absolute( void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state) { + if (time_msec == 0) { + time_msec = get_current_time_msec(); + } + struct wlr_surface *surface = NULL; double sx, sy; struct sway_container *cont = diff --git a/sway/input/seat.c b/sway/input/seat.c index 631a273f2..d1fc62c45 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -550,9 +550,7 @@ void seat_set_focus_warp(struct sway_seat *seat, wlr_output, seat->cursor->cursor->x, seat->cursor->cursor->y)) { wlr_cursor_warp(seat->cursor->cursor, NULL, x, y); - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - cursor_send_pointer_motion(seat->cursor, now.tv_nsec / 1000); + cursor_send_pointer_motion(seat->cursor, 0); } } } @@ -565,9 +563,7 @@ void seat_set_focus_warp(struct sway_seat *seat, } if (last_workspace && last_workspace != new_workspace) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - cursor_send_pointer_motion(seat->cursor, now.tv_nsec / 1000); + cursor_send_pointer_motion(seat->cursor, 0); } seat->has_focus = (container != NULL); From b96d774c7006075ab02e782d5d346f1ffccbeeeb Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 21 Apr 2018 14:08:48 +0100 Subject: [PATCH 10/17] Use wlr_renderer_init_wl_shm --- sway/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/server.c b/sway/server.c index 11cb95c08..f67f44d85 100644 --- a/sway/server.c +++ b/sway/server.c @@ -51,7 +51,7 @@ bool server_init(struct sway_server *server) { struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend); assert(renderer); - wl_display_init_shm(server->wl_display); + wlr_renderer_init_wl_shm(renderer, server->wl_display); server->compositor = wlr_compositor_create(server->wl_display, renderer); server->data_device_manager = From a41057714f786bfe6a797cb8393b49e6870d5329 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 21 Apr 2018 19:12:49 +0100 Subject: [PATCH 11/17] Update for wlroots#885 --- sway/tree/view.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index b92c70996..92767188c 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -327,7 +327,7 @@ static void view_child_handle_view_unmap(struct wl_listener *listener, static void view_init_subsurfaces(struct sway_view *view, struct wlr_surface *surface) { struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { view_subsurface_create(view, subsurface); } } From 4dfbc3160c937b4fcee2b27d78d7e46a48cd68e9 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sun, 22 Apr 2018 17:13:52 +1200 Subject: [PATCH 12/17] Fix swaybar axis event logic Uses 'visible' instead of 'focused', since we may scroll on a bar which isn't the focused output. We can't use "next_on_output" or "prev_on_output" to implement this, because it only modify the focused output. So scrolling on an unfocused output will affect the incorrect one. We just use the "workspace name" command instead. --- swaybar/bar.c | 69 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/swaybar/bar.c b/swaybar/bar.c index 669cb11ac..d407db4fc 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -156,31 +156,56 @@ static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, if (!sway_assert(output, "axis with no active output")) { return; } + double amt = wl_fixed_to_double(value); - if (!bar->config->wrap_scroll) { - int i = 0; - struct swaybar_workspace *ws = NULL; - wl_list_for_each(ws, &output->workspaces, link) { - if (ws->focused) { - break; - } - ++i; - } - int len = wl_list_length(&output->workspaces); - if (!sway_assert(i != len, "axis with null workspace")) { - return; - } - if (i == 0 && amt > 0) { - return; // Do not wrap - } - if (i == len - 1 && amt < 0) { - return; // Do not wrap - } + if (amt == 0.0) { + return; } - const char *workspace_name = - amt < 0 ? "prev_on_output" : "next_on_output"; - ipc_send_workspace_command(bar, workspace_name); + struct swaybar_workspace *first = NULL; + struct swaybar_workspace *active = NULL; + struct swaybar_workspace *last; + + struct swaybar_workspace *iter; + wl_list_for_each(iter, &output->workspaces, link) { + if (!first) { + first = iter; + } + + if (iter->visible) { + active = iter; + } + + last = iter; + } + + if (!sway_assert(active, "axis with null workspace")) { + return; + } + + struct swaybar_workspace *new; + + if (amt > 0.0) { + if (active == first) { + if (!bar->config->wrap_scroll) { + return; + } + new = last; + } + + new = wl_container_of(active->link.prev, new, link); + } else { + if (active == last) { + if (!bar->config->wrap_scroll) { + return; + } + new = first; + } + + new = wl_container_of(active->link.next, new, link); + } + + ipc_send_workspace_command(bar, new->name); } static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { From 4d2b3fc95069d4865ea56ad0edf26c20337baca8 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 23 Apr 2018 09:20:19 +1000 Subject: [PATCH 13/17] Render unmanaged xwayland views when an xwayland view is fullscreen This makes Chromium and Firefox context menus appear when fullscreen. --- sway/desktop/output.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 8d25caaec..b19b72df7 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -282,6 +282,11 @@ static void render_output(struct sway_output *output, struct timespec *when, wlr_renderer_clear(renderer, clear_color); // TODO: handle views smaller than the output render_container(output, workspace->sway_workspace->fullscreen->swayc); + + if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { + render_unmanaged(output, + &root_container.sway_root->xwayland_unmanaged); + } } else { float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; wlr_renderer_clear(renderer, clear_color); From d956286b92a71accb2ac6c895b51502a3eab3bcd Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 23 Apr 2018 13:04:16 +1000 Subject: [PATCH 14/17] Implement rename workspace command This implements the following commands: * rename workspace to new_name * rename workspace old_name to new_name * rename workspace number n to new_name --- include/sway/commands.h | 1 + sway/commands.c | 1 + sway/commands/rename.c | 78 +++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 1 + 4 files changed, 81 insertions(+) create mode 100644 sway/commands/rename.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 7b8c949b1..75534163c 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -131,6 +131,7 @@ sway_cmd cmd_output; sway_cmd cmd_permit; sway_cmd cmd_reject; sway_cmd cmd_reload; +sway_cmd cmd_rename; sway_cmd cmd_resize; sway_cmd cmd_scratchpad; sway_cmd cmd_seamless_mouse; diff --git a/sway/commands.c b/sway/commands.c index 2115bd8c3..6af3c5d0c 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -167,6 +167,7 @@ static struct cmd_handler command_handlers[] = { { "move", cmd_move }, { "opacity", cmd_opacity }, { "reload", cmd_reload }, + { "rename", cmd_rename }, { "resize", cmd_resize }, { "split", cmd_split }, { "splith", cmd_splith }, diff --git a/sway/commands/rename.c b/sway/commands/rename.c new file mode 100644 index 000000000..4be912a9f --- /dev/null +++ b/sway/commands/rename.c @@ -0,0 +1,78 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "log.h" +#include "stringop.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "sway/tree/container.h" +#include "sway/tree/workspace.h" + +static const char* expected_syntax = + "Expected 'rename workspace to ' or " + "'rename workspace to '"; + +struct cmd_results *cmd_rename(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "rename", EXPECTED_AT_LEAST, 3))) { + return error; + } + if (strcasecmp(argv[0], "workspace") != 0) { + return cmd_results_new(CMD_INVALID, "rename", expected_syntax); + } + + int argn = 1; + struct sway_container *workspace; + + if (strcasecmp(argv[1], "to") == 0) { + // 'rename workspace to new_name' + workspace = config->handler_context.current_container; + if (workspace->type != C_WORKSPACE) { + workspace = container_parent(workspace, C_WORKSPACE); + } + } else if (strcasecmp(argv[1], "number") == 0) { + // 'rename workspace number x to new_name' + workspace = workspace_by_number(argv[2]); + while (argn < argc && strcasecmp(argv[argn], "to") != 0) { + ++argn; + } + } else { + // 'rename workspace old_name to new_name' + int end = argn; + while (end < argc && strcasecmp(argv[end], "to") != 0) { + ++end; + } + char *old_name = join_args(argv + argn, end - argn); + workspace = workspace_by_name(old_name); + free(old_name); + argn = end; + } + + if (!workspace) { + return cmd_results_new(CMD_INVALID, "rename", + "There is no workspace with that name"); + } + + ++argn; // move past "to" + + if (argn >= argc) { + return cmd_results_new(CMD_INVALID, "rename", expected_syntax); + } + + char *new_name = join_args(argv + argn, argc - argn); + struct sway_container *tmp_workspace = workspace_by_name(new_name); + if (tmp_workspace) { + free(new_name); + return cmd_results_new(CMD_INVALID, "rename", + "Workspace already exists"); + } + + wlr_log(L_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name); + free(workspace->name); + workspace->name = new_name; + + ipc_event_workspace(NULL, workspace, "rename"); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 67dbe3dda..f3c319ede 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -45,6 +45,7 @@ sway_sources = files( 'commands/move.c', 'commands/output.c', 'commands/reload.c', + 'commands/rename.c', 'commands/resize.c', 'commands/seat.c', 'commands/seat/attach.c', From fbb5198e43ef1e8bbb2e83f0942fbe4e8d787e85 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 23 Apr 2018 18:53:24 +1000 Subject: [PATCH 15/17] Sort workspaces after rename --- sway/commands/rename.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 4be912a9f..104a33925 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c @@ -72,6 +72,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { free(workspace->name); workspace->name = new_name; + container_sort_workspaces(workspace->parent); ipc_event_workspace(NULL, workspace, "rename"); return cmd_results_new(CMD_SUCCESS, NULL, NULL); From 420a669f214a948bb4e47de1cca7ea02014b5251 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 22 Apr 2018 19:27:34 +0200 Subject: [PATCH 16/17] Updates per swaywm/wlroots#887 --- sway/desktop/layer_shell.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index f841e5f10..f9a1a8bd4 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -13,6 +13,7 @@ #include "sway/output.h" #include "sway/server.h" #include "sway/tree/layout.h" +#include "log.h" static void apply_exclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, @@ -316,6 +317,27 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { return; } + if (!layer_surface->output) { + // Assign last active output + struct sway_container *output = NULL; + struct sway_seat *seat = input_manager_get_default_seat(input_manager); + if (seat) { + output = seat_get_focus_inactive(seat, &root_container); + } + if (!output) { + if (!sway_assert(root_container.children->length, + "cannot auto-assign output for layer")) { + wlr_layer_surface_close(layer_surface); + return; + } + output = root_container.children->items[0]; + } + if (output->type != C_OUTPUT) { + output = container_parent(output, C_OUTPUT); + } + layer_surface->output = output->sway_output->wlr_output; + } + sway_layer->surface_commit.notify = handle_surface_commit; wl_signal_add(&layer_surface->surface->events.commit, &sway_layer->surface_commit); From 22b916963146d6235a49f3c9283e956e42fb22e9 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 24 Apr 2018 12:27:04 +1000 Subject: [PATCH 17/17] Fix crash in container_descendants() If root is a C_VIEW, the children property is a null pointer. --- sway/tree/container.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index f14e9b9a9..bd9f98944 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -355,14 +355,15 @@ struct sway_container *container_view_create(struct sway_container *sibling, void container_descendants(struct sway_container *root, enum sway_container_type type, void (*func)(struct sway_container *item, void *data), void *data) { + if (!root->children || !root->children->length) { + return; + } for (int i = 0; i < root->children->length; ++i) { struct sway_container *item = root->children->items[i]; if (item->type == type) { func(item, data); } - if (item->children && item->children->length) { - container_descendants(item, type, func, data); - } + container_descendants(item, type, func, data); } }