mirror of
https://github.com/swaywm/sway.git
synced 2026-04-16 08:21:30 -04:00
Merge branch 'master' into save-previous
This commit is contained in:
commit
0c45122862
24 changed files with 373 additions and 123 deletions
|
|
@ -84,28 +84,47 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
|
|||
|
||||
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
|
||||
int *baseline, double scale, bool markup, const char *fmt, ...) {
|
||||
if (width) {
|
||||
*width = 0;
|
||||
}
|
||||
if (height) {
|
||||
*height = 0;
|
||||
}
|
||||
if (baseline) {
|
||||
*baseline = 0;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *buf = vformat_str(fmt, args);
|
||||
va_end(args);
|
||||
if (buf == NULL) {
|
||||
sway_log(SWAY_ERROR, "Failed to format string");
|
||||
return;
|
||||
}
|
||||
|
||||
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
|
||||
pango_cairo_update_layout(cairo, layout);
|
||||
cairo_status_t status = cairo_status(cairo);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
sway_log(SWAY_ERROR, "pango_cairo_update_layout() failed: %s",
|
||||
cairo_status_to_string(status));
|
||||
goto out;
|
||||
}
|
||||
|
||||
pango_layout_get_pixel_size(layout, width, height);
|
||||
if (baseline) {
|
||||
*baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
|
||||
}
|
||||
g_object_unref(layout);
|
||||
|
||||
out:
|
||||
g_object_unref(layout);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) {
|
||||
cairo_t *cairo = cairo_create(NULL);
|
||||
PangoContext *pango = pango_cairo_create_context(cairo);
|
||||
PangoFontMap *fontmap = pango_cairo_font_map_get_default();
|
||||
PangoContext *pango = pango_font_map_create_context(fontmap);
|
||||
pango_context_set_round_glyph_positions(pango, false);
|
||||
// When passing NULL as a language, pango uses the current locale.
|
||||
PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);
|
||||
|
|
@ -115,7 +134,6 @@ void get_text_metrics(const PangoFontDescription *description, int *height, int
|
|||
|
||||
pango_font_metrics_unref(metrics);
|
||||
g_object_unref(pango);
|
||||
cairo_destroy(cairo);
|
||||
}
|
||||
|
||||
void render_text(cairo_t *cairo, const PangoFontDescription *desc,
|
||||
|
|
@ -125,6 +143,7 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
|
|||
char *buf = vformat_str(fmt, args);
|
||||
va_end(args);
|
||||
if (buf == NULL) {
|
||||
sway_log(SWAY_ERROR, "Failed to format string");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -133,9 +152,18 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
|
|||
cairo_get_font_options(cairo, fo);
|
||||
pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo);
|
||||
cairo_font_options_destroy(fo);
|
||||
pango_cairo_update_layout(cairo, layout);
|
||||
pango_cairo_show_layout(cairo, layout);
|
||||
g_object_unref(layout);
|
||||
|
||||
pango_cairo_update_layout(cairo, layout);
|
||||
cairo_status_t status = cairo_status(cairo);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
sway_log(SWAY_ERROR, "pango_cairo_update_layout() failed: %s",
|
||||
cairo_status_to_string(status));
|
||||
goto out;
|
||||
}
|
||||
|
||||
pango_cairo_show_layout(cairo, layout);
|
||||
|
||||
out:
|
||||
g_object_unref(layout);
|
||||
free(buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ struct sway_layer_popup {
|
|||
struct wl_listener destroy;
|
||||
struct wl_listener new_popup;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener reposition;
|
||||
};
|
||||
|
||||
struct sway_output;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ struct sway_output {
|
|||
struct wl_listener request_state;
|
||||
|
||||
struct wlr_color_transform *color_transform;
|
||||
struct wlr_ext_workspace_group_handle_v1 *ext_workspace_group;
|
||||
|
||||
struct timespec last_presentation;
|
||||
uint32_t refresh_nsec;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,9 @@ struct sway_server {
|
|||
struct wl_listener tearing_control_new_object;
|
||||
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
|
||||
|
||||
// The timeout for transactions, after which a transaction is applied
|
||||
|
|
|
|||
|
|
@ -93,8 +93,7 @@ struct sway_container {
|
|||
struct wlr_scene_tree *content_tree;
|
||||
struct wlr_scene_buffer *output_handler;
|
||||
|
||||
struct wl_listener output_enter;
|
||||
struct wl_listener output_leave;
|
||||
struct wl_listener outputs_update;
|
||||
struct wl_listener output_handler_destroy;
|
||||
|
||||
struct sway_container_state current;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
|
@ -52,6 +53,7 @@ struct sway_workspace {
|
|||
bool urgent;
|
||||
|
||||
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);
|
||||
|
|
@ -158,4 +160,11 @@ size_t workspace_num_sticky_containers(struct sway_workspace *ws);
|
|||
*/
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
project(
|
||||
'sway',
|
||||
'c',
|
||||
version: '1.12-dev',
|
||||
version: '1.13-dev',
|
||||
license: 'MIT',
|
||||
meson_version: '>=1.3',
|
||||
default_options: [
|
||||
|
|
@ -39,14 +39,14 @@ if is_freebsd
|
|||
endif
|
||||
|
||||
# Execute the wlroots subproject, if any
|
||||
wlroots_version = ['>=0.20.0', '<0.21.0']
|
||||
wlroots_version = ['>=0.21.0', '<0.22.0']
|
||||
subproject(
|
||||
'wlroots',
|
||||
default_options: ['examples=false'],
|
||||
required: false,
|
||||
version: wlroots_version,
|
||||
)
|
||||
wlroots = dependency('wlroots-0.20', version: wlroots_version, fallback: 'wlroots')
|
||||
wlroots = dependency('wlroots-0.21', version: wlroots_version, fallback: 'wlroots')
|
||||
wlroots_features = {
|
||||
'xwayland': false,
|
||||
'libinput_backend': false,
|
||||
|
|
@ -110,7 +110,7 @@ conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd
|
|||
conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind')
|
||||
conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu')
|
||||
conf_data.set10('HAVE_TRAY', have_tray)
|
||||
foreach sym : ['LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', 'LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY']
|
||||
foreach sym : ['LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', 'LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY', 'LIBINPUT_SWITCH_KEYPAD_SLIDE']
|
||||
conf_data.set10('HAVE_' + sym, cc.has_header_symbol('libinput.h', sym, dependencies: libinput))
|
||||
endforeach
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwlr_layer_shell_v1" version="4">
|
||||
<interface name="zwlr_layer_shell_v1" version="5">
|
||||
<description summary="create surfaces that are layers of the desktop">
|
||||
Clients can use this interface to assign the surface_layer role to
|
||||
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
|
||||
|
|
@ -100,7 +100,7 @@
|
|||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_layer_surface_v1" version="4">
|
||||
<interface name="zwlr_layer_surface_v1" version="5">
|
||||
<description summary="layer metadata interface">
|
||||
An interface that may be implemented by a wl_surface, for surfaces that
|
||||
are designed to be rendered as a layer of a stacked desktop-like
|
||||
|
|
@ -367,6 +367,7 @@
|
|||
<entry name="invalid_size" value="1" summary="size is invalid"/>
|
||||
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
|
||||
<entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/>
|
||||
<entry name="invalid_exclusive_edge" value="4" summary="exclusive edge is invalid given the surface anchors"/>
|
||||
</enum>
|
||||
|
||||
<enum name="anchor" bitfield="true">
|
||||
|
|
@ -386,5 +387,21 @@
|
|||
</description>
|
||||
<arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 5 additions -->
|
||||
|
||||
<request name="set_exclusive_edge" since="5">
|
||||
<description summary="set the edge the exclusive zone will be applied to">
|
||||
Requests an edge for the exclusive zone to apply. The exclusive
|
||||
edge will be automatically deduced from anchor points when possible,
|
||||
but when the surface is anchored to a corner, it will be necessary
|
||||
to set it explicitly to disambiguate, as it is not possible to deduce
|
||||
which one of the two corner edges should be used.
|
||||
|
||||
The edge must be one the surface is anchored to, otherwise the
|
||||
invalid_exclusive_edge protocol error will be raised.
|
||||
</description>
|
||||
<arg name="edge" type="uint" enum="anchor"/>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
<request name="get_output_power">
|
||||
<description summary="get a power management for an output">
|
||||
Create a output power management mode control that can be used to
|
||||
Create an output power management mode control that can be used to
|
||||
adjust the power management mode for a given output.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
</enum>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_mode" value="1" summary="inexistent power save mode"/>
|
||||
<entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_mode">
|
||||
|
|
|
|||
|
|
@ -543,6 +543,10 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
|
|||
binding->type = WLR_SWITCH_TYPE_TABLET_MODE;
|
||||
} else if (strcmp(split->items[0], "lid") == 0) {
|
||||
binding->type = WLR_SWITCH_TYPE_LID;
|
||||
#if HAVE_LIBINPUT_SWITCH_KEYPAD_SLIDE
|
||||
} else if (strcmp(split->items[0], "keypad_slide") == 0) {
|
||||
binding->type = WLR_SWITCH_TYPE_KEYPAD_SLIDE;
|
||||
#endif
|
||||
} else {
|
||||
free_switch_binding(binding);
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
|
|
|
|||
|
|
@ -627,40 +627,6 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
|
|||
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) {
|
||||
struct cmd_results *error = NULL;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
#include "sway/commands.h"
|
||||
|
|
@ -95,6 +96,8 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
|
|||
free(workspace->name);
|
||||
workspace->name = new_name;
|
||||
|
||||
wlr_ext_workspace_handle_v1_set_name(workspace->ext_workspace, workspace->name);
|
||||
|
||||
output_sort_workspaces(workspace->output);
|
||||
ipc_event_workspace(NULL, workspace, "rename");
|
||||
|
||||
|
|
|
|||
|
|
@ -555,8 +555,10 @@ static void queue_output_config(struct output_config *oc,
|
|||
}
|
||||
|
||||
bool hdr = oc && oc->hdr == 1;
|
||||
if (hdr && oc->color_transform != NULL) {
|
||||
sway_log(SWAY_ERROR, "Cannot HDR on output %s: output has an ICC profile set", wlr_output->name);
|
||||
bool color_profile = oc && (oc->color_transform != NULL
|
||||
|| oc->color_profile == COLOR_PROFILE_TRANSFORM_WITH_DEVICE_PRIMARIES);
|
||||
if (hdr && color_profile) {
|
||||
sway_log(SWAY_ERROR, "Cannot use HDR on output %s: output has a color profile set", wlr_output->name);
|
||||
hdr = false;
|
||||
}
|
||||
set_hdr(wlr_output, pending, hdr);
|
||||
|
|
|
|||
|
|
@ -196,6 +196,10 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
struct sway_container *focus = seat_get_focused_container(seat);
|
||||
struct sway_view *focused = focus ? focus->view : NULL;
|
||||
|
||||
if (!view->container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (criteria->title) {
|
||||
const char *title = view_get_title(view);
|
||||
if (!title) {
|
||||
|
|
@ -204,7 +208,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->title->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(title, view_get_title(focused))) {
|
||||
if (!focused || lenient_strcmp(title, view_get_title(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -224,7 +228,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->shell->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && strcmp(shell, view_get_shell(focused))) {
|
||||
if (!focused || strcmp(shell, view_get_shell(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -244,7 +248,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->app_id->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(app_id, view_get_app_id(focused))) {
|
||||
if (!focused || lenient_strcmp(app_id, view_get_app_id(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -264,7 +268,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->sandbox_engine->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(sandbox_engine, view_get_sandbox_engine(focused))) {
|
||||
if (!focused || lenient_strcmp(sandbox_engine, view_get_sandbox_engine(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -284,7 +288,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->sandbox_app_id->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(sandbox_app_id, view_get_sandbox_app_id(focused))) {
|
||||
if (!focused || lenient_strcmp(sandbox_app_id, view_get_sandbox_app_id(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -304,7 +308,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->sandbox_instance_id->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(sandbox_instance_id, view_get_sandbox_instance_id(focused))) {
|
||||
if (!focused || lenient_strcmp(sandbox_instance_id, view_get_sandbox_instance_id(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -324,7 +328,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->tag->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(tag, view_get_tag(focused))) {
|
||||
if (!focused || lenient_strcmp(tag, view_get_tag(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -356,7 +360,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->class->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(class, view_get_class(focused))) {
|
||||
if (!focused || lenient_strcmp(class, view_get_class(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -376,7 +380,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->instance->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(instance, view_get_instance(focused))) {
|
||||
if (!focused || lenient_strcmp(instance, view_get_instance(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -396,7 +400,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->window_role->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused && lenient_strcmp(window_role, view_get_window_role(focused))) {
|
||||
if (!focused || lenient_strcmp(window_role, view_get_window_role(focused))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -454,7 +458,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
|
||||
switch (criteria->workspace->match_type) {
|
||||
case PATTERN_FOCUSED:
|
||||
if (focused &&
|
||||
if (!focused ||
|
||||
strcmp(ws->name, focused->container->pending.workspace->name)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
|||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
wl_list_remove(&popup->commit.link);
|
||||
wl_list_remove(&popup->reposition.link);
|
||||
free(popup);
|
||||
}
|
||||
|
||||
|
|
@ -356,6 +357,11 @@ static void popup_handle_commit(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void popup_handle_reposition(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_popup *popup = wl_container_of(listener, popup, reposition);
|
||||
popup_unconstrain(popup);
|
||||
}
|
||||
|
||||
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
|
||||
|
||||
static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
|
||||
|
|
@ -376,11 +382,13 @@ static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
|
|||
}
|
||||
|
||||
popup->destroy.notify = popup_handle_destroy;
|
||||
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||
wl_signal_add(&wlr_popup->events.destroy, &popup->destroy);
|
||||
popup->new_popup.notify = popup_handle_new_popup;
|
||||
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||
popup->commit.notify = popup_handle_commit;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||
popup->reposition.notify = popup_handle_reposition;
|
||||
wl_signal_add(&wlr_popup->events.reposition, &popup->reposition);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -648,15 +648,7 @@ static void arrange_root(struct sway_root *root) {
|
|||
for (int i = 0; i < root->scratchpad->length; i++) {
|
||||
struct sway_container *con = root->scratchpad->items[i];
|
||||
|
||||
// When a container is moved to a scratchpad, it's possible that it
|
||||
// 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);
|
||||
}
|
||||
|
||||
disable_container(con);
|
||||
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/config.h>
|
||||
#include <wlr/types/wlr_cursor.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_keyboard_group.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");
|
||||
}
|
||||
|
||||
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
|
||||
if (new_workspace && new_output_last_ws
|
||||
&& new_workspace != new_output_last_ws) {
|
||||
|
|
|
|||
12
sway/main.c
12
sway/main.c
|
|
@ -381,14 +381,16 @@ int main(int argc, char **argv) {
|
|||
|
||||
struct swaynag_instance nag_gpu = (struct swaynag_instance){
|
||||
.args = "--type error "
|
||||
"--message 'Proprietary GPU drivers are not supported by sway. Do not report issues.' ",
|
||||
.detailed = false,
|
||||
"--message 'Proprietary GPU drivers are not supported by sway. Do not report issues.' "
|
||||
"--detailed-message",
|
||||
.detailed = true,
|
||||
};
|
||||
|
||||
if (unsupported_gpu_detected && !allow_unsupported_gpu) {
|
||||
if (!swaynag_spawn(config->swaynag_command, &nag_gpu)) {
|
||||
sway_log(SWAY_ERROR, "Unable to start swaynag");
|
||||
}
|
||||
swaynag_log(config->swaynag_command, &nag_gpu,
|
||||
"To remove this message, launch sway with --unsupported-gpu "
|
||||
"or set the environment variable SWAY_UNSUPPORTED_GPU=true.");
|
||||
swaynag_show(&nag_gpu);
|
||||
}
|
||||
|
||||
server_run(&server);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
#include "sway/server.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/tree/root.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
|
||||
#if WLR_HAS_XWAYLAND
|
||||
#include <wlr/xwayland/shell.h>
|
||||
|
|
@ -74,7 +75,7 @@
|
|||
#endif
|
||||
|
||||
#define SWAY_XDG_SHELL_VERSION 5
|
||||
#define SWAY_LAYER_SHELL_VERSION 4
|
||||
#define SWAY_LAYER_SHELL_VERSION 5
|
||||
#define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1
|
||||
#define SWAY_PRESENTATION_VERSION 2
|
||||
|
||||
|
|
@ -272,7 +273,7 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) {
|
||||
server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer(
|
||||
server->wl_display, 4, server->renderer);
|
||||
server->wl_display, 5, server->renderer);
|
||||
}
|
||||
if (wlr_renderer_get_drm_fd(server->renderer) >= 0 &&
|
||||
server->renderer->features.timeline &&
|
||||
|
|
@ -377,6 +378,7 @@ bool server_init(struct sway_server *server) {
|
|||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||
|
||||
sway_session_lock_init();
|
||||
sway_ext_workspace_init();
|
||||
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
server->drm_lease_manager=
|
||||
|
|
@ -440,7 +442,7 @@ bool server_init(struct sway_server *server) {
|
|||
&server->xdg_toplevel_tag_manager_v1_set_tag);
|
||||
|
||||
struct wlr_cursor_shape_manager_v1 *cursor_shape_manager =
|
||||
wlr_cursor_shape_manager_v1_create(server->wl_display, 1);
|
||||
wlr_cursor_shape_manager_v1_create(server->wl_display, 2);
|
||||
server->request_set_cursor_shape.notify = handle_request_set_cursor_shape;
|
||||
wl_signal_add(&cursor_shape_manager->events.request_set_shape, &server->request_set_cursor_shape);
|
||||
|
||||
|
|
@ -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->request_set_cursor_shape.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);
|
||||
|
||||
// TODO: free sway-specific resources
|
||||
|
|
|
|||
|
|
@ -506,11 +506,12 @@ runtime.
|
|||
|
||||
*bindswitch* [--locked] [--no-warn] [--reload] <switch>:<state> <command>
|
||||
Binds <switch> to execute the sway command _command_ on state changes.
|
||||
Supported switches are _lid_ (laptop lid) and _tablet_ (tablet mode)
|
||||
switches. Valid values for _state_ are _on_, _off_ and _toggle_. These
|
||||
switches are on when the device lid is shut and when tablet mode is active
|
||||
respectively. _toggle_ is also supported to run a command both when the
|
||||
switch is toggled on or off.
|
||||
Supported switches are _lid_ (laptop lid), _tablet_ (tablet mode) and
|
||||
_keypad_slide_ (whether the device keypad is exposed or not) switches. Valid
|
||||
values for _state_ are _on_, _off_ and _toggle_. These switches are on when
|
||||
the device lid is shut, when tablet mode is active and when the keypad is
|
||||
exposed respectively. _toggle_ is also supported to run a command both when
|
||||
the switch is toggled on or off.
|
||||
|
||||
Unless the flag _--locked_ is set, the command will not be run when a
|
||||
screen locking program is active. If there is a matching binding with
|
||||
|
|
|
|||
|
|
@ -198,19 +198,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
|||
static void text_calc_size(struct text_buffer *buffer) {
|
||||
struct sway_text_node *props = &buffer->props;
|
||||
|
||||
cairo_t *c = cairo_create(NULL);
|
||||
if (!c) {
|
||||
sway_log(SWAY_ERROR, "cairo_t allocation failed");
|
||||
return;
|
||||
cairo_surface_t *recorder = cairo_recording_surface_create(
|
||||
CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
||||
cairo_t *c = cairo_create(recorder);
|
||||
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);
|
||||
get_text_size(c, config->font_description, &props->width, NULL,
|
||||
&props->baseline, 1, props->pango_markup, "%s", buffer->text);
|
||||
cairo_destroy(c);
|
||||
|
||||
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
|
||||
get_text_width(props), props->height);
|
||||
out:
|
||||
cairo_destroy(c);
|
||||
}
|
||||
|
||||
struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
|
||||
|
|
|
|||
|
|
@ -25,27 +25,34 @@
|
|||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
|
||||
static void handle_output_enter(
|
||||
static void handle_outputs_update(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct sway_container *con = wl_container_of(
|
||||
listener, con, output_enter);
|
||||
struct wlr_scene_output *output = data;
|
||||
listener, con, outputs_update);
|
||||
struct wlr_scene_outputs_update_event *event = data;
|
||||
|
||||
if (con->view->foreign_toplevel) {
|
||||
wlr_foreign_toplevel_handle_v1_output_enter(
|
||||
con->view->foreign_toplevel, output->output);
|
||||
}
|
||||
}
|
||||
struct wlr_foreign_toplevel_handle_v1 *toplevel = con->view->foreign_toplevel;
|
||||
if (toplevel) {
|
||||
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output, *tmp;
|
||||
wl_list_for_each_safe(toplevel_output, tmp, &toplevel->outputs, link) {
|
||||
bool active = false;
|
||||
for (size_t i = 0; i < event->size; i++) {
|
||||
struct wlr_scene_output *scene_output = event->active[i];
|
||||
if (scene_output->output == toplevel_output->output) {
|
||||
active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_output_leave(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct sway_container *con = wl_container_of(
|
||||
listener, con, output_leave);
|
||||
struct wlr_scene_output *output = data;
|
||||
if (!active) {
|
||||
wlr_foreign_toplevel_handle_v1_output_leave(toplevel, toplevel_output->output);
|
||||
}
|
||||
}
|
||||
|
||||
if (con->view->foreign_toplevel) {
|
||||
wlr_foreign_toplevel_handle_v1_output_leave(
|
||||
con->view->foreign_toplevel, output->output);
|
||||
for (size_t i = 0; i < event->size; i++) {
|
||||
struct wlr_scene_output *scene_output = event->active[i];
|
||||
wlr_foreign_toplevel_handle_v1_output_enter(toplevel, scene_output->output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,12 +143,9 @@ struct sway_container *container_create(struct sway_view *view) {
|
|||
}
|
||||
|
||||
if (!failed) {
|
||||
c->output_enter.notify = handle_output_enter;
|
||||
wl_signal_add(&c->output_handler->events.output_enter,
|
||||
&c->output_enter);
|
||||
c->output_leave.notify = handle_output_leave;
|
||||
wl_signal_add(&c->output_handler->events.output_leave,
|
||||
&c->output_leave);
|
||||
c->outputs_update.notify = handle_outputs_update;
|
||||
wl_signal_add(&c->output_handler->events.outputs_update,
|
||||
&c->outputs_update);
|
||||
c->output_handler_destroy.notify = handle_destroy;
|
||||
wl_signal_add(&c->output_handler->node.events.destroy,
|
||||
&c->output_handler_destroy);
|
||||
|
|
@ -562,8 +566,7 @@ void container_begin_destroy(struct sway_container *con) {
|
|||
}
|
||||
|
||||
if (con->view && con->view->container == con) {
|
||||
wl_list_remove(&con->output_enter.link);
|
||||
wl_list_remove(&con->output_leave.link);
|
||||
wl_list_remove(&con->outputs_update.link);
|
||||
wl_list_remove(&con->output_handler_destroy.link);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "sway/ipc-server.h"
|
||||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
|
|
@ -158,6 +160,7 @@ void output_enable(struct sway_output *output) {
|
|||
output->enabled = true;
|
||||
list_add(root->outputs, output);
|
||||
|
||||
sway_ext_workspace_output_enable(output);
|
||||
restore_workspaces(output);
|
||||
|
||||
struct sway_workspace *ws = NULL;
|
||||
|
|
@ -297,6 +300,7 @@ void output_disable(struct sway_output *output) {
|
|||
|
||||
destroy_layers(output);
|
||||
output_evacuate(output);
|
||||
sway_ext_workspace_output_disable(output);
|
||||
}
|
||||
|
||||
void output_begin_destroy(struct sway_output *output) {
|
||||
|
|
@ -338,6 +342,10 @@ void output_add_workspace(struct sway_output *output,
|
|||
}
|
||||
list_add(output->workspaces, workspace);
|
||||
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(&workspace->node);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,12 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_ext_workspace_v1.h>
|
||||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/seat.h"
|
||||
|
|
@ -17,9 +21,124 @@
|
|||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "list.h"
|
||||
#include "log.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) {
|
||||
for (int i = 0; i < config->workspace_configs->length; ++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");
|
||||
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);
|
||||
|
||||
bool failed = false;
|
||||
|
|
@ -79,6 +208,7 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
|||
if (failed) {
|
||||
wlr_scene_node_destroy(&ws->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&ws->layers.fullscreen->node);
|
||||
wlr_ext_workspace_handle_v1_destroy(ws->ext_workspace);
|
||||
free(ws);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -128,6 +258,13 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
|||
output_add_workspace(output, ws);
|
||||
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");
|
||||
wl_signal_emit_mutable(&root->events.new_node, &ws->node);
|
||||
|
||||
|
|
@ -165,6 +302,9 @@ void workspace_begin_destroy(struct sway_workspace *workspace) {
|
|||
ipc_event_workspace(NULL, workspace, "empty"); // intentional
|
||||
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) {
|
||||
workspace_detach(workspace);
|
||||
}
|
||||
|
|
@ -204,8 +344,10 @@ static bool workspace_valid_on_output(const char *output_name,
|
|||
}
|
||||
|
||||
for (int i = 0; i < wsc->outputs->length; i++) {
|
||||
if (output_match_name_or_id(output, wsc->outputs->items[i])) {
|
||||
return true;
|
||||
struct sway_output *ws_output =
|
||||
output_by_name_or_id(wsc->outputs->items[i]);
|
||||
if (ws_output) {
|
||||
return ws_output == output;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -320,10 +462,14 @@ char *workspace_next_name(const char *output_name) {
|
|||
}
|
||||
bool found = false;
|
||||
for (int j = 0; j < wsc->outputs->length; ++j) {
|
||||
if (output_match_name_or_id(output, wsc->outputs->items[j])) {
|
||||
found = true;
|
||||
free(target);
|
||||
target = strdup(wsc->workspace);
|
||||
struct sway_output *ws_output =
|
||||
output_by_name_or_id(wsc->outputs->items[j]);
|
||||
if (ws_output) {
|
||||
if (ws_output == output) {
|
||||
found = true;
|
||||
free(target);
|
||||
target = strdup(wsc->workspace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -681,6 +827,7 @@ void workspace_detect_urgent(struct sway_workspace *workspace) {
|
|||
|
||||
if (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");
|
||||
}
|
||||
}
|
||||
|
|
@ -985,3 +1132,35 @@ void workspace_squash(struct sway_workspace *workspace) {
|
|||
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