mirror of
https://github.com/swaywm/sway.git
synced 2024-11-22 16:01:27 +00:00
commit
583c30dbe3
|
@ -5,11 +5,11 @@
|
||||||
|
|
||||||
void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2);
|
void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2);
|
||||||
#define sway_abort(FMT, ...) \
|
#define sway_abort(FMT, ...) \
|
||||||
_sway_abort("[%s:%d] " FMT, _strip_path(__FILE__), __LINE__, ##__VA_ARGS__)
|
_sway_abort("[%s:%d] " FMT, wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3);
|
bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3);
|
||||||
#define sway_assert(COND, FMT, ...) \
|
#define sway_assert(COND, FMT, ...) \
|
||||||
_sway_assert(COND, "[%s:%d] %s:" FMT, _strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
|
_sway_assert(COND, "[%s:%d] %s:" FMT, wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
|
||||||
|
|
||||||
void error_handler(int sig);
|
void error_handler(int sig);
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,9 @@ struct cmd_results *checkarg(int argc, const char *name,
|
||||||
enum expected_args type, int val);
|
enum expected_args type, int val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse and handles a command.
|
* Parse and executes a command.
|
||||||
*/
|
*/
|
||||||
struct cmd_results *handle_command(char *command);
|
struct cmd_results *execute_command(char *command, struct sway_seat *seat);
|
||||||
/**
|
/**
|
||||||
* Parse and handles a command during config file loading.
|
* Parse and handles a command during config file loading.
|
||||||
*
|
*
|
||||||
|
|
|
@ -106,10 +106,6 @@ struct sway_container {
|
||||||
* The parent of this container. NULL for the root container.
|
* The parent of this container. NULL for the root container.
|
||||||
*/
|
*/
|
||||||
struct sway_container *parent;
|
struct sway_container *parent;
|
||||||
/**
|
|
||||||
* Which of this container's children has focus.
|
|
||||||
*/
|
|
||||||
struct sway_container *focused;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of master views in auto layouts.
|
* Number of master views in auto layouts.
|
||||||
|
@ -162,4 +158,12 @@ void container_map(swayc_t *container,
|
||||||
swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
||||||
struct wlr_surface **surface, double *sx, double *sy);
|
struct wlr_surface **surface, double *sx, double *sy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the function for each child of the container breadth first.
|
||||||
|
*/
|
||||||
|
void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data),
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,14 +16,15 @@ struct sway_input_device {
|
||||||
struct wlr_input_device *wlr_device;
|
struct wlr_input_device *wlr_device;
|
||||||
struct input_config *config;
|
struct input_config *config;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
struct wl_listener device_destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sway_input_manager {
|
struct sway_input_manager {
|
||||||
struct wl_listener input_add;
|
|
||||||
struct wl_listener input_remove;
|
|
||||||
struct sway_server *server;
|
struct sway_server *server;
|
||||||
struct wl_list devices;
|
struct wl_list devices;
|
||||||
struct wl_list seats;
|
struct wl_list seats;
|
||||||
|
|
||||||
|
struct wl_listener new_input;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sway_input_manager *sway_input_manager_create(
|
struct sway_input_manager *sway_input_manager_create(
|
||||||
|
|
|
@ -12,14 +12,26 @@ struct sway_seat_device {
|
||||||
struct wl_list link; // sway_seat::devices
|
struct wl_list link; // sway_seat::devices
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sway_seat_container {
|
||||||
|
struct sway_seat *seat;
|
||||||
|
swayc_t *container;
|
||||||
|
|
||||||
|
struct wl_list link; // sway_seat::focus_stack
|
||||||
|
|
||||||
|
struct wl_listener destroy;
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_seat {
|
struct sway_seat {
|
||||||
struct wlr_seat *wlr_seat;
|
struct wlr_seat *wlr_seat;
|
||||||
struct seat_config *config;
|
struct seat_config *config;
|
||||||
struct sway_cursor *cursor;
|
struct sway_cursor *cursor;
|
||||||
struct sway_input_manager *input;
|
struct sway_input_manager *input;
|
||||||
swayc_t *focus;
|
|
||||||
|
bool has_focus;
|
||||||
|
struct wl_list focus_stack; // list of containers in focus order
|
||||||
|
|
||||||
struct wl_listener focus_destroy;
|
struct wl_listener focus_destroy;
|
||||||
|
struct wl_listener new_container;
|
||||||
|
|
||||||
struct wl_list devices; // sway_seat_device::link
|
struct wl_list devices; // sway_seat_device::link
|
||||||
|
|
||||||
|
@ -44,6 +56,22 @@ void sway_seat_configure_xcursor(struct sway_seat *seat);
|
||||||
|
|
||||||
void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container);
|
void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container);
|
||||||
|
|
||||||
|
swayc_t *sway_seat_get_focus(struct sway_seat *seat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the last container to be focused for the seat (or the most recently
|
||||||
|
* opened if no container has received focused) that is a child of the given
|
||||||
|
* container. The focus-inactive container of the root window is the focused
|
||||||
|
* container for the seat (if the seat does have focus). This function can be
|
||||||
|
* used to determine what container gets focused next if the focused container
|
||||||
|
* is destroyed, or focus moves to a container with children and we need to
|
||||||
|
* descend into the next leaf in focus order.
|
||||||
|
*/
|
||||||
|
swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container);
|
||||||
|
|
||||||
|
swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat,
|
||||||
|
enum swayc_types type);
|
||||||
|
|
||||||
void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config);
|
void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,6 +2,19 @@
|
||||||
#define _SWAY_LAYOUT_H
|
#define _SWAY_LAYOUT_H
|
||||||
|
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
#include "sway/container.h"
|
||||||
|
|
||||||
|
enum movement_direction {
|
||||||
|
MOVE_LEFT,
|
||||||
|
MOVE_RIGHT,
|
||||||
|
MOVE_UP,
|
||||||
|
MOVE_DOWN,
|
||||||
|
MOVE_PARENT,
|
||||||
|
MOVE_CHILD,
|
||||||
|
MOVE_NEXT,
|
||||||
|
MOVE_PREV,
|
||||||
|
MOVE_FIRST
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_container;
|
struct sway_container;
|
||||||
|
|
||||||
|
@ -11,13 +24,20 @@ struct sway_root {
|
||||||
struct wl_listener output_layout_change;
|
struct wl_listener output_layout_change;
|
||||||
|
|
||||||
struct wl_list unmanaged_views; // sway_view::unmanaged_view_link
|
struct wl_list unmanaged_views; // sway_view::unmanaged_view_link
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal new_container;
|
||||||
|
} events;
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_layout(void);
|
void init_layout(void);
|
||||||
void add_child(struct sway_container *parent, struct sway_container *child);
|
void add_child(struct sway_container *parent, struct sway_container *child);
|
||||||
|
swayc_t *add_sibling(swayc_t *parent, swayc_t *child);
|
||||||
struct sway_container *remove_child(struct sway_container *child);
|
struct sway_container *remove_child(struct sway_container *child);
|
||||||
enum swayc_layouts default_layout(struct sway_container *output);
|
enum swayc_layouts default_layout(struct sway_container *output);
|
||||||
void sort_workspaces(struct sway_container *output);
|
void sort_workspaces(struct sway_container *output);
|
||||||
void arrange_windows(struct sway_container *container, double width, double height);
|
void arrange_windows(struct sway_container *container, double width, double height);
|
||||||
|
swayc_t *get_swayc_in_direction(swayc_t *container,
|
||||||
|
struct sway_seat *seat, enum movement_direction dir);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,7 @@ struct sway_output {
|
||||||
struct timespec last_frame;
|
struct timespec last_frame;
|
||||||
|
|
||||||
struct wl_listener frame;
|
struct wl_listener frame;
|
||||||
|
struct wl_listener output_destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,8 +24,7 @@ struct sway_server {
|
||||||
|
|
||||||
struct sway_input_manager *input;
|
struct sway_input_manager *input;
|
||||||
|
|
||||||
struct wl_listener output_add;
|
struct wl_listener new_output;
|
||||||
struct wl_listener output_remove;
|
|
||||||
struct wl_listener output_frame;
|
struct wl_listener output_frame;
|
||||||
|
|
||||||
struct wlr_xdg_shell_v6 *xdg_shell_v6;
|
struct wlr_xdg_shell_v6 *xdg_shell_v6;
|
||||||
|
@ -45,8 +44,7 @@ bool server_init(struct sway_server *server);
|
||||||
void server_fini(struct sway_server *server);
|
void server_fini(struct sway_server *server);
|
||||||
void server_run(struct sway_server *server);
|
void server_run(struct sway_server *server);
|
||||||
|
|
||||||
void output_add_notify(struct wl_listener *listener, void *data);
|
void handle_new_output(struct wl_listener *listener, void *data);
|
||||||
void output_remove_notify(struct wl_listener *listener, void *data);
|
|
||||||
|
|
||||||
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
|
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
|
||||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef _SWAY_WORKSPACE_H
|
#ifndef _SWAY_WORKSPACE_H
|
||||||
#define _SWAY_WORKSPACE_H
|
#define _SWAY_WORKSPACE_H
|
||||||
|
|
||||||
struct sway_container;
|
#include "sway/container.h"
|
||||||
|
|
||||||
extern char *prev_workspace_name;
|
extern char *prev_workspace_name;
|
||||||
|
|
||||||
|
@ -12,9 +12,9 @@ bool workspace_switch(swayc_t *workspace);
|
||||||
struct sway_container *workspace_by_number(const char* name);
|
struct sway_container *workspace_by_number(const char* name);
|
||||||
swayc_t *workspace_by_name(const char*);
|
swayc_t *workspace_by_name(const char*);
|
||||||
|
|
||||||
struct sway_container *workspace_output_next(struct sway_container *current);
|
struct sway_container *workspace_output_next(swayc_t *current);
|
||||||
struct sway_container *workspace_next(struct sway_container *current);
|
struct sway_container *workspace_next(swayc_t *current);
|
||||||
struct sway_container *workspace_output_prev(struct sway_container *current);
|
struct sway_container *workspace_output_prev(swayc_t *current);
|
||||||
struct sway_container *workspace_prev(struct sway_container *current);
|
struct sway_container *workspace_prev(swayc_t *current);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,7 @@ project(
|
||||||
)
|
)
|
||||||
|
|
||||||
add_project_arguments('-Wno-unused-parameter', language: 'c')
|
add_project_arguments('-Wno-unused-parameter', language: 'c')
|
||||||
|
add_project_arguments('-Wno-unused-function', language: 'c')
|
||||||
|
|
||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
|
|
|
@ -125,23 +125,42 @@ struct cmd_results *add_color(const char *name, char *buffer, const char *color)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep alphabetized */
|
/**
|
||||||
|
* handlers that can run in either config or command context
|
||||||
|
* Keep alphabetized
|
||||||
|
*/
|
||||||
static struct cmd_handler handlers[] = {
|
static struct cmd_handler handlers[] = {
|
||||||
{ "bindcode", cmd_bindcode },
|
{ "bindcode", cmd_bindcode },
|
||||||
{ "bindsym", cmd_bindsym },
|
{ "bindsym", cmd_bindsym },
|
||||||
{ "exec", cmd_exec },
|
{ "exec", cmd_exec },
|
||||||
{ "exec_always", cmd_exec_always },
|
{ "exec_always", cmd_exec_always },
|
||||||
{ "exit", cmd_exit },
|
|
||||||
{ "include", cmd_include },
|
{ "include", cmd_include },
|
||||||
{ "input", cmd_input },
|
{ "input", cmd_input },
|
||||||
{ "kill", cmd_kill },
|
|
||||||
{ "output", cmd_output },
|
{ "output", cmd_output },
|
||||||
{ "reload", cmd_reload },
|
|
||||||
{ "seat", cmd_seat },
|
{ "seat", cmd_seat },
|
||||||
{ "set", cmd_set },
|
|
||||||
{ "workspace", cmd_workspace },
|
{ "workspace", cmd_workspace },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commands that can *only* run in the config loading context
|
||||||
|
* Keep alphabetized
|
||||||
|
*/
|
||||||
|
static struct cmd_handler config_handlers[] = {
|
||||||
|
{ "set", cmd_set },
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commands that can *not* run in the config loading context
|
||||||
|
* Keep alphabetized
|
||||||
|
*/
|
||||||
|
static struct cmd_handler command_handlers[] = {
|
||||||
|
{ "exit", cmd_exit },
|
||||||
|
{ "focus", cmd_focus },
|
||||||
|
{ "kill", cmd_kill },
|
||||||
|
{ "layout", cmd_layout },
|
||||||
|
{ "reload", cmd_reload },
|
||||||
|
};
|
||||||
|
|
||||||
static int handler_compare(const void *_a, const void *_b) {
|
static int handler_compare(const void *_a, const void *_b) {
|
||||||
const struct cmd_handler *a = _a;
|
const struct cmd_handler *a = _a;
|
||||||
const struct cmd_handler *b = _b;
|
const struct cmd_handler *b = _b;
|
||||||
|
@ -179,24 +198,48 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
|
||||||
struct cmd_handler *res = NULL;
|
struct cmd_handler *res = NULL;
|
||||||
wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT);
|
wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT);
|
||||||
|
|
||||||
|
bool config_loading = config->reading || !config->active;
|
||||||
|
|
||||||
if (block == CMD_BLOCK_INPUT) {
|
if (block == CMD_BLOCK_INPUT) {
|
||||||
res = bsearch(&d, input_handlers,
|
// input commands can run in either context
|
||||||
|
return bsearch(&d, input_handlers,
|
||||||
sizeof(input_handlers) / sizeof(struct cmd_handler),
|
sizeof(input_handlers) / sizeof(struct cmd_handler),
|
||||||
sizeof(struct cmd_handler), handler_compare);
|
sizeof(struct cmd_handler), handler_compare);
|
||||||
} else if (block == CMD_BLOCK_SEAT) {
|
} else if (block == CMD_BLOCK_SEAT) {
|
||||||
res = bsearch(&d, seat_handlers,
|
// seat commands can run in either context
|
||||||
|
return bsearch(&d, seat_handlers,
|
||||||
sizeof(seat_handlers) / sizeof(struct cmd_handler),
|
sizeof(seat_handlers) / sizeof(struct cmd_handler),
|
||||||
sizeof(struct cmd_handler), handler_compare);
|
sizeof(struct cmd_handler), handler_compare);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (!config_loading) {
|
||||||
|
res = bsearch(&d, command_handlers,
|
||||||
|
sizeof(command_handlers) / sizeof(struct cmd_handler),
|
||||||
|
sizeof(struct cmd_handler), handler_compare);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->reading) {
|
||||||
|
res = bsearch(&d, config_handlers,
|
||||||
|
sizeof(config_handlers) / sizeof(struct cmd_handler),
|
||||||
|
sizeof(struct cmd_handler), handler_compare);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res = bsearch(&d, handlers,
|
res = bsearch(&d, handlers,
|
||||||
sizeof(handlers) / sizeof(struct cmd_handler),
|
sizeof(handlers) / sizeof(struct cmd_handler),
|
||||||
sizeof(struct cmd_handler), handler_compare);
|
sizeof(struct cmd_handler), handler_compare);
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd_results *handle_command(char *_exec) {
|
struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
||||||
// Even though this function will process multiple commands we will only
|
// Even though this function will process multiple commands we will only
|
||||||
// return the last error, if any (for now). (Since we have access to an
|
// return the last error, if any (for now). (Since we have access to an
|
||||||
// error string we could e.g. concatenate all errors there.)
|
// error string we could e.g. concatenate all errors there.)
|
||||||
|
@ -207,6 +250,16 @@ struct cmd_results *handle_command(char *_exec) {
|
||||||
char *cmd;
|
char *cmd;
|
||||||
list_t *containers = NULL;
|
list_t *containers = NULL;
|
||||||
|
|
||||||
|
if (seat == NULL) {
|
||||||
|
// passing a NULL seat means we just pick the default seat
|
||||||
|
seat = sway_input_manager_get_default_seat(input_manager);
|
||||||
|
if (!sway_assert(seat, "could not find a seat to run the command on")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config->handler_context.seat = seat;
|
||||||
|
|
||||||
head = exec;
|
head = exec;
|
||||||
do {
|
do {
|
||||||
// Extract criteria (valid for this command list only).
|
// Extract criteria (valid for this command list only).
|
||||||
|
@ -276,12 +329,12 @@ struct cmd_results *handle_command(char *_exec) {
|
||||||
if (!has_criteria) {
|
if (!has_criteria) {
|
||||||
// without criteria, the command acts upon the focused
|
// without criteria, the command acts upon the focused
|
||||||
// container
|
// container
|
||||||
struct sway_seat *seat = config->handler_context.seat;
|
config->handler_context.current_container =
|
||||||
if (!seat) {
|
sway_seat_get_focus_inactive(seat, &root_container);
|
||||||
seat = sway_input_manager_get_default_seat(input_manager);
|
if (!sway_assert(config->handler_context.current_container,
|
||||||
|
"could not get focus-inactive for root container")) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
if (seat) {
|
|
||||||
config->handler_context.current_container = seat->focus;
|
|
||||||
struct cmd_results *res = handler->handle(argc-1, argv+1);
|
struct cmd_results *res = handler->handle(argc-1, argv+1);
|
||||||
if (res->status != CMD_SUCCESS) {
|
if (res->status != CMD_SUCCESS) {
|
||||||
free_argv(argc, argv);
|
free_argv(argc, argv);
|
||||||
|
@ -292,7 +345,6 @@ struct cmd_results *handle_command(char *_exec) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
free_cmd_results(res);
|
free_cmd_results(res);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < containers->length; ++i) {
|
for (int i = 0; i < containers->length; ++i) {
|
||||||
config->handler_context.current_container = containers->items[i];
|
config->handler_context.current_container = containers->items[i];
|
||||||
|
@ -319,13 +371,13 @@ cleanup:
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is like handle_command above, except:
|
// this is like execute_command above, except:
|
||||||
// 1) it ignores empty commands (empty lines)
|
// 1) it ignores empty commands (empty lines)
|
||||||
// 2) it does variable substitution
|
// 2) it does variable substitution
|
||||||
// 3) it doesn't split commands (because the multiple commands are supposed to
|
// 3) it doesn't split commands (because the multiple commands are supposed to
|
||||||
// be chained together)
|
// be chained together)
|
||||||
// 4) handle_command handles all state internally while config_command has some
|
// 4) execute_command handles all state internally while config_command has
|
||||||
// state handled outside (notably the block mode, in read_config)
|
// some state handled outside (notably the block mode, in read_config)
|
||||||
struct cmd_results *config_command(char *exec, enum cmd_status block) {
|
struct cmd_results *config_command(char *exec, enum cmd_status block) {
|
||||||
struct cmd_results *results = NULL;
|
struct cmd_results *results = NULL;
|
||||||
int argc;
|
int argc;
|
||||||
|
|
|
@ -6,9 +6,6 @@ void sway_terminate(int exit_code);
|
||||||
|
|
||||||
struct cmd_results *cmd_exit(int argc, char **argv) {
|
struct cmd_results *cmd_exit(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
if (config->reading) {
|
|
||||||
return cmd_results_new(CMD_FAILURE, "exit", "Can't be used in config file.");
|
|
||||||
}
|
|
||||||
if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) {
|
if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
59
sway/commands/focus.c
Normal file
59
sway/commands/focus.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include <strings.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "sway/input/input-manager.h"
|
||||||
|
#include "sway/input/seat.h"
|
||||||
|
#include "sway/view.h"
|
||||||
|
#include "sway/commands.h"
|
||||||
|
|
||||||
|
static bool parse_movement_direction(const char *name, enum movement_direction *out) {
|
||||||
|
if (strcasecmp(name, "left") == 0) {
|
||||||
|
*out = MOVE_LEFT;
|
||||||
|
} else if (strcasecmp(name, "right") == 0) {
|
||||||
|
*out = MOVE_RIGHT;
|
||||||
|
} else if (strcasecmp(name, "up") == 0) {
|
||||||
|
*out = MOVE_UP;
|
||||||
|
} else if (strcasecmp(name, "down") == 0) {
|
||||||
|
*out = MOVE_DOWN;
|
||||||
|
} else if (strcasecmp(name, "parent") == 0) {
|
||||||
|
*out = MOVE_PARENT;
|
||||||
|
} else if (strcasecmp(name, "child") == 0) {
|
||||||
|
*out = MOVE_CHILD;
|
||||||
|
} else if (strcasecmp(name, "next") == 0) {
|
||||||
|
*out = MOVE_NEXT;
|
||||||
|
} else if (strcasecmp(name, "prev") == 0) {
|
||||||
|
*out = MOVE_PREV;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd_results *cmd_focus(int argc, char **argv) {
|
||||||
|
swayc_t *con = config->handler_context.current_container;
|
||||||
|
struct sway_seat *seat = config->handler_context.seat;
|
||||||
|
if (con->type < C_WORKSPACE) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "focus",
|
||||||
|
"Command 'focus' cannot be used above the workspace level");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
sway_seat_set_focus(seat, con);
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO mode_toggle
|
||||||
|
enum movement_direction direction = 0;
|
||||||
|
if (!parse_movement_direction(argv[0], &direction)) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "focus",
|
||||||
|
"Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'");
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *next_focus = get_swayc_in_direction(con, seat, direction);
|
||||||
|
if (next_focus) {
|
||||||
|
sway_seat_set_focus(seat, next_focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||||
|
}
|
|
@ -6,15 +6,12 @@
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
|
|
||||||
struct cmd_results *cmd_kill(int argc, char **argv) {
|
struct cmd_results *cmd_kill(int argc, char **argv) {
|
||||||
if (config->reading) {
|
|
||||||
return cmd_results_new(CMD_FAILURE, "kill",
|
|
||||||
"Command 'kill' cannot be used in the config file");
|
|
||||||
}
|
|
||||||
enum swayc_types type = config->handler_context.current_container->type;
|
enum swayc_types type = config->handler_context.current_container->type;
|
||||||
if (type != C_VIEW || type != C_CONTAINER) {
|
if (type != C_VIEW && type != C_CONTAINER) {
|
||||||
return cmd_results_new(CMD_INVALID, NULL,
|
return cmd_results_new(CMD_INVALID, NULL,
|
||||||
"Can only kill views and containers with this command");
|
"Can only kill views and containers with this command");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO close arbitrary containers without a view
|
// TODO close arbitrary containers without a view
|
||||||
struct sway_view *view =
|
struct sway_view *view =
|
||||||
config->handler_context.current_container->sway_view;
|
config->handler_context.current_container->sway_view;
|
||||||
|
|
56
sway/commands/layout.c
Normal file
56
sway/commands/layout.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include "sway/commands.h"
|
||||||
|
#include "sway/container.h"
|
||||||
|
#include "sway/layout.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
struct cmd_results *cmd_layout(int argc, char **argv) {
|
||||||
|
struct cmd_results *error = NULL;
|
||||||
|
if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
swayc_t *parent = config->handler_context.current_container;
|
||||||
|
|
||||||
|
// TODO: floating
|
||||||
|
/*
|
||||||
|
if (parent->is_floating) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (parent->type == C_VIEW) {
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: stacks and tabs
|
||||||
|
|
||||||
|
if (strcasecmp(argv[0], "default") == 0) {
|
||||||
|
swayc_change_layout(parent, parent->prev_layout);
|
||||||
|
if (parent->layout == L_NONE) {
|
||||||
|
swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT);
|
||||||
|
swayc_change_layout(parent, default_layout(output));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parent->layout != L_TABBED && parent->layout != L_STACKED) {
|
||||||
|
parent->prev_layout = parent->layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp(argv[0], "splith") == 0) {
|
||||||
|
swayc_change_layout(parent, L_HORIZ);
|
||||||
|
} else if (strcasecmp(argv[0], "splitv") == 0) {
|
||||||
|
swayc_change_layout(parent, L_VERT);
|
||||||
|
} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
|
||||||
|
if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE
|
||||||
|
|| parent->workspace_layout == L_HORIZ)) {
|
||||||
|
swayc_change_layout(parent, L_VERT);
|
||||||
|
} else {
|
||||||
|
swayc_change_layout(parent, L_HORIZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arrange_windows(parent, parent->width, parent->height);
|
||||||
|
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||||
|
}
|
|
@ -4,9 +4,6 @@
|
||||||
|
|
||||||
struct cmd_results *cmd_reload(int argc, char **argv) {
|
struct cmd_results *cmd_reload(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
if (config->reading) {
|
|
||||||
return cmd_results_new(CMD_FAILURE, "reload", "Can't be used in config file.");
|
|
||||||
}
|
|
||||||
if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
|
if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ void free_sway_variable(struct sway_variable *var) {
|
||||||
struct cmd_results *cmd_set(int argc, char **argv) {
|
struct cmd_results *cmd_set(int argc, char **argv) {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
if (!config->reading) return cmd_results_new(CMD_FAILURE, "set", "Can only be used in config file.");
|
|
||||||
if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) {
|
if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,8 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
|
||||||
free(name);
|
free(name);
|
||||||
}
|
}
|
||||||
workspace_switch(ws);
|
workspace_switch(ws);
|
||||||
current_container = config->handler_context.seat->focus;
|
current_container =
|
||||||
|
sway_seat_get_focus(config->handler_context.seat);
|
||||||
swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT);
|
swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT);
|
||||||
|
|
||||||
if (config->mouse_warping && old_output != new_output) {
|
if (config->mouse_warping && old_output != new_output) {
|
||||||
|
|
|
@ -46,57 +46,22 @@ static void render_surface(struct wlr_surface *surface,
|
||||||
int height = surface->current->height;
|
int height = surface->current->height;
|
||||||
int render_width = width * wlr_output->scale;
|
int render_width = width * wlr_output->scale;
|
||||||
int render_height = height * wlr_output->scale;
|
int render_height = height * wlr_output->scale;
|
||||||
double ox = lx, oy = ly;
|
int owidth, oheight;
|
||||||
wlr_output_layout_output_coords(layout, wlr_output, &ox, &oy);
|
wlr_output_effective_resolution(wlr_output, &owidth, &oheight);
|
||||||
ox *= wlr_output->scale;
|
|
||||||
oy *= wlr_output->scale;
|
|
||||||
|
|
||||||
struct wlr_box render_box = {
|
// FIXME: view coords are inconsistently assumed to be in output or layout coords
|
||||||
.x = lx, .y = ly,
|
struct wlr_box layout_box = {
|
||||||
|
.x = lx + wlr_output->lx, .y = ly + wlr_output->ly,
|
||||||
.width = render_width, .height = render_height,
|
.width = render_width, .height = render_height,
|
||||||
};
|
};
|
||||||
if (wlr_output_layout_intersects(layout, wlr_output, &render_box)) {
|
if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) {
|
||||||
|
struct wlr_box render_box = {
|
||||||
|
.x = lx, .y = ly,
|
||||||
|
.width = render_width, .height = render_height
|
||||||
|
};
|
||||||
float matrix[16];
|
float matrix[16];
|
||||||
|
wlr_matrix_project_box(&matrix, &render_box,
|
||||||
float translate_center[16];
|
surface->current->transform, 0, &wlr_output->transform_matrix);
|
||||||
wlr_matrix_translate(&translate_center,
|
|
||||||
(int)ox + render_width / 2, (int)oy + render_height / 2, 0);
|
|
||||||
|
|
||||||
float rotate[16];
|
|
||||||
wlr_matrix_rotate(&rotate, rotation);
|
|
||||||
|
|
||||||
float translate_origin[16];
|
|
||||||
wlr_matrix_translate(&translate_origin, -render_width / 2,
|
|
||||||
-render_height / 2, 0);
|
|
||||||
|
|
||||||
float scale[16];
|
|
||||||
wlr_matrix_scale(&scale, render_width, render_height, 1);
|
|
||||||
|
|
||||||
float transform[16];
|
|
||||||
wlr_matrix_mul(&translate_center, &rotate, &transform);
|
|
||||||
wlr_matrix_mul(&transform, &translate_origin, &transform);
|
|
||||||
wlr_matrix_mul(&transform, &scale, &transform);
|
|
||||||
|
|
||||||
if (surface->current->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
|
|
||||||
float surface_translate_center[16];
|
|
||||||
wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0);
|
|
||||||
|
|
||||||
float surface_transform[16];
|
|
||||||
wlr_matrix_transform(surface_transform,
|
|
||||||
wlr_output_transform_invert(surface->current->transform));
|
|
||||||
|
|
||||||
float surface_translate_origin[16];
|
|
||||||
wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0);
|
|
||||||
|
|
||||||
wlr_matrix_mul(&transform, &surface_translate_center,
|
|
||||||
&transform);
|
|
||||||
wlr_matrix_mul(&transform, &surface_transform, &transform);
|
|
||||||
wlr_matrix_mul(&transform, &surface_translate_origin,
|
|
||||||
&transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix);
|
|
||||||
|
|
||||||
wlr_render_with_matrix(server.renderer, surface->texture,
|
wlr_render_with_matrix(server.renderer, surface->texture,
|
||||||
&matrix);
|
&matrix);
|
||||||
|
|
||||||
|
@ -125,8 +90,9 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface,
|
||||||
double width = surface->surface->current->width;
|
double width = surface->surface->current->width;
|
||||||
double height = surface->surface->current->height;
|
double height = surface->surface->current->height;
|
||||||
|
|
||||||
struct wlr_xdg_surface_v6 *popup;
|
struct wlr_xdg_popup_v6 *popup_state;
|
||||||
wl_list_for_each(popup, &surface->popups, popup_link) {
|
wl_list_for_each(popup_state, &surface->popups, link) {
|
||||||
|
struct wlr_xdg_surface_v6 *popup = popup_state->base;
|
||||||
if (!popup->configured) {
|
if (!popup->configured) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -215,11 +181,20 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
||||||
struct sway_output *soutput = wl_container_of(listener, soutput, frame);
|
struct sway_output *soutput = wl_container_of(listener, soutput, frame);
|
||||||
struct wlr_output *wlr_output = data;
|
struct wlr_output *wlr_output = data;
|
||||||
struct sway_server *server = soutput->server;
|
struct sway_server *server = soutput->server;
|
||||||
|
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
|
||||||
|
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
|
||||||
|
wlr_renderer_clear(renderer, &clear_color);
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
int buffer_age = -1;
|
||||||
|
wlr_output_make_current(wlr_output, &buffer_age);
|
||||||
wlr_renderer_begin(server->renderer, wlr_output);
|
wlr_renderer_begin(server->renderer, wlr_output);
|
||||||
|
|
||||||
swayc_t *workspace = soutput->swayc->focused;
|
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||||
|
swayc_t *focus = sway_seat_get_focus_inactive(seat, soutput->swayc);
|
||||||
|
swayc_t *workspace = (focus->type == C_WORKSPACE ?
|
||||||
|
focus :
|
||||||
|
swayc_parent_by_type(focus, C_WORKSPACE));
|
||||||
|
|
||||||
swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput);
|
swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput);
|
||||||
|
|
||||||
// render unmanaged views on top
|
// render unmanaged views on top
|
||||||
|
@ -236,15 +211,23 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_renderer_end(server->renderer);
|
wlr_renderer_end(server->renderer);
|
||||||
wlr_output_swap_buffers(wlr_output);
|
wlr_output_swap_buffers(wlr_output, &soutput->last_frame, NULL);
|
||||||
|
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
soutput->last_frame = now;
|
soutput->last_frame = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_add_notify(struct wl_listener *listener, void *data) {
|
static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||||
struct sway_server *server = wl_container_of(listener, server, output_add);
|
struct sway_output *output = wl_container_of(listener, output, output_destroy);
|
||||||
|
struct wlr_output *wlr_output = data;
|
||||||
|
wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name);
|
||||||
|
|
||||||
|
destroy_output(output->swayc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_server *server = wl_container_of(listener, server, new_output);
|
||||||
struct wlr_output *wlr_output = data;
|
struct wlr_output *wlr_output = data;
|
||||||
wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
|
wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
|
||||||
|
|
||||||
|
@ -269,27 +252,11 @@ void output_add_notify(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
sway_input_manager_configure_xcursor(input_manager);
|
sway_input_manager_configure_xcursor(input_manager);
|
||||||
|
|
||||||
output->frame.notify = output_frame_notify;
|
|
||||||
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
||||||
}
|
output->frame.notify = output_frame_notify;
|
||||||
|
|
||||||
void output_remove_notify(struct wl_listener *listener, void *data) {
|
wl_signal_add(&wlr_output->events.destroy, &output->output_destroy);
|
||||||
struct sway_server *server = wl_container_of(listener, server, output_remove);
|
output->output_destroy.notify = handle_output_destroy;
|
||||||
struct wlr_output *wlr_output = data;
|
|
||||||
wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name);
|
arrange_windows(&root_container, -1, -1);
|
||||||
|
|
||||||
swayc_t *output_container = NULL;
|
|
||||||
for (int i = 0 ; i < root_container.children->length; ++i) {
|
|
||||||
swayc_t *child = root_container.children->items[i];
|
|
||||||
if (child->type == C_OUTPUT &&
|
|
||||||
child->sway_output->wlr_output == wlr_output) {
|
|
||||||
output_container = child;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!output_container) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_output(output_container);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
|
||||||
wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy);
|
wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy);
|
||||||
|
|
||||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||||
swayc_t *cont = new_view(seat->focus, sway_view);
|
swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container);
|
||||||
|
swayc_t *cont = new_view(focus, sway_view);
|
||||||
sway_view->swayc = cont;
|
sway_view->swayc = cont;
|
||||||
|
|
||||||
arrange_windows(cont->parent, -1, -1);
|
arrange_windows(cont->parent, -1, -1);
|
||||||
|
|
|
@ -160,9 +160,34 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_add_notify(struct wl_listener *listener, void *data) {
|
static void handle_device_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_device *device = data;
|
||||||
|
|
||||||
|
struct sway_input_device *input_device =
|
||||||
|
input_sway_device_from_wlr(input_manager, device);
|
||||||
|
|
||||||
|
if (!sway_assert(input_device, "could not find sway device")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_log(L_DEBUG, "removing device: '%s'",
|
||||||
|
input_device->identifier);
|
||||||
|
|
||||||
|
struct sway_seat *seat = NULL;
|
||||||
|
wl_list_for_each(seat, &input_manager->seats, link) {
|
||||||
|
sway_seat_remove_device(seat, input_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&input_device->link);
|
||||||
|
wl_list_remove(&input_device->device_destroy.link);
|
||||||
|
free_input_config(input_device->config);
|
||||||
|
free(input_device->identifier);
|
||||||
|
free(input_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_new_input(struct wl_listener *listener, void *data) {
|
||||||
struct sway_input_manager *input =
|
struct sway_input_manager *input =
|
||||||
wl_container_of(listener, input, input_add);
|
wl_container_of(listener, input, new_input);
|
||||||
struct wlr_input_device *device = data;
|
struct wlr_input_device *device = data;
|
||||||
|
|
||||||
struct sway_input_device *input_device =
|
struct sway_input_device *input_device =
|
||||||
|
@ -226,32 +251,9 @@ static void input_add_notify(struct wl_listener *listener, void *data) {
|
||||||
"device '%s' is not configured on any seats",
|
"device '%s' is not configured on any seats",
|
||||||
input_device->identifier);
|
input_device->identifier);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void input_remove_notify(struct wl_listener *listener, void *data) {
|
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
|
||||||
struct sway_input_manager *input =
|
input_device->device_destroy.notify = handle_device_destroy;
|
||||||
wl_container_of(listener, input, input_remove);
|
|
||||||
struct wlr_input_device *device = data;
|
|
||||||
|
|
||||||
struct sway_input_device *input_device =
|
|
||||||
input_sway_device_from_wlr(input, device);
|
|
||||||
|
|
||||||
if (!sway_assert(input_device, "could not find sway device")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_log(L_DEBUG, "removing device: '%s'",
|
|
||||||
input_device->identifier);
|
|
||||||
|
|
||||||
struct sway_seat *seat = NULL;
|
|
||||||
wl_list_for_each(seat, &input->seats, link) {
|
|
||||||
sway_seat_remove_device(seat, input_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_list_remove(&input_device->link);
|
|
||||||
free_input_config(input_device->config);
|
|
||||||
free(input_device->identifier);
|
|
||||||
free(input_device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sway_input_manager *sway_input_manager_create(
|
struct sway_input_manager *sway_input_manager_create(
|
||||||
|
@ -269,11 +271,8 @@ struct sway_input_manager *sway_input_manager_create(
|
||||||
// create the default seat
|
// create the default seat
|
||||||
input_manager_get_seat(input, default_seat);
|
input_manager_get_seat(input, default_seat);
|
||||||
|
|
||||||
input->input_add.notify = input_add_notify;
|
input->new_input.notify = handle_new_input;
|
||||||
wl_signal_add(&server->backend->events.input_add, &input->input_add);
|
wl_signal_add(&server->backend->events.new_input, &input->new_input);
|
||||||
|
|
||||||
input->input_remove.notify = input_remove_notify;
|
|
||||||
wl_signal_add(&server->backend->events.input_remove, &input->input_remove);
|
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +281,7 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input,
|
||||||
swayc_t *container) {
|
swayc_t *container) {
|
||||||
struct sway_seat *seat = NULL;
|
struct sway_seat *seat = NULL;
|
||||||
wl_list_for_each(seat, &input->seats, link) {
|
wl_list_for_each(seat, &input->seats, link) {
|
||||||
if (seat->focus == container) {
|
if (sway_seat_get_focus(seat) == container) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard,
|
||||||
binding->command);
|
binding->command);
|
||||||
config_clear_handler_context(config);
|
config_clear_handler_context(config);
|
||||||
config->handler_context.seat = keyboard->seat_device->sway_seat;
|
config->handler_context.seat = keyboard->seat_device->sway_seat;
|
||||||
struct cmd_results *results = handle_command(binding->command);
|
struct cmd_results *results = execute_command(binding->command, NULL);
|
||||||
if (results->status != CMD_SUCCESS) {
|
if (results->status != CMD_SUCCESS) {
|
||||||
wlr_log(L_DEBUG, "could not run command for binding: %s",
|
wlr_log(L_DEBUG, "could not run command for binding: %s",
|
||||||
binding->command);
|
binding->command);
|
||||||
|
|
|
@ -32,6 +32,81 @@ void sway_seat_destroy(struct sway_seat *seat) {
|
||||||
wlr_seat_destroy(seat->wlr_seat);
|
wlr_seat_destroy(seat->wlr_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_seat_container_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct sway_seat_container *seat_con =
|
||||||
|
wl_container_of(listener, seat_con, destroy);
|
||||||
|
struct sway_seat *seat = seat_con->seat;
|
||||||
|
swayc_t *con = seat_con->container;
|
||||||
|
|
||||||
|
bool is_focus = (sway_seat_get_focus(seat) == con);
|
||||||
|
|
||||||
|
wl_list_remove(&seat_con->link);
|
||||||
|
|
||||||
|
if (is_focus) {
|
||||||
|
// pick next focus
|
||||||
|
sway_seat_set_focus(seat, NULL);
|
||||||
|
swayc_t *next = sway_seat_get_focus_inactive(seat, con->parent);
|
||||||
|
if (next == NULL) {
|
||||||
|
next = con->parent;
|
||||||
|
}
|
||||||
|
sway_seat_set_focus(seat, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&seat_con->destroy.link);
|
||||||
|
|
||||||
|
free(seat_con);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sway_seat_container *seat_container_from_container(
|
||||||
|
struct sway_seat *seat, swayc_t *con) {
|
||||||
|
if (con->type < C_WORKSPACE) {
|
||||||
|
// these don't get seat containers ever
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_seat_container *seat_con = NULL;
|
||||||
|
wl_list_for_each(seat_con, &seat->focus_stack, link) {
|
||||||
|
if (seat_con->container == con) {
|
||||||
|
return seat_con;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seat_con = calloc(1, sizeof(struct sway_seat_container));
|
||||||
|
if (seat_con == NULL) {
|
||||||
|
wlr_log(L_ERROR, "could not allocate seat container");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
seat_con->container = con;
|
||||||
|
seat_con->seat = seat;
|
||||||
|
wl_list_insert(seat->focus_stack.prev, &seat_con->link);
|
||||||
|
wl_signal_add(&con->events.destroy, &seat_con->destroy);
|
||||||
|
seat_con->destroy.notify = handle_seat_container_destroy;
|
||||||
|
|
||||||
|
return seat_con;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_new_container(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_seat *seat = wl_container_of(listener, seat, new_container);
|
||||||
|
swayc_t *con = data;
|
||||||
|
seat_container_from_container(seat, con);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collect_focus_iter(swayc_t *con, void *data) {
|
||||||
|
struct sway_seat *seat = data;
|
||||||
|
if (con->type > C_WORKSPACE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct sway_seat_container *seat_con =
|
||||||
|
seat_container_from_container(seat, con);
|
||||||
|
if (!seat_con) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_list_remove(&seat_con->link);
|
||||||
|
wl_list_insert(&seat->focus_stack, &seat_con->link);
|
||||||
|
}
|
||||||
|
|
||||||
struct sway_seat *sway_seat_create(struct sway_input_manager *input,
|
struct sway_seat *sway_seat_create(struct sway_input_manager *input,
|
||||||
const char *seat_name) {
|
const char *seat_name) {
|
||||||
struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
|
struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
|
||||||
|
@ -52,6 +127,15 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init the focus stack
|
||||||
|
wl_list_init(&seat->focus_stack);
|
||||||
|
|
||||||
|
container_for_each_bfs(&root_container, collect_focus_iter, seat);
|
||||||
|
|
||||||
|
wl_signal_add(&root_container.sway_root->events.new_container,
|
||||||
|
&seat->new_container);
|
||||||
|
seat->new_container.notify = handle_new_container;
|
||||||
|
|
||||||
seat->input = input;
|
seat->input = input;
|
||||||
wl_list_init(&seat->devices);
|
wl_list_init(&seat->devices);
|
||||||
|
|
||||||
|
@ -82,11 +166,12 @@ static void seat_configure_keyboard(struct sway_seat *seat,
|
||||||
sway_keyboard_configure(seat_device->keyboard);
|
sway_keyboard_configure(seat_device->keyboard);
|
||||||
wlr_seat_set_keyboard(seat->wlr_seat,
|
wlr_seat_set_keyboard(seat->wlr_seat,
|
||||||
seat_device->input_device->wlr_device);
|
seat_device->input_device->wlr_device);
|
||||||
if (seat->focus && seat->focus->type == C_VIEW) {
|
swayc_t *focus = sway_seat_get_focus(seat);
|
||||||
|
if (focus && focus->type == C_VIEW) {
|
||||||
// force notify reenter to pick up the new configuration
|
// force notify reenter to pick up the new configuration
|
||||||
wlr_seat_keyboard_clear_focus(seat->wlr_seat);
|
wlr_seat_keyboard_clear_focus(seat->wlr_seat);
|
||||||
wlr_seat_keyboard_notify_enter(seat->wlr_seat,
|
wlr_seat_keyboard_notify_enter(seat->wlr_seat,
|
||||||
seat->focus->sway_view->surface, wlr_keyboard->keycodes,
|
focus->sway_view->surface, wlr_keyboard->keycodes,
|
||||||
wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);
|
wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,29 +289,26 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) {
|
||||||
seat->cursor->cursor->y);
|
seat->cursor->cursor->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_focus_destroy(struct wl_listener *listener, void *data) {
|
|
||||||
struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy);
|
|
||||||
swayc_t *container = data;
|
|
||||||
sway_seat_set_focus(seat, container->parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
|
void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
|
||||||
swayc_t *last_focus = seat->focus;
|
swayc_t *last_focus = sway_seat_get_focus(seat);
|
||||||
|
|
||||||
if (last_focus == container) {
|
if (container && last_focus == container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_focus && last_focus->type == C_VIEW) {
|
if (container) {
|
||||||
wl_list_remove(&seat->focus_destroy.link);
|
struct sway_seat_container *seat_con =
|
||||||
|
seat_container_from_container(seat, container);
|
||||||
|
if (!seat_con) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container && container->type == C_VIEW) {
|
wl_list_remove(&seat_con->link);
|
||||||
|
wl_list_insert(&seat->focus_stack, &seat_con->link);
|
||||||
|
|
||||||
|
if (container->type == C_VIEW) {
|
||||||
struct sway_view *view = container->sway_view;
|
struct sway_view *view = container->sway_view;
|
||||||
view_set_activated(view, true);
|
view_set_activated(view, true);
|
||||||
wl_signal_add(&container->events.destroy, &seat->focus_destroy);
|
|
||||||
seat->focus_destroy.notify = handle_focus_destroy;
|
|
||||||
|
|
||||||
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
||||||
if (keyboard) {
|
if (keyboard) {
|
||||||
wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface,
|
wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface,
|
||||||
|
@ -237,14 +319,53 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
|
||||||
NULL, 0, NULL);
|
NULL, 0, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
seat->focus = container;
|
|
||||||
|
|
||||||
if (last_focus && last_focus->type == C_VIEW &&
|
if (last_focus && last_focus->type == C_VIEW &&
|
||||||
!sway_input_manager_has_focus(seat->input, last_focus)) {
|
!sway_input_manager_has_focus(seat->input, last_focus)) {
|
||||||
struct sway_view *view = last_focus->sway_view;
|
struct sway_view *view = last_focus->sway_view;
|
||||||
view_set_activated(view, false);
|
view_set_activated(view, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seat->has_focus = (container != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container) {
|
||||||
|
struct sway_seat_container *current = NULL;
|
||||||
|
swayc_t *parent = NULL;
|
||||||
|
wl_list_for_each(current, &seat->focus_stack, link) {
|
||||||
|
parent = current->container->parent;
|
||||||
|
|
||||||
|
if (current->container == container) {
|
||||||
|
return current->container;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (parent) {
|
||||||
|
if (parent == container) {
|
||||||
|
return current->container;
|
||||||
|
}
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *sway_seat_get_focus(struct sway_seat *seat) {
|
||||||
|
if (!seat->has_focus) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return sway_seat_get_focus_inactive(seat, &root_container);
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat,
|
||||||
|
enum swayc_types type) {
|
||||||
|
swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container);
|
||||||
|
if (focus->type == type) {
|
||||||
|
return focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
return swayc_parent_by_type(focus, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sway_seat_set_config(struct sway_seat *seat,
|
void sway_seat_set_config(struct sway_seat *seat,
|
||||||
|
|
|
@ -74,8 +74,8 @@ static void ipc_json_describe_output(swayc_t *container, json_object *object) {
|
||||||
json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh));
|
json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh));
|
||||||
json_object_object_add(object, "transform",
|
json_object_object_add(object, "transform",
|
||||||
json_object_new_string(ipc_json_get_output_transform(wlr_output->transform)));
|
json_object_new_string(ipc_json_get_output_transform(wlr_output->transform)));
|
||||||
json_object_object_add(object, "current_workspace",
|
// TODO WLR need to set "current_workspace" to the currently focused
|
||||||
(container->focused) ? json_object_new_string(container->focused->name) : NULL);
|
// workspace in a way that makes sense with multiseat
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) {
|
static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) {
|
||||||
|
|
|
@ -336,7 +336,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
||||||
case IPC_COMMAND:
|
case IPC_COMMAND:
|
||||||
{
|
{
|
||||||
config_clear_handler_context(config);
|
config_clear_handler_context(config);
|
||||||
struct cmd_results *results = handle_command(buf);
|
struct cmd_results *results = execute_command(buf, NULL);
|
||||||
const char *json = cmd_results_to_json(results);
|
const char *json = cmd_results_to_json(results);
|
||||||
char reply[256];
|
char reply[256];
|
||||||
int length = snprintf(reply, sizeof(reply), "%s", json);
|
int length = snprintf(reply, sizeof(reply), "%s", json);
|
||||||
|
|
|
@ -10,9 +10,11 @@ sway_sources = files(
|
||||||
'commands/exit.c',
|
'commands/exit.c',
|
||||||
'commands/exec.c',
|
'commands/exec.c',
|
||||||
'commands/exec_always.c',
|
'commands/exec_always.c',
|
||||||
|
'commands/focus.c',
|
||||||
'commands/kill.c',
|
'commands/kill.c',
|
||||||
'commands/include.c',
|
'commands/include.c',
|
||||||
'commands/input.c',
|
'commands/input.c',
|
||||||
|
'commands/layout.c',
|
||||||
'commands/seat.c',
|
'commands/seat.c',
|
||||||
'commands/seat/attach.c',
|
'commands/seat/attach.c',
|
||||||
'commands/seat/fallback.c',
|
'commands/seat/fallback.c',
|
||||||
|
|
|
@ -22,7 +22,7 @@ static void server_ready(struct wl_listener *listener, void *data) {
|
||||||
config->active = true;
|
config->active = true;
|
||||||
while (config->cmd_queue->length) {
|
while (config->cmd_queue->length) {
|
||||||
char *line = config->cmd_queue->items[0];
|
char *line = config->cmd_queue->items[0];
|
||||||
struct cmd_results *res = handle_command(line);
|
struct cmd_results *res = execute_command(line, NULL);
|
||||||
if (res->status != CMD_SUCCESS) {
|
if (res->status != CMD_SUCCESS) {
|
||||||
wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error);
|
wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error);
|
||||||
}
|
}
|
||||||
|
@ -48,12 +48,8 @@ bool server_init(struct sway_server *server) {
|
||||||
server->data_device_manager =
|
server->data_device_manager =
|
||||||
wlr_data_device_manager_create(server->wl_display);
|
wlr_data_device_manager_create(server->wl_display);
|
||||||
|
|
||||||
server->output_add.notify = output_add_notify;
|
server->new_output.notify = handle_new_output;
|
||||||
wl_signal_add(&server->backend->events.output_add, &server->output_add);
|
wl_signal_add(&server->backend->events.new_output, &server->new_output);
|
||||||
|
|
||||||
server->output_remove.notify = output_remove_notify;
|
|
||||||
wl_signal_add(&server->backend->events.output_remove,
|
|
||||||
&server->output_remove);
|
|
||||||
|
|
||||||
server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display);
|
server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display);
|
||||||
wl_signal_add(&server->xdg_shell_v6->events.new_surface,
|
wl_signal_add(&server->xdg_shell_v6->events.new_surface,
|
||||||
|
|
|
@ -17,6 +17,21 @@
|
||||||
#include "sway/workspace.h"
|
#include "sway/workspace.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
static list_t *bfs_queue;
|
||||||
|
|
||||||
|
static list_t *get_bfs_queue() {
|
||||||
|
if (!bfs_queue) {
|
||||||
|
bfs_queue = create_list();
|
||||||
|
if (!bfs_queue) {
|
||||||
|
wlr_log(L_ERROR, "could not allocate list for bfs queue");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bfs_queue->length = 0;
|
||||||
|
|
||||||
|
return bfs_queue;
|
||||||
|
}
|
||||||
|
|
||||||
swayc_t *swayc_by_test(swayc_t *container,
|
swayc_t *swayc_by_test(swayc_t *container,
|
||||||
bool (*test)(swayc_t *view, void *data), void *data) {
|
bool (*test)(swayc_t *view, void *data), void *data) {
|
||||||
if (!container->children) {
|
if (!container->children) {
|
||||||
|
@ -151,19 +166,16 @@ swayc_t *new_output(struct sway_output *sway_output) {
|
||||||
char *ws_name = workspace_next_name(output->name);
|
char *ws_name = workspace_next_name(output->name);
|
||||||
wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
|
wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
|
||||||
swayc_t *ws = new_workspace(output, ws_name);
|
swayc_t *ws = new_workspace(output, ws_name);
|
||||||
output->focused = ws;
|
|
||||||
// Set each seat's focus if not already set
|
// Set each seat's focus if not already set
|
||||||
// TODO FOCUS: this is probably stupid, we shouldn't define focus in two
|
|
||||||
// places. We should probably put the active workspace on the sway_output
|
|
||||||
// struct instead of trying to do focus semantics like this
|
|
||||||
struct sway_seat *seat = NULL;
|
struct sway_seat *seat = NULL;
|
||||||
wl_list_for_each(seat, &input_manager->seats, link) {
|
wl_list_for_each(seat, &input_manager->seats, link) {
|
||||||
if (!seat->focus) {
|
if (!seat->has_focus) {
|
||||||
seat->focus = ws;
|
sway_seat_set_focus(seat, ws);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ws_name);
|
free(ws_name);
|
||||||
|
wl_signal_emit(&root_container.sway_root->events.new_container, output);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +197,7 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
|
||||||
|
|
||||||
add_child(output, workspace);
|
add_child(output, workspace);
|
||||||
sort_workspaces(output);
|
sort_workspaces(output);
|
||||||
|
wl_signal_emit(&root_container.sway_root->events.new_container, workspace);
|
||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +220,9 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) {
|
||||||
add_child(sibling, swayc);
|
add_child(sibling, swayc);
|
||||||
} else {
|
} else {
|
||||||
// Regular case, create as sibling of current container
|
// Regular case, create as sibling of current container
|
||||||
// TODO WLR
|
add_sibling(sibling, swayc);
|
||||||
//add_sibling(sibling, swayc);
|
|
||||||
}
|
}
|
||||||
|
wl_signal_emit(&root_container.sway_root->events.new_container, swayc);
|
||||||
return swayc;
|
return swayc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,6 +248,8 @@ swayc_t *destroy_output(swayc_t *output) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&output->sway_output->output_destroy.link);
|
||||||
|
|
||||||
wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
|
wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
|
||||||
free_swayc(output);
|
free_swayc(output);
|
||||||
|
|
||||||
|
@ -273,7 +288,11 @@ swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
|
||||||
|
|
||||||
swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
struct wlr_surface **surface, double *sx, double *sy) {
|
||||||
list_t *queue = create_list();
|
list_t *queue = get_bfs_queue();
|
||||||
|
if (!queue) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
list_add(queue, parent);
|
list_add(queue, parent);
|
||||||
|
|
||||||
swayc_t *swayc = NULL;
|
swayc_t *swayc = NULL;
|
||||||
|
@ -313,7 +332,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
||||||
*sx = view_sx - popup_sx;
|
*sx = view_sx - popup_sx;
|
||||||
*sy = view_sy - popup_sy;
|
*sy = view_sy - popup_sy;
|
||||||
*surface = popup->surface;
|
*surface = popup->surface;
|
||||||
list_free(queue);
|
|
||||||
return swayc;
|
return swayc;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -332,7 +350,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
||||||
*sx = view_sx - sub_x;
|
*sx = view_sx - sub_x;
|
||||||
*sy = view_sy - sub_y;
|
*sy = view_sy - sub_y;
|
||||||
*surface = subsurface->surface;
|
*surface = subsurface->surface;
|
||||||
list_free(queue);
|
|
||||||
return swayc;
|
return swayc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +361,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
||||||
*sx = view_sx;
|
*sx = view_sx;
|
||||||
*sy = view_sy;
|
*sy = view_sy;
|
||||||
*surface = swayc->sway_view->surface;
|
*surface = swayc->sway_view->surface;
|
||||||
list_free(queue);
|
|
||||||
return swayc;
|
return swayc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -352,8 +368,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list_free(queue);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,3 +392,39 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi
|
||||||
f(container, data);
|
f(container, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data),
|
||||||
|
void *data) {
|
||||||
|
list_t *queue = get_bfs_queue();
|
||||||
|
if (!queue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue == NULL) {
|
||||||
|
wlr_log(L_ERROR, "could not allocate list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add(queue, con);
|
||||||
|
|
||||||
|
swayc_t *current = NULL;
|
||||||
|
while (queue->length) {
|
||||||
|
current = queue->items[0];
|
||||||
|
list_del(queue, 0);
|
||||||
|
f(current, data);
|
||||||
|
// TODO floating containers
|
||||||
|
list_cat(queue, current->children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) {
|
||||||
|
if (container->type == C_WORKSPACE) {
|
||||||
|
container->workspace_layout = layout;
|
||||||
|
if (layout == L_HORIZ || layout == L_VERT) {
|
||||||
|
container->layout = layout;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
container->layout = layout;
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "sway/layout.h"
|
#include "sway/layout.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/view.h"
|
#include "sway/view.h"
|
||||||
|
#include "sway/input/seat.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
@ -48,10 +49,12 @@ void init_layout(void) {
|
||||||
root_container.layout = L_NONE;
|
root_container.layout = L_NONE;
|
||||||
root_container.name = strdup("root");
|
root_container.name = strdup("root");
|
||||||
root_container.children = create_list();
|
root_container.children = create_list();
|
||||||
|
wl_signal_init(&root_container.events.destroy);
|
||||||
|
|
||||||
root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
|
root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
|
||||||
root_container.sway_root->output_layout = wlr_output_layout_create();
|
root_container.sway_root->output_layout = wlr_output_layout_create();
|
||||||
wl_list_init(&root_container.sway_root->unmanaged_views);
|
wl_list_init(&root_container.sway_root->unmanaged_views);
|
||||||
|
wl_signal_init(&root_container.sway_root->events.new_container);
|
||||||
|
|
||||||
root_container.sway_root->output_layout_change.notify =
|
root_container.sway_root->output_layout_change.notify =
|
||||||
output_layout_change_notify;
|
output_layout_change_notify;
|
||||||
|
@ -59,6 +62,32 @@ void init_layout(void) {
|
||||||
&root_container.sway_root->output_layout_change);
|
&root_container.sway_root->output_layout_change);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int index_child(const swayc_t *child) {
|
||||||
|
// TODO handle floating
|
||||||
|
swayc_t *parent = child->parent;
|
||||||
|
int i, len;
|
||||||
|
len = parent->children->length;
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
if (parent->children->items[i] == child) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sway_assert(i < len, "Stray container")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *add_sibling(swayc_t *fixed, swayc_t *active) {
|
||||||
|
// TODO handle floating
|
||||||
|
swayc_t *parent = fixed->parent;
|
||||||
|
int i = index_child(fixed);
|
||||||
|
list_insert(parent->children, i + 1, active);
|
||||||
|
active->parent = parent;
|
||||||
|
return active->parent;
|
||||||
|
}
|
||||||
|
|
||||||
void add_child(swayc_t *parent, swayc_t *child) {
|
void add_child(swayc_t *parent, swayc_t *child) {
|
||||||
wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
|
wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
|
||||||
child, child->type, child->width, child->height,
|
child, child->type, child->width, child->height,
|
||||||
|
@ -66,9 +95,6 @@ void add_child(swayc_t *parent, swayc_t *child) {
|
||||||
list_add(parent->children, child);
|
list_add(parent->children, child);
|
||||||
child->parent = parent;
|
child->parent = parent;
|
||||||
// set focus for this container
|
// set focus for this container
|
||||||
if (!parent->focused) {
|
|
||||||
parent->focused = child;
|
|
||||||
}
|
|
||||||
/* TODO WLR
|
/* TODO WLR
|
||||||
if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) {
|
if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) {
|
||||||
child = new_container(child, parent->workspace_layout);
|
child = new_container(child, parent->workspace_layout);
|
||||||
|
@ -321,3 +347,244 @@ void apply_vert_layout(swayc_t *container,
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get swayc in the direction of newly entered output.
|
||||||
|
*/
|
||||||
|
static swayc_t *get_swayc_in_output_direction(swayc_t *output,
|
||||||
|
enum movement_direction dir, struct sway_seat *seat) {
|
||||||
|
if (!output) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *ws = sway_seat_get_focus_inactive(seat, output);
|
||||||
|
if (ws->type != C_WORKSPACE) {
|
||||||
|
ws = swayc_parent_by_type(ws, C_WORKSPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws == NULL) {
|
||||||
|
wlr_log(L_ERROR, "got an output without a workspace");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws->children->length > 0) {
|
||||||
|
switch (dir) {
|
||||||
|
case MOVE_LEFT:
|
||||||
|
// get most right child of new output
|
||||||
|
return ws->children->items[ws->children->length-1];
|
||||||
|
case MOVE_RIGHT:
|
||||||
|
// get most left child of new output
|
||||||
|
return ws->children->items[0];
|
||||||
|
case MOVE_UP:
|
||||||
|
case MOVE_DOWN: {
|
||||||
|
swayc_t *focused = sway_seat_get_focus_inactive(seat, ws);
|
||||||
|
if (focused && focused->parent) {
|
||||||
|
swayc_t *parent = focused->parent;
|
||||||
|
if (parent->layout == L_VERT) {
|
||||||
|
if (dir == MOVE_UP) {
|
||||||
|
// get child furthest down on new output
|
||||||
|
return parent->children->items[parent->children->length-1];
|
||||||
|
} else if (dir == MOVE_DOWN) {
|
||||||
|
// get child furthest up on new output
|
||||||
|
return parent->children->items[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return focused;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_layout_center_position(swayc_t *container, int *x, int *y) {
|
||||||
|
// FIXME view coords are inconsistently referred to in layout/output systems
|
||||||
|
if (container->type == C_OUTPUT) {
|
||||||
|
*x = container->x + container->width/2;
|
||||||
|
*y = container->y + container->height/2;
|
||||||
|
} else {
|
||||||
|
swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
|
||||||
|
if (container->type == C_WORKSPACE) {
|
||||||
|
// Workspace coordinates are actually wrong/arbitrary, but should
|
||||||
|
// be same as output.
|
||||||
|
*x = output->x;
|
||||||
|
*y = output->y;
|
||||||
|
} else {
|
||||||
|
*x = output->x + container->x;
|
||||||
|
*y = output->y + container->y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out) {
|
||||||
|
switch (dir) {
|
||||||
|
case MOVE_UP:
|
||||||
|
*out = WLR_DIRECTION_UP;
|
||||||
|
break;
|
||||||
|
case MOVE_DOWN:
|
||||||
|
*out = WLR_DIRECTION_DOWN;
|
||||||
|
break;
|
||||||
|
case MOVE_LEFT:
|
||||||
|
*out = WLR_DIRECTION_LEFT;
|
||||||
|
break;
|
||||||
|
case MOVE_RIGHT:
|
||||||
|
*out = WLR_DIRECTION_RIGHT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static swayc_t *sway_output_from_wlr(struct wlr_output *output) {
|
||||||
|
if (output == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < root_container.children->length; ++i) {
|
||||||
|
swayc_t *o = root_container.children->items[i];
|
||||||
|
if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static swayc_t *get_swayc_in_direction_under(swayc_t *container,
|
||||||
|
enum movement_direction dir, struct sway_seat *seat, swayc_t *limit) {
|
||||||
|
if (dir == MOVE_CHILD) {
|
||||||
|
return sway_seat_get_focus_inactive(seat, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *parent = container->parent;
|
||||||
|
if (dir == MOVE_PARENT) {
|
||||||
|
if (parent->type == C_OUTPUT) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir == MOVE_PREV || dir == MOVE_NEXT) {
|
||||||
|
int focused_idx = index_child(container);
|
||||||
|
if (focused_idx == -1) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) %
|
||||||
|
parent->children->length;
|
||||||
|
if (desired < 0) {
|
||||||
|
desired += parent->children->length;
|
||||||
|
}
|
||||||
|
return parent->children->items[desired];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If moving to an adjacent output we need a starting position (since this
|
||||||
|
// output might border to multiple outputs).
|
||||||
|
//struct wlc_point abs_pos;
|
||||||
|
//get_layout_center_position(container, &abs_pos);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO WLR fullscreen
|
||||||
|
/*
|
||||||
|
if (container->type == C_VIEW && swayc_is_fullscreen(container)) {
|
||||||
|
wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output");
|
||||||
|
container = swayc_parent_by_type(container, C_OUTPUT);
|
||||||
|
get_layout_center_position(container, &abs_pos);
|
||||||
|
swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true);
|
||||||
|
return get_swayc_in_output_direction(output, dir);
|
||||||
|
}
|
||||||
|
if (container->type == C_WORKSPACE && container->fullscreen) {
|
||||||
|
sway_log(L_DEBUG, "Moving to fullscreen view");
|
||||||
|
return container->fullscreen;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
swayc_t *wrap_candidate = NULL;
|
||||||
|
while (true) {
|
||||||
|
// Test if we can even make a difference here
|
||||||
|
bool can_move = false;
|
||||||
|
int desired;
|
||||||
|
int idx = index_child(container);
|
||||||
|
if (parent->type == C_ROOT) {
|
||||||
|
enum wlr_direction wlr_dir = 0;
|
||||||
|
if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir),
|
||||||
|
"got invalid direction: %d", dir)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int lx, ly;
|
||||||
|
get_layout_center_position(container, &lx, &ly);
|
||||||
|
struct wlr_output_layout *layout = root_container.sway_root->output_layout;
|
||||||
|
struct wlr_output *wlr_adjacent =
|
||||||
|
wlr_output_layout_adjacent_output(layout, wlr_dir,
|
||||||
|
container->sway_output->wlr_output, lx, ly);
|
||||||
|
swayc_t *adjacent = sway_output_from_wlr(wlr_adjacent);
|
||||||
|
|
||||||
|
if (!adjacent || adjacent == container) {
|
||||||
|
return wrap_candidate;
|
||||||
|
}
|
||||||
|
swayc_t *next = get_swayc_in_output_direction(adjacent, dir, seat);
|
||||||
|
if (next == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (next->children && next->children->length) {
|
||||||
|
// TODO consider floating children as well
|
||||||
|
return sway_seat_get_focus_inactive(seat, next);
|
||||||
|
} else {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
|
||||||
|
if (parent->layout == L_HORIZ || parent->layout == L_TABBED) {
|
||||||
|
can_move = true;
|
||||||
|
desired = idx + (dir == MOVE_LEFT ? -1 : 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parent->layout == L_VERT || parent->layout == L_STACKED) {
|
||||||
|
can_move = true;
|
||||||
|
desired = idx + (dir == MOVE_UP ? -1 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_move) {
|
||||||
|
// TODO handle floating
|
||||||
|
if (desired < 0 || desired >= parent->children->length) {
|
||||||
|
can_move = false;
|
||||||
|
int len = parent->children->length;
|
||||||
|
if (!wrap_candidate && len > 1) {
|
||||||
|
if (desired < 0) {
|
||||||
|
wrap_candidate = parent->children->items[len-1];
|
||||||
|
} else {
|
||||||
|
wrap_candidate = parent->children->items[0];
|
||||||
|
}
|
||||||
|
if (config->force_focus_wrapping) {
|
||||||
|
return wrap_candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wlr_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__,
|
||||||
|
idx, container, dir, desired, parent->children->items[desired]);
|
||||||
|
return parent->children->items[desired];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!can_move) {
|
||||||
|
container = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
if (!parent || container == limit) {
|
||||||
|
// wrapping is the last chance
|
||||||
|
return wrap_candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swayc_t *get_swayc_in_direction(swayc_t *container, struct sway_seat *seat,
|
||||||
|
enum movement_direction dir) {
|
||||||
|
return get_swayc_in_direction_under(container, dir, seat, NULL);
|
||||||
|
}
|
||||||
|
|
|
@ -63,9 +63,10 @@ static bool _workspace_by_name(swayc_t *view, void *data) {
|
||||||
swayc_t *workspace_by_name(const char *name) {
|
swayc_t *workspace_by_name(const char *name) {
|
||||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||||
swayc_t *current_workspace = NULL, *current_output = NULL;
|
swayc_t *current_workspace = NULL, *current_output = NULL;
|
||||||
if (seat->focus) {
|
swayc_t *focus = sway_seat_get_focus(seat);
|
||||||
current_workspace = swayc_parent_by_type(seat->focus, C_WORKSPACE);
|
if (focus) {
|
||||||
current_output = swayc_parent_by_type(seat->focus, C_OUTPUT);
|
current_workspace = swayc_parent_by_type(focus, C_WORKSPACE);
|
||||||
|
current_output = swayc_parent_by_type(focus, C_OUTPUT);
|
||||||
}
|
}
|
||||||
if (strcmp(name, "prev") == 0) {
|
if (strcmp(name, "prev") == 0) {
|
||||||
return workspace_prev(current_workspace);
|
return workspace_prev(current_workspace);
|
||||||
|
@ -102,7 +103,8 @@ swayc_t *workspace_create(const char *name) {
|
||||||
}
|
}
|
||||||
// Otherwise create a new one
|
// Otherwise create a new one
|
||||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||||
parent = seat->focus;
|
swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container);
|
||||||
|
parent = focus;
|
||||||
parent = swayc_parent_by_type(parent, C_OUTPUT);
|
parent = swayc_parent_by_type(parent, C_OUTPUT);
|
||||||
return new_workspace(parent, name);
|
return new_workspace(parent, name);
|
||||||
}
|
}
|
||||||
|
@ -118,9 +120,15 @@ swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||||
|
swayc_t *focus = sway_seat_get_focus_inactive(seat, output);
|
||||||
|
swayc_t *workspace = (focus->type == C_WORKSPACE ?
|
||||||
|
focus :
|
||||||
|
swayc_parent_by_type(focus, C_WORKSPACE));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < output->children->length; i++) {
|
for (i = 0; i < output->children->length; i++) {
|
||||||
if (output->children->items[i] == output->focused) {
|
if (output->children->items[i] == workspace) {
|
||||||
return output->children->items[
|
return output->children->items[
|
||||||
wrap(i + (next ? 1 : -1), output->children->length)];
|
wrap(i + (next ? 1 : -1), output->children->length)];
|
||||||
}
|
}
|
||||||
|
@ -193,12 +201,13 @@ bool workspace_switch(swayc_t *workspace) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||||
if (!seat || !seat->focus) {
|
swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container);
|
||||||
|
if (!seat || !focus) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
swayc_t *active_ws = seat->focus;
|
swayc_t *active_ws = focus;
|
||||||
if (active_ws->type != C_WORKSPACE) {
|
if (active_ws->type != C_WORKSPACE) {
|
||||||
swayc_parent_by_type(seat->focus, C_WORKSPACE);
|
swayc_parent_by_type(focus, C_WORKSPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->auto_back_and_forth
|
if (config->auto_back_and_forth
|
||||||
|
@ -222,16 +231,12 @@ bool workspace_switch(swayc_t *workspace) {
|
||||||
// TODO: Deal with sticky containers
|
// TODO: Deal with sticky containers
|
||||||
|
|
||||||
wlr_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
|
wlr_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
|
||||||
// TODO FOCUS: Focus the last view this seat had focused on this workspace
|
swayc_t *next = sway_seat_get_focus_inactive(seat, workspace);
|
||||||
if (workspace->children->length) {
|
if (next == NULL) {
|
||||||
// TODO FOCUS: This is really fucking stupid
|
next = workspace;
|
||||||
sway_seat_set_focus(seat, workspace->children->items[0]);
|
|
||||||
} else {
|
|
||||||
sway_seat_set_focus(seat, workspace);
|
|
||||||
}
|
}
|
||||||
|
sway_seat_set_focus(seat, next);
|
||||||
swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
|
swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
|
||||||
// TODO FOCUS: take a look at this
|
|
||||||
output->focused = workspace;
|
|
||||||
arrange_windows(output, -1, -1);
|
arrange_windows(output, -1, -1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue