mirror of
https://github.com/swaywm/sway.git
synced 2026-04-07 08:21:29 -04:00
Compare commits
10 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faedde4e77 | ||
|
|
4e673a3515 | ||
|
|
1e96e73767 | ||
|
|
3aa4c46c13 | ||
|
|
fa889d020b | ||
|
|
257a0a7548 | ||
|
|
9d77163d6e | ||
|
|
948d481cfa | ||
|
|
07e3c06741 | ||
|
|
1826c38ecd |
17 changed files with 240 additions and 58 deletions
|
|
@ -25,7 +25,7 @@ packages:
|
||||||
- hwdata-dev
|
- hwdata-dev
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/swaywm/sway
|
- https://github.com/swaywm/sway
|
||||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.20
|
||||||
tasks:
|
tasks:
|
||||||
- wlroots: |
|
- wlroots: |
|
||||||
cd wlroots
|
cd wlroots
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ packages:
|
||||||
- hwdata
|
- hwdata
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/swaywm/sway
|
- https://github.com/swaywm/sway
|
||||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.20
|
||||||
tasks:
|
tasks:
|
||||||
- wlroots: |
|
- wlroots: |
|
||||||
cd wlroots
|
cd wlroots
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ packages:
|
||||||
- misc/hwdata
|
- misc/hwdata
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/swaywm/sway
|
- https://github.com/swaywm/sway
|
||||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.20
|
||||||
tasks:
|
tasks:
|
||||||
- setup: |
|
- setup: |
|
||||||
cd sway
|
cd sway
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,15 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
|
||||||
|
|
||||||
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
|
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
|
||||||
int *baseline, double scale, bool markup, const char *fmt, ...) {
|
int *baseline, double scale, bool markup, const char *fmt, ...) {
|
||||||
*width = *height = *baseline = 0;
|
if (width) {
|
||||||
|
*width = 0;
|
||||||
|
}
|
||||||
|
if (height) {
|
||||||
|
*height = 0;
|
||||||
|
}
|
||||||
|
if (baseline) {
|
||||||
|
*baseline = 0;
|
||||||
|
}
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
|
@ -115,8 +123,8 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) {
|
void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) {
|
||||||
cairo_t *cairo = cairo_create(NULL);
|
PangoFontMap *fontmap = pango_cairo_font_map_get_default();
|
||||||
PangoContext *pango = pango_cairo_create_context(cairo);
|
PangoContext *pango = pango_font_map_create_context(fontmap);
|
||||||
pango_context_set_round_glyph_positions(pango, false);
|
pango_context_set_round_glyph_positions(pango, false);
|
||||||
// When passing NULL as a language, pango uses the current locale.
|
// When passing NULL as a language, pango uses the current locale.
|
||||||
PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);
|
PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);
|
||||||
|
|
@ -126,7 +134,6 @@ void get_text_metrics(const PangoFontDescription *description, int *height, int
|
||||||
|
|
||||||
pango_font_metrics_unref(metrics);
|
pango_font_metrics_unref(metrics);
|
||||||
g_object_unref(pango);
|
g_object_unref(pango);
|
||||||
cairo_destroy(cairo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_text(cairo_t *cairo, const PangoFontDescription *desc,
|
void render_text(cairo_t *cairo, const PangoFontDescription *desc,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ struct sway_output {
|
||||||
struct wl_listener request_state;
|
struct wl_listener request_state;
|
||||||
|
|
||||||
struct wlr_color_transform *color_transform;
|
struct wlr_color_transform *color_transform;
|
||||||
|
struct wlr_ext_workspace_group_handle_v1 *ext_workspace_group;
|
||||||
|
|
||||||
struct timespec last_presentation;
|
struct timespec last_presentation;
|
||||||
uint32_t refresh_nsec;
|
uint32_t refresh_nsec;
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,9 @@ struct sway_server {
|
||||||
struct wl_listener tearing_control_new_object;
|
struct wl_listener tearing_control_new_object;
|
||||||
struct wl_list tearing_controllers; // sway_tearing_controller::link
|
struct wl_list tearing_controllers; // sway_tearing_controller::link
|
||||||
|
|
||||||
|
struct wlr_ext_workspace_manager_v1 *workspace_manager_v1;
|
||||||
|
struct wl_listener workspace_manager_v1_commit;
|
||||||
|
|
||||||
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
|
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
|
||||||
|
|
||||||
// The timeout for transactions, after which a transaction is applied
|
// The timeout for transactions, after which a transaction is applied
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
|
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
#include "sway/tree/node.h"
|
#include "sway/tree/node.h"
|
||||||
|
|
@ -51,6 +52,7 @@ struct sway_workspace {
|
||||||
bool urgent;
|
bool urgent;
|
||||||
|
|
||||||
struct sway_workspace_state current;
|
struct sway_workspace_state current;
|
||||||
|
struct wlr_ext_workspace_handle_v1 *ext_workspace; // Always set.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct workspace_config *workspace_find_config(const char *ws_name);
|
struct workspace_config *workspace_find_config(const char *ws_name);
|
||||||
|
|
@ -157,4 +159,11 @@ size_t workspace_num_sticky_containers(struct sway_workspace *ws);
|
||||||
*/
|
*/
|
||||||
void workspace_squash(struct sway_workspace *workspace);
|
void workspace_squash(struct sway_workspace *workspace);
|
||||||
|
|
||||||
|
void workspace_move_to_output(struct sway_workspace *workspace,
|
||||||
|
struct sway_output *output);
|
||||||
|
|
||||||
|
void sway_ext_workspace_init(void);
|
||||||
|
void sway_ext_workspace_output_enable(struct sway_output *output);
|
||||||
|
void sway_ext_workspace_output_disable(struct sway_output *output);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
project(
|
project(
|
||||||
'sway',
|
'sway',
|
||||||
'c',
|
'c',
|
||||||
version: '1.12-dev',
|
version: '1.12-rc1',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>=1.3',
|
meson_version: '>=1.3',
|
||||||
default_options: [
|
default_options: [
|
||||||
|
|
|
||||||
|
|
@ -627,40 +627,6 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void workspace_move_to_output(struct sway_workspace *workspace,
|
|
||||||
struct sway_output *output) {
|
|
||||||
if (workspace->output == output) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct sway_output *old_output = workspace->output;
|
|
||||||
workspace_detach(workspace);
|
|
||||||
struct sway_workspace *new_output_old_ws =
|
|
||||||
output_get_active_workspace(output);
|
|
||||||
if (!sway_assert(new_output_old_ws, "Expected output to have a workspace")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
output_add_workspace(output, workspace);
|
|
||||||
|
|
||||||
// If moving the last workspace from the old output, create a new workspace
|
|
||||||
// on the old output
|
|
||||||
struct sway_seat *seat = config->handler_context.seat;
|
|
||||||
if (old_output->workspaces->length == 0) {
|
|
||||||
char *ws_name = workspace_next_name(old_output->wlr_output->name);
|
|
||||||
struct sway_workspace *ws = workspace_create(old_output, ws_name);
|
|
||||||
free(ws_name);
|
|
||||||
seat_set_raw_focus(seat, &ws->node);
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace_consider_destroy(new_output_old_ws);
|
|
||||||
|
|
||||||
output_sort_workspaces(output);
|
|
||||||
struct sway_node *focus = seat_get_focus_inactive(seat, &workspace->node);
|
|
||||||
seat_set_focus(seat, focus);
|
|
||||||
workspace_output_raise_priority(workspace, old_output, output);
|
|
||||||
ipc_event_workspace(NULL, workspace, "move");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct cmd_results *cmd_move_workspace(int argc, char **argv) {
|
static struct cmd_results *cmd_move_workspace(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 1))) {
|
if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 1))) {
|
||||||
|
|
@ -696,6 +662,8 @@ static struct cmd_results *cmd_move_workspace(int argc, char **argv) {
|
||||||
arrange_output(new_output);
|
arrange_output(new_output);
|
||||||
|
|
||||||
struct sway_seat *seat = config->handler_context.seat;
|
struct sway_seat *seat = config->handler_context.seat;
|
||||||
|
struct sway_node *focus = seat_get_focus_inactive(seat, &workspace->node);
|
||||||
|
seat_set_focus(seat, focus);
|
||||||
seat_consider_warp_to_focus(seat);
|
seat_consider_warp_to_focus(seat);
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
|
|
@ -95,6 +96,8 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
|
||||||
free(workspace->name);
|
free(workspace->name);
|
||||||
workspace->name = new_name;
|
workspace->name = new_name;
|
||||||
|
|
||||||
|
wlr_ext_workspace_handle_v1_set_name(workspace->ext_workspace, workspace->name);
|
||||||
|
|
||||||
output_sort_workspaces(workspace->output);
|
output_sort_workspaces(workspace->output);
|
||||||
ipc_event_workspace(NULL, workspace, "rename");
|
ipc_event_workspace(NULL, workspace, "rename");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -648,15 +648,7 @@ static void arrange_root(struct sway_root *root) {
|
||||||
for (int i = 0; i < root->scratchpad->length; i++) {
|
for (int i = 0; i < root->scratchpad->length; i++) {
|
||||||
struct sway_container *con = root->scratchpad->items[i];
|
struct sway_container *con = root->scratchpad->items[i];
|
||||||
|
|
||||||
// When a container is moved to a scratchpad, it's possible that it
|
disable_container(con);
|
||||||
// was moved into a floating container as part of the same transaction.
|
|
||||||
// In this case, we need to make sure we reparent all the container's
|
|
||||||
// children so that disabling the container will disable all descendants.
|
|
||||||
if (!con->view) for (int ii = 0; ii < con->current.children->length; ii++) {
|
|
||||||
struct sway_container *child = con->current.children->items[ii];
|
|
||||||
wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
|
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
|
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||||
#include <wlr/types/wlr_idle_notify_v1.h>
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_keyboard_group.h>
|
#include <wlr/types/wlr_keyboard_group.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
|
@ -1204,6 +1205,15 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n
|
||||||
ipc_event_window(container, "focus");
|
ipc_event_window(container, "focus");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (last_workspace && last_workspace != new_workspace) {
|
||||||
|
wlr_ext_workspace_handle_v1_set_active(last_workspace->ext_workspace,
|
||||||
|
workspace_is_visible(last_workspace));
|
||||||
|
}
|
||||||
|
if (new_workspace) {
|
||||||
|
wlr_ext_workspace_handle_v1_set_active(new_workspace->ext_workspace,
|
||||||
|
workspace_is_visible(new_workspace));
|
||||||
|
}
|
||||||
|
|
||||||
// Move sticky containers to new workspace
|
// Move sticky containers to new workspace
|
||||||
if (new_workspace && new_output_last_ws
|
if (new_workspace && new_output_last_ws
|
||||||
&& new_workspace != new_output_last_ws) {
|
&& new_workspace != new_output_last_ws) {
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
|
#include "sway/tree/workspace.h"
|
||||||
|
|
||||||
#if WLR_HAS_XWAYLAND
|
#if WLR_HAS_XWAYLAND
|
||||||
#include <wlr/xwayland/shell.h>
|
#include <wlr/xwayland/shell.h>
|
||||||
|
|
@ -377,6 +378,7 @@ bool server_init(struct sway_server *server) {
|
||||||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||||
|
|
||||||
sway_session_lock_init();
|
sway_session_lock_init();
|
||||||
|
sway_ext_workspace_init();
|
||||||
|
|
||||||
#if WLR_HAS_DRM_BACKEND
|
#if WLR_HAS_DRM_BACKEND
|
||||||
server->drm_lease_manager=
|
server->drm_lease_manager=
|
||||||
|
|
@ -543,6 +545,7 @@ void server_fini(struct sway_server *server) {
|
||||||
wl_list_remove(&server->xdg_toplevel_tag_manager_v1_set_tag.link);
|
wl_list_remove(&server->xdg_toplevel_tag_manager_v1_set_tag.link);
|
||||||
wl_list_remove(&server->request_set_cursor_shape.link);
|
wl_list_remove(&server->request_set_cursor_shape.link);
|
||||||
wl_list_remove(&server->new_foreign_toplevel_capture_request.link);
|
wl_list_remove(&server->new_foreign_toplevel_capture_request.link);
|
||||||
|
wl_list_remove(&server->workspace_manager_v1_commit.link);
|
||||||
input_manager_finish(server->input);
|
input_manager_finish(server->input);
|
||||||
|
|
||||||
// TODO: free sway-specific resources
|
// TODO: free sway-specific resources
|
||||||
|
|
|
||||||
|
|
@ -198,19 +198,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
static void text_calc_size(struct text_buffer *buffer) {
|
static void text_calc_size(struct text_buffer *buffer) {
|
||||||
struct sway_text_node *props = &buffer->props;
|
struct sway_text_node *props = &buffer->props;
|
||||||
|
|
||||||
cairo_t *c = cairo_create(NULL);
|
cairo_surface_t *recorder = cairo_recording_surface_create(
|
||||||
if (!c) {
|
CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
||||||
sway_log(SWAY_ERROR, "cairo_t allocation failed");
|
cairo_t *c = cairo_create(recorder);
|
||||||
return;
|
cairo_surface_destroy(recorder);
|
||||||
|
if (cairo_status(c) != CAIRO_STATUS_SUCCESS) {
|
||||||
|
sway_log(SWAY_ERROR, "cairo_t allocation failed: %s",
|
||||||
|
cairo_status_to_string(cairo_status(c)));
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
|
cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
|
||||||
get_text_size(c, config->font_description, &props->width, NULL,
|
get_text_size(c, config->font_description, &props->width, NULL,
|
||||||
&props->baseline, 1, props->pango_markup, "%s", buffer->text);
|
&props->baseline, 1, props->pango_markup, "%s", buffer->text);
|
||||||
cairo_destroy(c);
|
|
||||||
|
|
||||||
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
|
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
|
||||||
get_text_width(props), props->height);
|
get_text_width(props), props->height);
|
||||||
|
out:
|
||||||
|
cairo_destroy(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
|
struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||||
|
#include "sway/tree/workspace.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
#include "sway/layers.h"
|
#include "sway/layers.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
|
|
@ -153,6 +155,7 @@ void output_enable(struct sway_output *output) {
|
||||||
output->enabled = true;
|
output->enabled = true;
|
||||||
list_add(root->outputs, output);
|
list_add(root->outputs, output);
|
||||||
|
|
||||||
|
sway_ext_workspace_output_enable(output);
|
||||||
restore_workspaces(output);
|
restore_workspaces(output);
|
||||||
|
|
||||||
struct sway_workspace *ws = NULL;
|
struct sway_workspace *ws = NULL;
|
||||||
|
|
@ -292,6 +295,7 @@ void output_disable(struct sway_output *output) {
|
||||||
|
|
||||||
destroy_layers(output);
|
destroy_layers(output);
|
||||||
output_evacuate(output);
|
output_evacuate(output);
|
||||||
|
sway_ext_workspace_output_disable(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_begin_destroy(struct sway_output *output) {
|
void output_begin_destroy(struct sway_output *output) {
|
||||||
|
|
@ -333,6 +337,10 @@ void output_add_workspace(struct sway_output *output,
|
||||||
}
|
}
|
||||||
list_add(output->workspaces, workspace);
|
list_add(output->workspaces, workspace);
|
||||||
workspace->output = output;
|
workspace->output = output;
|
||||||
|
if (workspace->output && workspace->output->ext_workspace_group) {
|
||||||
|
wlr_ext_workspace_handle_v1_set_group(workspace->ext_workspace,
|
||||||
|
workspace->output->ext_workspace_group);
|
||||||
|
}
|
||||||
node_set_dirty(&output->node);
|
node_set_dirty(&output->node);
|
||||||
node_set_dirty(&workspace->node);
|
node_set_dirty(&workspace->node);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -988,7 +988,7 @@ void view_center_and_clip_surface(struct sway_view *view) {
|
||||||
|
|
||||||
bool clip_to_geometry = true;
|
bool clip_to_geometry = true;
|
||||||
|
|
||||||
if (container_is_floating(con)) {
|
if (container_is_floating(con) || con->pending.fullscreen_mode != FULLSCREEN_NONE) {
|
||||||
// We always center the current coordinates rather than the next, as the
|
// We always center the current coordinates rather than the next, as the
|
||||||
// geometry immediately affects the currently active rendering.
|
// geometry immediately affects the currently active rendering.
|
||||||
int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2);
|
int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2);
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,12 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||||
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
|
|
@ -17,9 +21,124 @@
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/view.h"
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
static const uint32_t WORKSPACE_CAPABILITIES =
|
||||||
|
EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ACTIVATE |
|
||||||
|
EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ASSIGN;
|
||||||
|
|
||||||
|
static const uint32_t GROUP_CAPABILITIES =
|
||||||
|
EXT_WORKSPACE_GROUP_HANDLE_V1_GROUP_CAPABILITIES_CREATE_WORKSPACE;
|
||||||
|
|
||||||
|
// Helper to find the output associated with a workspace group.
|
||||||
|
static struct sway_output *group_to_output(
|
||||||
|
struct wlr_ext_workspace_group_handle_v1 *group) {
|
||||||
|
for (int i = 0; i < root->outputs->length; i++) {
|
||||||
|
struct sway_output *output = root->outputs->items[i];
|
||||||
|
if (output->ext_workspace_group == group) {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
abort(); // unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback for ext-workspace-v1 commit events.
|
||||||
|
static void handle_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_server *server =
|
||||||
|
wl_container_of(listener, server, workspace_manager_v1_commit);
|
||||||
|
struct wlr_ext_workspace_v1_commit_event *event = data;
|
||||||
|
|
||||||
|
struct wlr_ext_workspace_v1_request *req, *tmp;
|
||||||
|
wl_list_for_each_safe(req, tmp, event->requests, link) {
|
||||||
|
switch (req->type) {
|
||||||
|
case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE:
|
||||||
|
if (req->activate.workspace) {
|
||||||
|
workspace_switch(req->activate.workspace->data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE:;
|
||||||
|
struct sway_output *output = group_to_output(req->create_workspace.group);
|
||||||
|
sway_assert(output, "NULL output given to create_workspace");
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
if (req->create_workspace.name) {
|
||||||
|
if (workspace_by_name(req->create_workspace.name)) {
|
||||||
|
sway_log(SWAY_ERROR, "Refusing to create workspace with duplicate name.");
|
||||||
|
break; // Already exists.
|
||||||
|
}
|
||||||
|
name = strdup(req->create_workspace.name);
|
||||||
|
} else {
|
||||||
|
name = workspace_next_name(output->wlr_output->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_workspace *new_ws = workspace_create(output, name);
|
||||||
|
if (new_ws) {
|
||||||
|
workspace_switch(new_ws);
|
||||||
|
}
|
||||||
|
free(name);
|
||||||
|
break;
|
||||||
|
case WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN:;
|
||||||
|
if (!req->assign.workspace || !req->assign.group) break;
|
||||||
|
|
||||||
|
struct sway_workspace *ws = req->assign.workspace->data;
|
||||||
|
struct sway_output *new_output = group_to_output(req->assign.group);
|
||||||
|
struct sway_output *old_output = ws->output;
|
||||||
|
workspace_move_to_output(ws, new_output);
|
||||||
|
arrange_output(old_output);
|
||||||
|
arrange_output(new_output);
|
||||||
|
break;
|
||||||
|
case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE:
|
||||||
|
case WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE:
|
||||||
|
break; // No-op.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction_commit_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize ext-workspace. Must be called once at startup.
|
||||||
|
void sway_ext_workspace_init(void) {
|
||||||
|
server.workspace_manager_v1 =
|
||||||
|
wlr_ext_workspace_manager_v1_create(server.wl_display, 1);
|
||||||
|
if (!server.workspace_manager_v1) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to create ext_workspace_manager_v1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
server.workspace_manager_v1_commit.notify = handle_commit;
|
||||||
|
wl_signal_add(&server.workspace_manager_v1->events.commit,
|
||||||
|
&server.workspace_manager_v1_commit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be called whenever an output is enabled.
|
||||||
|
void sway_ext_workspace_output_enable(struct sway_output *output) {
|
||||||
|
if (!output->wlr_output) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->ext_workspace_group =
|
||||||
|
wlr_ext_workspace_group_handle_v1_create(
|
||||||
|
server.workspace_manager_v1, GROUP_CAPABILITIES);
|
||||||
|
if (!output->ext_workspace_group) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to create workspace group for output '%s'",
|
||||||
|
output->wlr_output->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_ext_workspace_group_handle_v1_output_enter(
|
||||||
|
output->ext_workspace_group, output->wlr_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be called whenever an output is disabled.
|
||||||
|
void sway_ext_workspace_output_disable(struct sway_output *output) {
|
||||||
|
if (!output->ext_workspace_group) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_ext_workspace_group_handle_v1_destroy(output->ext_workspace_group);
|
||||||
|
output->ext_workspace_group = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct workspace_config *workspace_find_config(const char *ws_name) {
|
struct workspace_config *workspace_find_config(const char *ws_name) {
|
||||||
for (int i = 0; i < config->workspace_configs->length; ++i) {
|
for (int i = 0; i < config->workspace_configs->length; ++i) {
|
||||||
struct workspace_config *wsc = config->workspace_configs->items[i];
|
struct workspace_config *wsc = config->workspace_configs->items[i];
|
||||||
|
|
@ -70,6 +189,16 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
||||||
sway_log(SWAY_ERROR, "Unable to allocate sway_workspace");
|
sway_log(SWAY_ERROR, "Unable to allocate sway_workspace");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ws->ext_workspace = wlr_ext_workspace_handle_v1_create(
|
||||||
|
server.workspace_manager_v1, NULL, WORKSPACE_CAPABILITIES);
|
||||||
|
if (!ws->ext_workspace) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to create ext_workspace for '%s'", name);
|
||||||
|
free(ws);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ws->ext_workspace->data = ws;
|
||||||
|
|
||||||
node_init(&ws->node, N_WORKSPACE, ws);
|
node_init(&ws->node, N_WORKSPACE, ws);
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
|
@ -79,6 +208,7 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
||||||
if (failed) {
|
if (failed) {
|
||||||
wlr_scene_node_destroy(&ws->layers.tiling->node);
|
wlr_scene_node_destroy(&ws->layers.tiling->node);
|
||||||
wlr_scene_node_destroy(&ws->layers.fullscreen->node);
|
wlr_scene_node_destroy(&ws->layers.fullscreen->node);
|
||||||
|
wlr_ext_workspace_handle_v1_destroy(ws->ext_workspace);
|
||||||
free(ws);
|
free(ws);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -127,6 +257,13 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
||||||
output_add_workspace(output, ws);
|
output_add_workspace(output, ws);
|
||||||
output_sort_workspaces(output);
|
output_sort_workspaces(output);
|
||||||
|
|
||||||
|
wlr_ext_workspace_handle_v1_set_name(ws->ext_workspace, ws->name);
|
||||||
|
if (ws->output && ws->output->ext_workspace_group) {
|
||||||
|
wlr_ext_workspace_handle_v1_set_group(ws->ext_workspace,
|
||||||
|
ws->output->ext_workspace_group);
|
||||||
|
}
|
||||||
|
wlr_ext_workspace_handle_v1_set_active(ws->ext_workspace,
|
||||||
|
workspace_is_visible(ws));
|
||||||
ipc_event_workspace(NULL, ws, "init");
|
ipc_event_workspace(NULL, ws, "init");
|
||||||
wl_signal_emit_mutable(&root->events.new_node, &ws->node);
|
wl_signal_emit_mutable(&root->events.new_node, &ws->node);
|
||||||
|
|
||||||
|
|
@ -163,6 +300,9 @@ void workspace_begin_destroy(struct sway_workspace *workspace) {
|
||||||
ipc_event_workspace(NULL, workspace, "empty"); // intentional
|
ipc_event_workspace(NULL, workspace, "empty"); // intentional
|
||||||
wl_signal_emit_mutable(&workspace->node.events.destroy, &workspace->node);
|
wl_signal_emit_mutable(&workspace->node.events.destroy, &workspace->node);
|
||||||
|
|
||||||
|
wlr_ext_workspace_handle_v1_destroy(workspace->ext_workspace);
|
||||||
|
workspace->ext_workspace = NULL;
|
||||||
|
|
||||||
if (workspace->output) {
|
if (workspace->output) {
|
||||||
workspace_detach(workspace);
|
workspace_detach(workspace);
|
||||||
}
|
}
|
||||||
|
|
@ -687,6 +827,7 @@ void workspace_detect_urgent(struct sway_workspace *workspace) {
|
||||||
|
|
||||||
if (workspace->urgent != new_urgent) {
|
if (workspace->urgent != new_urgent) {
|
||||||
workspace->urgent = new_urgent;
|
workspace->urgent = new_urgent;
|
||||||
|
wlr_ext_workspace_handle_v1_set_urgent(workspace->ext_workspace, workspace->urgent);
|
||||||
ipc_event_workspace(NULL, workspace, "urgent");
|
ipc_event_workspace(NULL, workspace, "urgent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -985,3 +1126,35 @@ void workspace_squash(struct sway_workspace *workspace) {
|
||||||
i += container_squash(child);
|
i += container_squash(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void workspace_move_to_output(struct sway_workspace *workspace,
|
||||||
|
struct sway_output *output) {
|
||||||
|
if (workspace->output == output) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct sway_output *old_output = workspace->output;
|
||||||
|
workspace_detach(workspace);
|
||||||
|
struct sway_workspace *new_output_old_ws =
|
||||||
|
output_get_active_workspace(output);
|
||||||
|
if (!sway_assert(new_output_old_ws, "Expected output to have a workspace")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output_add_workspace(output, workspace);
|
||||||
|
|
||||||
|
// If moving the last workspace from the old output, create a new workspace
|
||||||
|
// on the old output
|
||||||
|
if (old_output->workspaces->length == 0) {
|
||||||
|
char *ws_name = workspace_next_name(old_output->wlr_output->name);
|
||||||
|
struct sway_workspace *ws = workspace_create(old_output, ws_name);
|
||||||
|
free(ws_name);
|
||||||
|
struct sway_seat *seat = input_manager_current_seat();
|
||||||
|
seat_set_raw_focus(seat, &ws->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace_consider_destroy(new_output_old_ws);
|
||||||
|
|
||||||
|
output_sort_workspaces(output);
|
||||||
|
workspace_output_raise_priority(workspace, old_output, output);
|
||||||
|
ipc_event_workspace(NULL, workspace, "move");
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue