Merge branch 'master' into master

This commit is contained in:
Brian Ashworth 2018-08-08 15:26:44 -04:00 committed by GitHub
commit 3c26536267
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 697 additions and 281 deletions

View file

@ -76,10 +76,6 @@ Führe diese Befehle aus:
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
In Systemen mit logind musst du `sway` einige Capabilities geben:
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
In Systemen ohne logind musst du `sway` das suid-Flag geben: In Systemen ohne logind musst du `sway` das suid-Flag geben:
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway

View file

@ -69,10 +69,6 @@ _\*\*Απαιτείται μόνο για swaylock_
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
Σε συστήματα με logind, χρειάζεται να ορίσετε μερικά δικαιώματα caps στο εκτελέσιμο αρχείο:
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
Σε συστήματα χωρίς logind, χρειάζεται να θέσετε το suid bit στο εκτελέσιμο αρχείο: Σε συστήματα χωρίς logind, χρειάζεται να θέσετε το suid bit στο εκτελέσιμο αρχείο:
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway

View file

@ -71,10 +71,6 @@ Exécutez ces commandes :
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
Sur les systèmes avec logind, vous devez définir quelques caps sur le binaire :
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
Sur les systèmes sans logind, vous devez suid le binaire de sway : Sur les systèmes sans logind, vous devez suid le binaire de sway :
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway

View file

@ -72,10 +72,6 @@ Esegui questi comandi:
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
Per i sistemi con logind, devi impostare un paio di caps sull'eseguibile:
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
Per i sistemi senza logind, devi cambiare i permessi (suid): Per i sistemi senza logind, devi cambiare i permessi (suid):
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway

View file

@ -62,14 +62,12 @@ _\*\*swaylockでのみ必要です_
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
logindを使用しているシステムでは、バイナリにいくつかのケーパビリティを設定する必要があります:
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
logindを使用していないシステムでは、バイナリにsuidを設定する必要があります: logindを使用していないシステムでは、バイナリにsuidを設定する必要があります:
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway
swayは起動後、すぐにroot許可を落とします。
## 設定 ## 設定
既にi3を使用している場合は、i3の設定ファイルを`~/.config/sway/config`にコピーすれば動きます。そうでない場合は、サンプルの設定ファイルを`~/.config/sway/config`にコピーしてください。サンプルの設定ファイルは、通常`/etc/sway/config`にあります。`man 5 sway`を実行することで、設定に関する情報を見ることができます。 既にi3を使用している場合は、i3の設定ファイルを`~/.config/sway/config`にコピーすれば動きます。そうでない場合は、サンプルの設定ファイルを`~/.config/sway/config`にコピーしてください。サンプルの設定ファイルは、通常`/etc/sway/config`にあります。`man 5 sway`を実行することで、設定に関する情報を見ることができます。

View file

@ -72,14 +72,12 @@ Run these commands:
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
On systems with logind, you need to set a few caps on the binary:
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
On systems without logind, you need to suid the sway binary: On systems without logind, you need to suid the sway binary:
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway
Sway will drop root permissions shortly after startup.
## Configuration ## Configuration
If you already use i3, then copy your i3 config to `~/.config/sway/config` and If you already use i3, then copy your i3 config to `~/.config/sway/config` and

View file

@ -25,6 +25,7 @@ char *get_socketpath(void) {
if (line && *line) { if (line && *line) {
return line; return line;
} }
free(line);
} }
const char *i3sock = getenv("I3SOCK"); const char *i3sock = getenv("I3SOCK");
if (i3sock) { if (i3sock) {
@ -37,6 +38,7 @@ char *get_socketpath(void) {
if (line && *line) { if (line && *line) {
return line; return line;
} }
free(line);
} }
return NULL; return NULL;
} }

17
include/sway/decoration.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef _SWAY_DECORATION_H
#define _SWAY_DECORATION_H
#include <wlr/types/wlr_server_decoration.h>
struct sway_server_decoration {
struct wlr_server_decoration *wlr_server_decoration;
struct wl_list link;
struct wl_listener destroy;
struct wl_listener mode;
};
struct sway_server_decoration *decoration_from_surface(
struct wlr_surface *surface);
#endif

View file

@ -4,12 +4,13 @@
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/backend/session.h> #include <wlr/backend/session.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_layer_shell.h> #include <wlr/types/wlr_layer_shell.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xdg_shell_v6.h>
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include <wlr/render/wlr_renderer.h>
// TODO WLR: make Xwayland optional // TODO WLR: make Xwayland optional
#include "list.h" #include "list.h"
#include "config.h" #include "config.h"
@ -42,11 +43,17 @@ struct sway_server {
struct wlr_xdg_shell *xdg_shell; struct wlr_xdg_shell *xdg_shell;
struct wl_listener xdg_shell_surface; struct wl_listener xdg_shell_surface;
#ifdef HAVE_XWAYLAND #ifdef HAVE_XWAYLAND
struct sway_xwayland xwayland; struct sway_xwayland xwayland;
struct wl_listener xwayland_surface; struct wl_listener xwayland_surface;
struct wl_listener xwayland_ready; struct wl_listener xwayland_ready;
#endif #endif
struct wlr_server_decoration_manager *server_decoration_manager;
struct wl_listener server_decoration;
struct wl_list decorations; // sway_server_decoration::link
bool debug_txn_timings; bool debug_txn_timings;
list_t *transactions; list_t *transactions;
@ -71,4 +78,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
#ifdef HAVE_XWAYLAND #ifdef HAVE_XWAYLAND
void handle_xwayland_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data);
#endif #endif
void handle_server_decoration(struct wl_listener *listener, void *data);
#endif #endif

View file

@ -113,7 +113,7 @@ struct sway_container {
enum sway_container_type type; enum sway_container_type type;
enum sway_container_layout layout; enum sway_container_layout layout;
enum sway_container_layout prev_layout; enum sway_container_layout prev_split_layout;
bool is_sticky; bool is_sticky;
@ -322,12 +322,23 @@ void container_get_box(struct sway_container *container, struct wlr_box *box);
void container_floating_translate(struct sway_container *con, void container_floating_translate(struct sway_container *con,
double x_amount, double y_amount); double x_amount, double y_amount);
/**
* Choose an output for the floating container's new position.
*/
struct sway_container *container_floating_find_output(
struct sway_container *con);
/** /**
* Move a floating container to a new layout-local position. * Move a floating container to a new layout-local position.
*/ */
void container_floating_move_to(struct sway_container *con, void container_floating_move_to(struct sway_container *con,
double lx, double ly); double lx, double ly);
/**
* Move a floating container to the center of the workspace.
*/
void container_floating_move_to_center(struct sway_container *con);
/** /**
* Mark a container as dirty if it isn't already. Dirty containers will be * Mark a container as dirty if it isn't already. Dirty containers will be
* included in the next transaction then unmarked as dirty. * included in the next transaction then unmarked as dirty.

View file

@ -118,6 +118,8 @@ struct sway_view {
struct sway_xdg_shell_v6_view { struct sway_xdg_shell_v6_view {
struct sway_view view; struct sway_view view;
enum wlr_server_decoration_manager_mode deco_mode;
struct wl_listener commit; struct wl_listener commit;
struct wl_listener request_move; struct wl_listener request_move;
struct wl_listener request_resize; struct wl_listener request_resize;
@ -134,6 +136,8 @@ struct sway_xdg_shell_v6_view {
struct sway_xdg_shell_view { struct sway_xdg_shell_view {
struct sway_view view; struct sway_view view;
enum wlr_server_decoration_manager_mode deco_mode;
struct wl_listener commit; struct wl_listener commit;
struct wl_listener request_move; struct wl_listener request_move;
struct wl_listener request_resize; struct wl_listener request_resize;
@ -315,6 +319,11 @@ void view_update_title(struct sway_view *view, bool force);
*/ */
void view_execute_criteria(struct sway_view *view); void view_execute_criteria(struct sway_view *view);
/**
* Find any view that has the given mark and return it.
*/
struct sway_view *view_find_mark(char *mark);
/** /**
* Find any view that has the given mark and remove the mark from the view. * Find any view that has the given mark and remove the mark from the view.
* Returns true if it matched a view. * Returns true if it matched a view.

View file

@ -1,6 +1,7 @@
#ifndef _SWAY_WORKSPACE_H #ifndef _SWAY_WORKSPACE_H
#define _SWAY_WORKSPACE_H #define _SWAY_WORKSPACE_H
#include <stdbool.h>
#include "sway/tree/container.h" #include "sway/tree/container.h"
struct sway_view; struct sway_view;
@ -15,9 +16,12 @@ struct sway_workspace {
extern char *prev_workspace_name; extern char *prev_workspace_name;
struct sway_container *workspace_get_initial_output(const char *name);
char *workspace_next_name(const char *output_name); char *workspace_next_name(const char *output_name);
bool workspace_switch(struct sway_container *workspace); bool workspace_switch(struct sway_container *workspace,
bool no_auto_back_and_forth);
struct sway_container *workspace_by_number(const char* name); struct sway_container *workspace_by_number(const char* name);

View file

@ -1,3 +1,4 @@
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include "sway/commands.h" #include "sway/commands.h"
@ -5,6 +6,26 @@
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "log.h" #include "log.h"
static bool parse_layout_string(char *s, enum sway_container_layout *ptr) {
if (strcasecmp(s, "splith") == 0) {
*ptr = L_HORIZ;
} else if (strcasecmp(s, "splitv") == 0) {
*ptr = L_VERT;
} else if (strcasecmp(s, "tabbed") == 0) {
*ptr = L_TABBED;
} else if (strcasecmp(s, "stacking") == 0) {
*ptr = L_STACKED;
} else {
return false;
}
return true;
}
static const char* expected_syntax =
"Expected 'layout default|tabbed|stacking|splitv|splith' or "
"'layout toggle [split|all]' or "
"'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'";
struct cmd_results *cmd_layout(int argc, char **argv) { struct cmd_results *cmd_layout(int argc, char **argv) {
struct cmd_results *error = NULL; struct cmd_results *error = NULL;
if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) {
@ -21,35 +42,69 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
parent = parent->parent; parent = parent->parent;
} }
if (strcasecmp(argv[0], "default") == 0) { enum sway_container_layout prev = parent->layout;
parent->layout = parent->prev_layout; bool assigned_directly = parse_layout_string(argv[0], &parent->layout);
if (parent->layout == L_NONE) { if (!assigned_directly) {
parent->layout = container_get_default_layout(parent); if (strcasecmp(argv[0], "default") == 0) {
} parent->layout = parent->prev_split_layout;
} else { } else if (strcasecmp(argv[0], "toggle") == 0) {
if (parent->layout != L_TABBED && parent->layout != L_STACKED) { if (argc == 1) {
parent->prev_layout = parent->layout; parent->layout =
} parent->layout == L_STACKED ? L_TABBED :
parent->layout == L_TABBED ? parent->prev_split_layout : L_STACKED;
if (strcasecmp(argv[0], "splith") == 0) { } else if (argc == 2) {
parent->layout = L_HORIZ; if (strcasecmp(argv[1], "all") == 0) {
} else if (strcasecmp(argv[0], "splitv") == 0) { parent->layout =
parent->layout = L_VERT; parent->layout == L_HORIZ ? L_VERT :
} else if (strcasecmp(argv[0], "tabbed") == 0) { parent->layout == L_VERT ? L_STACKED :
parent->layout = L_TABBED; parent->layout == L_STACKED ? L_TABBED : L_HORIZ;
} else if (strcasecmp(argv[0], "stacking") == 0) { } else if (strcasecmp(argv[1], "split") == 0) {
parent->layout = L_STACKED; parent->layout =
} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { parent->layout == L_HORIZ ? L_VERT :
if (parent->layout == L_HORIZ) { parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout;
parent->layout = L_VERT; } else {
return cmd_results_new(CMD_INVALID, "layout", expected_syntax);
}
} else { } else {
parent->layout = L_HORIZ; enum sway_container_layout parsed_layout;
int curr = 1;
for (; curr < argc; curr++) {
bool valid = parse_layout_string(argv[curr], &parsed_layout);
if ((valid && parsed_layout == parent->layout) ||
(strcmp(argv[curr], "split") == 0 &&
(parent->layout == L_VERT || parent->layout == L_HORIZ))) {
break;
}
}
for (int i = curr + 1; i != curr; ++i) {
// cycle round to find next valid layout
if (i >= argc) {
i = 1;
}
if (parse_layout_string(argv[i], &parent->layout)) {
break;
} else if (strcmp(argv[i], "split") == 0) {
parent->layout =
parent->layout == L_HORIZ ? L_VERT :
parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout;
break;
} // invalid layout strings are silently ignored
}
} }
} else {
return cmd_results_new(CMD_INVALID, "layout", expected_syntax);
} }
} }
if (parent->layout == L_NONE) {
container_notify_subtree_changed(parent); parent->layout = container_get_default_layout(parent);
arrange_windows(parent); }
if (prev != parent->layout) {
if (prev != L_TABBED && prev != L_STACKED) {
parent->prev_split_layout = prev;
}
container_notify_subtree_changed(parent);
arrange_windows(parent);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }

View file

@ -1,4 +1,5 @@
#define _XOPEN_SOURCE 500 #define _XOPEN_SOURCE 500
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
@ -8,6 +9,7 @@
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/input/cursor.h" #include "sway/input/cursor.h"
#include "sway/input/seat.h" #include "sway/input/seat.h"
#include "sway/ipc-server.h"
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/arrange.h" #include "sway/tree/arrange.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
@ -15,12 +17,13 @@
#include "sway/tree/workspace.h" #include "sway/tree/workspace.h"
#include "stringop.h" #include "stringop.h"
#include "list.h" #include "list.h"
#include "log.h"
static const char* expected_syntax = static const char *expected_syntax =
"Expected 'move <left|right|up|down> <[px] px>' or " "Expected 'move <left|right|up|down> <[px] px>' or "
"'move <container|window> to workspace <name>' or " "'move [--no-auto-back-and-forth] <container|window> [to] workspace <name>' or "
"'move <container|window|workspace> to output <name|direction>' or " "'move [--no-auto-back-and-forth] <container|window|workspace> [to] output <name|direction>' or "
"'move position mouse'"; "'move <container|window> [to] mark <mark>'";
static struct sway_container *output_in_direction(const char *direction, static struct sway_container *output_in_direction(const char *direction,
struct wlr_output *reference, int ref_lx, int ref_ly) { struct wlr_output *reference, int ref_lx, int ref_ly) {
@ -52,128 +55,236 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
int argc, char **argv) { int argc, char **argv) {
struct cmd_results *error = NULL; struct cmd_results *error = NULL;
if ((error = checkarg(argc, "move container/window", if ((error = checkarg(argc, "move container/window",
EXPECTED_AT_LEAST, 4))) { EXPECTED_AT_LEAST, 3))) {
return error; return error;
} else if (strcasecmp(argv[1], "to") == 0 }
&& strcasecmp(argv[2], "workspace") == 0) {
// move container to workspace x
if (current->type == C_WORKSPACE) {
if (current->children->length == 0) {
return cmd_results_new(CMD_FAILURE, "move",
"Can't move an empty workspace");
}
current = container_wrap_children(current);
} else if (current->type != C_CONTAINER && current->type != C_VIEW) {
return cmd_results_new(CMD_FAILURE, "move",
"Can only move containers and views.");
}
struct sway_container *ws;
char *ws_name = NULL;
if (argc == 5 && strcasecmp(argv[3], "number") == 0) {
// move "container to workspace number x"
ws_name = strdup(argv[4]);
ws = workspace_by_number(ws_name);
} else {
ws_name = join_args(argv + 3, argc - 3);
ws = workspace_by_name(ws_name);
}
if (config->auto_back_and_forth && prev_workspace_name) { if (current->type == C_WORKSPACE) {
// auto back and forth move if (current->children->length == 0) {
struct sway_container *curr_ws = container_parent(current, C_WORKSPACE); return cmd_results_new(CMD_FAILURE, "move",
if (curr_ws->name && strcmp(curr_ws->name, ws_name) == 0) { "Can't move an empty workspace");
// if target workspace is the current one }
free(ws_name); current = container_wrap_children(current);
ws_name = strdup(prev_workspace_name); } else if (current->type != C_CONTAINER && current->type != C_VIEW) {
return cmd_results_new(CMD_FAILURE, "move",
"Can only move containers and views.");
}
bool no_auto_back_and_forth = false;
while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) {
no_auto_back_and_forth = true;
if (--argc < 3) {
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
}
++argv;
}
while (strcasecmp(argv[1], "--no-auto-back-and-forth") == 0) {
no_auto_back_and_forth = true;
if (--argc < 3) {
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
}
argv++;
}
while (strcasecmp(argv[1], "to") == 0) {
if (--argc < 3) {
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
}
argv++;
}
struct sway_container *old_parent = current->parent;
struct sway_container *old_ws = container_parent(current, C_WORKSPACE);
struct sway_container *destination = NULL;
// determine destination
if (strcasecmp(argv[1], "workspace") == 0) {
// move container to workspace x
struct sway_container *ws = NULL;
char *ws_name = NULL;
if (strcasecmp(argv[2], "next") == 0 ||
strcasecmp(argv[2], "prev") == 0 ||
strcasecmp(argv[2], "next_on_output") == 0 ||
strcasecmp(argv[2], "prev_on_output") == 0 ||
strcasecmp(argv[2], "current") == 0) {
ws = workspace_by_name(argv[2]);
} else if (strcasecmp(argv[2], "back_and_forth") == 0) {
if (!(ws = workspace_by_name(argv[2]))) {
if (prev_workspace_name) {
ws_name = strdup(prev_workspace_name);
} else {
return cmd_results_new(CMD_FAILURE, "move",
"No workspace was previously active.");
}
}
} else {
if (strcasecmp(argv[2], "number") == 0) {
// move "container to workspace number x"
if (argc < 4) {
return cmd_results_new(CMD_INVALID, "move",
expected_syntax);
}
ws_name = strdup(argv[3]);
ws = workspace_by_number(ws_name);
} else {
ws_name = join_args(argv + 2, argc - 2);
ws = workspace_by_name(ws_name); ws = workspace_by_name(ws_name);
} }
}
if (!no_auto_back_and_forth && config->auto_back_and_forth &&
prev_workspace_name) {
// auto back and forth move
if (old_ws->name && strcmp(old_ws->name, ws_name) == 0) {
// if target workspace is the current one
free(ws_name);
ws_name = strdup(prev_workspace_name);
ws = workspace_by_name(ws_name);
}
}
}
if (!ws) { if (!ws) {
// We have to create the workspace, but if the container is
// sticky and the workspace is going to be created on the same
// output, we'll bail out first.
if (container_is_floating(current) && current->is_sticky) {
struct sway_container *old_output =
container_parent(current, C_OUTPUT);
struct sway_container *new_output =
workspace_get_initial_output(ws_name);
if (old_output == new_output) {
free(ws_name);
return cmd_results_new(CMD_FAILURE, "move",
"Can't move sticky container to another workspace "
"on the same output");
}
}
ws = workspace_create(NULL, ws_name); ws = workspace_create(NULL, ws_name);
} }
free(ws_name); free(ws_name);
struct sway_container *old_parent = current->parent; destination = seat_get_focus_inactive(config->handler_context.seat, ws);
struct sway_container *old_ws = container_parent(current, C_WORKSPACE); } else if (strcasecmp(argv[1], "output") == 0) {
struct sway_container *destination = seat_get_focus_inactive(
config->handler_context.seat, ws);
container_move_to(current, destination);
struct sway_container *focus = seat_get_focus_inactive(
config->handler_context.seat, old_parent);
seat_set_focus_warp(config->handler_context.seat, focus, true, false);
container_reap_empty(old_parent);
container_reap_empty(destination->parent);
// TODO: Ideally we would arrange the surviving parent after reaping,
// but container_reap_empty does not return it, so we arrange the
// workspace instead.
arrange_windows(old_ws);
arrange_windows(destination->parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} else if (strcasecmp(argv[1], "to") == 0
&& strcasecmp(argv[2], "output") == 0) {
if (current->type == C_WORKSPACE) {
// TODO: Wrap children in a container and move that
return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
} else if (current->type != C_CONTAINER
&& current->type != C_VIEW) {
return cmd_results_new(CMD_FAILURE, "move",
"Can only move containers and views.");
}
struct sway_container *source = container_parent(current, C_OUTPUT); struct sway_container *source = container_parent(current, C_OUTPUT);
struct sway_container *destination = output_in_direction(argv[3], struct sway_container *dest_output = output_in_direction(argv[2],
source->sway_output->wlr_output, current->x, current->y); source->sway_output->wlr_output, current->x, current->y);
if (!destination) { if (!dest_output) {
return cmd_results_new(CMD_FAILURE, "move workspace", return cmd_results_new(CMD_FAILURE, "move workspace",
"Can't find output with name/direction '%s'", argv[3]); "Can't find output with name/direction '%s'", argv[2]);
} }
struct sway_container *focus = seat_get_focus_inactive( destination = seat_get_focus_inactive(
config->handler_context.seat, destination); config->handler_context.seat, dest_output);
if (!focus) { if (!destination) {
// We've never been to this output before // We've never been to this output before
focus = destination->children->items[0]; destination = dest_output->children->items[0];
} }
struct sway_container *old_parent = current->parent; } else if (strcasecmp(argv[1], "mark") == 0) {
struct sway_container *old_ws = container_parent(current, C_WORKSPACE); struct sway_view *dest_view = view_find_mark(argv[2]);
container_move_to(current, focus); if (dest_view == NULL) {
seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); return cmd_results_new(CMD_FAILURE, "move",
container_reap_empty(old_parent); "Mark '%s' not found", argv[2]);
container_reap_empty(focus->parent); }
destination = dest_view->swayc;
// TODO: Ideally we would arrange the surviving parent after reaping, } else {
// but container_reap_empty does not return it, so we arrange the return cmd_results_new(CMD_INVALID, "move", expected_syntax);
// workspace instead.
arrange_windows(old_ws);
arrange_windows(focus->parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
if (container_is_floating(current) && current->is_sticky) {
struct sway_container *old_output = container_parent(current, C_OUTPUT);
struct sway_container *new_output = destination->type == C_OUTPUT ?
destination : container_parent(destination, C_OUTPUT);
if (old_output == new_output) {
return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky "
"container to another workspace on the same output");
}
}
// move container, arrange windows and return focus
container_move_to(current, destination);
struct sway_container *focus =
seat_get_focus_inactive(config->handler_context.seat, old_parent);
seat_set_focus_warp(config->handler_context.seat, focus, true, false);
container_reap_empty(old_parent);
container_reap_empty(destination->parent);
// TODO: Ideally we would arrange the surviving parent after reaping,
// but container_reap_empty does not return it, so we arrange the
// workspace instead.
arrange_windows(old_ws);
arrange_windows(destination->parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
static void workspace_move_to_output(struct sway_container *workspace,
struct sway_container *output) {
if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
return;
}
if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
return;
}
if (workspace->parent == output) {
return;
}
struct sway_container *old_output = container_remove_child(workspace);
struct sway_seat *seat = input_manager_get_default_seat(input_manager);
struct sway_container *new_output_focus =
seat_get_focus_inactive(seat, output);
container_add_child(output, workspace);
wl_signal_emit(&workspace->events.reparent, old_output);
// If moving the last workspace from the old output, create a new workspace
// on the old output
if (old_output->children->length == 0) {
char *ws_name = workspace_next_name(old_output->name);
struct sway_container *ws = workspace_create(old_output, ws_name);
free(ws_name);
seat_set_focus(seat, ws);
}
// Try to remove an empty workspace from the destination output.
container_reap_empty_recursive(new_output_focus);
container_sort_workspaces(output);
seat_set_focus(seat, output);
workspace_output_raise_priority(workspace, old_output, output);
ipc_event_workspace(NULL, workspace, "move");
container_notify_subtree_changed(old_output);
container_notify_subtree_changed(output);
} }
static struct cmd_results *cmd_move_workspace(struct sway_container *current, static struct cmd_results *cmd_move_workspace(struct sway_container *current,
int argc, char **argv) { int argc, char **argv) {
struct cmd_results *error = NULL; struct cmd_results *error = NULL;
if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) {
return error; return error;
} else if (strcasecmp(argv[1], "to") != 0 }
|| strcasecmp(argv[2], "output") != 0) {
while (strcasecmp(argv[1], "to") == 0) {
if (--argc < 3) {
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
}
++argv;
}
if (strcasecmp(argv[1], "output") != 0) {
return cmd_results_new(CMD_INVALID, "move", expected_syntax); return cmd_results_new(CMD_INVALID, "move", expected_syntax);
} }
struct sway_container *source = container_parent(current, C_OUTPUT); struct sway_container *source = container_parent(current, C_OUTPUT);
int center_x = current->width / 2 + current->x, int center_x = current->width / 2 + current->x,
center_y = current->height / 2 + current->y; center_y = current->height / 2 + current->y;
struct sway_container *destination = output_in_direction(argv[3], struct sway_container *destination = output_in_direction(argv[2],
source->sway_output->wlr_output, center_x, center_y); source->sway_output->wlr_output, center_x, center_y);
if (!destination) { if (!destination) {
return cmd_results_new(CMD_FAILURE, "move workspace", return cmd_results_new(CMD_FAILURE, "move workspace",
"Can't find output with name/direction '%s'", argv[3]); "Can't find output with name/direction '%s'", argv[2]);
} }
if (current->type != C_WORKSPACE) { if (current->type != C_WORKSPACE) {
current = container_parent(current, C_WORKSPACE); current = container_parent(current, C_WORKSPACE);
} }
container_move_to(current, destination); workspace_move_to_output(current, destination);
arrange_windows(source); arrange_windows(source);
arrange_windows(destination); arrange_windows(destination);
@ -242,9 +353,9 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }
static const char* expected_position_syntax = static const char *expected_position_syntax =
"Expected 'move [absolute] position <x> <y>' or " "Expected 'move [absolute] position <x> [px] <y> [px]' or "
"'move [absolute] position mouse'"; "'move [absolute] position center|mouse'";
static struct cmd_results *move_to_position(struct sway_container *container, static struct cmd_results *move_to_position(struct sway_container *container,
int argc, char **argv) { int argc, char **argv) {
@ -279,10 +390,18 @@ static struct cmd_results *move_to_position(struct sway_container *container,
double ly = seat->cursor->cursor->y - container->height / 2; double ly = seat->cursor->cursor->y - container->height / 2;
container_floating_move_to(container, lx, ly); container_floating_move_to(container, lx, ly);
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} else if (strcmp(argv[0], "center") == 0) {
struct sway_container *ws = container_parent(container, C_WORKSPACE);
double lx = ws->x + (ws->width - container->width) / 2;
double ly = ws->y + (ws->height - container->height) / 2;
container_floating_move_to(container, lx, ly);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }
if (argc != 2) {
if (argc < 2) {
return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
} }
double lx, ly; double lx, ly;
char *inv; char *inv;
lx = (double)strtol(argv[0], &inv, 10); lx = (double)strtol(argv[0], &inv, 10);
@ -290,11 +409,22 @@ static struct cmd_results *move_to_position(struct sway_container *container,
return cmd_results_new(CMD_FAILURE, "move", return cmd_results_new(CMD_FAILURE, "move",
"Invalid position specified"); "Invalid position specified");
} }
if (strcmp(argv[1], "px") == 0) {
--argc;
++argv;
}
if (argc > 3) {
return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
}
ly = (double)strtol(argv[1], &inv, 10); ly = (double)strtol(argv[1], &inv, 10);
if (*inv != '\0' && strcasecmp(inv, "px") != 0) { if ((*inv != '\0' && strcasecmp(inv, "px") != 0) ||
(argc == 3 && strcmp(argv[2], "px") != 0)) {
return cmd_results_new(CMD_FAILURE, "move", return cmd_results_new(CMD_FAILURE, "move",
"Invalid position specified"); "Invalid position specified");
} }
container_floating_move_to(container, lx, ly); container_floating_move_to(container, lx, ly);
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }
@ -342,8 +472,11 @@ struct cmd_results *cmd_move(int argc, char **argv) {
return move_in_direction(current, MOVE_UP, argc, argv); return move_in_direction(current, MOVE_UP, argc, argv);
} else if (strcasecmp(argv[0], "down") == 0) { } else if (strcasecmp(argv[0], "down") == 0) {
return move_in_direction(current, MOVE_DOWN, argc, argv); return move_in_direction(current, MOVE_DOWN, argc, argv);
} else if (strcasecmp(argv[0], "container") == 0 } else if ((strcasecmp(argv[0], "container") == 0
|| strcasecmp(argv[0], "window") == 0) { || strcasecmp(argv[0], "window") == 0) ||
(strcasecmp(argv[0], "--no-auto-back-and-forth") &&
(strcasecmp(argv[0], "container") == 0
|| strcasecmp(argv[0], "window") == 0))) {
return cmd_move_container(current, argc, argv); return cmd_move_container(current, argc, argv);
} else if (strcasecmp(argv[0], "workspace") == 0) { } else if (strcasecmp(argv[0], "workspace") == 0) {
return cmd_move_workspace(current, argc, argv); return cmd_move_workspace(current, argc, argv);

View file

@ -61,6 +61,16 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
} }
char *new_name = join_args(argv + argn, argc - argn); char *new_name = join_args(argv + argn, argc - argn);
if (strcasecmp(new_name, "next") == 0 ||
strcasecmp(new_name, "prev") == 0 ||
strcasecmp(new_name, "next_on_output") == 0 ||
strcasecmp(new_name, "prev_on_output") == 0 ||
strcasecmp(new_name, "back_and_forth") == 0 ||
strcasecmp(new_name, "current") == 0) {
free(new_name);
return cmd_results_new(CMD_INVALID, "rename",
"Cannot use special workspace name '%s'", argv[argn]);
}
struct sway_container *tmp_workspace = workspace_by_name(new_name); struct sway_container *tmp_workspace = workspace_by_name(new_name);
if (tmp_workspace) { if (tmp_workspace) {
free(new_name); free(new_name);

View file

@ -17,17 +17,6 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
int output_location = -1; int output_location = -1;
struct sway_container *current_container = config->handler_context.current_container;
struct sway_container *old_workspace = NULL, *old_output = NULL;
if (current_container) {
if (current_container->type == C_WORKSPACE) {
old_workspace = current_container;
} else {
old_workspace = container_parent(current_container, C_WORKSPACE);
}
old_output = container_parent(current_container, C_OUTPUT);
}
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
if (strcasecmp(argv[i], "output") == 0) { if (strcasecmp(argv[i], "output") == 0) {
output_location = i; output_location = i;
@ -57,29 +46,36 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
if (config->reading || !config->active) { if (config->reading || !config->active) {
return cmd_results_new(CMD_DEFER, "workspace", NULL); return cmd_results_new(CMD_DEFER, "workspace", NULL);
} }
bool no_auto_back_and_forth = false;
while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) {
no_auto_back_and_forth = true;
if ((error = checkarg(--argc, "workspace", EXPECTED_AT_LEAST, 1))) {
return error;
}
++argv;
}
struct sway_container *ws = NULL; struct sway_container *ws = NULL;
if (strcasecmp(argv[0], "number") == 0) { if (strcasecmp(argv[0], "number") == 0) {
if (argc < 2) {
cmd_results_new(CMD_INVALID, "workspace",
"Expected workspace number");
}
if (!(ws = workspace_by_number(argv[1]))) { if (!(ws = workspace_by_number(argv[1]))) {
char *name = join_args(argv + 1, argc - 1); char *name = join_args(argv + 1, argc - 1);
ws = workspace_create(NULL, name); ws = workspace_create(NULL, name);
free(name); free(name);
} }
} else if (strcasecmp(argv[0], "next") == 0) { } else if (strcasecmp(argv[0], "next") == 0 ||
ws = workspace_next(old_workspace); strcasecmp(argv[0], "prev") == 0 ||
} else if (strcasecmp(argv[0], "prev") == 0) { strcasecmp(argv[0], "next_on_output") == 0 ||
ws = workspace_prev(old_workspace); strcasecmp(argv[0], "prev_on_output") == 0 ||
} else if (strcasecmp(argv[0], "next_on_output") == 0) { strcasecmp(argv[0], "current") == 0) {
ws = workspace_output_next(old_output); ws = workspace_by_name(argv[0]);
} else if (strcasecmp(argv[0], "prev_on_output") == 0) {
ws = workspace_output_prev(old_output);
} else if (strcasecmp(argv[0], "back_and_forth") == 0) { } else if (strcasecmp(argv[0], "back_and_forth") == 0) {
// if auto_back_and_forth is enabled, workspace_switch will swap if (!(ws = workspace_by_name(argv[0])) && prev_workspace_name) {
// the workspaces. If we created prev_workspace here, workspace_switch
// would put us back on original workspace.
if (config->auto_back_and_forth) {
ws = old_workspace;
} else if (prev_workspace_name
&& !(ws = workspace_by_name(prev_workspace_name))) {
ws = workspace_create(NULL, prev_workspace_name); ws = workspace_create(NULL, prev_workspace_name);
} }
} else { } else {
@ -89,7 +85,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
} }
free(name); free(name);
} }
workspace_switch(ws); workspace_switch(ws, no_auto_back_and_forth);
} }
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }

View file

@ -361,8 +361,17 @@ static char *get_focused_prop(enum criteria_token token) {
} }
} }
break; break;
case T_CON_ID: // These do not support __focused__ case T_CON_ID:
case T_CON_MARK: if (view->swayc == NULL) {
return NULL;
}
size_t id = view->swayc->id;
size_t id_size = snprintf(NULL, 0, "%zu", id) + 1;
char *id_str = malloc(id_size);
snprintf(id_str, id_size, "%zu", id);
value = id_str;
break;
case T_CON_MARK: // These do not support __focused__
case T_FLOATING: case T_FLOATING:
#ifdef HAVE_XWAYLAND #ifdef HAVE_XWAYLAND
case T_ID: case T_ID:
@ -425,7 +434,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
case T_CON_ID: case T_CON_ID:
criteria->con_id = strtoul(effective_value, &endptr, 10); criteria->con_id = strtoul(effective_value, &endptr, 10);
if (*endptr != 0) { if (*endptr != 0) {
error = strdup("The value for 'con_id' should be numeric"); error = strdup("The value for 'con_id' should be '__focused__' or numeric");
} }
break; break;
case T_CON_MARK: case T_CON_MARK:
@ -452,13 +461,18 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
criteria->tiling = true; criteria->tiling = true;
break; break;
case T_URGENT: case T_URGENT:
if (strcmp(effective_value, "latest") == 0) { if (strcmp(effective_value, "latest") == 0 ||
strcmp(effective_value, "newest") == 0 ||
strcmp(effective_value, "last") == 0 ||
strcmp(effective_value, "recent") == 0) {
criteria->urgent = 'l'; criteria->urgent = 'l';
} else if (strcmp(effective_value, "oldest") == 0) { } else if (strcmp(effective_value, "oldest") == 0 ||
strcmp(effective_value, "first") == 0) {
criteria->urgent = 'o'; criteria->urgent = 'o';
} else { } else {
error = error =
strdup("The value for 'urgent' must be 'latest' or 'oldest'"); strdup("The value for 'urgent' must be 'first', 'last', "
"'latest', 'newest', 'oldest' or 'recent'");
} }
break; break;
case T_WORKSPACE: case T_WORKSPACE:

71
sway/decoration.c Normal file
View file

@ -0,0 +1,71 @@
#include <stdlib.h>
#include "sway/decoration.h"
#include "sway/server.h"
#include "sway/tree/view.h"
#include "log.h"
static void server_decoration_handle_destroy(struct wl_listener *listener,
void *data) {
struct sway_server_decoration *deco =
wl_container_of(listener, deco, destroy);
wl_list_remove(&deco->destroy.link);
wl_list_remove(&deco->mode.link);
wl_list_remove(&deco->link);
free(deco);
}
static void server_decoration_handle_mode(struct wl_listener *listener,
void *data) {
struct sway_server_decoration *deco =
wl_container_of(listener, deco, mode);
struct sway_view *view =
view_from_wlr_surface(deco->wlr_server_decoration->surface);
if (view == NULL || view->surface != deco->wlr_server_decoration->surface) {
return;
}
switch (view->type) {
case SWAY_VIEW_XDG_SHELL_V6:;
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
(struct sway_xdg_shell_v6_view *)view;
xdg_shell_v6_view->deco_mode = deco->wlr_server_decoration->mode;
break;
case SWAY_VIEW_XDG_SHELL:;
struct sway_xdg_shell_view *xdg_shell_view =
(struct sway_xdg_shell_view *)view;
xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode;
break;
default:
break;
}
}
void handle_server_decoration(struct wl_listener *listener, void *data) {
struct wlr_server_decoration *wlr_deco = data;
struct sway_server_decoration *deco = calloc(1, sizeof(*deco));
if (deco == NULL) {
return;
}
deco->wlr_server_decoration = wlr_deco;
wl_signal_add(&wlr_deco->events.destroy, &deco->destroy);
deco->destroy.notify = server_decoration_handle_destroy;
wl_signal_add(&wlr_deco->events.mode, &deco->mode);
deco->mode.notify = server_decoration_handle_mode;
wl_list_insert(&server.decorations, &deco->link);
}
struct sway_server_decoration *decoration_from_surface(
struct wlr_surface *surface) {
struct sway_server_decoration *deco;
wl_list_for_each(deco, &server.decorations, link) {
if (deco->wlr_server_decoration->surface == surface) {
return deco;
}
}
return NULL;
}

View file

@ -6,6 +6,7 @@
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/edges.h> #include <wlr/util/edges.h>
#include "log.h" #include "log.h"
#include "sway/decoration.h"
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
#include "sway/input/seat.h" #include "sway/input/seat.h"
#include "sway/server.h" #include "sway/server.h"
@ -170,6 +171,15 @@ static bool wants_floating(struct sway_view *view) {
|| toplevel->parent; || toplevel->parent;
} }
static bool has_client_side_decorations(struct sway_view *view) {
struct sway_xdg_shell_view *xdg_shell_view =
xdg_shell_view_from_view(view);
if (xdg_shell_view == NULL) {
return true;
}
return xdg_shell_view->deco_mode != WLR_SERVER_DECORATION_MANAGER_MODE_SERVER;
}
static void for_each_surface(struct sway_view *view, static void for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data) { wlr_surface_iterator_func_t iterator, void *user_data) {
if (xdg_shell_view_from_view(view) == NULL) { if (xdg_shell_view_from_view(view) == NULL) {
@ -226,6 +236,7 @@ static const struct sway_view_impl view_impl = {
.set_tiled = set_tiled, .set_tiled = set_tiled,
.set_fullscreen = set_fullscreen, .set_fullscreen = set_fullscreen,
.wants_floating = wants_floating, .wants_floating = wants_floating,
.has_client_side_decorations = has_client_side_decorations,
.for_each_surface = for_each_surface, .for_each_surface = for_each_surface,
.for_each_popup = for_each_popup, .for_each_popup = for_each_popup,
.close = _close, .close = _close,
@ -357,6 +368,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
view->natural_height = view->wlr_xdg_surface->surface->current.height; view->natural_height = view->wlr_xdg_surface->surface->current.height;
} }
struct sway_server_decoration *deco =
decoration_from_surface(xdg_surface->surface);
if (deco != NULL) {
xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode;
} else {
xdg_shell_view->deco_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
}
view_map(view, view->wlr_xdg_surface->surface); view_map(view, view->wlr_xdg_surface->surface);
if (xdg_surface->toplevel->client_pending.fullscreen) { if (xdg_surface->toplevel->client_pending.fullscreen) {

View file

@ -4,14 +4,15 @@
#include <stdlib.h> #include <stdlib.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xdg_shell_v6.h>
#include "log.h"
#include "sway/decoration.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/server.h" #include "sway/server.h"
#include "sway/tree/arrange.h" #include "sway/tree/arrange.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/layout.h" #include "sway/tree/layout.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/input/seat.h"
#include "sway/input/input-manager.h"
#include "log.h"
static const struct sway_view_child_impl popup_impl; static const struct sway_view_child_impl popup_impl;
@ -166,6 +167,15 @@ static bool wants_floating(struct sway_view *view) {
|| toplevel->parent; || toplevel->parent;
} }
static bool has_client_side_decorations(struct sway_view *view) {
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
xdg_shell_v6_view_from_view(view);
if (xdg_shell_v6_view == NULL) {
return true;
}
return xdg_shell_v6_view->deco_mode != WLR_SERVER_DECORATION_MANAGER_MODE_SERVER;
}
static void for_each_surface(struct sway_view *view, static void for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data) { wlr_surface_iterator_func_t iterator, void *user_data) {
if (xdg_shell_v6_view_from_view(view) == NULL) { if (xdg_shell_v6_view_from_view(view) == NULL) {
@ -223,6 +233,7 @@ static const struct sway_view_impl view_impl = {
.set_tiled = set_tiled, .set_tiled = set_tiled,
.set_fullscreen = set_fullscreen, .set_fullscreen = set_fullscreen,
.wants_floating = wants_floating, .wants_floating = wants_floating,
.has_client_side_decorations = has_client_side_decorations,
.for_each_surface = for_each_surface, .for_each_surface = for_each_surface,
.for_each_popup = for_each_popup, .for_each_popup = for_each_popup,
.close = _close, .close = _close,
@ -353,6 +364,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
view->natural_height = view->wlr_xdg_surface_v6->surface->current.height; view->natural_height = view->wlr_xdg_surface_v6->surface->current.height;
} }
struct sway_server_decoration *deco =
decoration_from_surface(xdg_surface->surface);
if (deco != NULL) {
xdg_shell_v6_view->deco_mode = deco->wlr_server_decoration->mode;
} else {
xdg_shell_v6_view->deco_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
}
view_map(view, view->wlr_xdg_surface_v6->surface); view_map(view, view->wlr_xdg_surface_v6->surface);
if (xdg_surface->toplevel->client_pending.fullscreen) { if (xdg_surface->toplevel->client_pending.fullscreen) {

View file

@ -429,6 +429,8 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
struct sway_container *cont) { struct sway_container *cont) {
struct sway_seat *seat = cursor->seat; struct sway_seat *seat = cursor->seat;
seat_set_focus(seat, cont);
// Deny moving or resizing a fullscreen container // Deny moving or resizing a fullscreen container
if (container_is_fullscreen_or_child(cont)) { if (container_is_fullscreen_or_child(cont)) {
seat_pointer_notify_button(seat, time_msec, button, state); seat_pointer_notify_button(seat, time_msec, button, state);
@ -469,8 +471,6 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
return; return;
} }
// Send event to surface
seat_set_focus(seat, cont);
seat_pointer_notify_button(seat, time_msec, button, state); seat_pointer_notify_button(seat, time_msec, button, state);
} }

View file

@ -717,12 +717,8 @@ void seat_set_focus_warp(struct sway_seat *seat,
// If we've focused a floating container, bring it to the front. // If we've focused a floating container, bring it to the front.
// We do this by putting it at the end of the floating list. // We do this by putting it at the end of the floating list.
// This must happen for both the pending and current children lists.
if (container && container_is_floating(container)) { if (container && container_is_floating(container)) {
list_move_to_end(container->parent->children, container); list_move_to_end(container->parent->children, container);
if (container_has_ancestor(container, container->current.parent)) {
list_move_to_end(container->parent->current.children, container);
}
} }
// clean up unfocused empty workspace on new output // clean up unfocused empty workspace on new output

View file

@ -1,13 +1,14 @@
sway_sources = files( sway_sources = files(
'main.c',
'server.c',
'commands.c', 'commands.c',
'config.c', 'config.c',
'criteria.c', 'criteria.c',
'debug-tree.c', 'debug-tree.c',
'decoration.c',
'ipc-json.c', 'ipc-json.c',
'ipc-server.c', 'ipc-server.c',
'main.c',
'security.c', 'security.c',
'server.c',
'swaynag.c', 'swaynag.c',
'desktop/desktop.c', 'desktop/desktop.c',

View file

@ -19,7 +19,6 @@
#include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_output.h> #include <wlr/types/wlr_xdg_output.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
// TODO WLR: make Xwayland optional
#include "list.h" #include "list.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/desktop/idle_inhibit_v1.h" #include "sway/desktop/idle_inhibit_v1.h"
@ -85,7 +84,6 @@ bool server_init(struct sway_server *server) {
&server->xdg_shell_surface); &server->xdg_shell_surface);
server->xdg_shell_surface.notify = handle_xdg_shell_surface; server->xdg_shell_surface.notify = handle_xdg_shell_surface;
// TODO make xwayland optional
#ifdef HAVE_XWAYLAND #ifdef HAVE_XWAYLAND
server->xwayland.wlr_xwayland = server->xwayland.wlr_xwayland =
wlr_xwayland_create(server->wl_display, server->compositor, true); wlr_xwayland_create(server->wl_display, server->compositor, true);
@ -109,11 +107,15 @@ bool server_init(struct sway_server *server) {
} }
#endif #endif
// TODO: Integration with sway borders server->server_decoration_manager =
struct wlr_server_decoration_manager *deco_manager =
wlr_server_decoration_manager_create(server->wl_display); wlr_server_decoration_manager_create(server->wl_display);
wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_set_default_mode(
deco_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); server->server_decoration_manager,
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
wl_signal_add(&server->server_decoration_manager->events.new_decoration,
&server->server_decoration);
server->server_decoration.notify = handle_server_decoration;
wl_list_init(&server->decorations);
wlr_linux_dmabuf_v1_create(server->wl_display, renderer); wlr_linux_dmabuf_v1_create(server->wl_display, renderer);
wlr_export_dmabuf_manager_v1_create(server->wl_display); wlr_export_dmabuf_manager_v1_create(server->wl_display);

View file

@ -84,6 +84,9 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
*floating* enable|disable|toggle *floating* enable|disable|toggle
Make focused view floating, non-floating, or the opposite of what it is now. Make focused view floating, non-floating, or the opposite of what it is now.
<criteria> *focus*
Moves focus to the container that matches the specified criteria.
*focus* up|right|down|left *focus* up|right|down|left
Moves focus to the next container in the specified direction. Moves focus to the next container in the specified direction.
@ -111,33 +114,53 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
*fullscreen* *fullscreen*
Toggles fullscreen for the focused view. Toggles fullscreen for the focused view.
*layout* splith|splitv|stacking|tabbed *layout* default|splith|splitv|stacking|tabbed
Sets the layout mode of the focused container. Sets the layout mode of the focused container.
*layout* toggle split *layout* toggle [split|all]
Switches the focused container between the splitv and splith layouts. Cycles the layout mode of the focused container though a preset list of
layouts. If no argument is given, then it cycles through stacking, tabbed
and the last split layout. If "split" is given, then it cycles through
splith and splitv. If "all" is given, then it cycles through every layout.
*move* left|right|up|down [<px>] *layout* toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...
Cycles the layout mode of the focused container through a list of layouts.
*move* left|right|up|down [<px> px]
Moves the focused container in the direction specified. If the container, Moves the focused container in the direction specified. If the container,
the optional _px_ argument specifies how many pixels to move the container. the optional _px_ argument specifies how many pixels to move the container.
If unspecified, the default is 10 pixels. Pixels are ignored when moving If unspecified, the default is 10 pixels. Pixels are ignored when moving
tiled containers. tiled containers.
*move* container|window to workspace <name> *move* [absolute] position <pos_x> [px] <pos_y> [px]
Moves the focused container to the specified workspace. Moves the focused container to the specified position.
*move* container|window to workspace prev|next *move* [absolute] position center|mouse
Moves the focused container to the previous or next workspace on this Moves the focused container to be centered on the workspace or mouse.
output, or if no workspaces remain, the previous or next output.
*move* container|window to workspace prev\_on\_output|next\_on\_output *move* container|window [to] mark <mark>
Moves the focused container to the specified mark.
*move* [--no-auto-back-and-forth] container|window [to] workspace [number] <name>
Moves the focused container to the specified workspace. The string "number"
is optional and is used to match a workspace with the same number, even if
it has a different name.
*move* container|window [to] workspace prev|next|current
Moves the focused container to the previous, next or current workspace on
this output, or if no workspaces remain, the previous or next output.
*move* container|window [to] workspace prev\_on\_output|next\_on\_output
Moves the focused container to the previous or next workspace on this Moves the focused container to the previous or next workspace on this
output, wrapping around if already at the first or last workspace. output, wrapping around if already at the first or last workspace.
*move* container|window|workspace to output <name> *move* container|window [to] workspace back_and_forth
Moves the focused container to previously focused workspace.
*move* container|window|workspace [to] output <name>
Moves the focused container or workspace to the specified output. Moves the focused container or workspace to the specified output.
*move* container|window|workspace to output up|right|down|left *move* container|window|workspace [to] output up|right|down|left
Moves the focused container or workspace to next output in the specified Moves the focused container or workspace to next output in the specified
direction. direction.
@ -511,7 +534,7 @@ config after the others, or it will be matched instead of the others.
state. Using _allow_ or _deny_ controls the window's ability to set itself state. Using _allow_ or _deny_ controls the window's ability to set itself
as urgent. By default, windows are allowed to set their own urgency. as urgent. By default, windows are allowed to set their own urgency.
*workspace* [number] <name> *workspace* [--no-auto-back-and-forth] [number] <name>
Switches to the specified workspace. The string "number" is optional and is Switches to the specified workspace. The string "number" is optional and is
used to sort workspaces. used to sort workspaces.
@ -522,6 +545,9 @@ config after the others, or it will be matched instead of the others.
*workspace* prev\_on\_output|next\_on\_output *workspace* prev\_on\_output|next\_on\_output
Switches to the next workspace on the current output. Switches to the next workspace on the current output.
*workspace* back_and_forth
Switches to the previously focused workspace.
*workspace* <name> output <output> *workspace* <name> output <output>
Specifies that workspace _name_ should be shown on the specified _output_. Specifies that workspace _name_ should be shown on the specified _output_.
@ -582,7 +608,9 @@ The following attributes may be matched with:
the currently focused window. the currently focused window.
*con\_id* *con\_id*
Compare against the internal container ID, which you can find via IPC. Compare against the internal container ID, which you can find via IPC. If
value is \_\_focused\_\_, then the id must be the same as that of the
currently focused window.
*con\_mark* *con\_mark*
Compare against the window marks. Can be a regular expression. Compare against the window marks. Can be a regular expression.
@ -612,7 +640,8 @@ The following attributes may be matched with:
currently focused window. currently focused window.
*urgent* *urgent*
Compares the urgent state of the window. Can be "latest" or "oldest". Compares the urgent state of the window. Can be "first", "last", "latest",
"newest", "oldest" or "recent".
*window\_role* *window\_role*
Compare against the window role (WM\_WINDOW\_ROLE). Can be a regular Compare against the window role (WM\_WINDOW\_ROLE). Can be a regular

View file

@ -533,11 +533,10 @@ struct sway_container *container_parent(struct sway_container *container,
return container; return container;
} }
static struct sway_container *container_at_view(struct sway_container *swayc, static void surface_at_view(struct sway_container *swayc, double lx, double ly,
double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) { struct wlr_surface **surface, double *sx, double *sy) {
if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) {
return NULL; return;
} }
struct sway_view *sview = swayc->sway_view; struct sway_view *sview = swayc->sway_view;
double view_sx = lx - sview->x; double view_sx = lx - sview->x;
@ -567,9 +566,7 @@ static struct sway_container *container_at_view(struct sway_container *swayc,
*sx = _sx; *sx = _sx;
*sy = _sy; *sy = _sy;
*surface = _surface; *surface = _surface;
return swayc;
} }
return NULL;
} }
/** /**
@ -682,7 +679,8 @@ struct sway_container *tiling_container_at(
struct sway_container *con, double lx, double ly, struct sway_container *con, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) { struct wlr_surface **surface, double *sx, double *sy) {
if (con->type == C_VIEW) { if (con->type == C_VIEW) {
return container_at_view(con, lx, ly, surface, sx, sy); surface_at_view(con, lx, ly, surface, sx, sy);
return con;
} }
if (!con->children->length) { if (!con->children->length) {
return NULL; return NULL;
@ -745,7 +743,7 @@ struct sway_container *container_at(struct sway_container *workspace,
struct sway_container *focus = struct sway_container *focus =
seat_get_focus_inactive(seat, &root_container); seat_get_focus_inactive(seat, &root_container);
if (focus && focus->type == C_VIEW) { if (focus && focus->type == C_VIEW) {
container_at_view(focus, lx, ly, surface, sx, sy); surface_at_view(focus, lx, ly, surface, sx, sy);
if (*surface && surface_is_popup(*surface)) { if (*surface && surface_is_popup(*surface)) {
return focus; return focus;
} }
@ -1163,19 +1161,16 @@ void container_floating_translate(struct sway_container *con,
double x_amount, double y_amount) { double x_amount, double y_amount) {
con->x += x_amount; con->x += x_amount;
con->y += y_amount; con->y += y_amount;
con->current.swayc_x += x_amount;
con->current.swayc_y += y_amount;
if (con->type == C_VIEW) { if (con->type == C_VIEW) {
con->sway_view->x += x_amount; con->sway_view->x += x_amount;
con->sway_view->y += y_amount; con->sway_view->y += y_amount;
con->current.view_x += x_amount;
con->current.view_y += y_amount;
} else { } else {
for (int i = 0; i < con->children->length; ++i) { for (int i = 0; i < con->children->length; ++i) {
struct sway_container *child = con->children->items[i]; struct sway_container *child = con->children->items[i];
container_floating_translate(child, x_amount, y_amount); container_floating_translate(child, x_amount, y_amount);
} }
} }
container_set_dirty(con);
} }
/** /**
@ -1185,7 +1180,7 @@ void container_floating_translate(struct sway_container *con,
* one, otherwise we'll choose whichever output is closest to the container's * one, otherwise we'll choose whichever output is closest to the container's
* center. * center.
*/ */
static struct sway_container *container_floating_find_output( struct sway_container *container_floating_find_output(
struct sway_container *con) { struct sway_container *con) {
double center_x = con->x + con->width / 2; double center_x = con->x + con->width / 2;
double center_y = con->y + con->height / 2; double center_y = con->y + con->height / 2;
@ -1219,9 +1214,7 @@ void container_floating_move_to(struct sway_container *con,
"Expected a floating container")) { "Expected a floating container")) {
return; return;
} }
desktop_damage_whole_container(con);
container_floating_translate(con, lx - con->x, ly - con->y); container_floating_translate(con, lx - con->x, ly - con->y);
desktop_damage_whole_container(con);
struct sway_container *old_workspace = container_parent(con, C_WORKSPACE); struct sway_container *old_workspace = container_parent(con, C_WORKSPACE);
struct sway_container *new_output = container_floating_find_output(con); struct sway_container *new_output = container_floating_find_output(con);
if (!sway_assert(new_output, "Unable to find any output")) { if (!sway_assert(new_output, "Unable to find any output")) {
@ -1239,6 +1232,17 @@ void container_floating_move_to(struct sway_container *con,
} }
} }
void container_floating_move_to_center(struct sway_container *con) {
if (!sway_assert(container_is_floating(con),
"Expected a floating container")) {
return;
}
struct sway_container *ws = container_parent(con, C_WORKSPACE);
double new_lx = ws->x + (ws->width - con->width) / 2;
double new_ly = ws->y + (ws->height - con->height) / 2;
container_floating_translate(con, new_lx - con->x, new_ly - con->y);
}
void container_set_dirty(struct sway_container *container) { void container_set_dirty(struct sway_container *container) {
if (container->dirty) { if (container->dirty) {
return; return;
@ -1318,6 +1322,11 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
container->y = container->saved_y; container->y = container->saved_y;
container->width = container->saved_width; container->width = container->saved_width;
container->height = container->saved_height; container->height = container->saved_height;
struct sway_container *output =
container_floating_find_output(container);
if (!container_has_ancestor(container, output)) {
container_floating_move_to_center(container);
}
} else { } else {
container->width = container->saved_width; container->width = container->saved_width;
container->height = container->saved_height; container->height = container->saved_height;

View file

@ -142,49 +142,55 @@ struct sway_container *container_remove_child(struct sway_container *child) {
void container_move_to(struct sway_container *container, void container_move_to(struct sway_container *container,
struct sway_container *destination) { struct sway_container *destination) {
if (!sway_assert(container->type == C_CONTAINER ||
container->type == C_VIEW, "Expected a container or view")) {
return;
}
if (container == destination if (container == destination
|| container_has_ancestor(container, destination)) { || container_has_ancestor(container, destination)) {
return; return;
} }
struct sway_container *old_parent = NULL;
struct sway_container *new_parent = NULL;
if (container_is_floating(container)) { if (container_is_floating(container)) {
// TODO // Resolve destination into a workspace
return; struct sway_container *new_ws = NULL;
} if (destination->type == C_OUTPUT) {
struct sway_container *old_parent = container_remove_child(container); new_ws = output_get_active_workspace(destination->sway_output);
container->width = container->height = 0; } else if (destination->type == C_WORKSPACE) {
container->saved_width = container->saved_height = 0; new_ws = destination;
} else {
struct sway_container *new_parent, *new_parent_focus; new_ws = container_parent(destination, C_WORKSPACE);
struct sway_seat *seat = input_manager_get_default_seat(input_manager); }
if (!new_ws) {
// Get the focus of the destination before we change it. // This can happen if the user has run "move container to mark foo",
new_parent_focus = seat_get_focus_inactive(seat, destination); // where mark foo is on a hidden scratchpad container.
if (destination->type == C_VIEW) { return;
new_parent = container_add_sibling(destination, container); }
struct sway_container *old_output =
container_parent(container, C_OUTPUT);
old_parent = container_remove_child(container);
container_add_child(new_ws->sway_workspace->floating, container);
// If changing output, center it within the workspace
if (old_output != new_ws->parent && !container->is_fullscreen) {
container_floating_move_to_center(container);
}
} else { } else {
new_parent = destination; old_parent = container_remove_child(container);
container_add_child(destination, container); container->width = container->height = 0;
container->saved_width = container->saved_height = 0;
if (destination->type == C_VIEW) {
new_parent = container_add_sibling(destination, container);
} else {
new_parent = destination;
container_add_child(destination, container);
}
} }
wl_signal_emit(&container->events.reparent, old_parent); wl_signal_emit(&container->events.reparent, old_parent);
if (container->type == C_WORKSPACE) { if (container->type == C_VIEW) {
// If moving a workspace to a new output, maybe create a new workspace
// on the previous output
if (old_parent->children->length == 0) {
char *ws_name = workspace_next_name(old_parent->name);
struct sway_container *ws = workspace_create(old_parent, ws_name);
free(ws_name);
seat_set_focus(seat, ws);
}
// Try to remove an empty workspace from the destination output.
container_reap_empty_recursive(new_parent_focus);
container_sort_workspaces(new_parent);
seat_set_focus(seat, new_parent);
workspace_output_raise_priority(container, old_parent, new_parent);
ipc_event_workspace(NULL, container, "move");
} else if (container->type == C_VIEW) {
ipc_event_window(container, "move"); ipc_event_window(container, "move");
} }
container_notify_subtree_changed(old_parent); container_notify_subtree_changed(old_parent);
@ -859,7 +865,7 @@ struct sway_container *container_split(struct sway_container *child,
} }
if (child->type == C_WORKSPACE && child->children->length == 0) { if (child->type == C_WORKSPACE && child->children->length == 0) {
// Special case: this just behaves like splitt // Special case: this just behaves like splitt
child->prev_layout = child->layout; child->prev_split_layout = child->layout;
child->layout = layout; child->layout = layout;
return child; return child;
} }
@ -870,7 +876,7 @@ struct sway_container *container_split(struct sway_container *child,
remove_gaps(child); remove_gaps(child);
cont->prev_layout = L_NONE; cont->prev_split_layout = L_NONE;
cont->width = child->width; cont->width = child->width;
cont->height = child->height; cont->height = child->height;
cont->x = child->x; cont->x = child->x;

View file

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <stdlib.h> #include <stdlib.h>
#include <strings.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h> #include <wlr/types/wlr_buffer.h>
@ -456,7 +457,13 @@ static struct sway_container *select_workspace(struct sway_view *view) {
if (criteria->type == CT_ASSIGN_WORKSPACE) { if (criteria->type == CT_ASSIGN_WORKSPACE) {
ws = workspace_by_name(criteria->target); ws = workspace_by_name(criteria->target);
if (!ws) { if (!ws) {
ws = workspace_create(NULL, criteria->target); if (strcasecmp(criteria->target, "back_and_forth") == 0) {
if (prev_workspace_name) {
ws = workspace_create(NULL, prev_workspace_name);
}
} else {
ws = workspace_create(NULL, criteria->target);
}
} }
break; break;
} else { } else {
@ -891,6 +898,15 @@ static bool find_by_mark_iterator(struct sway_container *con,
return con->type == C_VIEW && view_has_mark(con->sway_view, mark); return con->type == C_VIEW && view_has_mark(con->sway_view, mark);
} }
struct sway_view *view_find_mark(char *mark) {
struct sway_container *container = container_find(&root_container,
find_by_mark_iterator, mark);
if (!container) {
return NULL;
}
return container->sway_view;
}
bool view_find_and_unmark(char *mark) { bool view_find_and_unmark(char *mark) {
struct sway_container *container = container_find(&root_container, struct sway_container *container = container_find(&root_container,
find_by_mark_iterator, mark); find_by_mark_iterator, mark);

View file

@ -18,7 +18,7 @@
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
static struct sway_container *get_workspace_initial_output(const char *name) { struct sway_container *workspace_get_initial_output(const char *name) {
struct sway_container *parent; struct sway_container *parent;
// Search for workspace<->output pair // Search for workspace<->output pair
int e = config->workspace_outputs->length; int e = config->workspace_outputs->length;
@ -48,7 +48,7 @@ static struct sway_container *get_workspace_initial_output(const char *name) {
struct sway_container *workspace_create(struct sway_container *output, struct sway_container *workspace_create(struct sway_container *output,
const char *name) { const char *name) {
if (output == NULL) { if (output == NULL) {
output = get_workspace_initial_output(name); output = workspace_get_initial_output(name);
} }
wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name);
@ -59,7 +59,7 @@ struct sway_container *workspace_create(struct sway_container *output,
workspace->width = output->width; workspace->width = output->width;
workspace->height = output->height; workspace->height = output->height;
workspace->name = !name ? NULL : strdup(name); workspace->name = !name ? NULL : strdup(name);
workspace->prev_layout = L_NONE; workspace->prev_split_layout = L_NONE;
workspace->layout = container_get_default_layout(output); workspace->layout = container_get_default_layout(output);
struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace));
@ -250,6 +250,7 @@ struct sway_container *workspace_by_name(const char *name) {
current_workspace = container_parent(focus, C_WORKSPACE); current_workspace = container_parent(focus, C_WORKSPACE);
current_output = container_parent(focus, C_OUTPUT); current_output = container_parent(focus, C_OUTPUT);
} }
if (strcmp(name, "prev") == 0) { if (strcmp(name, "prev") == 0) {
return workspace_prev(current_workspace); return workspace_prev(current_workspace);
} else if (strcmp(name, "prev_on_output") == 0) { } else if (strcmp(name, "prev_on_output") == 0) {
@ -260,6 +261,9 @@ struct sway_container *workspace_by_name(const char *name) {
return workspace_output_next(current_output); return workspace_output_next(current_output);
} else if (strcmp(name, "current") == 0) { } else if (strcmp(name, "current") == 0) {
return current_workspace; return current_workspace;
} else if (strcasecmp(name, "back_and_forth") == 0) {
return prev_workspace_name ? container_find(&root_container,
_workspace_by_name, (void *)prev_workspace_name) : NULL;
} else { } else {
return container_find(&root_container, _workspace_by_name, return container_find(&root_container, _workspace_by_name,
(void *)name); (void *)name);
@ -364,7 +368,8 @@ struct sway_container *workspace_prev(struct sway_container *current) {
return workspace_prev_next_impl(current, false); return workspace_prev_next_impl(current, false);
} }
bool workspace_switch(struct sway_container *workspace) { bool workspace_switch(struct sway_container *workspace,
bool no_auto_back_and_forth) {
if (!workspace) { if (!workspace) {
return false; return false;
} }
@ -379,7 +384,7 @@ bool workspace_switch(struct sway_container *workspace) {
active_ws = container_parent(focus, C_WORKSPACE); active_ws = container_parent(focus, C_WORKSPACE);
} }
if (config->auto_back_and_forth if (!no_auto_back_and_forth && config->auto_back_and_forth
&& active_ws == workspace && active_ws == workspace
&& prev_workspace_name) { && prev_workspace_name) {
struct sway_container *new_ws = workspace_by_name(prev_workspace_name); struct sway_container *new_ws = workspace_by_name(prev_workspace_name);
@ -406,17 +411,20 @@ bool workspace_switch(struct sway_container *workspace) {
struct sway_container *floating = struct sway_container *floating =
next_output_prev_ws->sway_workspace->floating; next_output_prev_ws->sway_workspace->floating;
bool has_sticky = false; bool has_sticky = false;
for (int i = 0; i < floating->children->length; ++i) { if (workspace != next_output_prev_ws) {
struct sway_container *floater = floating->children->items[i]; for (int i = 0; i < floating->children->length; ++i) {
if (floater->is_sticky) { struct sway_container *floater = floating->children->items[i];
has_sticky = true; if (floater->is_sticky) {
container_remove_child(floater); has_sticky = true;
container_add_child(workspace->sway_workspace->floating, floater); container_remove_child(floater);
if (floater == focus) { container_add_child(workspace->sway_workspace->floating,
seat_set_focus(seat, NULL); floater);
seat_set_focus(seat, floater); if (floater == focus) {
seat_set_focus(seat, NULL);
seat_set_focus(seat, floater);
}
--i;
} }
--i;
} }
} }