diff --git a/include/sway/output.h b/include/sway/output.h index 26b9709f9..e28065673 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -4,9 +4,11 @@ #include #include #include +#include #include "config.h" #include "sway/tree/node.h" #include "sway/tree/view.h" +#include struct sway_server; struct sway_container; @@ -55,6 +57,8 @@ struct sway_output { uint32_t refresh_nsec; int max_render_time; // In milliseconds struct wl_event_source *repaint_timer; + + struct wlr_ext_workspace_group_handle_v1 *workspace_group; }; struct sway_output *output_create(struct wlr_output *wlr_output); diff --git a/include/sway/server.h b/include/sway/server.h index 3d59ca562..558300184 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,8 @@ struct sway_server { struct wlr_input_method_manager_v2 *input_method; struct wlr_text_input_manager_v3 *text_input; struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; + struct wlr_ext_workspace_manager_v1 *workspace_manager; + struct wl_listener workspace_manager_commit_request; struct wlr_xdg_activation_v1 *xdg_activation_v1; struct wl_listener xdg_activation_v1_request_activate; diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index b3d93a813..baf506452 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -43,6 +43,9 @@ struct sway_workspace { bool urgent; struct sway_workspace_state current; + + struct wlr_workspace_handle_v1 *workspace_handle; + struct wl_listener *workspace_activate_request; }; struct workspace_config *workspace_find_config(const char *ws_name); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 5b7ad4eee..49c7f107d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -901,6 +901,8 @@ void handle_new_output(struct wl_listener *listener, void *data) { return; } output->server = server; + output->workspace_group = wlr_ext_workspace_group_handle_v1_create(output->server->workspace_manager); + wlr_ext_workspace_group_handle_v1_output_enter(output->workspace_group, wlr_output); output->damage = wlr_output_damage_create(wlr_output); wl_signal_add(&wlr_output->events.destroy, &output->destroy); diff --git a/sway/server.c b/sway/server.c index 627d80d66..29a30e096 100644 --- a/sway/server.c +++ b/sway/server.c @@ -60,6 +60,27 @@ bool server_privileged_prepare(struct sway_server *server) { return true; } +static void handle_workspace_manager_commit_request(struct wl_listener *listener, void *data) { + struct sway_server *_server = wl_container_of(listener, _server, workspace_manager_commit_request); + struct wlr_ext_workspace_manager_v1 *manager = data; + struct wlr_ext_workspace_group_handle_v1 *group; + wl_list_for_each(group, &manager->groups, link) { + struct wlr_ext_workspace_handle_v1 *workspace; + struct wlr_ext_workspace_handle_v1 *next_active_workspace = NULL; + wl_list_for_each(workspace, &group->workspaces, link) { + if (workspace->current & WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { + next_active_workspace = workspace; + } + } + if (!next_active_workspace) { + continue; + } + + struct sway_workspace *sw_workspace = workspace_by_name(next_active_workspace->name); + workspace_switch(sw_workspace); + } +} + static void handle_drm_lease_request(struct wl_listener *listener, void *data) { /* We only offer non-desktop outputs, but in the future we might want to do * more logic here. */ @@ -185,6 +206,12 @@ bool server_init(struct sway_server *server) { server->text_input = wlr_text_input_manager_v3_create(server->wl_display); server->foreign_toplevel_manager = wlr_foreign_toplevel_manager_v1_create(server->wl_display); + server->workspace_manager = + wlr_ext_workspace_manager_v1_create(server->wl_display); + server->workspace_manager_commit_request.notify = + handle_workspace_manager_commit_request; + wl_signal_add(&server->workspace_manager->events.commit, + &server->workspace_manager_commit_request); sway_session_lock_init(); diff --git a/sway/tree/output.c b/sway/tree/output.c index 52826c915..e3fa49a13 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -131,6 +131,7 @@ void output_enable(struct sway_output *output) { wl_list_for_each(seat, &server.input->seats, link) { if (!seat->has_focus) { seat_set_focus_workspace(seat, ws); + wlr_workspace_handle_v1_set_active(ws->workspace_handle, true); } } free(ws_name); @@ -238,6 +239,8 @@ void output_destroy(struct sway_output *output) { "which is still referenced by transactions")) { return; } + wlr_workspace_group_handle_v1_output_leave(output->workspace_group, output->wlr_output); + free(output->workspace_group); list_free(output->workspaces); list_free(output->current.workspaces); wl_event_source_remove(output->repaint_timer); @@ -379,8 +382,21 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { return 0; } +static void set_workspace_coordinates(list_t *workspaces) { + for (int i = 0; i < workspaces->length; ++i) { + struct wl_array coordinates; + wl_array_init(&coordinates); + *(int*)wl_array_add(&coordinates, sizeof(int)) = i + 1; + wlr_ext_workspace_handle_v1_set_coordinates( + ((struct sway_workspace*)workspaces->items[i]) + ->workspace_handle, &coordinates); + wl_array_release(&coordinates); + } +} + void output_sort_workspaces(struct sway_output *output) { list_stable_sort(output->workspaces, sort_workspace_cmp_qsort); + set_workspace_coordinates(output->workspaces); } void output_get_box(struct sway_output *output, struct wlr_box *box) { diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index c84320bda..6e17710a4 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -110,6 +110,9 @@ struct sway_workspace *workspace_create(struct sway_output *output, // If not already added, add the output to the lowest priority workspace_output_add_priority(ws, output); + ws->workspace_handle = wlr_workspace_handle_v1_create(output->workspace_group); + wlr_workspace_handle_v1_set_name(ws->workspace_handle, ws->name); + output_add_workspace(output, ws); output_sort_workspaces(output); @@ -128,7 +131,9 @@ void workspace_destroy(struct sway_workspace *workspace) { "which is still referenced by transactions")) { return; } + wlr_workspace_handle_v1_destroy(workspace->workspace_handle); + free(workspace->workspace_handle); free(workspace->name); free(workspace->representation); list_free_items_and_destroy(workspace->output_priority); @@ -551,6 +556,16 @@ struct sway_workspace *workspace_output_prev(struct sway_workspace *current) { return workspace_output_prev_next_impl(current->output, -1); } +static void set_active_current_and_diactivate_others(struct wlr_workspace_handle_v1 *workspace) { + wlr_workspace_handle_v1_set_active(workspace, true); + struct wlr_workspace_handle_v1 *tmp_workspace; + wl_list_for_each(tmp_workspace, &workspace->group->workspaces, link) { + if (workspace != tmp_workspace) { + wlr_workspace_handle_v1_set_active(tmp_workspace, false); + } + } +} + struct sway_workspace *workspace_auto_back_and_forth( struct sway_workspace *workspace) { struct sway_seat *seat = input_manager_current_seat(); @@ -578,6 +593,9 @@ bool workspace_switch(struct sway_workspace *workspace) { sway_log(SWAY_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); + + set_active_current_and_diactivate_others(workspace->workspace_handle); + struct sway_node *next = seat_get_focus_inactive(seat, &workspace->node); if (next == NULL) { next = &workspace->node;