mirror of
https://github.com/NickHu/sway
synced 2024-12-27 21:58:11 +01:00
Merge branch 'master' into master
This commit is contained in:
commit
3c26536267
29 changed files with 697 additions and 281 deletions
|
@ -76,10 +76,6 @@ Führe diese Befehle aus:
|
|||
ninja -C build
|
||||
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:
|
||||
|
||||
sudo chmod a+s /usr/local/bin/sway
|
||||
|
|
|
@ -69,10 +69,6 @@ _\*\*Απαιτείται μόνο για swaylock_
|
|||
ninja -C build
|
||||
sudo ninja -C build install
|
||||
|
||||
Σε συστήματα με logind, χρειάζεται να ορίσετε μερικά δικαιώματα caps στο εκτελέσιμο αρχείο:
|
||||
|
||||
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
|
||||
|
||||
Σε συστήματα χωρίς logind, χρειάζεται να θέσετε το suid bit στο εκτελέσιμο αρχείο:
|
||||
|
||||
sudo chmod a+s /usr/local/bin/sway
|
||||
|
|
|
@ -71,10 +71,6 @@ Exécutez ces commandes :
|
|||
ninja -C build
|
||||
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 :
|
||||
|
||||
sudo chmod a+s /usr/local/bin/sway
|
||||
|
|
|
@ -72,10 +72,6 @@ Esegui questi comandi:
|
|||
ninja -C build
|
||||
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):
|
||||
|
||||
sudo chmod a+s /usr/local/bin/sway
|
||||
|
|
|
@ -62,14 +62,12 @@ _\*\*swaylockでのみ必要です_
|
|||
ninja -C build
|
||||
sudo ninja -C build install
|
||||
|
||||
logindを使用しているシステムでは、バイナリにいくつかのケーパビリティを設定する必要があります:
|
||||
|
||||
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
|
||||
|
||||
logindを使用していないシステムでは、バイナリにsuidを設定する必要があります:
|
||||
|
||||
sudo chmod a+s /usr/local/bin/sway
|
||||
|
||||
swayは起動後、すぐにroot許可を落とします。
|
||||
|
||||
## 設定
|
||||
|
||||
既にi3を使用している場合は、i3の設定ファイルを`~/.config/sway/config`にコピーすれば動きます。そうでない場合は、サンプルの設定ファイルを`~/.config/sway/config`にコピーしてください。サンプルの設定ファイルは、通常`/etc/sway/config`にあります。`man 5 sway`を実行することで、設定に関する情報を見ることができます。
|
||||
|
|
|
@ -72,14 +72,12 @@ Run these commands:
|
|||
ninja -C build
|
||||
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:
|
||||
|
||||
sudo chmod a+s /usr/local/bin/sway
|
||||
|
||||
Sway will drop root permissions shortly after startup.
|
||||
|
||||
## Configuration
|
||||
|
||||
If you already use i3, then copy your i3 config to `~/.config/sway/config` and
|
||||
|
|
|
@ -25,6 +25,7 @@ char *get_socketpath(void) {
|
|||
if (line && *line) {
|
||||
return line;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
const char *i3sock = getenv("I3SOCK");
|
||||
if (i3sock) {
|
||||
|
@ -37,6 +38,7 @@ char *get_socketpath(void) {
|
|||
if (line && *line) {
|
||||
return line;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
17
include/sway/decoration.h
Normal file
17
include/sway/decoration.h
Normal 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
|
|
@ -4,12 +4,13 @@
|
|||
#include <wayland-server.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_data_device.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.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
// TODO WLR: make Xwayland optional
|
||||
#include "list.h"
|
||||
#include "config.h"
|
||||
|
@ -42,11 +43,17 @@ struct sway_server {
|
|||
|
||||
struct wlr_xdg_shell *xdg_shell;
|
||||
struct wl_listener xdg_shell_surface;
|
||||
|
||||
#ifdef HAVE_XWAYLAND
|
||||
struct sway_xwayland xwayland;
|
||||
struct wl_listener xwayland_surface;
|
||||
struct wl_listener xwayland_ready;
|
||||
#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;
|
||||
|
||||
list_t *transactions;
|
||||
|
@ -71,4 +78,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
|
|||
#ifdef HAVE_XWAYLAND
|
||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
||||
#endif
|
||||
void handle_server_decoration(struct wl_listener *listener, void *data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -113,7 +113,7 @@ struct sway_container {
|
|||
|
||||
enum sway_container_type type;
|
||||
enum sway_container_layout layout;
|
||||
enum sway_container_layout prev_layout;
|
||||
enum sway_container_layout prev_split_layout;
|
||||
|
||||
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,
|
||||
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.
|
||||
*/
|
||||
void container_floating_move_to(struct sway_container *con,
|
||||
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
|
||||
* included in the next transaction then unmarked as dirty.
|
||||
|
|
|
@ -118,6 +118,8 @@ struct sway_view {
|
|||
struct sway_xdg_shell_v6_view {
|
||||
struct sway_view view;
|
||||
|
||||
enum wlr_server_decoration_manager_mode deco_mode;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener request_move;
|
||||
struct wl_listener request_resize;
|
||||
|
@ -134,6 +136,8 @@ struct sway_xdg_shell_v6_view {
|
|||
struct sway_xdg_shell_view {
|
||||
struct sway_view view;
|
||||
|
||||
enum wlr_server_decoration_manager_mode deco_mode;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener request_move;
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Returns true if it matched a view.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _SWAY_WORKSPACE_H
|
||||
#define _SWAY_WORKSPACE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "sway/tree/container.h"
|
||||
|
||||
struct sway_view;
|
||||
|
@ -15,9 +16,12 @@ struct sway_workspace {
|
|||
|
||||
extern char *prev_workspace_name;
|
||||
|
||||
struct sway_container *workspace_get_initial_output(const char *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);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include "sway/commands.h"
|
||||
|
@ -5,6 +6,26 @@
|
|||
#include "sway/tree/container.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 *error = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[0], "default") == 0) {
|
||||
parent->layout = parent->prev_layout;
|
||||
if (parent->layout == L_NONE) {
|
||||
parent->layout = container_get_default_layout(parent);
|
||||
}
|
||||
} else {
|
||||
if (parent->layout != L_TABBED && parent->layout != L_STACKED) {
|
||||
parent->prev_layout = parent->layout;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[0], "splith") == 0) {
|
||||
parent->layout = L_HORIZ;
|
||||
} else if (strcasecmp(argv[0], "splitv") == 0) {
|
||||
parent->layout = L_VERT;
|
||||
} else if (strcasecmp(argv[0], "tabbed") == 0) {
|
||||
parent->layout = L_TABBED;
|
||||
} else if (strcasecmp(argv[0], "stacking") == 0) {
|
||||
parent->layout = L_STACKED;
|
||||
} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
|
||||
if (parent->layout == L_HORIZ) {
|
||||
parent->layout = L_VERT;
|
||||
enum sway_container_layout prev = parent->layout;
|
||||
bool assigned_directly = parse_layout_string(argv[0], &parent->layout);
|
||||
if (!assigned_directly) {
|
||||
if (strcasecmp(argv[0], "default") == 0) {
|
||||
parent->layout = parent->prev_split_layout;
|
||||
} else if (strcasecmp(argv[0], "toggle") == 0) {
|
||||
if (argc == 1) {
|
||||
parent->layout =
|
||||
parent->layout == L_STACKED ? L_TABBED :
|
||||
parent->layout == L_TABBED ? parent->prev_split_layout : L_STACKED;
|
||||
} else if (argc == 2) {
|
||||
if (strcasecmp(argv[1], "all") == 0) {
|
||||
parent->layout =
|
||||
parent->layout == L_HORIZ ? L_VERT :
|
||||
parent->layout == L_VERT ? L_STACKED :
|
||||
parent->layout == L_STACKED ? L_TABBED : L_HORIZ;
|
||||
} else if (strcasecmp(argv[1], "split") == 0) {
|
||||
parent->layout =
|
||||
parent->layout == L_HORIZ ? L_VERT :
|
||||
parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, "layout", expected_syntax);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
container_notify_subtree_changed(parent);
|
||||
arrange_windows(parent);
|
||||
if (parent->layout == L_NONE) {
|
||||
parent->layout = container_get_default_layout(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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#define _XOPEN_SOURCE 500
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
|
@ -8,6 +9,7 @@
|
|||
#include "sway/commands.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/ipc-server.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
|
@ -15,12 +17,13 @@
|
|||
#include "sway/tree/workspace.h"
|
||||
#include "stringop.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 "
|
||||
"'move <container|window> to workspace <name>' or "
|
||||
"'move <container|window|workspace> to output <name|direction>' or "
|
||||
"'move position mouse'";
|
||||
"'move [--no-auto-back-and-forth] <container|window> [to] workspace <name>' or "
|
||||
"'move [--no-auto-back-and-forth] <container|window|workspace> [to] output <name|direction>' or "
|
||||
"'move <container|window> [to] mark <mark>'";
|
||||
|
||||
static struct sway_container *output_in_direction(const char *direction,
|
||||
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) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "move container/window",
|
||||
EXPECTED_AT_LEAST, 4))) {
|
||||
EXPECTED_AT_LEAST, 3))) {
|
||||
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) {
|
||||
// auto back and forth move
|
||||
struct sway_container *curr_ws = container_parent(current, C_WORKSPACE);
|
||||
if (curr_ws->name && strcmp(curr_ws->name, ws_name) == 0) {
|
||||
// if target workspace is the current one
|
||||
free(ws_name);
|
||||
ws_name = strdup(prev_workspace_name);
|
||||
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.");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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);
|
||||
}
|
||||
free(ws_name);
|
||||
struct sway_container *old_parent = current->parent;
|
||||
struct sway_container *old_ws = container_parent(current, C_WORKSPACE);
|
||||
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.");
|
||||
}
|
||||
destination = seat_get_focus_inactive(config->handler_context.seat, ws);
|
||||
} else if (strcasecmp(argv[1], "output") == 0) {
|
||||
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);
|
||||
if (!destination) {
|
||||
if (!dest_output) {
|
||||
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(
|
||||
config->handler_context.seat, destination);
|
||||
if (!focus) {
|
||||
destination = seat_get_focus_inactive(
|
||||
config->handler_context.seat, dest_output);
|
||||
if (!destination) {
|
||||
// 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;
|
||||
struct sway_container *old_ws = container_parent(current, C_WORKSPACE);
|
||||
container_move_to(current, focus);
|
||||
seat_set_focus_warp(config->handler_context.seat, old_parent, true, false);
|
||||
container_reap_empty(old_parent);
|
||||
container_reap_empty(focus->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(focus->parent);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
} else if (strcasecmp(argv[1], "mark") == 0) {
|
||||
struct sway_view *dest_view = view_find_mark(argv[2]);
|
||||
if (dest_view == NULL) {
|
||||
return cmd_results_new(CMD_FAILURE, "move",
|
||||
"Mark '%s' not found", argv[2]);
|
||||
}
|
||||
destination = dest_view->swayc;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
|
||||
}
|
||||
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,
|
||||
int argc, char **argv) {
|
||||
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;
|
||||
} 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);
|
||||
}
|
||||
|
||||
struct sway_container *source = container_parent(current, C_OUTPUT);
|
||||
int center_x = current->width / 2 + current->x,
|
||||
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);
|
||||
if (!destination) {
|
||||
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) {
|
||||
current = container_parent(current, C_WORKSPACE);
|
||||
}
|
||||
container_move_to(current, destination);
|
||||
workspace_move_to_output(current, destination);
|
||||
|
||||
arrange_windows(source);
|
||||
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);
|
||||
}
|
||||
|
||||
static const char* expected_position_syntax =
|
||||
"Expected 'move [absolute] position <x> <y>' or "
|
||||
"'move [absolute] position mouse'";
|
||||
static const char *expected_position_syntax =
|
||||
"Expected 'move [absolute] position <x> [px] <y> [px]' or "
|
||||
"'move [absolute] position center|mouse'";
|
||||
|
||||
static struct cmd_results *move_to_position(struct sway_container *container,
|
||||
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;
|
||||
container_floating_move_to(container, lx, ly);
|
||||
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);
|
||||
}
|
||||
|
||||
double lx, ly;
|
||||
char *inv;
|
||||
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",
|
||||
"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);
|
||||
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",
|
||||
"Invalid position specified");
|
||||
}
|
||||
|
||||
container_floating_move_to(container, lx, ly);
|
||||
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);
|
||||
} else if (strcasecmp(argv[0], "down") == 0) {
|
||||
return move_in_direction(current, MOVE_DOWN, argc, argv);
|
||||
} else if (strcasecmp(argv[0], "container") == 0
|
||||
|| strcasecmp(argv[0], "window") == 0) {
|
||||
} else if ((strcasecmp(argv[0], "container") == 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);
|
||||
} else if (strcasecmp(argv[0], "workspace") == 0) {
|
||||
return cmd_move_workspace(current, argc, argv);
|
||||
|
|
|
@ -61,6 +61,16 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
|
|||
}
|
||||
|
||||
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);
|
||||
if (tmp_workspace) {
|
||||
free(new_name);
|
||||
|
|
|
@ -17,17 +17,6 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
|
|||
|
||||
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) {
|
||||
if (strcasecmp(argv[i], "output") == 0) {
|
||||
output_location = i;
|
||||
|
@ -57,29 +46,36 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
|
|||
if (config->reading || !config->active) {
|
||||
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;
|
||||
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]))) {
|
||||
char *name = join_args(argv + 1, argc - 1);
|
||||
ws = workspace_create(NULL, name);
|
||||
free(name);
|
||||
}
|
||||
} else if (strcasecmp(argv[0], "next") == 0) {
|
||||
ws = workspace_next(old_workspace);
|
||||
} else if (strcasecmp(argv[0], "prev") == 0) {
|
||||
ws = workspace_prev(old_workspace);
|
||||
} else if (strcasecmp(argv[0], "next_on_output") == 0) {
|
||||
ws = workspace_output_next(old_output);
|
||||
} else if (strcasecmp(argv[0], "prev_on_output") == 0) {
|
||||
ws = workspace_output_prev(old_output);
|
||||
} else if (strcasecmp(argv[0], "next") == 0 ||
|
||||
strcasecmp(argv[0], "prev") == 0 ||
|
||||
strcasecmp(argv[0], "next_on_output") == 0 ||
|
||||
strcasecmp(argv[0], "prev_on_output") == 0 ||
|
||||
strcasecmp(argv[0], "current") == 0) {
|
||||
ws = workspace_by_name(argv[0]);
|
||||
} else if (strcasecmp(argv[0], "back_and_forth") == 0) {
|
||||
// if auto_back_and_forth is enabled, workspace_switch will swap
|
||||
// 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))) {
|
||||
if (!(ws = workspace_by_name(argv[0])) && prev_workspace_name) {
|
||||
ws = workspace_create(NULL, prev_workspace_name);
|
||||
}
|
||||
} else {
|
||||
|
@ -89,7 +85,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
|
|||
}
|
||||
free(name);
|
||||
}
|
||||
workspace_switch(ws);
|
||||
workspace_switch(ws, no_auto_back_and_forth);
|
||||
}
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
|
|
@ -361,8 +361,17 @@ static char *get_focused_prop(enum criteria_token token) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case T_CON_ID: // These do not support __focused__
|
||||
case T_CON_MARK:
|
||||
case T_CON_ID:
|
||||
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:
|
||||
#ifdef HAVE_XWAYLAND
|
||||
case T_ID:
|
||||
|
@ -425,7 +434,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
|
|||
case T_CON_ID:
|
||||
criteria->con_id = strtoul(effective_value, &endptr, 10);
|
||||
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;
|
||||
case T_CON_MARK:
|
||||
|
@ -452,13 +461,18 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
|
|||
criteria->tiling = true;
|
||||
break;
|
||||
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';
|
||||
} else if (strcmp(effective_value, "oldest") == 0) {
|
||||
} else if (strcmp(effective_value, "oldest") == 0 ||
|
||||
strcmp(effective_value, "first") == 0) {
|
||||
criteria->urgent = 'o';
|
||||
} else {
|
||||
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;
|
||||
case T_WORKSPACE:
|
||||
|
|
71
sway/decoration.c
Normal file
71
sway/decoration.c
Normal 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;
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/edges.h>
|
||||
#include "log.h"
|
||||
#include "sway/decoration.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/server.h"
|
||||
|
@ -170,6 +171,15 @@ static bool wants_floating(struct sway_view *view) {
|
|||
|| 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,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data) {
|
||||
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_fullscreen = set_fullscreen,
|
||||
.wants_floating = wants_floating,
|
||||
.has_client_side_decorations = has_client_side_decorations,
|
||||
.for_each_surface = for_each_surface,
|
||||
.for_each_popup = for_each_popup,
|
||||
.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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (xdg_surface->toplevel->client_pending.fullscreen) {
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <wayland-server.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/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/layout.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;
|
||||
|
||||
|
@ -166,6 +167,15 @@ static bool wants_floating(struct sway_view *view) {
|
|||
|| 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,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data) {
|
||||
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_fullscreen = set_fullscreen,
|
||||
.wants_floating = wants_floating,
|
||||
.has_client_side_decorations = has_client_side_decorations,
|
||||
.for_each_surface = for_each_surface,
|
||||
.for_each_popup = for_each_popup,
|
||||
.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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (xdg_surface->toplevel->client_pending.fullscreen) {
|
||||
|
|
|
@ -429,6 +429,8 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
|
|||
struct sway_container *cont) {
|
||||
struct sway_seat *seat = cursor->seat;
|
||||
|
||||
seat_set_focus(seat, cont);
|
||||
|
||||
// Deny moving or resizing a fullscreen container
|
||||
if (container_is_fullscreen_or_child(cont)) {
|
||||
seat_pointer_notify_button(seat, time_msec, button, state);
|
||||
|
@ -469,8 +471,6 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
|
|||
return;
|
||||
}
|
||||
|
||||
// Send event to surface
|
||||
seat_set_focus(seat, cont);
|
||||
seat_pointer_notify_button(seat, time_msec, button, state);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
// 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)) {
|
||||
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
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
sway_sources = files(
|
||||
'main.c',
|
||||
'server.c',
|
||||
'commands.c',
|
||||
'config.c',
|
||||
'criteria.c',
|
||||
'debug-tree.c',
|
||||
'decoration.c',
|
||||
'ipc-json.c',
|
||||
'ipc-server.c',
|
||||
'main.c',
|
||||
'security.c',
|
||||
'server.c',
|
||||
'swaynag.c',
|
||||
|
||||
'desktop/desktop.c',
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/types/wlr_xdg_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
// TODO WLR: make Xwayland optional
|
||||
#include "list.h"
|
||||
#include "sway/config.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.notify = handle_xdg_shell_surface;
|
||||
|
||||
// TODO make xwayland optional
|
||||
#ifdef HAVE_XWAYLAND
|
||||
server->xwayland.wlr_xwayland =
|
||||
wlr_xwayland_create(server->wl_display, server->compositor, true);
|
||||
|
@ -109,11 +107,15 @@ bool server_init(struct sway_server *server) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// TODO: Integration with sway borders
|
||||
struct wlr_server_decoration_manager *deco_manager =
|
||||
server->server_decoration_manager =
|
||||
wlr_server_decoration_manager_create(server->wl_display);
|
||||
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_export_dmabuf_manager_v1_create(server->wl_display);
|
||||
|
|
|
@ -84,6 +84,9 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
|
|||
*floating* enable|disable|toggle
|
||||
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
|
||||
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*
|
||||
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.
|
||||
|
||||
*layout* toggle split
|
||||
Switches the focused container between the splitv and splith layouts.
|
||||
*layout* toggle [split|all]
|
||||
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,
|
||||
the optional _px_ argument specifies how many pixels to move the container.
|
||||
If unspecified, the default is 10 pixels. Pixels are ignored when moving
|
||||
tiled containers.
|
||||
|
||||
*move* container|window to workspace <name>
|
||||
Moves the focused container to the specified workspace.
|
||||
*move* [absolute] position <pos_x> [px] <pos_y> [px]
|
||||
Moves the focused container to the specified position.
|
||||
|
||||
*move* container|window to workspace prev|next
|
||||
Moves the focused container to the previous or next workspace on this
|
||||
output, or if no workspaces remain, the previous or next output.
|
||||
*move* [absolute] position center|mouse
|
||||
Moves the focused container to be centered on the workspace or mouse.
|
||||
|
||||
*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
|
||||
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.
|
||||
|
||||
*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
|
||||
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
|
||||
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
|
||||
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
|
||||
Switches to the next workspace on the current output.
|
||||
|
||||
*workspace* back_and_forth
|
||||
Switches to the previously focused workspace.
|
||||
|
||||
*workspace* <name> output <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.
|
||||
|
||||
*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*
|
||||
Compare against the window marks. Can be a regular expression.
|
||||
|
@ -612,7 +640,8 @@ The following attributes may be matched with:
|
|||
currently focused window.
|
||||
|
||||
*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*
|
||||
Compare against the window role (WM\_WINDOW\_ROLE). Can be a regular
|
||||
|
|
|
@ -533,11 +533,10 @@ struct sway_container *container_parent(struct sway_container *container,
|
|||
return container;
|
||||
}
|
||||
|
||||
static struct sway_container *container_at_view(struct sway_container *swayc,
|
||||
double lx, double ly,
|
||||
static void surface_at_view(struct sway_container *swayc, double lx, double ly,
|
||||
struct wlr_surface **surface, double *sx, double *sy) {
|
||||
if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) {
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
struct sway_view *sview = swayc->sway_view;
|
||||
double view_sx = lx - sview->x;
|
||||
|
@ -567,9 +566,7 @@ static struct sway_container *container_at_view(struct sway_container *swayc,
|
|||
*sx = _sx;
|
||||
*sy = _sy;
|
||||
*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 wlr_surface **surface, double *sx, double *sy) {
|
||||
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) {
|
||||
return NULL;
|
||||
|
@ -745,7 +743,7 @@ struct sway_container *container_at(struct sway_container *workspace,
|
|||
struct sway_container *focus =
|
||||
seat_get_focus_inactive(seat, &root_container);
|
||||
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)) {
|
||||
return focus;
|
||||
}
|
||||
|
@ -1163,19 +1161,16 @@ void container_floating_translate(struct sway_container *con,
|
|||
double x_amount, double y_amount) {
|
||||
con->x += x_amount;
|
||||
con->y += y_amount;
|
||||
con->current.swayc_x += x_amount;
|
||||
con->current.swayc_y += y_amount;
|
||||
if (con->type == C_VIEW) {
|
||||
con->sway_view->x += x_amount;
|
||||
con->sway_view->y += y_amount;
|
||||
con->current.view_x += x_amount;
|
||||
con->current.view_y += y_amount;
|
||||
} else {
|
||||
for (int i = 0; i < con->children->length; ++i) {
|
||||
struct sway_container *child = con->children->items[i];
|
||||
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
|
||||
* center.
|
||||
*/
|
||||
static struct sway_container *container_floating_find_output(
|
||||
struct sway_container *container_floating_find_output(
|
||||
struct sway_container *con) {
|
||||
double center_x = con->x + con->width / 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")) {
|
||||
return;
|
||||
}
|
||||
desktop_damage_whole_container(con);
|
||||
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 *new_output = container_floating_find_output(con);
|
||||
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) {
|
||||
if (container->dirty) {
|
||||
return;
|
||||
|
@ -1318,6 +1322,11 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
|
|||
container->y = container->saved_y;
|
||||
container->width = container->saved_width;
|
||||
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 {
|
||||
container->width = container->saved_width;
|
||||
container->height = container->saved_height;
|
||||
|
|
|
@ -142,49 +142,55 @@ struct sway_container *container_remove_child(struct sway_container *child) {
|
|||
|
||||
void container_move_to(struct sway_container *container,
|
||||
struct sway_container *destination) {
|
||||
if (!sway_assert(container->type == C_CONTAINER ||
|
||||
container->type == C_VIEW, "Expected a container or view")) {
|
||||
return;
|
||||
}
|
||||
if (container == destination
|
||||
|| container_has_ancestor(container, destination)) {
|
||||
return;
|
||||
}
|
||||
struct sway_container *old_parent = NULL;
|
||||
struct sway_container *new_parent = NULL;
|
||||
if (container_is_floating(container)) {
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
struct sway_container *old_parent = container_remove_child(container);
|
||||
container->width = container->height = 0;
|
||||
container->saved_width = container->saved_height = 0;
|
||||
|
||||
struct sway_container *new_parent, *new_parent_focus;
|
||||
struct sway_seat *seat = input_manager_get_default_seat(input_manager);
|
||||
|
||||
// Get the focus of the destination before we change it.
|
||||
new_parent_focus = seat_get_focus_inactive(seat, destination);
|
||||
if (destination->type == C_VIEW) {
|
||||
new_parent = container_add_sibling(destination, container);
|
||||
// Resolve destination into a workspace
|
||||
struct sway_container *new_ws = NULL;
|
||||
if (destination->type == C_OUTPUT) {
|
||||
new_ws = output_get_active_workspace(destination->sway_output);
|
||||
} else if (destination->type == C_WORKSPACE) {
|
||||
new_ws = destination;
|
||||
} else {
|
||||
new_ws = container_parent(destination, C_WORKSPACE);
|
||||
}
|
||||
if (!new_ws) {
|
||||
// This can happen if the user has run "move container to mark foo",
|
||||
// where mark foo is on a hidden scratchpad container.
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
new_parent = destination;
|
||||
container_add_child(destination, container);
|
||||
old_parent = container_remove_child(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);
|
||||
|
||||
if (container->type == C_WORKSPACE) {
|
||||
// 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) {
|
||||
if (container->type == C_VIEW) {
|
||||
ipc_event_window(container, "move");
|
||||
}
|
||||
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) {
|
||||
// Special case: this just behaves like splitt
|
||||
child->prev_layout = child->layout;
|
||||
child->prev_split_layout = child->layout;
|
||||
child->layout = layout;
|
||||
return child;
|
||||
}
|
||||
|
@ -870,7 +876,7 @@ struct sway_container *container_split(struct sway_container *child,
|
|||
|
||||
remove_gaps(child);
|
||||
|
||||
cont->prev_layout = L_NONE;
|
||||
cont->prev_split_layout = L_NONE;
|
||||
cont->width = child->width;
|
||||
cont->height = child->height;
|
||||
cont->x = child->x;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/render/wlr_renderer.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) {
|
||||
ws = workspace_by_name(criteria->target);
|
||||
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;
|
||||
} 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
struct sway_container *container = container_find(&root_container,
|
||||
find_by_mark_iterator, mark);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "log.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;
|
||||
// Search for workspace<->output pair
|
||||
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,
|
||||
const char *name) {
|
||||
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);
|
||||
|
@ -59,7 +59,7 @@ struct sway_container *workspace_create(struct sway_container *output,
|
|||
workspace->width = output->width;
|
||||
workspace->height = output->height;
|
||||
workspace->name = !name ? NULL : strdup(name);
|
||||
workspace->prev_layout = L_NONE;
|
||||
workspace->prev_split_layout = L_NONE;
|
||||
workspace->layout = container_get_default_layout(output);
|
||||
|
||||
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_output = container_parent(focus, C_OUTPUT);
|
||||
}
|
||||
|
||||
if (strcmp(name, "prev") == 0) {
|
||||
return workspace_prev(current_workspace);
|
||||
} 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);
|
||||
} else if (strcmp(name, "current") == 0) {
|
||||
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 {
|
||||
return container_find(&root_container, _workspace_by_name,
|
||||
(void *)name);
|
||||
|
@ -364,7 +368,8 @@ struct sway_container *workspace_prev(struct sway_container *current) {
|
|||
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) {
|
||||
return false;
|
||||
}
|
||||
|
@ -379,7 +384,7 @@ bool workspace_switch(struct sway_container *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
|
||||
&& 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 =
|
||||
next_output_prev_ws->sway_workspace->floating;
|
||||
bool has_sticky = false;
|
||||
for (int i = 0; i < floating->children->length; ++i) {
|
||||
struct sway_container *floater = floating->children->items[i];
|
||||
if (floater->is_sticky) {
|
||||
has_sticky = true;
|
||||
container_remove_child(floater);
|
||||
container_add_child(workspace->sway_workspace->floating, floater);
|
||||
if (floater == focus) {
|
||||
seat_set_focus(seat, NULL);
|
||||
seat_set_focus(seat, floater);
|
||||
if (workspace != next_output_prev_ws) {
|
||||
for (int i = 0; i < floating->children->length; ++i) {
|
||||
struct sway_container *floater = floating->children->items[i];
|
||||
if (floater->is_sticky) {
|
||||
has_sticky = true;
|
||||
container_remove_child(floater);
|
||||
container_add_child(workspace->sway_workspace->floating,
|
||||
floater);
|
||||
if (floater == focus) {
|
||||
seat_set_focus(seat, NULL);
|
||||
seat_set_focus(seat, floater);
|
||||
}
|
||||
--i;
|
||||
}
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue