diff --git a/include/sway/config.h b/include/sway/config.h index 6024f0f60..2fef0081a 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -407,7 +407,9 @@ struct sway_config { struct output_config *output_config; struct seat_config *seat_config; struct sway_seat *seat; - struct sway_container *current_container; + struct sway_node *node; + struct sway_container *container; + struct sway_workspace *workspace; bool using_criteria; struct { int argc; @@ -486,8 +488,7 @@ struct output_config *new_output_config(const char *name); void merge_output_config(struct output_config *dst, struct output_config *src); -void apply_output_config(struct output_config *oc, - struct sway_container *output); +void apply_output_config(struct output_config *oc, struct sway_output *output); struct output_config *store_output_config(struct output_config *oc); diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h index 7ac924e7e..66e8c9a25 100644 --- a/include/sway/desktop/transaction.h +++ b/include/sway/desktop/transaction.h @@ -1,7 +1,6 @@ #ifndef _SWAY_TRANSACTION_H #define _SWAY_TRANSACTION_H -#include -#include "sway/tree/container.h" +#include /** * Transactions enable us to perform atomic layout updates. @@ -21,6 +20,7 @@ */ struct sway_transaction_instruction; +struct sway_view; /** * Find all dirty containers, create and commit a transaction containing them, diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index aa2f6f19b..bde3cf46c 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -37,10 +37,10 @@ struct sway_input_manager { struct sway_input_manager *input_manager_create(struct sway_server *server); bool input_manager_has_focus(struct sway_input_manager *input, - struct sway_container *container); + struct sway_node *node); void input_manager_set_focus(struct sway_input_manager *input, - struct sway_container *container); + struct sway_node *node); void input_manager_configure_xcursor(struct sway_input_manager *input); diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 5c404ecd3..8a7e5450a 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -13,9 +13,9 @@ struct sway_seat_device { struct wl_list link; // sway_seat::devices }; -struct sway_seat_container { +struct sway_seat_node { struct sway_seat *seat; - struct sway_container *container; + struct sway_node *node; struct wl_list link; // sway_seat::focus_stack @@ -76,7 +76,7 @@ struct sway_seat { uint32_t last_button_serial; struct wl_listener focus_destroy; - struct wl_listener new_container; + struct wl_listener new_node; struct wl_listener new_drag_icon; struct wl_list devices; // sway_seat_device::link @@ -100,10 +100,10 @@ void seat_remove_device(struct sway_seat *seat, void seat_configure_xcursor(struct sway_seat *seat); -void seat_set_focus(struct sway_seat *seat, struct sway_container *container); +void seat_set_focus(struct sway_seat *seat, struct sway_node *node); void seat_set_focus_warp(struct sway_seat *seat, - struct sway_container *container, bool warp, bool notify); + struct sway_node *node, bool warp, bool notify); void seat_set_focus_surface(struct sway_seat *seat, struct wlr_surface *surface, bool unfocus); @@ -114,7 +114,11 @@ void seat_set_focus_layer(struct sway_seat *seat, void seat_set_exclusive_client(struct sway_seat *seat, struct wl_client *client); -struct sway_container *seat_get_focus(struct sway_seat *seat); +struct sway_node *seat_get_focus(struct sway_seat *seat); + +struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat); + +struct sway_container *seat_get_focused_container(struct sway_seat *seat); /** * Return the last container to be focused for the seat (or the most recently @@ -125,32 +129,31 @@ struct sway_container *seat_get_focus(struct sway_seat *seat); * is destroyed, or focus moves to a container with children and we need to * descend into the next leaf in focus order. */ -struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, - struct sway_container *container); +struct sway_node *seat_get_focus_inactive(struct sway_seat *seat, + struct sway_node *node); struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, - struct sway_container *container); + struct sway_workspace *workspace); /** * Descend into the focus stack to find the focus-inactive view. Useful for * container placement when they change position in the tree. */ struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, - struct sway_container *container); + struct sway_node *ancestor); /** * Return the immediate child of container which was most recently focused. */ -struct sway_container *seat_get_active_child(struct sway_seat *seat, - struct sway_container *container); +struct sway_node *seat_get_active_child(struct sway_seat *seat, + struct sway_node *parent); /** * Iterate over the focus-inactive children of the container calling the * function on each. */ -void seat_focus_inactive_children_for_each(struct sway_seat *seat, - struct sway_container *container, - void (*f)(struct sway_container *container, void *data), void *data); +void seat_for_each_node(struct sway_seat *seat, + void (*f)(struct sway_node *node, void *data), void *data); void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config); @@ -173,7 +176,7 @@ void seat_begin_resize_tiling(struct sway_seat *seat, struct sway_container *con, uint32_t button, enum wlr_edges edge); struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, - struct sway_container *container); + struct sway_workspace *workspace); void seat_end_mouse_operation(struct sway_seat *seat); diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h index eaaa21645..fef243e38 100644 --- a/include/sway/ipc-json.h +++ b/include/sway/ipc-json.h @@ -7,8 +7,8 @@ json_object *ipc_json_get_version(); json_object *ipc_json_describe_disabled_output(struct sway_output *o); -json_object *ipc_json_describe_container(struct sway_container *c); -json_object *ipc_json_describe_container_recursive(struct sway_container *c); +json_object *ipc_json_describe_node(struct sway_node *node); +json_object *ipc_json_describe_node_recursive(struct sway_node *node); json_object *ipc_json_describe_input(struct sway_input_device *device); json_object *ipc_json_describe_seat(struct sway_seat *seat); json_object *ipc_json_describe_bar_config(struct bar_config *bar); diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 4b6d0e256..80180ec4e 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -11,8 +11,8 @@ void ipc_init(struct sway_server *server); struct sockaddr_un *ipc_user_sockaddr(void); -void ipc_event_workspace(struct sway_container *old, - struct sway_container *new, const char *change); +void ipc_event_workspace(struct sway_workspace *old, + struct sway_workspace *new, const char *change); void ipc_event_window(struct sway_container *window, const char *change); void ipc_event_barconfig_update(struct bar_config *bar); void ipc_event_mode(const char *mode, bool pango); diff --git a/include/sway/output.h b/include/sway/output.h index 651fdfe77..540ed8a03 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -6,14 +6,20 @@ #include #include #include "config.h" +#include "sway/tree/node.h" #include "sway/tree/view.h" struct sway_server; struct sway_container; +struct sway_output_state { + list_t *workspaces; + struct sway_workspace *active_workspace; +}; + struct sway_output { + struct sway_node node; struct wlr_output *wlr_output; - struct sway_container *swayc; struct sway_server *server; struct wl_list layers[4]; // sway_layer_surface::link @@ -22,11 +28,15 @@ struct sway_output { struct timespec last_frame; struct wlr_output_damage *damage; + bool enabled; + list_t *workspaces; + + struct sway_output_state current; + struct wl_listener destroy; struct wl_listener mode; struct wl_listener transform; struct wl_listener scale; - struct wl_listener damage_destroy; struct wl_listener damage_frame; @@ -39,13 +49,19 @@ struct sway_output { } events; }; -struct sway_container *output_create(struct sway_output *sway_output); +struct sway_output *output_create(struct wlr_output *wlr_output); -void output_destroy(struct sway_container *output); +void output_destroy(struct sway_output *output); -void output_begin_destroy(struct sway_container *output); +void output_begin_destroy(struct sway_output *output); -struct sway_container *output_from_wlr_output(struct wlr_output *output); +struct sway_output *output_from_wlr_output(struct wlr_output *output); + +struct sway_output *output_get_in_direction(struct sway_output *reference, + enum movement_direction direction); + +void output_add_workspace(struct sway_output *output, + struct sway_workspace *workspace); typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, struct wlr_surface *surface, struct wlr_box *box, float rotation, @@ -64,15 +80,19 @@ void output_damage_box(struct sway_output *output, struct wlr_box *box); void output_damage_whole_container(struct sway_output *output, struct sway_container *con); -struct sway_container *output_by_name(const char *name); +struct sway_output *output_by_name(const char *name); -void output_sort_workspaces(struct sway_container *output); +void output_sort_workspaces(struct sway_output *output); -void output_enable(struct sway_output *output); +struct output_config *output_find_config(struct sway_output *output); + +void output_enable(struct sway_output *output, struct output_config *oc); + +void output_disable(struct sway_output *output); bool output_has_opaque_overlay_layer_surface(struct sway_output *output); -struct sway_container *output_get_active_workspace(struct sway_output *output); +struct sway_workspace *output_get_active_workspace(struct sway_output *output); void output_render(struct sway_output *output, struct timespec *when, pixman_region32_t *damage); @@ -103,16 +123,23 @@ void output_drag_icons_for_each_surface(struct sway_output *output, struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, void *user_data); -void output_for_each_workspace(struct sway_container *output, +void output_for_each_workspace(struct sway_output *output, + void (*f)(struct sway_workspace *ws, void *data), void *data); + +void output_for_each_container(struct sway_output *output, void (*f)(struct sway_container *con, void *data), void *data); -void output_for_each_container(struct sway_container *output, - void (*f)(struct sway_container *con, void *data), void *data); +struct sway_workspace *output_find_workspace(struct sway_output *output, + bool (*test)(struct sway_workspace *ws, void *data), void *data); -struct sway_container *output_find_workspace(struct sway_container *output, +struct sway_container *output_find_container(struct sway_output *output, bool (*test)(struct sway_container *con, void *data), void *data); -struct sway_container *output_find_container(struct sway_container *output, - bool (*test)(struct sway_container *con, void *data), void *data); +void output_get_box(struct sway_output *output, struct wlr_box *box); + +enum sway_container_layout output_get_default_layout( + struct sway_output *output); + +void output_add_listeners(struct sway_output *output); #endif diff --git a/include/sway/server.h b/include/sway/server.h index 1e20f2c8d..07e0949a0 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -56,7 +56,7 @@ struct sway_server { size_t txn_timeout_ms; list_t *transactions; - list_t *dirty_containers; + list_t *dirty_nodes; }; struct sway_server server; diff --git a/include/sway/tree/arrange.h b/include/sway/tree/arrange.h index f47e8db5e..06a2279c1 100644 --- a/include/sway/tree/arrange.h +++ b/include/sway/tree/arrange.h @@ -1,16 +1,19 @@ #ifndef _SWAY_ARRANGE_H #define _SWAY_ARRANGE_H +struct sway_output; +struct sway_workspace; struct sway_container; +struct sway_node; void arrange_container(struct sway_container *container); -void arrange_workspace(struct sway_container *workspace); +void arrange_workspace(struct sway_workspace *workspace); -void arrange_output(struct sway_container *output); +void arrange_output(struct sway_output *output); void arrange_root(void); -void arrange_windows(struct sway_container *container); +void arrange_node(struct sway_node *node); #endif diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index e4071cfea..c51425c93 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -5,8 +5,7 @@ #include #include #include "list.h" - -extern struct sway_container root_container; +#include "sway/tree/node.h" struct sway_view; struct sway_seat; @@ -17,23 +16,6 @@ struct sway_seat; #define TITLEBAR_H_PADDING 3 #define TITLEBAR_V_PADDING 4 -/** - * Different kinds of containers. - * - * This enum is in order. A container will never be inside of a container below - * it on this list. - */ -enum sway_container_type { - C_ROOT, - C_OUTPUT, - C_WORKSPACE, - C_CONTAINER, - C_VIEW, - - // Keep last - C_TYPES, -}; - enum sway_container_layout { L_NONE, L_HORIZ, @@ -57,18 +39,14 @@ enum movement_direction; enum wlr_direction; struct sway_container_state { - // Container/swayc properties + // Container properties enum sway_container_layout layout; - double swayc_x, swayc_y; - double swayc_width, swayc_height; + double con_x, con_y; + double con_width, con_height; bool is_fullscreen; - bool has_gaps; - double current_gaps; - double gaps_inner; - double gaps_outer; - + struct sway_workspace *workspace; struct sway_container *parent; list_t *children; @@ -86,35 +64,19 @@ struct sway_container_state { bool border_left; bool border_right; bool using_csd; - - // Workspace properties - struct sway_container *ws_fullscreen; - list_t *ws_floating; }; struct sway_container { - union { - // TODO: Encapsulate state for other node types as well like C_CONTAINER - struct sway_root *sway_root; - struct sway_output *sway_output; - struct sway_workspace *sway_workspace; - struct sway_view *sway_view; - }; - - /** - * A unique ID to identify this container. Primarily used in the - * get_tree JSON output. - */ - size_t id; + struct sway_node node; + struct sway_view *view; // The pending state is the main container properties, and the current state is in the below struct. // This means most places of the code can refer to the main variables (pending state) and it'll just work. struct sway_container_state current; - char *name; // The view's title (unformatted) + char *title; // The view's title (unformatted) char *formatted_title; // The title displayed in the title bar - enum sway_container_type type; enum sway_container_layout layout; enum sway_container_layout prev_split_layout; @@ -132,14 +94,13 @@ struct sway_container { // The gaps currently applied to the container. double current_gaps; - bool has_gaps; double gaps_inner; double gaps_outer; - list_t *children; - - struct sway_container *parent; + struct sway_workspace *workspace; // NULL when hidden in the scratchpad + struct sway_container *parent; // NULL if container in root of workspace + list_t *children; // struct sway_container // Outputs currently being intersected list_t *outputs; // struct sway_output @@ -157,42 +118,17 @@ struct sway_container { struct wlr_texture *title_urgent; size_t title_height; - // The number of transactions which reference this container. - size_t ntxnrefs; - - // If this container is a view and is waiting for the client to respond to a - // configure then this will be populated, otherwise NULL. - struct sway_transaction_instruction *instruction; - - bool destroying; - - // If true, indicates that the container has pending state that differs from - // the current. - bool dirty; - struct { struct wl_signal destroy; } events; }; -struct sway_container *container_create(enum sway_container_type type); - -const char *container_type_to_str(enum sway_container_type type); - -/* - * Create a new view container. A view can be a child of a workspace container - * or a container container and are rendered in the order and structure of - * how they are attached to the tree. - */ -struct sway_container *container_view_create( - struct sway_container *sibling, struct sway_view *sway_view); +struct sway_container *container_create(struct sway_view *view); void container_destroy(struct sway_container *con); void container_begin_destroy(struct sway_container *con); -struct sway_container *container_close(struct sway_container *container); - /** * Search a container's descendants a container based on test criteria. Returns * the first container that passes the test. @@ -200,23 +136,17 @@ struct sway_container *container_close(struct sway_container *container); struct sway_container *container_find_child(struct sway_container *container, bool (*test)(struct sway_container *view, void *data), void *data); -/** - * Finds a parent container with the given struct sway_containerype. - */ -struct sway_container *container_parent(struct sway_container *container, - enum sway_container_type type); - /** * Find a container at the given coordinates. Returns the the surface and * surface-local coordinates of the given layout coordinates if the container * is a view and the view contains a surface at those coordinates. */ -struct sway_container *container_at(struct sway_container *workspace, +struct sway_container *container_at(struct sway_workspace *workspace, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); struct sway_container *tiling_container_at( - struct sway_container *con, double lx, double ly, + struct sway_node *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); void container_for_each_child(struct sway_container *container, @@ -228,16 +158,11 @@ void container_for_each_child(struct sway_container *container, bool container_has_ancestor(struct sway_container *container, struct sway_container *ancestor); -int container_count_descendants_of_type(struct sway_container *con, - enum sway_container_type type); - -void container_create_notify(struct sway_container *container); - void container_update_textures_recursive(struct sway_container *con); void container_damage_whole(struct sway_container *container); -struct sway_container *container_reap_empty(struct sway_container *con); +void container_reap_empty(struct sway_container *con); struct sway_container *container_flatten(struct sway_container *container); @@ -248,11 +173,10 @@ void container_update_title_textures(struct sway_container *container); */ void container_calculate_title_height(struct sway_container *container); -/** - * Notify a container that a tree modification has changed in its children, - * so the container can update its tree representation. - */ -void container_notify_subtree_changed(struct sway_container *container); +size_t container_build_representation(enum sway_container_layout layout, + list_t *children, char *buffer); + +void container_update_representation(struct sway_container *container); /** * Return the height of a regular title bar. @@ -288,8 +212,7 @@ void container_floating_translate(struct sway_container *con, /** * Choose an output for the floating container's new position. */ -struct sway_container *container_floating_find_output( - struct sway_container *con); +struct sway_output *container_floating_find_output(struct sway_container *con); /** * Move a floating container to a new layout-local position. @@ -302,12 +225,6 @@ void container_floating_move_to(struct sway_container *con, */ 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. - */ -void container_set_dirty(struct sway_container *container); - bool container_has_urgent_child(struct sway_container *container); /** @@ -342,10 +259,18 @@ void container_remove_gaps(struct sway_container *container); void container_add_gaps(struct sway_container *container); +enum sway_container_layout container_parent_layout(struct sway_container *con); + +enum sway_container_layout container_current_parent_layout( + struct sway_container *con); + +list_t *container_get_siblings(const struct sway_container *container); + int container_sibling_index(const struct sway_container *child); -void container_handle_fullscreen_reparent(struct sway_container *con, - struct sway_container *old_parent); +list_t *container_get_current_siblings(struct sway_container *container); + +void container_handle_fullscreen_reparent(struct sway_container *con); void container_add_child(struct sway_container *parent, struct sway_container *child); @@ -353,19 +278,16 @@ void container_add_child(struct sway_container *parent, void container_insert_child(struct sway_container *parent, struct sway_container *child, int i); -struct sway_container *container_add_sibling(struct sway_container *parent, - struct sway_container *child); +void container_add_sibling(struct sway_container *parent, + struct sway_container *child, int offset); -struct sway_container *container_remove_child(struct sway_container *child); +void container_detach(struct sway_container *child); -struct sway_container *container_replace_child(struct sway_container *child, - struct sway_container *new_child); +void container_replace(struct sway_container *container, + struct sway_container *replacement); bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out); -enum sway_container_layout container_get_default_layout( - struct sway_container *con); - struct sway_container *container_split(struct sway_container *child, enum sway_container_layout layout); diff --git a/include/sway/tree/node.h b/include/sway/tree/node.h new file mode 100644 index 000000000..5b8c19093 --- /dev/null +++ b/include/sway/tree/node.h @@ -0,0 +1,74 @@ +#ifndef _SWAY_NODE_H +#define _SWAY_NODE_H +#include +#include "list.h" + +struct sway_root; +struct sway_output; +struct sway_workspace; +struct sway_container; +struct sway_transaction_instruction; +struct wlr_box; + +enum sway_node_type { + N_ROOT, + N_OUTPUT, + N_WORKSPACE, + N_CONTAINER, +}; + +struct sway_node { + enum sway_node_type type; + union { + struct sway_root *sway_root; + struct sway_output *sway_output; + struct sway_workspace *sway_workspace; + struct sway_container *sway_container; + }; + + /** + * A unique ID to identify this node. + * Primarily used in the get_tree JSON output. + */ + size_t id; + + struct sway_transaction_instruction *instruction; + size_t ntxnrefs; + bool destroying; + + // If true, indicates that the container has pending state that differs from + // the current. + bool dirty; + + struct { + struct wl_signal destroy; + } events; +}; + +void node_init(struct sway_node *node, enum sway_node_type type, void *thing); + +const char *node_type_to_str(enum sway_node_type type); + +/** + * Mark a node as dirty if it isn't already. Dirty nodes will be included in the + * next transaction then unmarked as dirty. + */ +void node_set_dirty(struct sway_node *node); + +bool node_is_view(struct sway_node *node); + +char *node_get_name(struct sway_node *node); + +void node_get_box(struct sway_node *node, struct wlr_box *box); + +struct sway_output *node_get_output(struct sway_node *node); + +enum sway_container_layout node_get_layout(struct sway_node *node); + +struct sway_node *node_get_parent(struct sway_node *node); + +list_t *node_get_children(struct sway_node *node); + +bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor); + +#endif diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index ec6516c99..a2d464f95 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -5,12 +5,14 @@ #include #include #include "sway/tree/container.h" +#include "sway/tree/node.h" #include "config.h" #include "list.h" -extern struct sway_container root_container; +extern struct sway_root *root; struct sway_root { + struct sway_node node; struct wlr_output_layout *output_layout; struct wl_listener output_layout_change; @@ -24,17 +26,21 @@ struct sway_root { // Includes disabled outputs struct wl_list all_outputs; // sway_output::link + double x, y; + double width, height; + + list_t *outputs; // struct sway_output list_t *scratchpad; // struct sway_container list_t *saved_workspaces; // For when there's no connected outputs struct { - struct wl_signal new_container; + struct wl_signal new_node; } events; }; -void root_create(void); +struct sway_root *root_create(void); -void root_destroy(void); +void root_destroy(struct sway_root *root); /** * Move a container to the scratchpad. @@ -56,23 +62,25 @@ void root_scratchpad_show(struct sway_container *con); */ void root_scratchpad_hide(struct sway_container *con); -struct sway_container *root_workspace_for_pid(pid_t pid); +struct sway_workspace *root_workspace_for_pid(pid_t pid); void root_record_workspace_pid(pid_t pid); -void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), +void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), void *data); void root_for_each_container(void (*f)(struct sway_container *con, void *data), void *data); -struct sway_container *root_find_output( - bool (*test)(struct sway_container *con, void *data), void *data); +struct sway_output *root_find_output( + bool (*test)(struct sway_output *output, void *data), void *data); -struct sway_container *root_find_workspace( - bool (*test)(struct sway_container *con, void *data), void *data); +struct sway_workspace *root_find_workspace( + bool (*test)(struct sway_workspace *ws, void *data), void *data); struct sway_container *root_find_container( bool (*test)(struct sway_container *con, void *data), void *data); +void root_get_box(struct sway_root *root, struct wlr_box *box); + #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 30d3e742d..439dc1bf6 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -58,7 +58,7 @@ struct sway_view { enum sway_view_type type; const struct sway_view_impl *impl; - struct sway_container *swayc; // NULL for unmapped views + struct sway_container *container; // NULL if unmapped and transactions finished struct wlr_surface *surface; // NULL for unmapped views // Geometry of the view itself (excludes borders) in layout coordinates @@ -254,7 +254,7 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, int height); /** - * Configure the view's position and size based on the swayc's position and + * Configure the view's position and size based on the container's position and * size, taking borders into consideration. */ void view_autoconfigure(struct sway_view *view); diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 043259191..af9a071ab 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -3,66 +3,98 @@ #include #include "sway/tree/container.h" +#include "sway/tree/node.h" struct sway_view; -struct sway_workspace { - struct sway_container *swayc; +struct sway_workspace_state { struct sway_container *fullscreen; - list_t *floating; // struct sway_container + double x, y; + int width, height; + enum sway_container_layout layout; + struct sway_output *output; + list_t *floating; + list_t *tiling; + + struct sway_container *focused_inactive_child; + bool focused; +}; + +struct sway_workspace { + struct sway_node node; + struct sway_container *fullscreen; + + char *name; + char *representation; + + double x, y; + int width, height; + enum sway_container_layout layout; + enum sway_container_layout prev_split_layout; + + double current_gaps; + bool has_gaps; + double gaps_inner; + double gaps_outer; + + struct sway_output *output; // NULL if no outputs are connected + list_t *floating; // struct sway_container + list_t *tiling; // struct sway_container list_t *output_priority; bool urgent; + + struct sway_workspace_state current; }; extern char *prev_workspace_name; -struct sway_container *workspace_get_initial_output(const char *name); +struct sway_output *workspace_get_initial_output(const char *name); -struct sway_container *workspace_create(struct sway_container *output, +struct sway_workspace *workspace_create(struct sway_output *output, const char *name); -void workspace_destroy(struct sway_container *workspace); +void workspace_destroy(struct sway_workspace *workspace); -void workspace_begin_destroy(struct sway_container *workspace); +void workspace_begin_destroy(struct sway_workspace *workspace); -void workspace_consider_destroy(struct sway_container *ws); +void workspace_consider_destroy(struct sway_workspace *ws); char *workspace_next_name(const char *output_name); -bool workspace_switch(struct sway_container *workspace, +bool workspace_switch(struct sway_workspace *workspace, bool no_auto_back_and_forth); -struct sway_container *workspace_by_number(const char* name); +struct sway_workspace *workspace_by_number(const char* name); -struct sway_container *workspace_by_name(const char*); +struct sway_workspace *workspace_by_name(const char*); -struct sway_container *workspace_output_next(struct sway_container *current); +struct sway_workspace *workspace_output_next(struct sway_workspace *current); -struct sway_container *workspace_next(struct sway_container *current); +struct sway_workspace *workspace_next(struct sway_workspace *current); -struct sway_container *workspace_output_prev(struct sway_container *current); +struct sway_workspace *workspace_output_prev(struct sway_workspace *current); -struct sway_container *workspace_prev(struct sway_container *current); +struct sway_workspace *workspace_prev(struct sway_workspace *current); -bool workspace_is_visible(struct sway_container *ws); +bool workspace_is_visible(struct sway_workspace *ws); -bool workspace_is_empty(struct sway_container *ws); +bool workspace_is_empty(struct sway_workspace *ws); -void workspace_output_raise_priority(struct sway_container *workspace, - struct sway_container *old_output, struct sway_container *new_output); +void workspace_output_raise_priority(struct sway_workspace *workspace, + struct sway_output *old_output, struct sway_output *new_output); -void workspace_output_add_priority(struct sway_container *workspace, - struct sway_container *output); +void workspace_output_add_priority(struct sway_workspace *workspace, + struct sway_output *output); -struct sway_container *workspace_output_get_highest_available( - struct sway_container *ws, struct sway_container *exclude); +struct sway_output *workspace_output_get_highest_available( + struct sway_workspace *ws, struct sway_output *exclude); -void workspace_detect_urgent(struct sway_container *workspace); +void workspace_detect_urgent(struct sway_workspace *workspace); -void workspace_for_each_container(struct sway_container *ws, +void workspace_for_each_container(struct sway_workspace *ws, void (*f)(struct sway_container *con, void *data), void *data); -struct sway_container *workspace_find_container(struct sway_container *ws, +struct sway_container *workspace_find_container(struct sway_workspace *ws, bool (*test)(struct sway_container *con, void *data), void *data); /** @@ -70,13 +102,28 @@ struct sway_container *workspace_find_container(struct sway_container *ws, * The new container will be the only direct tiling child of the workspace. * The new container is returned. */ -struct sway_container *workspace_wrap_children(struct sway_container *ws); +struct sway_container *workspace_wrap_children(struct sway_workspace *ws); -void workspace_add_floating(struct sway_container *workspace, +void workspace_detach(struct sway_workspace *workspace); + +void workspace_add_tiling(struct sway_workspace *workspace, struct sway_container *con); -void workspace_remove_gaps(struct sway_container *ws); +void workspace_add_floating(struct sway_workspace *workspace, + struct sway_container *con); -void workspace_add_gaps(struct sway_container *ws); +void workspace_insert_tiling(struct sway_workspace *workspace, + struct sway_container *con, int index); + +void workspace_remove_gaps(struct sway_workspace *ws); + +void workspace_add_gaps(struct sway_workspace *ws); + +struct sway_container *workspace_split(struct sway_workspace *workspace, + enum sway_container_layout layout); + +void workspace_update_representation(struct sway_workspace *ws); + +void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box); #endif diff --git a/sway/commands.c b/sway/commands.c index e72b89167..b32628cdc 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -212,6 +212,24 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, return res; } +static void set_config_node(struct sway_node *node) { + config->handler_context.node = node; + switch (node->type) { + case N_CONTAINER: + config->handler_context.container = node->sway_container; + config->handler_context.workspace = node->sway_container->workspace; + break; + case N_WORKSPACE: + config->handler_context.container = NULL; + config->handler_context.workspace = node->sway_workspace; + break; + default: + config->handler_context.container = NULL; + config->handler_context.workspace = NULL; + break; + } +} + struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { // 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 @@ -295,12 +313,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { if (!config->handler_context.using_criteria) { // without criteria, the command acts upon the focused // container - config->handler_context.current_container = - seat_get_focus_inactive(seat, &root_container); - if (!sway_assert(config->handler_context.current_container, - "could not get focus-inactive for root container")) { - return NULL; - } + set_config_node(seat_get_focus_inactive(seat, &root->node)); struct cmd_results *res = handler->handle(argc-1, argv+1); if (res->status != CMD_SUCCESS) { free_argv(argc, argv); @@ -314,7 +327,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { } else { for (int i = 0; i < views->length; ++i) { struct sway_view *view = views->items[i]; - config->handler_context.current_container = view->swayc; + set_config_node(&view->container->node); struct cmd_results *res = handler->handle(argc-1, argv+1); if (res->status != CMD_SUCCESS) { free_argv(argc, argv); diff --git a/sway/commands/border.c b/sway/commands/border.c index 9502c877f..95498b2f8 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c @@ -13,13 +13,12 @@ struct cmd_results *cmd_border(int argc, char **argv) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "border", "Only views can have borders"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; if (strcmp(argv[0], "none") == 0) { view->border = B_NONE; @@ -38,11 +37,11 @@ struct cmd_results *cmd_border(int argc, char **argv) { view->border_thickness = atoi(argv[1]); } - if (container_is_floating(view->swayc)) { - container_set_geometry_from_floating_view(view->swayc); + if (container_is_floating(view->container)) { + container_set_geometry_from_floating_view(view->container); } - arrange_windows(view->swayc); + arrange_container(view->container); struct sway_seat *seat = input_manager_current_seat(input_manager); if (seat->cursor) { diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 436376e3b..d8729094c 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c @@ -15,24 +15,23 @@ struct cmd_results *cmd_floating(int argc, char **argv) { if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type == C_WORKSPACE && container->children->length == 0) { + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; + if (!container && workspace->tiling->length == 0) { return cmd_results_new(CMD_INVALID, "floating", "Can't float an empty workspace"); } - if (container->type == C_WORKSPACE) { + if (!container) { // Wrap the workspace's children in a container so we can float it - struct sway_container *workspace = container; - container = workspace_wrap_children(container); + container = workspace_wrap_children(workspace); workspace->layout = L_HORIZ; - seat_set_focus(config->handler_context.seat, container); + seat_set_focus(config->handler_context.seat, &container->node); } // If the container is in a floating split container, // operate on the split container instead of the child. if (container_is_floating_or_child(container)) { - while (container->parent->type != C_WORKSPACE) { + while (container->parent) { container = container->parent; } } @@ -51,8 +50,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { container_set_floating(container, wants_floating); - struct sway_container *workspace = container_parent(container, C_WORKSPACE); - arrange_windows(workspace); + arrange_workspace(container->workspace); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/focus.c b/sway/commands/focus.c index f342e524b..e31898af3 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -34,211 +34,139 @@ static bool parse_movement_direction(const char *name, } /** - * Get swayc in the direction of newly entered output. + * Get node in the direction of newly entered output. */ -static struct sway_container *get_swayc_in_output_direction( - struct sway_container *output, enum movement_direction dir, - struct sway_seat *seat) { - if (!output) { - return NULL; +static struct sway_node *get_node_in_output_direction( + struct sway_output *output, enum movement_direction dir) { + struct sway_seat *seat = config->handler_context.seat; + struct sway_workspace *ws = output_get_active_workspace(output); + if (ws->fullscreen) { + return seat_get_focus_inactive(seat, &ws->fullscreen->node); } + struct sway_container *container = NULL; - struct sway_container *ws = seat_get_focus_inactive(seat, output); - if (ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } - - if (ws == NULL) { - wlr_log(WLR_ERROR, "got an output without a workspace"); - return NULL; - } - - if (ws->children->length > 0) { + if (ws->tiling->length > 0) { switch (dir) { case MOVE_LEFT: if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { // get most right child of new output - return ws->children->items[ws->children->length-1]; + container = ws->tiling->items[ws->tiling->length-1]; } else { - return seat_get_focus_inactive(seat, ws); + container = seat_get_focus_inactive_tiling(seat, ws); } + return &container->node; case MOVE_RIGHT: if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { // get most left child of new output - return ws->children->items[0]; + container = ws->tiling->items[0]; } else { - return seat_get_focus_inactive(seat, ws); + container = seat_get_focus_inactive_tiling(seat, ws); } + return &container->node; case MOVE_UP: - case MOVE_DOWN: { - struct sway_container *focused = - seat_get_focus_inactive(seat, ws); - if (focused && focused->parent) { - struct sway_container *parent = focused->parent; - if (parent->layout == L_VERT) { - if (dir == MOVE_UP) { - // get child furthest down on new output - int idx = parent->children->length - 1; - return parent->children->items[idx]; - } else if (dir == MOVE_DOWN) { - // get child furthest up on new output - return parent->children->items[0]; - } - } - return focused; + if (ws->layout == L_VERT || ws->layout == L_STACKED) { + // get most bottom child of new output + container = ws->tiling->items[ws->tiling->length-1]; + } else { + container = seat_get_focus_inactive_tiling(seat, ws); } - break; + return &container->node; + case MOVE_DOWN: { + if (ws->layout == L_VERT || ws->layout == L_STACKED) { + // get most top child of new output + container = ws->tiling->items[0]; + } else { + container = seat_get_focus_inactive_tiling(seat, ws); + } + return &container->node; } default: break; } } - return ws; + return &ws->node; } -static struct sway_container *container_get_in_direction( - struct sway_container *container, struct sway_seat *seat, - enum movement_direction dir) { - struct sway_container *parent = container->parent; - +static struct sway_node *node_get_in_direction(struct sway_container *container, + struct sway_seat *seat, enum movement_direction dir) { if (dir == MOVE_CHILD) { - return seat_get_focus_inactive(seat, container); + return seat_get_active_child(seat, &container->node); } if (container->is_fullscreen) { if (dir == MOVE_PARENT) { return NULL; } - container = container_parent(container, C_OUTPUT); - parent = container->parent; - } else { - if (dir == MOVE_PARENT) { - if (parent->type == C_OUTPUT || container_is_floating(container)) { - return NULL; - } else { - return parent; - } - } + // Fullscreen container with a direction - go straight to outputs + struct sway_output *output = container->workspace->output; + struct sway_output *new_output = output_get_in_direction(output, dir); + return get_node_in_output_direction(new_output, dir); + } + if (dir == MOVE_PARENT) { + return node_get_parent(&container->node); } struct sway_container *wrap_candidate = NULL; - while (true) { + struct sway_container *current = container; + while (current) { bool can_move = false; int desired; - int idx = list_find(container->parent->children, container); - if (idx == -1) { - return NULL; - } - 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 = container->x + container->width / 2; - int ly = container->y + container->height / 2; - 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); - struct sway_container *adjacent = - output_from_wlr_output(wlr_adjacent); + int idx = container_sibling_index(current); + enum sway_container_layout parent_layout = + container_parent_layout(current); + list_t *siblings = container_get_siblings(current); - if (!adjacent || adjacent == container) { - if (!wrap_candidate) { - return NULL; - } - return seat_get_focus_inactive_view(seat, wrap_candidate); - } - struct sway_container *next = - get_swayc_in_output_direction(adjacent, dir, seat); - if (next == NULL) { - return NULL; - } - struct sway_container *next_workspace = next; - if (next_workspace->type != C_WORKSPACE) { - next_workspace = container_parent(next_workspace, C_WORKSPACE); - } - sway_assert(next_workspace, "Next container has no workspace"); - if (next_workspace->sway_workspace->fullscreen) { - return seat_get_focus_inactive(seat, - next_workspace->sway_workspace->fullscreen); - } - if (next->children && next->children->length) { - // TODO consider floating children as well - return seat_get_focus_inactive_view(seat, next); - } else { - return next; + 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 (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 (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) { + if (desired < 0 || desired >= siblings->length) { can_move = false; - int len = parent->children->length; + int len = siblings->length; if (config->focus_wrapping != WRAP_NO && !wrap_candidate && len > 1) { if (desired < 0) { - wrap_candidate = parent->children->items[len-1]; + wrap_candidate = siblings->items[len-1]; } else { - wrap_candidate = parent->children->items[0]; + wrap_candidate = siblings->items[0]; } if (config->focus_wrapping == WRAP_FORCE) { - return seat_get_focus_inactive_view(seat, - wrap_candidate); + struct sway_container *c = seat_get_focus_inactive_view( + seat, &wrap_candidate->node); + return &c->node; } } } else { - struct sway_container *desired_con = - parent->children->items[desired]; - wlr_log(WLR_DEBUG, - "cont %d-%p dir %i sibling %d: %p", idx, - container, dir, desired, desired_con); - return seat_get_focus_inactive_view(seat, desired_con); + struct sway_container *desired_con = siblings->items[desired]; + struct sway_container *c = seat_get_focus_inactive_view( + seat, &desired_con->node); + return &c->node; } } - if (!can_move) { - container = parent; - parent = parent->parent; - if (!parent) { - // wrapping is the last chance - if (!wrap_candidate) { - return NULL; - } - return seat_get_focus_inactive_view(seat, wrap_candidate); - } - } + current = current->parent; } + + // Check a different output + struct sway_output *output = container->workspace->output; + struct sway_output *new_output = output_get_in_direction(output, dir); + if (new_output) { + return get_node_in_output_direction(new_output, dir); + } + return NULL; } -static struct cmd_results *focus_mode(struct sway_container *con, +static struct cmd_results *focus_mode(struct sway_workspace *ws, struct sway_seat *seat, bool floating) { - struct sway_container *ws = con->type == C_WORKSPACE ? - con : container_parent(con, C_WORKSPACE); - - // If the container is in a floating split container, - // operate on the split container instead of the child. - if (container_is_floating_or_child(con)) { - while (con->parent->type != C_WORKSPACE) { - con = con->parent; - } - } - struct sway_container *new_focus = NULL; if (floating) { new_focus = seat_get_focus_inactive_floating(seat, ws); @@ -246,7 +174,7 @@ static struct cmd_results *focus_mode(struct sway_container *con, new_focus = seat_get_focus_inactive_tiling(seat, ws); } if (new_focus) { - seat_set_focus(seat, new_focus); + seat_set_focus(seat, &new_focus->node); } else { return cmd_results_new(CMD_FAILURE, "focus", "Failed to find a %s container in workspace", @@ -255,14 +183,14 @@ static struct cmd_results *focus_mode(struct sway_container *con, return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static struct cmd_results *focus_output(struct sway_container *con, - struct sway_seat *seat, int argc, char **argv) { +static struct cmd_results *focus_output(struct sway_seat *seat, + int argc, char **argv) { if (!argc) { return cmd_results_new(CMD_INVALID, "focus", "Expected 'focus output '"); } char *identifier = join_args(argv, argc); - struct sway_container *output = output_by_name(identifier); + struct sway_output *output = output_by_name(identifier); if (!output) { enum movement_direction direction; @@ -272,14 +200,13 @@ static struct cmd_results *focus_output(struct sway_container *con, return cmd_results_new(CMD_INVALID, "focus", "There is no output with that name"); } - struct sway_container *focus = seat_get_focus(seat); - focus = container_parent(focus, C_OUTPUT); - output = container_get_in_direction(focus, seat, direction); + struct sway_workspace *ws = seat_get_focused_workspace(seat); + output = output_get_in_direction(ws->output, direction); } free(identifier); if (output) { - seat_set_focus(seat, seat_get_focus_inactive(seat, output)); + seat_set_focus(seat, seat_get_focus_inactive(seat, &output->node)); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); @@ -289,29 +216,32 @@ struct cmd_results *cmd_focus(int argc, char **argv) { if (config->reading || !config->active) { return cmd_results_new(CMD_DEFER, NULL, NULL); } - struct sway_container *con = config->handler_context.current_container; + struct sway_node *node = config->handler_context.node; + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; struct sway_seat *seat = config->handler_context.seat; - if (con->type < C_WORKSPACE) { + if (node->type < N_WORKSPACE) { return cmd_results_new(CMD_FAILURE, "focus", "Command 'focus' cannot be used above the workspace level"); } if (argc == 0) { - seat_set_focus(seat, con); + seat_set_focus(seat, node); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } if (strcmp(argv[0], "floating") == 0) { - return focus_mode(con, seat, true); + return focus_mode(workspace, seat, true); } else if (strcmp(argv[0], "tiling") == 0) { - return focus_mode(con, seat, false); + return focus_mode(workspace, seat, false); } else if (strcmp(argv[0], "mode_toggle") == 0) { - return focus_mode(con, seat, !container_is_floating_or_child(con)); + bool floating = container && container_is_floating_or_child(container); + return focus_mode(workspace, seat, !floating); } if (strcmp(argv[0], "output") == 0) { argc--; argv++; - return focus_output(con, seat, argc, argv); + return focus_output(seat, argc, argv); } enum movement_direction direction = 0; @@ -321,8 +251,18 @@ struct cmd_results *cmd_focus(int argc, char **argv) { "or 'focus output '"); } - struct sway_container *next_focus = container_get_in_direction( - con, seat, direction); + if (node->type == N_WORKSPACE) { + // A workspace is focused, so just jump to the next output + struct sway_output *new_output = + output_get_in_direction(workspace->output, direction); + struct sway_node *node = + get_node_in_output_direction(new_output, direction); + seat_set_focus(seat, node); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + struct sway_node *next_focus = + node_get_in_direction(container, seat, direction); if (next_focus) { seat_set_focus(seat, next_focus); } diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index ac65dffbf..3bbe00c5e 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c @@ -12,18 +12,18 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type == C_WORKSPACE && container->children->length == 0) { + struct sway_node *node = config->handler_context.node; + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; + if (node->type == N_WORKSPACE && workspace->tiling->length == 0) { return cmd_results_new(CMD_INVALID, "fullscreen", "Can't fullscreen an empty workspace"); } - if (container->type == C_WORKSPACE) { + if (node->type == N_WORKSPACE) { // Wrap the workspace's children in a container so we can fullscreen it - struct sway_container *workspace = container; - container = workspace_wrap_children(container); + container = workspace_wrap_children(workspace); workspace->layout = L_HORIZ; - seat_set_focus(config->handler_context.seat, container); + seat_set_focus(config->handler_context.seat, &container->node); } bool enable = !container->is_fullscreen; @@ -32,9 +32,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { } container_set_fullscreen(container, enable); - - struct sway_container *workspace = container_parent(container, C_WORKSPACE); - arrange_windows(workspace->parent); + arrange_workspace(workspace); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 3906eb709..d676e475b 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c @@ -2,6 +2,7 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/tree/arrange.h" +#include "sway/tree/workspace.h" #include "log.h" #include "stringop.h" #include @@ -43,7 +44,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "gaps", "gaps edge_gaps on|off|toggle"); } - arrange_windows(&root_container); + arrange_root(); } else { int amount_idx = 0; // the current index in argv enum gaps_op op = GAPS_OP_SET; @@ -124,7 +125,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { if (amount_idx == 0) { // gaps config->gaps_inner = val; config->gaps_outer = val; - arrange_windows(&root_container); + arrange_root(); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } // Other variants. The middle-length variant (gaps inner|outer ) @@ -155,21 +156,27 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { } else { config->gaps_outer = total; } - arrange_windows(&root_container); + arrange_root(); } else { - struct sway_container *c = - config->handler_context.current_container; - if (scope == GAPS_SCOPE_WORKSPACE && c->type != C_WORKSPACE) { - c = container_parent(c, C_WORKSPACE); - } - c->has_gaps = true; - if (inner) { - c->gaps_inner = total; + if (scope == GAPS_SCOPE_WORKSPACE) { + struct sway_workspace *ws = config->handler_context.workspace; + ws->has_gaps = true; + if (inner) { + ws->gaps_inner = total; + } else { + ws->gaps_outer = total; + } + arrange_workspace(ws); } else { - c->gaps_outer = total; + struct sway_container *c = config->handler_context.container; + c->has_gaps = true; + if (inner) { + c->gaps_inner = total; + } else { + c->gaps_outer = total; + } + arrange_workspace(c->workspace); } - - arrange_windows(c->parent ? c->parent : &root_container); } } diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c index e494f6aa5..0a5c7f28a 100644 --- a/sway/commands/hide_edge_borders.c +++ b/sway/commands/hide_edge_borders.c @@ -5,8 +5,8 @@ #include "sway/tree/view.h" static void _configure_view(struct sway_container *con, void *data) { - if (con->type == C_VIEW) { - view_autoconfigure(con->sway_view); + if (con->view) { + view_autoconfigure(con->view); } } diff --git a/sway/commands/kill.c b/sway/commands/kill.c index f3fa52f14..85ca0f339 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -2,15 +2,27 @@ #include "log.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" -#include "sway/tree/view.h" #include "sway/tree/container.h" +#include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "sway/commands.h" -struct cmd_results *cmd_kill(int argc, char **argv) { - struct sway_container *con = - config->handler_context.current_container; +static void close_container_iterator(struct sway_container *con, void *data) { + if (con->view) { + view_close(con->view); + } +} - container_close(con); +struct cmd_results *cmd_kill(int argc, char **argv) { + struct sway_container *con = config->handler_context.container; + struct sway_workspace *ws = config->handler_context.workspace; + + if (con) { + close_container_iterator(con, NULL); + container_for_each_child(con, close_container_iterator, NULL); + } else { + workspace_for_each_container(ws, close_container_iterator, NULL); + } return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/layout.c b/sway/commands/layout.c index a06832de7..8fa1ce98a 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -4,21 +4,20 @@ #include "sway/commands.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" +#include "sway/tree/workspace.h" #include "log.h" -static bool parse_layout_string(char *s, enum sway_container_layout *ptr) { +static enum sway_container_layout parse_layout_string(char *s) { if (strcasecmp(s, "splith") == 0) { - *ptr = L_HORIZ; + return L_HORIZ; } else if (strcasecmp(s, "splitv") == 0) { - *ptr = L_VERT; + return L_VERT; } else if (strcasecmp(s, "tabbed") == 0) { - *ptr = L_TABBED; + return L_TABBED; } else if (strcasecmp(s, "stacking") == 0) { - *ptr = L_STACKED; - } else { - return false; + return L_STACKED; } - return true; + return L_NONE; } static const char* expected_syntax = @@ -26,85 +25,130 @@ static const char* expected_syntax = "'layout toggle [split|all]' or " "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; +static enum sway_container_layout get_layout_toggle(int argc, char **argv, + enum sway_container_layout layout, + enum sway_container_layout prev_split_layout) { + // "layout toggle" + if (argc == 0) { + return layout == L_HORIZ ? L_VERT : L_HORIZ; + } + + if (argc == 2) { + // "layout toggle split" (same as "layout toggle") + if (strcasecmp(argv[1], "split") == 0) { + return layout == L_HORIZ ? L_VERT : L_HORIZ; + } + // "layout toggle all" + if (strcasecmp(argv[1], "all") == 0) { + return layout == L_HORIZ ? L_VERT : + layout == L_VERT ? L_STACKED : + layout == L_STACKED ? L_TABBED : L_HORIZ; + } + return L_NONE; + } + + enum sway_container_layout parsed; + int curr = 1; + for (; curr < argc; curr++) { + parsed = parse_layout_string(argv[curr]); + if (parsed == layout || (strcmp(argv[curr], "split") == 0 && + (layout == L_VERT || layout == L_HORIZ))) { + break; + } + } + for (int i = curr + 1; i != curr; ++i) { + // cycle round to find next valid layout + if (i >= argc) { + i = 1; + } + parsed = parse_layout_string(argv[i]); + if (parsed != L_NONE) { + return parsed; + } + if (strcmp(argv[i], "split") == 0) { + return layout == L_HORIZ ? L_VERT : + layout == L_VERT ? L_HORIZ : prev_split_layout; + } + // invalid layout strings are silently ignored + } + return L_NONE; +} + +static enum sway_container_layout get_layout(int argc, char **argv, + enum sway_container_layout layout, + enum sway_container_layout prev_split_layout) { + // Check if assigned directly + enum sway_container_layout parsed = parse_layout_string(argv[0]); + if (parsed != L_NONE) { + return parsed; + } + + if (strcasecmp(argv[0], "default") == 0) { + return prev_split_layout; + } + + if (strcasecmp(argv[0], "toggle") == 0) { + argc--; argv++; + return get_layout_toggle(argc, argv, layout, prev_split_layout); + } + + return L_NONE; +} + 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; } - struct sway_container *parent = config->handler_context.current_container; + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; - if (container_is_floating(parent)) { + if (container && container_is_floating(container)) { return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); } - while (parent->type == C_VIEW) { - parent = parent->parent; + // Typically we change the layout of the current container, but if the + // current container is a view (it usually is) then we'll change the layout + // of the parent instead, as it doesn't make sense for views to have layout. + if (container && container->view) { + container = container->parent; } - 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 { - 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 - } + // We could be working with a container OR a workspace. These are different + // structures, so we set up pointers to they layouts so we can refer them in + // an abstract way. + enum sway_container_layout new_layout = L_NONE; + enum sway_container_layout old_layout = L_NONE; + if (container) { + old_layout = container->layout; + new_layout = get_layout(argc, argv, + container->layout, container->prev_split_layout); + } else { + old_layout = workspace->layout; + new_layout = get_layout(argc, argv, + workspace->layout, workspace->prev_split_layout); + } + if (new_layout == L_NONE) { + return cmd_results_new(CMD_INVALID, "layout", expected_syntax); + } + if (new_layout != old_layout) { + if (container) { + if (old_layout != L_TABBED && old_layout != L_STACKED) { + container->prev_split_layout = old_layout; } + container->layout = new_layout; + container_update_representation(container); + arrange_container(container); } else { - return cmd_results_new(CMD_INVALID, "layout", expected_syntax); + if (old_layout != L_TABBED && old_layout != L_STACKED) { + workspace->prev_split_layout = old_layout; + } + workspace->layout = new_layout; + workspace_update_representation(workspace); + arrange_workspace(workspace); } } - 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->parent); - } return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/mark.c b/sway/commands/mark.c index 9ea8c3015..fb95a7d03 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c @@ -18,13 +18,12 @@ struct cmd_results *cmd_mark(int argc, char **argv) { if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "mark", "Only views can have marks"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; bool add = false, toggle = false; while (argc > 0 && strncmp(*argv, "--", 2) == 0) { diff --git a/sway/commands/move.c b/sway/commands/move.c index 4426f24ef..1b2e830c6 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -40,7 +40,7 @@ enum wlr_direction opposite_direction(enum wlr_direction d) { } } -static struct sway_container *output_in_direction(const char *direction_string, +static struct sway_output *output_in_direction(const char *direction_string, struct wlr_output *reference, int ref_lx, int ref_ly) { struct { char *name; @@ -63,113 +63,22 @@ static struct sway_container *output_in_direction(const char *direction_string, if (direction) { struct wlr_output *target = wlr_output_layout_adjacent_output( - root_container.sway_root->output_layout, - direction, reference, ref_lx, ref_ly); + root->output_layout, direction, reference, ref_lx, ref_ly); if (!target) { target = wlr_output_layout_farthest_output( - root_container.sway_root->output_layout, - opposite_direction(direction), reference, ref_lx, ref_ly); + root->output_layout, opposite_direction(direction), + reference, ref_lx, ref_ly); } if (target) { - struct sway_output *sway_output = target->data; - return sway_output->swayc; + return target->data; } } return output_by_name(direction_string); } -static 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)) { - // 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); - workspace_add_floating(new_ws, container); - container_handle_fullscreen_reparent(container, old_parent); - // If changing output, center it within the workspace - if (old_output != new_ws->parent && !container->is_fullscreen) { - container_floating_move_to_center(container); - } - } else { - 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); - } - } - - if (container->type == C_VIEW) { - ipc_event_window(container, "move"); - } - container_notify_subtree_changed(old_parent); - container_notify_subtree_changed(new_parent); - - // If view was moved to a fullscreen workspace, refocus the fullscreen view - struct sway_container *new_workspace = container; - if (new_workspace->type != C_WORKSPACE) { - new_workspace = container_parent(new_workspace, C_WORKSPACE); - } - if (new_workspace->sway_workspace->fullscreen) { - struct sway_seat *seat; - struct sway_container *focus, *focus_ws; - wl_list_for_each(seat, &input_manager->seats, link) { - focus = seat_get_focus(seat); - focus_ws = focus; - if (focus_ws->type != C_WORKSPACE) { - focus_ws = container_parent(focus_ws, C_WORKSPACE); - } - if (focus_ws == new_workspace) { - struct sway_container *new_focus = seat_get_focus_inactive(seat, - new_workspace->sway_workspace->fullscreen); - seat_set_focus(seat, new_focus); - } - } - } - // Update workspace urgent state - struct sway_container *old_workspace = old_parent; - if (old_workspace->type != C_WORKSPACE) { - old_workspace = container_parent(old_workspace, C_WORKSPACE); - } - if (new_workspace != old_workspace) { - workspace_detect_urgent(new_workspace); - if (old_workspace) { - workspace_detect_urgent(old_workspace); - } - } -} - static bool is_parallel(enum sway_container_layout layout, enum movement_direction dir) { switch (layout) { @@ -184,326 +93,337 @@ static bool is_parallel(enum sway_container_layout layout, } } -static enum movement_direction invert_movement(enum movement_direction dir) { - switch (dir) { - case MOVE_LEFT: - return MOVE_RIGHT; - case MOVE_RIGHT: - return MOVE_LEFT; - case MOVE_UP: - return MOVE_DOWN; - case MOVE_DOWN: - return MOVE_UP; - default: - sway_assert(0, "This function expects left|right|up|down"); - return MOVE_LEFT; +/** + * Ensures all seats focus the fullscreen container if needed. + */ +static void workspace_focus_fullscreen(struct sway_workspace *workspace) { + if (!workspace->fullscreen) { + return; + } + struct sway_seat *seat; + struct sway_workspace *focus_ws; + wl_list_for_each(seat, &input_manager->seats, link) { + focus_ws = seat_get_focused_workspace(seat); + if (focus_ws == workspace) { + struct sway_node *new_focus = + seat_get_focus_inactive(seat, &workspace->fullscreen->node); + seat_set_focus(seat, new_focus); + } } } -static int move_offs(enum movement_direction move_dir) { - return move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; +static void container_move_to_container_from_direction( + struct sway_container *container, struct sway_container *destination, + enum movement_direction move_dir) { + if (destination->view) { + if (destination->parent == container->parent) { + wlr_log(WLR_DEBUG, "Swapping siblings"); + list_t *siblings = container_get_siblings(container); + int container_index = list_find(siblings, container); + int destination_index = list_find(siblings, destination); + list_swap(siblings, container_index, destination_index); + } else { + wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); + int offset = move_dir == MOVE_LEFT || move_dir == MOVE_UP; + int index = container_sibling_index(destination) + offset; + if (destination->parent) { + container_insert_child(destination->parent, container, index); + } else { + workspace_insert_tiling(destination->workspace, + container, index); + } + container->width = container->height = 0; + } + return; + } + + if (is_parallel(destination->layout, move_dir)) { + wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); + int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? + 0 : destination->children->length; + container_insert_child(destination, container, index); + container->width = container->height = 0; + return; + } + + wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); + struct sway_node *focus_inactive = seat_get_active_child( + config->handler_context.seat, &destination->node); + if (!focus_inactive || focus_inactive == &destination->node) { + // The container has no children + container_add_child(destination, container); + return; + } + + // Try again but with the child + container_move_to_container_from_direction(container, + focus_inactive->sway_container, move_dir); } -/* Gets the index of the most extreme member based on the movement offset */ -static int container_limit(struct sway_container *container, +static void container_move_to_workspace_from_direction( + struct sway_container *container, struct sway_workspace *workspace, enum movement_direction move_dir) { - return move_offs(move_dir) < 0 ? 0 : container->children->length; + if (is_parallel(workspace->layout, move_dir)) { + wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); + int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? + 0 : workspace->tiling->length; + workspace_insert_tiling(workspace, container, index); + return; + } + + wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); + struct sway_container *focus_inactive = seat_get_focus_inactive_tiling( + config->handler_context.seat, workspace); + if (!focus_inactive) { + // The workspace has no tiling children + workspace_add_tiling(workspace, container); + return; + } + while (focus_inactive->parent) { + focus_inactive = focus_inactive->parent; + } + container_move_to_container_from_direction(container, focus_inactive, + move_dir); +} + +static void container_move_to_workspace(struct sway_container *container, + struct sway_workspace *workspace) { + if (container->workspace == workspace) { + return; + } + struct sway_workspace *old_workspace = container->workspace; + if (container_is_floating(container)) { + struct sway_output *old_output = container->workspace->output; + container_detach(container); + workspace_add_floating(workspace, container); + container_handle_fullscreen_reparent(container); + // If changing output, center it within the workspace + if (old_output != workspace->output && !container->is_fullscreen) { + container_floating_move_to_center(container); + } + } else { + container_detach(container); + container->width = container->height = 0; + container->saved_width = container->saved_height = 0; + workspace_add_tiling(workspace, container); + container_update_representation(container); + } + if (container->view) { + ipc_event_window(container, "move"); + } + workspace_detect_urgent(old_workspace); + workspace_detect_urgent(workspace); + workspace_focus_fullscreen(workspace); +} + +static void container_move_to_container(struct sway_container *container, + struct sway_container *destination) { + if (container == destination + || container_has_ancestor(container, destination) + || container_has_ancestor(destination, container)) { + return; + } + if (container_is_floating(container)) { + return; + } + struct sway_workspace *old_workspace = container->workspace; + + container_detach(container); + container->width = container->height = 0; + container->saved_width = container->saved_height = 0; + + if (destination->view) { + container_add_sibling(destination, container, 1); + } else { + container_add_child(destination, container); + } + + if (container->view) { + ipc_event_window(container, "move"); + } + + workspace_focus_fullscreen(destination->workspace); + + // Update workspace urgent state + workspace_detect_urgent(destination->workspace); + if (old_workspace != destination->workspace) { + workspace_detect_urgent(old_workspace); + } } /* Takes one child, sets it aside, wraps the rest of the children in a new * container, switches the layout of the workspace, and drops the child back in. * In other words, rejigger it. */ -static void workspace_rejigger(struct sway_container *ws, +static void workspace_rejigger(struct sway_workspace *ws, struct sway_container *child, enum movement_direction move_dir) { - struct sway_container *original_parent = child->parent; - struct sway_container *new_parent = - container_split(ws, ws->layout); - - container_remove_child(child); - for (int i = 0; i < ws->children->length; ++i) { - struct sway_container *_child = ws->children->items[i]; - container_move_to(new_parent, _child); + if (!sway_assert(child->parent == NULL, "Expected a root child")) { + return; } + container_detach(child); + workspace_wrap_children(ws); - int index = move_offs(move_dir); - container_insert_child(ws, child, index < 0 ? 0 : 1); + int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1; + workspace_insert_tiling(ws, child, index); ws->layout = move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; - - container_flatten(ws); - container_reap_empty(original_parent); - container_create_notify(new_parent); + workspace_update_representation(ws); } static void move_out_of_tabs_stacks(struct sway_container *container, struct sway_container *current, enum movement_direction move_dir, int offs) { - if (container->parent == current->parent - && current->parent->children->length == 1) { - wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id); - current->parent->layout = move_dir == - MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; + enum sway_container_layout layout = move_dir == + MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; + list_t *siblings = container_get_siblings(container); + if (container == current && siblings->length == 1) { + wlr_log(WLR_DEBUG, "Changing layout of parent"); + if (container->parent) { + container->parent->layout = layout; + container_update_representation(container); + } else { + container->workspace->layout = layout; + workspace_update_representation(container->workspace); + } return; } wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); - bool is_workspace = current->parent->type == C_WORKSPACE; - struct sway_container *new_parent = container_split(current->parent, - move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); - if (is_workspace) { - container_insert_child(new_parent->parent, container, offs < 0 ? 0 : 1); - } else { + if (container->parent) { + struct sway_container *new_parent = + container_split(current->parent, layout); container_insert_child(new_parent, container, offs < 0 ? 0 : 1); - container_reap_empty(new_parent->parent); - container_flatten(new_parent->parent); + container_reap_empty(new_parent); + container_flatten(new_parent); + } else { + // Changing a workspace + struct sway_workspace *workspace = container->workspace; + workspace_split(workspace, layout); + workspace_insert_tiling(workspace, container, offs < 0 ? 0 : 1); } - container_create_notify(new_parent); - container_notify_subtree_changed(new_parent); } -static void container_move(struct sway_container *container, - enum movement_direction move_dir, int move_amt) { - if (!sway_assert( - container->type != C_CONTAINER || container->type != C_VIEW, - "Can only move containers and views")) { - return; - } - int offs = move_offs(move_dir); - - struct sway_container *sibling = NULL; - struct sway_container *current = container; - struct sway_container *parent = current->parent; - struct sway_container *top = &root_container; - +// Returns true if moved +static bool container_move_in_direction(struct sway_container *container, + enum movement_direction move_dir) { // If moving a fullscreen view, only consider outputs if (container->is_fullscreen) { - current = container_parent(container, C_OUTPUT); - } else if (container_is_fullscreen_or_child(container) || - container_is_floating_or_child(container)) { - // If we've fullscreened a split container, only allow the child to move - // around within the fullscreen parent. - // Same with floating a split container. - struct sway_container *ws = container_parent(container, C_WORKSPACE); - top = ws->sway_workspace->fullscreen; + struct sway_output *new_output = + output_get_in_direction(container->workspace->output, move_dir); + if (!new_output) { + return false; + } + struct sway_workspace *ws = output_get_active_workspace(new_output); + container_move_to_workspace(container, ws); + return true; } - struct sway_container *new_parent = container_flatten(parent); - if (new_parent != parent) { - // Special case: we were the last one in this container, so leave - return; + // If container is in a split container by itself, move out of the split + if (container->parent) { + struct sway_container *new_parent = + container_flatten(container->parent); + if (new_parent != container->parent) { + return true; + } } - while (!sibling) { - if (current == top) { - return; - } + // Look for a suitable *container* sibling or parent. + // The below loop stops once we hit the workspace because current->parent + // is NULL for the topmost containers in a workspace. + struct sway_container *current = container; + int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; - parent = current->parent; - wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current, - container_type_to_str(current->type), current->name); + while (current) { + struct sway_container *parent = current->parent; + list_t *siblings = container_get_siblings(current); + enum sway_container_layout layout = container_parent_layout(current); + int index = list_find(siblings, current); + int desired = index + offs; - int index = container_sibling_index(current); - - switch (current->type) { - case C_OUTPUT: { - enum wlr_direction wlr_dir = 0; - if (!sway_assert(sway_dir_to_wlr(move_dir, &wlr_dir), - "got invalid direction: %d", move_dir)) { - return; - } - double ref_lx = current->x + current->width / 2; - double ref_ly = current->y + current->height / 2; - struct wlr_output *next = wlr_output_layout_adjacent_output( - root_container.sway_root->output_layout, wlr_dir, - current->sway_output->wlr_output, ref_lx, ref_ly); - if (!next) { - wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); - return; - } - struct sway_output *next_output = next->data; - current = next_output->swayc; - wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name); - // Select workspace and get outta here - current = seat_get_focus_inactive( - config->handler_context.seat, current); - if (current->type != C_WORKSPACE) { - current = container_parent(current, C_WORKSPACE); - } - sibling = current; - break; - } - case C_WORKSPACE: - if (!is_parallel(current->layout, move_dir)) { - if (current->children->length >= 2) { - wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)", - current->children->length); - workspace_rejigger(current, container, move_dir); - return; - } else { - wlr_log(WLR_DEBUG, "Selecting output"); - current = current->parent; - } - } else if (current->layout == L_TABBED - || current->layout == L_STACKED) { - wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks"); - workspace_rejigger(current, container, move_dir); - } else { - wlr_log(WLR_DEBUG, "Selecting output"); - current = current->parent; - } - break; - case C_CONTAINER: - case C_VIEW: - if (is_parallel(parent->layout, move_dir)) { - if ((index == parent->children->length - 1 && offs > 0) - || (index == 0 && offs < 0)) { - if (current->parent == container->parent) { - if (!parent->is_fullscreen && - (parent->layout == L_TABBED || - parent->layout == L_STACKED)) { - move_out_of_tabs_stacks(container, current, - move_dir, offs); - return; - } else { - wlr_log(WLR_DEBUG, "Hit limit, selecting parent"); - current = current->parent; - } + if (is_parallel(layout, move_dir)) { + if (desired == -1 || desired == siblings->length) { + if (current->parent == container->parent) { + if (!(parent && parent->is_fullscreen) && + (layout == L_TABBED || layout == L_STACKED)) { + move_out_of_tabs_stacks(container, current, + move_dir, offs); + return true; } else { - wlr_log(WLR_DEBUG, "Hit limit, " - "promoting descendant to sibling"); - // Special case + current = current->parent; + continue; + } + } else { + // Special case + if (current->parent) { container_insert_child(current->parent, container, index + (offs < 0 ? 0 : 1)); - container->width = container->height = 0; - return; + } else { + workspace_insert_tiling(current->workspace, container, + index + (offs < 0 ? 0 : 1)); } - } else { - sibling = parent->children->items[index + offs]; - wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); + return true; } - } else if (!parent->is_fullscreen && (parent->layout == L_TABBED || - parent->layout == L_STACKED)) { - move_out_of_tabs_stacks(container, current, move_dir, offs); - return; } else { - wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); - current = current->parent; + // Container can move within its siblings + container_move_to_container_from_direction(container, + siblings->items[desired], move_dir); + return true; } - break; - default: - sway_assert(0, "Not expecting to see container of type %s here", - container_type_to_str(current->type)); - return; + } else if (!(parent && parent->is_fullscreen) && + (layout == L_TABBED || layout == L_STACKED)) { + move_out_of_tabs_stacks(container, current, move_dir, offs); + return true; + } + + current = current->parent; + + // Don't allow containers to move out of their + // fullscreen or floating parent + if (current && + (current->is_fullscreen || container_is_floating(current))) { + return false; } } - // Part two: move stuff around - int index = container_sibling_index(container); - struct sway_container *old_parent = container->parent; - - while (sibling) { - switch (sibling->type) { - case C_VIEW: - if (sibling->parent == container->parent) { - wlr_log(WLR_DEBUG, "Swapping siblings"); - sibling->parent->children->items[index + offs] = container; - sibling->parent->children->items[index] = sibling; - } else { - wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); - container_insert_child(sibling->parent, container, - container_sibling_index(sibling) + (offs > 0 ? 0 : 1)); - container->width = container->height = 0; - } - sibling = NULL; - break; - case C_WORKSPACE: // Note: only in the case of moving between outputs - case C_CONTAINER: - if (is_parallel(sibling->layout, move_dir)) { - int limit = container_limit(sibling, invert_movement(move_dir)); - wlr_log(WLR_DEBUG, "limit: %d", limit); - wlr_log(WLR_DEBUG, - "Reparenting container (parallel) to index %d " - "(move dir: %d)", limit, move_dir); - container_insert_child(sibling, container, limit); - container->width = container->height = 0; - sibling = NULL; - } else { - wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); - struct sway_container *focus_inactive = seat_get_focus_inactive( - config->handler_context.seat, sibling); - if (focus_inactive && focus_inactive != sibling) { - while (focus_inactive->parent != sibling) { - focus_inactive = focus_inactive->parent; - } - wlr_log(WLR_DEBUG, "Focus inactive: id:%zd", - focus_inactive->id); - sibling = focus_inactive; - continue; - } else if (sibling->children->length) { - wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily"); - container_remove_child(container); - container_add_sibling(sibling->children->items[0], container); - } else { - wlr_log(WLR_DEBUG, "No kiddos, adding container alone"); - container_remove_child(container); - container_add_child(sibling, container); - } - container->width = container->height = 0; - sibling = NULL; - } - break; - default: - sway_assert(0, "Not expecting to see container of type %s here", - container_type_to_str(sibling->type)); - return; + // Maybe rejigger the workspace + struct sway_workspace *ws = container->workspace; + if (!is_parallel(ws->layout, move_dir)) { + if (ws->tiling->length >= 2) { + workspace_rejigger(ws, container, move_dir); + return true; } + } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) { + workspace_rejigger(ws, container, move_dir); + return true; } - container_notify_subtree_changed(old_parent); - container_notify_subtree_changed(container->parent); - - if (container->type == C_VIEW) { - ipc_event_window(container, "move"); + // Try adjacent output + struct sway_output *output = + output_get_in_direction(container->workspace->output, move_dir); + if (output) { + struct sway_workspace *ws = output_get_active_workspace(output); + container_move_to_workspace_from_direction(container, ws, move_dir); + return true; } - - if (old_parent) { - seat_set_focus(config->handler_context.seat, old_parent); - seat_set_focus(config->handler_context.seat, container); - } - - struct sway_container *last_ws = old_parent; - struct sway_container *next_ws = container->parent; - if (last_ws && last_ws->type != C_WORKSPACE) { - last_ws = container_parent(last_ws, C_WORKSPACE); - } - if (next_ws && next_ws->type != C_WORKSPACE) { - next_ws = container_parent(next_ws, C_WORKSPACE); - } - if (last_ws && next_ws && last_ws != next_ws) { - ipc_event_workspace(last_ws, next_ws, "focus"); - workspace_detect_urgent(last_ws); - workspace_detect_urgent(next_ws); - } - container_end_mouse_operation(container); + wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); + return false; } -static struct cmd_results *cmd_move_container(struct sway_container *current, - int argc, char **argv) { +static struct cmd_results *cmd_move_container(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "move container/window", EXPECTED_AT_LEAST, 3))) { return error; } - if (current->type == C_WORKSPACE) { - if (current->children->length == 0) { + struct sway_node *node = config->handler_context.node; + struct sway_workspace *workspace = config->handler_context.workspace; + struct sway_container *container = config->handler_context.container; + if (node->type == N_WORKSPACE) { + if (workspace->tiling->length == 0) { return cmd_results_new(CMD_FAILURE, "move", "Can't move an empty workspace"); } - current = workspace_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."); + container = workspace_wrap_children(workspace); } bool no_auto_back_and_forth = false; @@ -530,15 +450,15 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, } struct sway_seat *seat = config->handler_context.seat; - struct sway_container *old_parent = current->parent; - struct sway_container *old_ws = container_parent(current, C_WORKSPACE); - struct sway_container *old_output = container_parent(current, C_OUTPUT); - struct sway_container *destination = NULL; + struct sway_container *old_parent = container->parent; + struct sway_workspace *old_ws = container->workspace; + struct sway_output *old_output = old_ws->output; + struct sway_node *destination = NULL; // determine destination if (strcasecmp(argv[1], "workspace") == 0) { // move container to workspace x - struct sway_container *ws = NULL; + struct sway_workspace *ws = NULL; char *ws_name = NULL; if (strcasecmp(argv[2], "next") == 0 || strcasecmp(argv[2], "prev") == 0 || @@ -588,8 +508,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, // 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 (current->is_sticky) { - struct sway_container *new_output = + if (container->is_sticky) { + struct sway_output *new_output = workspace_get_initial_output(ws_name); if (old_output == new_output) { free(ws_name); @@ -601,105 +521,113 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, ws = workspace_create(NULL, ws_name); } free(ws_name); - destination = seat_get_focus_inactive(seat, ws); + destination = seat_get_focus_inactive(seat, &ws->node); } else if (strcasecmp(argv[1], "output") == 0) { - struct sway_container *dest_output = output_in_direction(argv[2], - old_output->sway_output->wlr_output, current->x, current->y); - if (!dest_output) { + struct sway_output *new_output = output_in_direction(argv[2], + old_output->wlr_output, container->x, container->y); + if (!new_output) { return cmd_results_new(CMD_FAILURE, "move workspace", "Can't find output with name/direction '%s'", argv[2]); } - destination = seat_get_focus_inactive(seat, dest_output); - if (!destination) { - // We've never been to this output before - destination = dest_output->children->items[0]; - } + destination = seat_get_focus_inactive(seat, &new_output->node); } 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; + destination = &dest_view->container->node; } else { return cmd_results_new(CMD_INVALID, "move", expected_syntax); } - struct sway_container *new_output = destination->type == C_OUTPUT ? - destination : container_parent(destination, C_OUTPUT); - if (current->is_sticky && old_output == new_output) { + if (container->is_sticky && + node_has_ancestor(destination, &old_output->node)) { return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky " "container to another workspace on the same output"); } - struct sway_container *new_output_last_ws = old_output == new_output ? - NULL : seat_get_active_child(seat, new_output); - struct sway_container *new_workspace = destination->type == C_WORKSPACE ? - destination : container_parent(destination, C_WORKSPACE); + struct sway_output *new_output = node_get_output(destination); + struct sway_workspace *new_output_last_ws = old_output == new_output ? + NULL : output_get_active_workspace(new_output); // move container, arrange windows and return focus - container_move_to(current, destination); + switch (destination->type) { + case N_WORKSPACE: + container_move_to_workspace(container, destination->sway_workspace); + break; + case N_OUTPUT: { + struct sway_output *output = destination->sway_output; + struct sway_workspace *ws = output_get_active_workspace(output); + container_move_to_workspace(container, ws); + } + break; + case N_CONTAINER: + container_move_to_container(container, destination->sway_container); + break; + case N_ROOT: + break; + } + struct sway_workspace *new_workspace = + output_get_active_workspace(new_output); if (new_output_last_ws && new_output_last_ws != new_workspace) { // change focus on destination output back to its last active workspace - struct sway_container *new_output_last_focus = - seat_get_focus_inactive(seat, new_output_last_ws); + struct sway_node *new_output_last_focus = + seat_get_focus_inactive(seat, &new_output_last_ws->node); seat_set_focus_warp(seat, new_output_last_focus, false, false); } - struct sway_container *focus = seat_get_focus_inactive(seat, old_parent); - seat_set_focus_warp(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); + struct sway_node *focus = NULL; + if (old_parent) { + focus = seat_get_focus_inactive(seat, &old_parent->node); + } else { + focus = seat_get_focus_inactive(seat, &old_ws->node); + } + seat_set_focus_warp(seat, focus, true, false); + + if (old_parent) { + container_reap_empty(old_parent); + } else { + workspace_consider_destroy(old_ws); + } + + arrange_workspace(old_ws); + arrange_node(node_get_parent(destination)); 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")) { +static void workspace_move_to_output(struct sway_workspace *workspace, + struct sway_output *output) { + if (workspace->output == output) { 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); + struct sway_output *old_output = workspace->output; + workspace_detach(workspace); + struct sway_workspace *new_output_old_ws = + output_get_active_workspace(output); - container_add_child(output, workspace); + output_add_workspace(output, workspace); // If moving the last workspace from the old output, create a new workspace // on the old output - if (old_output->children->length == 0) { - char *ws_name = workspace_next_name(old_output->name); - struct sway_container *ws = workspace_create(old_output, ws_name); + struct sway_seat *seat = config->handler_context.seat; + if (old_output->workspaces->length == 0) { + char *ws_name = workspace_next_name(old_output->wlr_output->name); + struct sway_workspace *ws = workspace_create(old_output, ws_name); free(ws_name); - seat_set_focus(seat, ws); + seat_set_focus(seat, &ws->node); } - // Try to remove an empty workspace from the destination output. - container_reap_empty(new_output_focus); + workspace_consider_destroy(new_output_old_ws); output_sort_workspaces(output); - seat_set_focus(seat, output); + seat_set_focus(seat, &output->node); 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) { +static struct cmd_results *cmd_move_workspace(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { return error; @@ -716,27 +644,25 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current, 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[2], - source->sway_output->wlr_output, center_x, center_y); - if (!destination) { + struct sway_workspace *workspace = config->handler_context.workspace; + struct sway_output *old_output = workspace->output; + int center_x = workspace->width / 2 + workspace->x, + center_y = workspace->height / 2 + workspace->y; + struct sway_output *new_output = output_in_direction(argv[2], + old_output->wlr_output, center_x, center_y); + if (!new_output) { return cmd_results_new(CMD_FAILURE, "move workspace", "Can't find output with name/direction '%s'", argv[2]); } - if (current->type != C_WORKSPACE) { - current = container_parent(current, C_WORKSPACE); - } - workspace_move_to_output(current, destination); + workspace_move_to_output(workspace, new_output); - arrange_windows(source); - arrange_windows(destination); + arrange_output(old_output); + arrange_output(new_output); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static struct cmd_results *move_in_direction(struct sway_container *container, +static struct cmd_results *cmd_move_in_direction( enum movement_direction direction, int argc, char **argv) { int move_amt = 10; if (argc > 1) { @@ -748,7 +674,8 @@ static struct cmd_results *move_in_direction(struct sway_container *container, } } - if (container->type == C_WORKSPACE) { + struct sway_container *container = config->handler_context.container; + if (!container) { return cmd_results_new(CMD_FAILURE, "move", "Cannot move workspaces in a direction"); } @@ -780,20 +707,34 @@ static struct cmd_results *move_in_direction(struct sway_container *container, container_floating_move_to(container, lx, ly); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } - // For simplicity, we'll arrange the entire workspace. The reason for this - // is moving the container might reap the old parent, and container_move - // does not return a surviving parent. - // TODO: Make container_move return the surviving parent so we can arrange - // just that. - struct sway_container *old_ws = container_parent(container, C_WORKSPACE); - container_move(container, direction, move_amt); - struct sway_container *new_ws = container_parent(container, C_WORKSPACE); + struct sway_workspace *old_ws = container->workspace; - arrange_windows(old_ws); - if (new_ws != old_ws) { - arrange_windows(new_ws); + if (!container_move_in_direction(container, direction)) { + // Container didn't move + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } + struct sway_workspace *new_ws = container->workspace; + + arrange_workspace(old_ws); + if (new_ws != old_ws) { + arrange_workspace(new_ws); + } + + if (container->view) { + ipc_event_window(container, "move"); + } + + seat_set_focus(config->handler_context.seat, &new_ws->node); + seat_set_focus(config->handler_context.seat, &container->node); + + if (old_ws != new_ws) { + ipc_event_workspace(old_ws, new_ws, "focus"); + workspace_detect_urgent(old_ws); + workspace_detect_urgent(new_ws); + } + container_end_mouse_operation(container); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -802,9 +743,9 @@ static const char *expected_position_syntax = "'move [absolute] position center' or " "'move position cursor|mouse|pointer'"; -static struct cmd_results *move_to_position(struct sway_container *container, - int argc, char **argv) { - if (!container_is_floating(container)) { +static struct cmd_results *cmd_move_to_position(int argc, char **argv) { + struct sway_container *container = config->handler_context.container; + if (!container || !container_is_floating(container)) { return cmd_results_new(CMD_FAILURE, "move", "Only floating containers " "can be moved to an absolute position"); @@ -842,10 +783,10 @@ static struct cmd_results *move_to_position(struct sway_container *container, } else if (strcmp(argv[0], "center") == 0) { double lx, ly; if (absolute) { - lx = root_container.x + (root_container.width - container->width) / 2; - ly = root_container.y + (root_container.height - container->height) / 2; + lx = root->x + (root->width - container->width) / 2; + ly = root->y + (root->height - container->height) / 2; } else { - struct sway_container *ws = container_parent(container, C_WORKSPACE); + struct sway_workspace *ws = container->workspace; lx = ws->x + (ws->width - container->width) / 2; ly = ws->y + (ws->height - container->height) / 2; } @@ -881,30 +822,31 @@ static struct cmd_results *move_to_position(struct sway_container *container, } if (!absolute) { - struct sway_container *ws = container_parent(container, C_WORKSPACE); - lx += ws->x; - ly += ws->y; + lx += container->workspace->x; + ly += container->workspace->y; } container_floating_move_to(container, lx, ly); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static struct cmd_results *move_to_scratchpad(struct sway_container *con) { - if (con->type == C_WORKSPACE && con->children->length == 0) { +static struct cmd_results *cmd_move_to_scratchpad(void) { + struct sway_node *node = config->handler_context.node; + struct sway_container *con = config->handler_context.container; + struct sway_workspace *ws = config->handler_context.workspace; + if (node->type == N_WORKSPACE && ws->tiling->length == 0) { return cmd_results_new(CMD_INVALID, "move", "Can't move an empty workspace to the scratchpad"); } - if (con->type == C_WORKSPACE) { + if (node->type == N_WORKSPACE) { // Wrap the workspace's children in a container - struct sway_container *workspace = con; - con = workspace_wrap_children(con); - workspace->layout = L_HORIZ; + con = workspace_wrap_children(ws); + ws->layout = L_HORIZ; } // If the container is in a floating split container, // operate on the split container instead of the child. if (container_is_floating_or_child(con)) { - while (con->parent->type != C_WORKSPACE) { + while (con->parent) { con = con->parent; } } @@ -922,32 +864,31 @@ struct cmd_results *cmd_move(int argc, char **argv) { if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { return error; } - struct sway_container *current = config->handler_context.current_container; if (strcasecmp(argv[0], "left") == 0) { - return move_in_direction(current, MOVE_LEFT, argc, argv); + return cmd_move_in_direction(MOVE_LEFT, argc, argv); } else if (strcasecmp(argv[0], "right") == 0) { - return move_in_direction(current, MOVE_RIGHT, argc, argv); + return cmd_move_in_direction(MOVE_RIGHT, argc, argv); } else if (strcasecmp(argv[0], "up") == 0) { - return move_in_direction(current, MOVE_UP, argc, argv); + return cmd_move_in_direction(MOVE_UP, argc, argv); } else if (strcasecmp(argv[0], "down") == 0) { - return move_in_direction(current, MOVE_DOWN, argc, argv); + return cmd_move_in_direction(MOVE_DOWN, argc, argv); } 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); + (strcasecmp(argv[0], "--no-auto-back-and-forth") && argc >= 2 + && (strcasecmp(argv[1], "container") == 0 + || strcasecmp(argv[1], "window") == 0))) { + return cmd_move_container(argc, argv); } else if (strcasecmp(argv[0], "workspace") == 0) { - return cmd_move_workspace(current, argc, argv); + return cmd_move_workspace(argc, argv); } else if (strcasecmp(argv[0], "scratchpad") == 0 || (strcasecmp(argv[0], "to") == 0 && argc == 2 && strcasecmp(argv[1], "scratchpad") == 0)) { - return move_to_scratchpad(current); + return cmd_move_to_scratchpad(); } else if (strcasecmp(argv[0], "position") == 0) { - return move_to_position(current, argc, argv); + return cmd_move_to_position(argc, argv); } else if (strcasecmp(argv[0], "absolute") == 0) { - return move_to_position(current, argc, argv); + return cmd_move_to_position(argc, argv); } else { return cmd_results_new(CMD_INVALID, "move", expected_syntax); } diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c index 68fd9f427..9cdaad7f4 100644 --- a/sway/commands/opacity.c +++ b/sway/commands/opacity.c @@ -19,8 +19,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) { return error; } - struct sway_container *con = - config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; float opacity = 0.0f; diff --git a/sway/commands/reload.c b/sway/commands/reload.c index f8ca374d0..36fb90920 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -42,7 +42,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) { } list_free(bar_ids); - arrange_windows(&root_container); + arrange_root(); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 21d2aa642..d982f9415 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c @@ -25,14 +25,11 @@ struct cmd_results *cmd_rename(int argc, char **argv) { } int argn = 1; - struct sway_container *workspace; + struct sway_workspace *workspace = NULL; if (strcasecmp(argv[1], "to") == 0) { // 'rename workspace to new_name' - workspace = config->handler_context.current_container; - if (workspace->type != C_WORKSPACE) { - workspace = container_parent(workspace, C_WORKSPACE); - } + workspace = config->handler_context.workspace; } else if (strcasecmp(argv[1], "number") == 0) { // 'rename workspace number x to new_name' if (!isdigit(argv[2][0])) { @@ -78,7 +75,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "rename", "Cannot use special workspace name '%s'", argv[argn]); } - struct sway_container *tmp_workspace = workspace_by_name(new_name); + struct sway_workspace *tmp_workspace = workspace_by_name(new_name); if (tmp_workspace) { free(new_name); return cmd_results_new(CMD_INVALID, "rename", @@ -89,7 +86,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { free(workspace->name); workspace->name = new_name; - output_sort_workspaces(workspace->parent); + output_sort_workspaces(workspace->output); ipc_event_workspace(NULL, workspace, "rename"); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/resize.c b/sway/commands/resize.c index ad659ef56..99e9dbda3 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c @@ -10,6 +10,7 @@ #include "sway/commands.h" #include "sway/tree/arrange.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "log.h" static const int MIN_SANE_W = 100, MIN_SANE_H = 60; @@ -75,7 +76,7 @@ static int parse_resize_amount(int argc, char **argv, static void calculate_constraints(int *min_width, int *max_width, int *min_height, int *max_height) { - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; if (config->floating_minimum_width == -1) { // no minimum *min_width = 0; @@ -96,8 +97,7 @@ static void calculate_constraints(int *min_width, int *max_width, if (config->floating_maximum_width == -1) { // no maximum *max_width = INT_MAX; } else if (config->floating_maximum_width == 0) { // automatic - struct sway_container *ws = container_parent(con, C_WORKSPACE); - *max_width = ws->width; + *max_width = con->workspace->width; } else { *max_width = config->floating_maximum_width; } @@ -105,8 +105,7 @@ static void calculate_constraints(int *min_width, int *max_width, if (config->floating_maximum_height == -1) { // no maximum *max_height = INT_MAX; } else if (config->floating_maximum_height == 0) { // automatic - struct sway_container *ws = container_parent(con, C_WORKSPACE); - *max_height = ws->height; + *max_height = con->workspace->height; } else { *max_height = config->floating_maximum_height; } @@ -191,11 +190,11 @@ static void resize_tiled(struct sway_container *parent, int amount, normalize_axis(axis) == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; int minor_weight = 0; int major_weight = 0; - while (parent->parent) { - struct sway_container *next = parent->parent; - if (next->layout == parallel_layout) { - for (int i = 0; i < next->children->length; i++) { - struct sway_container *sibling = next->children->items[i]; + while (parent) { + list_t *siblings = container_get_siblings(parent); + if (container_parent_layout(parent) == parallel_layout) { + for (int i = 0; i < siblings->length; i++) { + struct sway_container *sibling = siblings->items[i]; int sibling_pos = parallel_coord(sibling, axis); int focused_pos = parallel_coord(focused, axis); @@ -213,17 +212,13 @@ static void resize_tiled(struct sway_container *parent, int amount, break; } } - parent = next; + parent = parent->parent; } - - if (parent->type == C_ROOT) { + if (!parent) { + // Can't resize in this direction return; } - wlr_log(WLR_DEBUG, - "Found the proper parent: %p. It has %d l conts, and %d r conts", - parent->parent, minor_weight, major_weight); - // Implement up/down/left/right direction by zeroing one of the weights, // then setting the axis to be horizontal or vertical if (axis == RESIZE_AXIS_UP || axis == RESIZE_AXIS_LEFT) { @@ -237,9 +232,10 @@ static void resize_tiled(struct sway_container *parent, int amount, //TODO: Ensure rounding is done in such a way that there are NO pixel leaks // ^ ????? + list_t *siblings = container_get_siblings(parent); - for (int i = 0; i < parent->parent->children->length; i++) { - struct sway_container *sibling = parent->parent->children->items[i]; + for (int i = 0; i < siblings->length; i++) { + struct sway_container *sibling = siblings->items[i]; int sibling_pos = parallel_coord(sibling, axis); int focused_pos = parallel_coord(focused, axis); @@ -277,8 +273,8 @@ static void resize_tiled(struct sway_container *parent, int amount, enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; - for (int i = 0; i < parent->parent->children->length; i++) { - struct sway_container *sibling = parent->parent->children->items[i]; + for (int i = 0; i < siblings->length; i++) { + struct sway_container *sibling = siblings->items[i]; int sibling_pos = parallel_coord(sibling, axis); int focused_pos = parallel_coord(focused, axis); @@ -316,7 +312,11 @@ static void resize_tiled(struct sway_container *parent, int amount, } } - arrange_windows(parent->parent); + if (parent->parent) { + arrange_container(parent->parent); + } else { + arrange_workspace(parent->workspace); + } } void container_resize_tiled(struct sway_container *parent, @@ -346,7 +346,7 @@ void container_resize_tiled(struct sway_container *parent, */ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, struct resize_amount *amount) { - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; int grow_width = 0, grow_height = 0; switch (axis) { case RESIZE_AXIS_HORIZONTAL: @@ -400,15 +400,15 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, con->width += grow_width; con->height += grow_height; - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; + if (con->view) { + struct sway_view *view = con->view; view->x += grow_x; view->y += grow_y; view->width += grow_width; view->height += grow_height; } - arrange_windows(con); + arrange_container(con); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -418,7 +418,7 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, */ static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, struct resize_amount *amount) { - struct sway_container *current = config->handler_context.current_container; + struct sway_container *current = config->handler_context.container; if (amount->unit == RESIZE_UNIT_DEFAULT) { amount->unit = RESIZE_UNIT_PPT; @@ -456,13 +456,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, width->unit == RESIZE_UNIT_DEFAULT) { // Convert to px struct sway_container *parent = con->parent; - while (parent->type >= C_WORKSPACE && parent->layout != L_HORIZ) { + while (parent && parent->layout != L_HORIZ) { parent = parent->parent; } - if (parent->type >= C_WORKSPACE) { + if (parent) { width->amount = parent->width * width->amount / 100; - width->unit = RESIZE_UNIT_PX; + } else { + width->amount = con->workspace->width * width->amount / 100; } + width->unit = RESIZE_UNIT_PX; } if (width->unit == RESIZE_UNIT_PX) { resize_tiled(con, width->amount - con->width, @@ -475,13 +477,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, height->unit == RESIZE_UNIT_DEFAULT) { // Convert to px struct sway_container *parent = con->parent; - while (parent->type >= C_WORKSPACE && parent->layout != L_VERT) { + while (parent && parent->layout != L_VERT) { parent = parent->parent; } - if (parent->type >= C_WORKSPACE) { + if (parent) { height->amount = parent->height * height->amount / 100; - height->unit = RESIZE_UNIT_PX; + } else { + height->amount = con->workspace->height * height->amount / 100; } + height->unit = RESIZE_UNIT_PX; } if (height->unit == RESIZE_UNIT_PX) { resize_tiled(con, height->amount - con->height, @@ -508,15 +512,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, con->width = width->amount; con->height = height->amount; - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; + if (con->view) { + struct sway_view *view = con->view; view->x -= grow_width / 2; view->y -= grow_height / 2; view->width += grow_width; view->height += grow_height; } - arrange_windows(con); + arrange_container(con); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -555,7 +559,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) { } // If 0, don't resize that dimension - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; if (width.amount <= 0) { width.amount = con->width; } @@ -624,7 +628,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, first_amount.amount *= multiplier; second_amount.amount *= multiplier; - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; if (container_is_floating(con)) { // Floating containers can only resize in px. Choose an amount which // uses px, with fallback to an amount that specified no unit. @@ -657,14 +661,10 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, } struct cmd_results *cmd_resize(int argc, char **argv) { - struct sway_container *current = config->handler_context.current_container; + struct sway_container *current = config->handler_context.container; if (!current) { return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); } - if (current->type != C_VIEW && current->type != C_CONTAINER) { - return cmd_results_new(CMD_INVALID, "resize", - "Can only resize views/containers"); - } struct cmd_results *error; if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index 7da200154..d8bae615f 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c @@ -9,36 +9,34 @@ static void scratchpad_toggle_auto(void) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *ws = focus->type == C_WORKSPACE ? - focus : container_parent(focus, C_WORKSPACE); + struct sway_container *focus = seat_get_focused_container(seat); + struct sway_workspace *ws = seat_get_focused_workspace(seat); // If the focus is in a floating split container, // operate on the split container instead of the child. - if (container_is_floating_or_child(focus)) { - while (focus->parent->type != C_WORKSPACE) { + if (focus && container_is_floating_or_child(focus)) { + while (focus->parent) { focus = focus->parent; } } - // Check if the currently focused window is a scratchpad window and should // be hidden again. - if (focus->scratchpad) { + if (focus && focus->scratchpad) { wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", - focus->name); + focus->title); root_scratchpad_hide(focus); return; } // Check if there is an unfocused scratchpad window on the current workspace // and focus it. - for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { - struct sway_container *floater = ws->sway_workspace->floating->items[i]; + for (int i = 0; i < ws->floating->length; ++i) { + struct sway_container *floater = ws->floating->items[i]; if (floater->scratchpad && focus != floater) { wlr_log(WLR_DEBUG, "Focusing other scratchpad window (%s) in this workspace", - floater->name); + floater->title); root_scratchpad_show(floater); return; } @@ -46,25 +44,23 @@ static void scratchpad_toggle_auto(void) { // Check if there is a visible scratchpad window on another workspace. // In this case we move it to the current workspace. - for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { - struct sway_container *con = - root_container.sway_root->scratchpad->items[i]; + for (int i = 0; i < root->scratchpad->length; ++i) { + struct sway_container *con = root->scratchpad->items[i]; if (con->parent) { wlr_log(WLR_DEBUG, "Moving a visible scratchpad window (%s) to this workspace", - con->name); + con->title); root_scratchpad_show(con); return; } } // Take the container at the bottom of the scratchpad list - if (!sway_assert(root_container.sway_root->scratchpad->length, - "Scratchpad is empty")) { + if (!sway_assert(root->scratchpad->length, "Scratchpad is empty")) { return; } - struct sway_container *con = root_container.sway_root->scratchpad->items[0]; - wlr_log(WLR_DEBUG, "Showing %s from list", con->name); + struct sway_container *con = root->scratchpad->items[0]; + wlr_log(WLR_DEBUG, "Showing %s from list", con->title); root_scratchpad_show(con); } @@ -74,7 +70,7 @@ static void scratchpad_toggle_container(struct sway_container *con) { } // Check if it matches a currently visible scratchpad window and hide it. - if (con->parent) { + if (con->workspace) { root_scratchpad_hide(con); return; } @@ -91,18 +87,18 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "scratchpad", "Expected 'scratchpad show'"); } - if (!root_container.sway_root->scratchpad->length) { + if (!root->scratchpad->length) { return cmd_results_new(CMD_INVALID, "scratchpad", "Scratchpad is empty"); } if (config->handler_context.using_criteria) { - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; // If the container is in a floating split container, // operate on the split container instead of the child. if (container_is_floating_or_child(con)) { - while (con->parent->type != C_WORKSPACE) { + while (con->parent) { con = con->parent; } } diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 4d0a22c78..cd6630e0d 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -42,8 +42,8 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); } // map absolute coords (0..1,0..1) to root container coords - float x = strtof(argv[1], NULL) / root_container.width; - float y = strtof(argv[2], NULL) / root_container.height; + float x = strtof(argv[1], NULL) / root->width; + float y = strtof(argv[2], NULL) / root->height; wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); cursor_send_pointer_motion(cursor, 0, true); } else { diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index 1844e9172..d501584a0 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c @@ -11,8 +11,8 @@ #include "util.h" static void rebuild_marks_iterator(struct sway_container *con, void *data) { - if (con->type == C_VIEW) { - view_update_marks_textures(con->sway_view); + if (con->view) { + view_update_marks_textures(con->view); } } @@ -28,9 +28,9 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) { root_for_each_container(rebuild_marks_iterator, NULL); } - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *con = root_container.children->items[i]; - output_damage_whole(con->sway_output); + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_whole(output); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c index 7d27e5719..273905df1 100644 --- a/sway/commands/smart_gaps.c +++ b/sway/commands/smart_gaps.c @@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) { "Expected 'smart_gaps ' "); } - arrange_windows(&root_container); + arrange_root(); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/split.c b/sway/commands/split.c index a8eddf543..9a53f3d3d 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c @@ -4,15 +4,21 @@ #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "log.h" static struct cmd_results *do_split(int layout) { - struct sway_container *con = config->handler_context.current_container; - struct sway_container *parent = container_split(con, layout); - container_create_notify(parent); - arrange_windows(parent->parent); + struct sway_container *con = config->handler_context.container; + struct sway_workspace *ws = config->handler_context.workspace; + if (con) { + container_split(con, layout); + } else { + workspace_split(ws, layout); + } + + arrange_workspace(ws); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -29,10 +35,9 @@ struct cmd_results *cmd_split(int argc, char **argv) { return do_split(L_HORIZ); } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) { - struct sway_container *focused = - config->handler_context.current_container; + struct sway_container *focused = config->handler_context.container; - if (focused->parent->layout == L_VERT) { + if (focused && container_parent_layout(focused) == L_VERT) { return do_split(L_HORIZ); } else { return do_split(L_VERT); @@ -66,9 +71,9 @@ struct cmd_results *cmd_splitt(int argc, char **argv) { return error; } - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; - if (con->parent->layout == L_VERT) { + if (con && container_parent_layout(con) == L_VERT) { return do_split(L_HORIZ); } else { return do_split(L_VERT); diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 8692e08d8..7995cdd61 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c @@ -15,8 +15,7 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; + struct sway_container *container = config->handler_context.container; if (!container_is_floating(container)) { return cmd_results_new(CMD_FAILURE, "sticky", "Can't set sticky on a tiled container"); @@ -37,20 +36,16 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { container->is_sticky = wants_sticky; if (wants_sticky) { - // move container to focused workspace - struct sway_container *output = container_parent(container, C_OUTPUT); - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, output); - struct sway_container *focused_workspace = container_parent(focus, C_WORKSPACE); - struct sway_container *current_workspace = container_parent(container, C_WORKSPACE); - if (current_workspace != focused_workspace) { - container_remove_child(container); - workspace_add_floating(focused_workspace, container); - container_handle_fullscreen_reparent(container, current_workspace); - arrange_windows(focused_workspace); - if (!container_reap_empty(current_workspace)) { - arrange_windows(current_workspace); - } + // move container to active workspace + struct sway_workspace *active_workspace = + output_get_active_workspace(container->workspace->output); + if (container->workspace != active_workspace) { + struct sway_workspace *old_workspace = container->workspace; + container_detach(container); + workspace_add_floating(active_workspace, container); + container_handle_fullscreen_reparent(container); + arrange_workspace(active_workspace); + workspace_consider_destroy(old_workspace); } } diff --git a/sway/commands/swap.c b/sway/commands/swap.c index f25c43a1e..a0ffbda82 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -4,6 +4,7 @@ #include "config.h" #include "log.h" #include "sway/commands.h" +#include "sway/output.h" #include "sway/tree/arrange.h" #include "sway/tree/root.h" #include "sway/tree/view.h" @@ -43,27 +44,28 @@ static void swap_focus(struct sway_container *con1, struct sway_container *con2, struct sway_seat *seat, struct sway_container *focus) { if (focus == con1 || focus == con2) { - struct sway_container *ws1 = container_parent(con1, C_WORKSPACE); - struct sway_container *ws2 = container_parent(con2, C_WORKSPACE); - if (focus == con1 && (con2->parent->layout == L_TABBED - || con2->parent->layout == L_STACKED)) { + struct sway_workspace *ws1 = con1->workspace; + struct sway_workspace *ws2 = con2->workspace; + enum sway_container_layout layout1 = container_parent_layout(con1); + enum sway_container_layout layout2 = container_parent_layout(con2); + if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { if (workspace_is_visible(ws2)) { - seat_set_focus_warp(seat, con2, false, true); + seat_set_focus_warp(seat, &con2->node, false, true); } - seat_set_focus(seat, ws1 != ws2 ? con2 : con1); - } else if (focus == con2 && (con1->parent->layout == L_TABBED - || con1->parent->layout == L_STACKED)) { + seat_set_focus(seat, ws1 != ws2 ? &con2->node : &con1->node); + } else if (focus == con2 && (layout1 == L_TABBED + || layout1 == L_STACKED)) { if (workspace_is_visible(ws1)) { - seat_set_focus_warp(seat, con1, false, true); + seat_set_focus_warp(seat, &con1->node, false, true); } - seat_set_focus(seat, ws1 != ws2 ? con1 : con2); + seat_set_focus(seat, ws1 != ws2 ? &con1->node : &con2->node); } else if (ws1 != ws2) { - seat_set_focus(seat, focus == con1 ? con2 : con1); + seat_set_focus(seat, focus == con1 ? &con2->node : &con1->node); } else { - seat_set_focus(seat, focus); + seat_set_focus(seat, &focus->node); } } else { - seat_set_focus(seat, focus); + seat_set_focus(seat, &focus->node); } } @@ -72,10 +74,6 @@ static void container_swap(struct sway_container *con1, if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { return; } - if (!sway_assert(con1->type >= C_CONTAINER && con2->type >= C_CONTAINER, - "Can only swap containers and views")) { - return; - } if (!sway_assert(!container_has_ancestor(con1, con2) && !container_has_ancestor(con2, con1), "Cannot swap ancestor and descendant")) { @@ -87,10 +85,11 @@ static void container_swap(struct sway_container *con1, return; } - wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); + wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", + con1->node.id, con2->node.id); - int fs1 = con1->is_fullscreen; - int fs2 = con2->is_fullscreen; + bool fs1 = con1->is_fullscreen; + bool fs2 = con2->is_fullscreen; if (fs1) { container_set_fullscreen(con1, false); } @@ -99,13 +98,11 @@ static void container_swap(struct sway_container *con1, } struct sway_seat *seat = input_manager_get_default_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *vis1 = container_parent( - seat_get_focus_inactive(seat, container_parent(con1, C_OUTPUT)), - C_WORKSPACE); - struct sway_container *vis2 = container_parent( - seat_get_focus_inactive(seat, container_parent(con2, C_OUTPUT)), - C_WORKSPACE); + struct sway_container *focus = seat_get_focused_container(seat); + struct sway_workspace *vis1 = + output_get_active_workspace(con1->workspace->output); + struct sway_workspace *vis2 = + output_get_active_workspace(con2->workspace->output); char *stored_prev_name = NULL; if (prev_workspace_name) { @@ -115,10 +112,10 @@ static void container_swap(struct sway_container *con1, swap_places(con1, con2); if (!workspace_is_visible(vis1)) { - seat_set_focus(seat, seat_get_focus_inactive(seat, vis1)); + seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node)); } if (!workspace_is_visible(vis2)) { - seat_set_focus(seat, seat_get_focus_inactive(seat, vis2)); + seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node)); } swap_focus(con1, con2, seat, focus); @@ -137,23 +134,22 @@ static void container_swap(struct sway_container *con1, } static bool test_con_id(struct sway_container *container, void *con_id) { - return container->id == (size_t)con_id; + return container->node.id == (size_t)con_id; } static bool test_id(struct sway_container *container, void *id) { #ifdef HAVE_XWAYLAND xcb_window_t *wid = id; - return (container->type == C_VIEW - && container->sway_view->type == SWAY_VIEW_XWAYLAND - && container->sway_view->wlr_xwayland_surface->window_id == *wid); + return (container->view && container->view->type == SWAY_VIEW_XWAYLAND + && container->view->wlr_xwayland_surface->window_id == *wid); #else return false; #endif } static bool test_mark(struct sway_container *container, void *mark) { - if (container->type == C_VIEW && container->sway_view->marks->length) { - return !list_seq_find(container->sway_view->marks, + if (container->view && container->view->marks->length) { + return !list_seq_find(container->view->marks, (int (*)(const void *, const void *))strcmp, mark); } return false; @@ -169,7 +165,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); } - struct sway_container *current = config->handler_context.current_container; + struct sway_container *current = config->handler_context.container; struct sway_container *other; char *value = join_args(argv + 3, argc - 3); @@ -191,7 +187,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { if (!other) { error = cmd_results_new(CMD_FAILURE, "swap", "Failed to find %s '%s'", argv[2], value); - } else if (current->type < C_CONTAINER || other->type < C_CONTAINER) { + } else if (!current) { error = cmd_results_new(CMD_FAILURE, "swap", "Can only swap with containers and views"); } else if (container_has_ancestor(current, other) @@ -211,9 +207,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) { container_swap(current, other); - arrange_windows(current->parent); - if (other->parent != current->parent) { - arrange_windows(other->parent); + arrange_node(node_get_parent(¤t->node)); + if (node_get_parent(&other->node) != node_get_parent(¤t->node)) { + arrange_node(node_get_parent(&other->node)); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 3d1c578c6..c9ffe8fa2 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c @@ -11,13 +11,12 @@ struct cmd_results *cmd_title_format(int argc, char **argv) { if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "title_format", "Only views can have a title_format"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; char *format = join_args(argv, argc); if (view->title_format) { free(view->title_format); diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index 62127c975..c6251dc8a 100644 --- a/sway/commands/unmark.c +++ b/sway/commands/unmark.c @@ -9,9 +9,9 @@ #include "stringop.h" static void remove_all_marks_iterator(struct sway_container *con, void *data) { - if (con->type == C_VIEW) { - view_clear_marks(con->sway_view); - view_update_marks_textures(con->sway_view); + if (con->view) { + view_clear_marks(con->view); + view_update_marks_textures(con->view); } } @@ -24,13 +24,12 @@ struct cmd_results *cmd_unmark(int argc, char **argv) { // Determine the view struct sway_view *view = NULL; if (config->handler_context.using_criteria) { - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "unmark", "Only views can have marks"); } - view = container->sway_view; + view = container->view; } // Determine the mark diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c index bccb33fec..53c37d4d5 100644 --- a/sway/commands/urgent.c +++ b/sway/commands/urgent.c @@ -11,13 +11,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) { if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "urgent", "Only views can be urgent"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; if (strcmp(argv[0], "allow") == 0) { view->allow_request_urgent = true; diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index ceb4cd6e0..f026a39d4 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -58,7 +58,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { } - struct sway_container *ws = NULL; + struct sway_workspace *ws = NULL; if (strcasecmp(argv[0], "number") == 0) { if (argc < 2) { return cmd_results_new(CMD_INVALID, "workspace", diff --git a/sway/config.c b/sway/config.c index 8105722ad..89701640e 100644 --- a/sway/config.c +++ b/sway/config.c @@ -825,6 +825,6 @@ void config_update_font_height(bool recalculate) { root_for_each_container(find_font_height_iterator, &recalculate); if (config->font_height != prev_max_height) { - arrange_windows(&root_container); + arrange_root(); } } diff --git a/sway/config/bar.c b/sway/config/bar.c index ae9383d65..f83b37d1d 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -12,6 +12,7 @@ #include #include #include "sway/config.h" +#include "sway/output.h" #include "stringop.h" #include "list.h" #include "log.h" @@ -218,17 +219,6 @@ void invoke_swaybar(struct bar_config *bar) { close(filedes[1]); } -static bool active_output(const char *name) { - struct sway_container *cont = NULL; - for (int i = 0; i < root_container.children->length; ++i) { - cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) { - return true; - } - } - return false; -} - void load_swaybars() { for (int i = 0; i < config->bars->length; ++i) { struct bar_config *bar = config->bars->items[i]; @@ -236,7 +226,7 @@ void load_swaybars() { if (bar->outputs) { for (int j = 0; j < bar->outputs->length; ++j) { char *o = bar->outputs->items[j]; - if (!strcmp(o, "*") || active_output(o)) { + if (!strcmp(o, "*") || output_by_name(o)) { apply = true; break; } diff --git a/sway/config/output.c b/sway/config/output.c index 65f09258e..aa53fc467 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -174,21 +174,16 @@ void terminate_swaybg(pid_t pid) { } } -void apply_output_config(struct output_config *oc, struct sway_container *output) { - assert(output->type == C_OUTPUT); - - struct wlr_output_layout *output_layout = - root_container.sway_root->output_layout; - struct wlr_output *wlr_output = output->sway_output->wlr_output; +void apply_output_config(struct output_config *oc, struct sway_output *output) { + struct wlr_output *wlr_output = output->wlr_output; if (oc && oc->enabled == 0) { - if (output->sway_output->bg_pid != 0) { - terminate_swaybg(output->sway_output->bg_pid); - output->sway_output->bg_pid = 0; + if (output->bg_pid != 0) { + terminate_swaybg(output->bg_pid); + output->bg_pid = 0; } - output_begin_destroy(output); - wlr_output_layout_remove(root_container.sway_root->output_layout, - wlr_output); + output_disable(output); + wlr_output_layout_remove(root->output_layout, wlr_output); return; } @@ -213,21 +208,21 @@ void apply_output_config(struct output_config *oc, struct sway_container *output // Find position for it if (oc && (oc->x != -1 || oc->y != -1)) { wlr_log(WLR_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); - wlr_output_layout_add(output_layout, wlr_output, oc->x, oc->y); + wlr_output_layout_add(root->output_layout, wlr_output, oc->x, oc->y); } else { - wlr_output_layout_add_auto(output_layout, wlr_output); + wlr_output_layout_add_auto(root->output_layout, wlr_output); } int output_i; - for (output_i = 0; output_i < root_container.children->length; ++output_i) { - if (root_container.children->items[output_i] == output) { + for (output_i = 0; output_i < root->outputs->length; ++output_i) { + if (root->outputs->items[output_i] == output) { break; } } if (oc && oc->background) { - if (output->sway_output->bg_pid != 0) { - terminate_swaybg(output->sway_output->bg_pid); + if (output->bg_pid != 0) { + terminate_swaybg(output->bg_pid); } wlr_log(WLR_DEBUG, "Setting background for output %d to %s", @@ -249,8 +244,8 @@ void apply_output_config(struct output_config *oc, struct sway_container *output wlr_log(WLR_DEBUG, "-> %s", command); char *const cmd[] = { "sh", "-c", command, NULL }; - output->sway_output->bg_pid = fork(); - if (output->sway_output->bg_pid == 0) { + output->bg_pid = fork(); + if (output->bg_pid == 0) { execvp(cmd[0], cmd); } else { free(command); @@ -293,12 +288,11 @@ void apply_output_config_to_outputs(struct output_config *oc) { bool wildcard = strcmp(oc->name, "*") == 0; char id[128]; struct sway_output *sway_output; - wl_list_for_each(sway_output, - &root_container.sway_root->all_outputs, link) { + wl_list_for_each(sway_output, &root->all_outputs, link) { char *name = sway_output->wlr_output->name; output_get_identifier(id, sizeof(id), sway_output); if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) { - if (!sway_output->swayc) { + if (!sway_output->enabled) { if (!oc->enabled) { if (!wildcard) { break; @@ -306,7 +300,7 @@ void apply_output_config_to_outputs(struct output_config *oc) { continue; } - output_enable(sway_output); + output_enable(sway_output, oc); } struct output_config *current = oc; @@ -316,7 +310,7 @@ void apply_output_config_to_outputs(struct output_config *oc) { current = tmp; } } - apply_output_config(current, sway_output->swayc); + apply_output_config(current, sway_output); if (!wildcard) { // Stop looking if the output config isn't applicable to all @@ -354,8 +348,7 @@ static void default_output_config(struct output_config *oc, void create_default_output_configs(void) { struct sway_output *sway_output; - wl_list_for_each(sway_output, - &root_container.sway_root->all_outputs, link) { + wl_list_for_each(sway_output, &root->all_outputs, link) { char *name = sway_output->wlr_output->name; struct output_config *oc = new_output_config(name); default_output_config(oc, sway_output->wlr_output); diff --git a/sway/criteria.c b/sway/criteria.c index feca904a9..e5b308e06 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -9,6 +9,7 @@ #include "sway/config.h" #include "sway/tree/root.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "stringop.h" #include "list.h" #include "log.h" @@ -87,12 +88,12 @@ static int cmp_urgent(const void *_a, const void *_b) { return 0; } -static void find_urgent_iterator(struct sway_container *swayc, void *data) { - if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) { +static void find_urgent_iterator(struct sway_container *con, void *data) { + if (!con->view || !view_is_urgent(con->view)) { return; } list_t *urgent_views = data; - list_add(urgent_views, swayc->sway_view); + list_add(urgent_views, con->view); } static bool criteria_matches_view(struct criteria *criteria, @@ -132,7 +133,7 @@ static bool criteria_matches_view(struct criteria *criteria, } if (criteria->con_id) { // Internal ID - if (!view->swayc || view->swayc->id != criteria->con_id) { + if (!view->container || view->container->node.id != criteria->con_id) { return false; } } @@ -174,13 +175,13 @@ static bool criteria_matches_view(struct criteria *criteria, #endif if (criteria->floating) { - if (!container_is_floating(view->swayc)) { + if (!container_is_floating(view->container)) { return false; } } if (criteria->tiling) { - if (container_is_floating(view->swayc)) { + if (container_is_floating(view->container)) { return false; } } @@ -205,10 +206,7 @@ static bool criteria_matches_view(struct criteria *criteria, } if (criteria->workspace) { - if (!view->swayc) { - return false; - } - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + struct sway_workspace *ws = view->container->workspace; if (!ws || strcmp(ws->name, criteria->workspace) != 0) { return false; } @@ -237,9 +235,9 @@ struct match_data { static void criteria_get_views_iterator(struct sway_container *container, void *data) { struct match_data *match_data = data; - if (container->type == C_VIEW) { - if (criteria_matches_view(match_data->criteria, container->sway_view)) { - list_add(match_data->matches, container->sway_view); + if (!container->view) { + if (criteria_matches_view(match_data->criteria, container->view)) { + list_add(match_data->matches, container->view); } } } @@ -355,12 +353,12 @@ static enum criteria_token token_from_name(char *name) { */ static char *get_focused_prop(enum criteria_token token) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); + struct sway_container *focus = seat_get_focused_container(seat); - if (!focus || focus->type != C_VIEW) { + if (!focus || !focus->view) { return NULL; } - struct sway_view *view = focus->sway_view; + struct sway_view *view = focus->view; const char *value = NULL; switch (token) { @@ -374,18 +372,15 @@ static char *get_focused_prop(enum criteria_token token) { value = view_get_title(view); break; case T_WORKSPACE: - { - struct sway_container *ws = container_parent(focus, C_WORKSPACE); - if (ws) { - value = ws->name; - } + if (focus->workspace) { + value = focus->workspace->name; } break; case T_CON_ID: - if (view->swayc == NULL) { + if (view->container == NULL) { return NULL; } - size_t id = view->swayc->id; + size_t id = view->container->node.id; size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; char *id_str = malloc(id_size); snprintf(id_str, id_size, "%zu", id); diff --git a/sway/debug-tree.c b/sway/debug-tree.c index 2768cf58b..2ed3c087d 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c @@ -10,6 +10,7 @@ #include "sway/server.h" #include "sway/tree/container.h" #include "sway/tree/root.h" +#include "sway/tree/workspace.h" #include "cairo.h" #include "config.h" #include "pango.h" @@ -32,28 +33,78 @@ static const char *layout_to_str(enum sway_container_layout layout) { return "L_NONE"; } -static int draw_container(cairo_t *cairo, struct sway_container *container, - struct sway_container *focus, int x, int y) { +static char *get_string(struct sway_node *node) { + char *buffer = malloc(512); + switch (node->type) { + case N_ROOT: + snprintf(buffer, 512, "N_ROOT id:%zd %.fx%.f@%.f,%.f", node->id, + root->width, root->height, root->x, root->y); + break; + case N_OUTPUT: + snprintf(buffer, 512, "N_OUTPUT id:%zd '%s' %dx%d@%d,%d", node->id, + node->sway_output->wlr_output->name, + node->sway_output->wlr_output->width, + node->sway_output->wlr_output->height, + node->sway_output->wlr_output->lx, + node->sway_output->wlr_output->ly); + break; + case N_WORKSPACE: + snprintf(buffer, 512, "N_WORKSPACE id:%zd '%s' %s %dx%d@%.f,%.f", + node->id, node->sway_workspace->name, + layout_to_str(node->sway_workspace->layout), + node->sway_workspace->width, node->sway_workspace->height, + node->sway_workspace->x, node->sway_workspace->y); + break; + case N_CONTAINER: + snprintf(buffer, 512, "N_CONTAINER id:%zd '%s' %s %.fx%.f@%.f,%.f", + node->id, node->sway_container->title, + layout_to_str(node->sway_container->layout), + node->sway_container->width, node->sway_container->height, + node->sway_container->x, node->sway_container->y); + break; + } + return buffer; +} + +static list_t *get_children(struct sway_node *node) { + switch (node->type) { + case N_ROOT: + return root->outputs; + case N_OUTPUT: + return node->sway_output->workspaces; + case N_WORKSPACE: + return node->sway_workspace->tiling; + case N_CONTAINER: + return node->sway_container->children; + } + return NULL; +} + +static int draw_node(cairo_t *cairo, struct sway_node *node, + struct sway_node *focus, int x, int y) { int text_width, text_height; + char *buffer = get_string(node); get_text_size(cairo, "monospace", &text_width, &text_height, - 1, false, "%s id:%zd '%s' %s %.fx%.f@%.f,%.f", - container_type_to_str(container->type), container->id, container->name, - layout_to_str(container->layout), - container->width, container->height, container->x, container->y); + 1, false, buffer); cairo_save(cairo); cairo_rectangle(cairo, x + 2, y, text_width - 2, text_height); cairo_set_source_u32(cairo, 0xFFFFFFE0); cairo_fill(cairo); int height = text_height; - if (container->children) { - for (int i = 0; i < container->children->length; ++i) { - struct sway_container *child = container->children->items[i]; - if (child->parent == container) { + list_t *children = get_children(node); + if (children) { + for (int i = 0; i < children->length; ++i) { + // This is really dirty - the list contains specific structs but + // we're casting them as nodes. This works because node is the first + // item in each specific struct. This is acceptable because this is + // debug code. + struct sway_node *child = children->items[i]; + if (node_get_parent(child) == node) { cairo_set_source_u32(cairo, 0x000000FF); } else { cairo_set_source_u32(cairo, 0xFF0000FF); } - height += draw_container(cairo, child, focus, x + 10, y + height); + height += draw_node(cairo, child, focus, x + 10, y + height); } } cairo_set_source_u32(cairo, 0xFFFFFFE0); @@ -61,13 +112,11 @@ static int draw_container(cairo_t *cairo, struct sway_container *container, cairo_fill(cairo); cairo_restore(cairo); cairo_move_to(cairo, x, y); - if (focus == container) { + if (focus == node) { cairo_set_source_u32(cairo, 0x0000FFFF); } - pango_printf(cairo, "monospace", 1, false, "%s id:%zd '%s' %s %.fx%.f@%.f,%.f", - container_type_to_str(container->type), container->id, container->name, - layout_to_str(container->layout), - container->width, container->height, container->x, container->y); + pango_printf(cairo, "monospace", 1, false, buffer); + free(buffer); return height; } @@ -77,13 +126,13 @@ void update_debug_tree() { } int width = 640, height = 480; - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *container = root_container.children->items[i]; - if (container->width > width) { - width = container->width; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + if (output->wlr_output->width > width) { + width = output->wlr_output->width; } - if (container->height > height) { - height = container->height; + if (output->wlr_output->height > height) { + height = output->wlr_output->height; } } cairo_surface_t *surface = @@ -91,28 +140,22 @@ void update_debug_tree() { cairo_t *cairo = cairo_create(surface); PangoContext *pango = pango_cairo_create_context(cairo); - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &input_manager->seats, link) { - break; - } + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_node *focus = seat_get_focus(seat); - struct sway_container *focus = NULL; - if (seat != NULL) { - focus = seat_get_focus(seat); - } cairo_set_source_u32(cairo, 0x000000FF); - draw_container(cairo, &root_container, focus, 0, 0); + draw_node(cairo, &root->node, focus, 0, 0); cairo_surface_flush(surface); struct wlr_renderer *renderer = wlr_backend_get_renderer(server.backend); - if (root_container.sway_root->debug_tree) { - wlr_texture_destroy(root_container.sway_root->debug_tree); + if (root->debug_tree) { + wlr_texture_destroy(root->debug_tree); } unsigned char *data = cairo_image_surface_get_data(surface); int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); struct wlr_texture *texture = wlr_texture_from_pixels(renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); - root_container.sway_root->debug_tree = texture; + root->debug_tree = texture; cairo_surface_destroy(surface); g_object_unref(pango); cairo_destroy(cairo); diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index 726503970..771b58fec 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c @@ -4,37 +4,32 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, bool whole) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT) { - output_damage_surface(cont->sway_output, - lx - cont->current.swayc_x, ly - cont->current.swayc_y, - surface, whole); - } + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_surface(output, lx - output->wlr_output->lx, + ly - output->wlr_output->ly, surface, whole); } } void desktop_damage_whole_container(struct sway_container *con) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT) { - output_damage_whole_container(cont->sway_output, con); - } + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_whole_container(output, con); } } void desktop_damage_box(struct wlr_box *box) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *cont = root_container.children->items[i]; - output_damage_box(cont->sway_output, box); + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_box(output, box); } } void desktop_damage_view(struct sway_view *view) { - desktop_damage_whole_container(view->swayc); + desktop_damage_whole_container(view->container); struct wlr_box box = { - .x = view->swayc->current.view_x - view->geometry.x, - .y = view->swayc->current.view_y - view->geometry.y, + .x = view->container->current.view_x - view->geometry.x, + .y = view->container->current.view_y - view->geometry.y, .width = view->surface->current.width, .height = view->surface->current.height, }; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index a4f7f928d..7d2541731 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -14,6 +14,7 @@ #include "sway/output.h" #include "sway/server.h" #include "sway/tree/arrange.h" +#include "sway/tree/workspace.h" #include "log.h" static void apply_exclusive(struct wlr_box *usable_area, @@ -176,7 +177,7 @@ void arrange_layers(struct sway_output *output) { sizeof(struct wlr_box)) != 0) { wlr_log(WLR_DEBUG, "Usable area changed, rearranging output"); memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); - arrange_output(output->swayc); + arrange_output(output); } // Arrange non-exlusive surfaces from top->bottom @@ -256,7 +257,7 @@ static void unmap(struct sway_layer_surface *sway_layer) { return; } struct sway_output *output = wlr_output->data; - if (output == NULL || output->swayc == NULL) { + if (output == NULL) { return; } output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, @@ -283,9 +284,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&sway_layer->surface_commit.link); if (sway_layer->layer_surface->output != NULL) { struct sway_output *output = sway_layer->layer_surface->output->data; - if (output != NULL && output->swayc != NULL) { + if (output != NULL) { arrange_layers(output); - arrange_windows(output->swayc); + arrange_output(output); transaction_commit_dirty(); } wl_list_remove(&sway_layer->output_destroy.link); @@ -332,23 +333,21 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { if (!layer_surface->output) { // Assign last active output - struct sway_container *output = NULL; + struct sway_output *output = NULL; struct sway_seat *seat = input_manager_get_default_seat(input_manager); if (seat) { - output = seat_get_focus_inactive(seat, &root_container); + struct sway_workspace *ws = seat_get_focused_workspace(seat); + output = ws->output; } if (!output) { - if (!sway_assert(root_container.children->length, + if (!sway_assert(root->outputs->length, "cannot auto-assign output for layer")) { wlr_layer_surface_close(layer_surface); return; } - output = root_container.children->items[0]; + output = root->outputs->items[0]; } - if (output->type != C_OUTPUT) { - output = container_parent(output, C_OUTPUT); - } - layer_surface->output = output->sway_output->wlr_output; + layer_surface->output = output->wlr_output; } struct sway_layer_surface *sway_layer = diff --git a/sway/desktop/output.c b/sway/desktop/output.c index c30e52a1c..c182bad63 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -28,10 +28,10 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" -struct sway_container *output_by_name(const char *name) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - if (strcasecmp(output->name, name) == 0) { +struct sway_output *output_by_name(const char *name) { + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + if (strcasecmp(output->wlr_output->name, name) == 0) { return output; } } @@ -98,8 +98,8 @@ static bool get_surface_box(struct surface_iterator_data *data, wlr_box_rotated_bounds(&box, data->rotation, &rotated_box); struct wlr_box output_box = { - .width = output->swayc->current.swayc_width, - .height = output->swayc->current.swayc_height, + .width = output->wlr_output->width, + .height = output->wlr_output->height, }; struct wlr_box intersection; @@ -145,12 +145,12 @@ void output_view_for_each_surface(struct sway_output *output, .user_iterator = iterator, .user_data = user_data, .output = output, - .ox = view->swayc->current.view_x - output->swayc->current.swayc_x + .ox = view->container->current.view_x - output->wlr_output->lx - view->geometry.x, - .oy = view->swayc->current.view_y - output->swayc->current.swayc_y + .oy = view->container->current.view_y - output->wlr_output->ly - view->geometry.y, - .width = view->swayc->current.view_width, - .height = view->swayc->current.view_height, + .width = view->container->current.view_width, + .height = view->container->current.view_height, .rotation = 0, // TODO }; @@ -164,12 +164,12 @@ void output_view_for_each_popup(struct sway_output *output, .user_iterator = iterator, .user_data = user_data, .output = output, - .ox = view->swayc->current.view_x - output->swayc->current.swayc_x + .ox = view->container->current.view_x - output->wlr_output->lx - view->geometry.x, - .oy = view->swayc->current.view_y - output->swayc->current.swayc_y + .oy = view->container->current.view_y - output->wlr_output->ly - view->geometry.y, - .width = view->swayc->current.view_width, - .height = view->swayc->current.view_height, + .width = view->container->current.view_width, + .height = view->container->current.view_height, .rotation = 0, // TODO }; @@ -197,8 +197,8 @@ void output_unmanaged_for_each_surface(struct sway_output *output, wl_list_for_each(unmanaged_surface, unmanaged, link) { struct wlr_xwayland_surface *xsurface = unmanaged_surface->wlr_xwayland_surface; - double ox = unmanaged_surface->lx - output->swayc->current.swayc_x; - double oy = unmanaged_surface->ly - output->swayc->current.swayc_y; + double ox = unmanaged_surface->lx - output->wlr_output->lx; + double oy = unmanaged_surface->ly - output->wlr_output->ly; output_surface_for_each_surface(output, xsurface->surface, ox, oy, iterator, user_data); @@ -211,8 +211,8 @@ void output_drag_icons_for_each_surface(struct sway_output *output, void *user_data) { struct sway_drag_icon *drag_icon; wl_list_for_each(drag_icon, drag_icons, link) { - double ox = drag_icon->x - output->swayc->x; - double oy = drag_icon->y - output->swayc->y; + double ox = drag_icon->x - output->wlr_output->lx; + double oy = drag_icon->y - output->wlr_output->ly; if (drag_icon->wlr_drag_icon->mapped) { output_surface_for_each_surface(output, @@ -229,19 +229,13 @@ static void scale_box(struct wlr_box *box, float scale) { box->height *= scale; } -struct sway_container *output_get_active_workspace(struct sway_output *output) { +struct sway_workspace *output_get_active_workspace(struct sway_output *output) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = - seat_get_focus_inactive(seat, output->swayc); + struct sway_node *focus = seat_get_active_child(seat, &output->node); if (!focus) { - // We've never been to this output before - focus = output->swayc->current.children->items[0]; + return output->workspaces->items[0]; } - struct sway_container *workspace = focus; - if (workspace->type != C_WORKSPACE) { - workspace = container_parent(workspace, C_WORKSPACE); - } - return workspace; + return focus->sway_workspace; } bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { @@ -255,8 +249,8 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { struct sway_layer_surface *sway_layer_surface = layer_from_wlr_layer_surface(wlr_layer_surface); pixman_box32_t output_box = { - .x2 = output->swayc->current.swayc_width, - .y2 = output->swayc->current.swayc_height, + .x2 = output->wlr_output->width, + .y2 = output->wlr_output->height, }; pixman_region32_t surface_opaque_box; pixman_region32_init(&surface_opaque_box); @@ -307,15 +301,15 @@ struct send_frame_done_data { static void send_frame_done_container_iterator(struct sway_container *con, void *_data) { - if (con->type != C_VIEW) { + if (!con->view) { return; } - if (!view_is_visible(con->sway_view)) { + if (!view_is_visible(con->view)) { return; } struct send_frame_done_data *data = _data; - output_view_for_each_surface(data->output, con->sway_view, + output_view_for_each_surface(data->output, con->view, send_frame_done_iterator, data->when); } @@ -328,15 +322,14 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { .output = output, .when = when, }; - struct sway_container *workspace = output_get_active_workspace(output); - if (workspace->current.ws_fullscreen) { + struct sway_workspace *workspace = output_get_active_workspace(output); + if (workspace->current.fullscreen) { send_frame_done_container_iterator( - workspace->current.ws_fullscreen, &data); - container_for_each_child(workspace->current.ws_fullscreen, + workspace->current.fullscreen, &data); + container_for_each_child(workspace->current.fullscreen, send_frame_done_container_iterator, &data); #ifdef HAVE_XWAYLAND - send_frame_done_unmanaged(output, - &root_container.sway_root->xwayland_unmanaged, when); + send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when); #endif } else { send_frame_done_layer(output, @@ -348,8 +341,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { send_frame_done_container_iterator, &data); #ifdef HAVE_XWAYLAND - send_frame_done_unmanaged(output, - &root_container.sway_root->xwayland_unmanaged, when); + send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when); #endif send_frame_done_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], when); @@ -358,8 +350,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { send_frame_overlay: send_frame_done_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], when); - send_frame_done_drag_icons(output, &root_container.sway_root->drag_icons, - when); + send_frame_done_drag_icons(output, &root->drag_icons, when); } static void damage_handle_frame(struct wl_listener *listener, void *data) { @@ -391,7 +382,11 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) { } void output_damage_whole(struct sway_output *output) { - wlr_output_damage_add_whole(output->damage); + // The output can exist with no wlr_output if it's just been disconnected + // and the transaction to evacuate it has't completed yet. + if (output && output->wlr_output) { + wlr_output_damage_add_whole(output->damage); + } } static void damage_surface_iterator(struct sway_output *output, @@ -446,14 +441,9 @@ void output_damage_surface(struct sway_output *output, double ox, double oy, static void output_damage_view(struct sway_output *output, struct sway_view *view, bool whole) { - if (!sway_assert(view->swayc != NULL, "expected a view in the tree")) { - return; - } - if (!view_is_visible(view)) { return; } - output_view_for_each_surface(output, view, damage_surface_iterator, &whole); } @@ -466,31 +456,29 @@ void output_damage_from_view(struct sway_output *output, void output_damage_box(struct sway_output *output, struct wlr_box *_box) { struct wlr_box box; memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= output->swayc->current.swayc_x; - box.y -= output->swayc->current.swayc_y; + box.x -= output->wlr_output->lx; + box.y -= output->wlr_output->ly; scale_box(&box, output->wlr_output->scale); wlr_output_damage_add_box(output->damage, &box); } static void output_damage_whole_container_iterator(struct sway_container *con, void *data) { - struct sway_output *output = data; - - if (!sway_assert(con->type == C_VIEW, "expected a view")) { + if (!sway_assert(con->view, "expected a view")) { return; } - - output_damage_view(output, con->sway_view, true); + struct sway_output *output = data; + output_damage_view(output, con->view, true); } void output_damage_whole_container(struct sway_output *output, struct sway_container *con) { // Pad the box by 1px, because the width is a double and might be a fraction struct wlr_box box = { - .x = con->current.swayc_x - output->wlr_output->lx - 1, - .y = con->current.swayc_y - output->wlr_output->ly - 1, - .width = con->current.swayc_width + 2, - .height = con->current.swayc_height + 2, + .x = con->current.con_x - output->wlr_output->lx - 1, + .y = con->current.con_y - output->wlr_output->ly - 1, + .width = con->current.con_width + 2, + .height = con->current.con_height + 2, }; scale_box(&box, output->wlr_output->scale); wlr_output_damage_add_box(output->damage, &box); @@ -499,44 +487,48 @@ void output_damage_whole_container(struct sway_output *output, static void damage_handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, damage_destroy); - output_begin_destroy(output->swayc); + output_disable(output); + transaction_commit_dirty(); } static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, destroy); wl_signal_emit(&output->events.destroy, output); - if (output->swayc) { - output_begin_destroy(output->swayc); + if (output->enabled) { + output_disable(output); } + output_begin_destroy(output); - wl_list_remove(&output->link); - wl_list_remove(&output->destroy.link); - output->wlr_output->data = NULL; - free(output); - - arrange_windows(&root_container); + transaction_commit_dirty(); } static void handle_mode(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, mode); arrange_layers(output); - arrange_windows(output->swayc); + arrange_output(output); transaction_commit_dirty(); } static void handle_transform(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, transform); arrange_layers(output); - arrange_windows(output->swayc); + arrange_output(output); transaction_commit_dirty(); } +static void update_textures(struct sway_container *con, void *data) { + container_update_title_textures(con); + if (con->view) { + view_update_marks_textures(con->view); + } +} + static void handle_scale(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, scale); arrange_layers(output); - container_update_textures_recursive(output->swayc); - arrange_windows(output->swayc); + output_for_each_container(output, update_textures, NULL); + arrange_output(output); transaction_commit_dirty(); } @@ -545,57 +537,27 @@ void handle_new_output(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); - struct sway_output *output = calloc(1, sizeof(struct sway_output)); + struct sway_output *output = output_create(wlr_output); if (!output) { return; } - output->wlr_output = wlr_output; - wlr_output->data = output; output->server = server; output->damage = wlr_output_damage_create(wlr_output); - - wl_signal_add(&wlr_output->events.destroy, &output->destroy); output->destroy.notify = handle_destroy; - wl_list_insert(&root_container.sway_root->all_outputs, &output->link); + struct output_config *oc = output_find_config(output); - output_enable(output); -} - -void output_enable(struct sway_output *output) { - struct wlr_output *wlr_output = output->wlr_output; - - if (!sway_assert(output->swayc == NULL, "output is already enabled")) { - return; + if (oc && oc->enabled) { + output_enable(output, oc); } - output->swayc = output_create(output); - if (!output->swayc) { - // Output is disabled - return; - } - - size_t len = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len; ++i) { - wl_list_init(&output->layers[i]); - } - wl_signal_init(&output->events.destroy); - - input_manager_configure_xcursor(input_manager); - - wl_signal_add(&wlr_output->events.mode, &output->mode); - output->mode.notify = handle_mode; - wl_signal_add(&wlr_output->events.transform, &output->transform); - output->transform.notify = handle_transform; - wl_signal_add(&wlr_output->events.scale, &output->scale); - output->scale.notify = handle_scale; - - wl_signal_add(&output->damage->events.frame, &output->damage_frame); - output->damage_frame.notify = damage_handle_frame; - wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); - output->damage_destroy.notify = damage_handle_destroy; - - arrange_layers(output); - arrange_windows(&root_container); transaction_commit_dirty(); } + +void output_add_listeners(struct sway_output *output) { + output->mode.notify = handle_mode; + output->transform.notify = handle_transform; + output->scale.notify = handle_scale; + output->damage_frame.notify = damage_handle_frame; + output->damage_destroy.notify = damage_handle_destroy; +} diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 695213eb5..99b2cf3dc 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -193,10 +193,10 @@ static void render_view_toplevels(struct sway_view *view, .alpha = alpha, }; // Render all toplevels without descending into popups - double ox = - view->swayc->current.view_x - output->wlr_output->lx - view->geometry.x; - double oy = - view->swayc->current.view_y - output->wlr_output->ly - view->geometry.y; + double ox = view->container->current.view_x - + output->wlr_output->lx - view->geometry.x; + double oy = view->container->current.view_y - + output->wlr_output->ly - view->geometry.y; output_surface_for_each_surface(output, view->surface, ox, oy, render_surface_iterator, &data); } @@ -229,17 +229,17 @@ static void render_saved_view(struct sway_view *view, return; } struct wlr_box box = { - .x = view->swayc->current.view_x - output->swayc->current.swayc_x - + .x = view->container->current.view_x - output->wlr_output->lx - view->saved_geometry.x, - .y = view->swayc->current.view_y - output->swayc->current.swayc_y - + .y = view->container->current.view_y - output->wlr_output->ly - view->saved_geometry.y, .width = view->saved_buffer_width, .height = view->saved_buffer_height, }; struct wlr_box output_box = { - .width = output->swayc->current.swayc_width, - .height = output->swayc->current.swayc_height, + .width = output->wlr_output->width, + .height = output->wlr_output->height, }; struct wlr_box intersection; @@ -263,14 +263,14 @@ static void render_saved_view(struct sway_view *view, */ static void render_view(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, struct border_colors *colors) { - struct sway_view *view = con->sway_view; + struct sway_view *view = con->view; if (view->saved_buffer) { - render_saved_view(view, output, damage, view->swayc->alpha); + render_saved_view(view, output, damage, view->container->alpha); } else { - render_view_toplevels(view, output, damage, view->swayc->alpha); + render_view_toplevels(view, output, damage, view->container->alpha); } - if (view->swayc->current.using_csd) { + if (view->container->current.using_csd) { return; } @@ -283,7 +283,7 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, if (state->border_left) { memcpy(&color, colors->child_border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; + box.x = state->con_x; box.y = state->view_y; box.width = state->border_thickness; box.height = state->view_height; @@ -291,9 +291,12 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, render_rect(output->wlr_output, damage, &box, color); } + list_t *siblings = container_get_current_siblings(con); + enum sway_container_layout layout = + container_current_parent_layout(con); + if (state->border_right) { - if (state->parent->current.children->length == 1 - && state->parent->current.layout == L_HORIZ) { + if (siblings->length == 1 && layout == L_HORIZ) { memcpy(&color, colors->indicator, sizeof(float) * 4); } else { memcpy(&color, colors->child_border, sizeof(float) * 4); @@ -308,16 +311,15 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, } if (state->border_bottom) { - if (state->parent->current.children->length == 1 - && con->current.parent->current.layout == L_VERT) { + if (siblings->length == 1 && layout == L_VERT) { memcpy(&color, colors->indicator, sizeof(float) * 4); } else { memcpy(&color, colors->child_border, sizeof(float) * 4); } premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; + box.x = state->con_x; box.y = state->view_y + state->view_height; - box.width = state->swayc_width; + box.width = state->con_width; box.height = state->border_thickness; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); @@ -344,12 +346,12 @@ static void render_titlebar(struct sway_output *output, float color[4]; struct sway_container_state *state = &con->current; float output_scale = output->wlr_output->scale; - enum sway_container_layout layout = state->parent->current.layout; - list_t *children = state->parent->current.children; + enum sway_container_layout layout = container_current_parent_layout(con); + list_t *children = container_get_current_siblings(con); bool is_last_child = children->length == 0 || children->items[children->length - 1] == con; - double output_x = output->swayc->current.swayc_x; - double output_y = output->swayc->current.swayc_y; + double output_x = output->wlr_output->lx; + double output_y = output->wlr_output->ly; // Single pixel bar above title memcpy(&color, colors->border, sizeof(float) * 4); @@ -366,7 +368,7 @@ static void render_titlebar(struct sway_output *output, bool connects_sides = false; if (layout == L_HORIZ || layout == L_VERT || (layout == L_STACKED && is_last_child)) { - if (con->type == C_VIEW) { + if (con->view) { left_offset = state->border_left * state->border_thickness; right_offset = state->border_right * state->border_thickness; connects_sides = true; @@ -542,14 +544,22 @@ static void render_top_border(struct sway_output *output, // Child border - top edge memcpy(&color, colors->child_border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; - box.y = state->swayc_y; - box.width = state->swayc_width; + box.x = state->con_x; + box.y = state->con_y; + box.width = state->con_width; box.height = state->border_thickness; scale_box(&box, output_scale); render_rect(output->wlr_output, output_damage, &box, color); } +struct parent_data { + enum sway_container_layout layout; + struct wlr_box box; + list_t *children; + bool focused; + struct sway_container *active_child; +}; + static void render_container(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, bool parent_focused); @@ -559,14 +569,13 @@ static void render_container(struct sway_output *output, * Wrap child views in borders and leave child containers borderless because * they'll apply their own borders to their children. */ -static void render_container_simple(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; +static void render_containers_linear(struct sway_output *output, + pixman_region32_t *damage, struct parent_data *parent) { + for (int i = 0; i < parent->children->length; ++i) { + struct sway_container *child = parent->children->items[i]; - if (child->type == C_VIEW) { - struct sway_view *view = child->sway_view; + if (child->view) { + struct sway_view *view = child->view; struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; @@ -576,11 +585,11 @@ static void render_container_simple(struct sway_output *output, colors = &config->border_colors.urgent; title_texture = child->title_urgent; marks_texture = view->marks_urgent; - } else if (state->focused || parent_focused) { + } else if (state->focused || parent->focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view->marks_focused; - } else if (con->current.focused_inactive_child == child) { + } else if (child == parent->active_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view->marks_focused_inactive; @@ -590,10 +599,10 @@ static void render_container_simple(struct sway_output *output, marks_texture = view->marks_unfocused; } - if (!view->swayc->current.using_csd) { + if (!view->container->current.using_csd) { if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, state->swayc_x, - state->swayc_y, state->swayc_width, colors, + render_titlebar(output, damage, child, state->con_x, + state->con_y, state->con_width, colors, title_texture, marks_texture); } else { render_top_border(output, damage, child, colors); @@ -602,7 +611,7 @@ static void render_container_simple(struct sway_output *output, render_view(output, damage, child, colors); } else { render_container(output, damage, child, - parent_focused || child->current.focused); + parent->focused || child->current.focused); } } } @@ -610,22 +619,19 @@ static void render_container_simple(struct sway_output *output, /** * Render a container's children using the L_TABBED layout. */ -static void render_container_tabbed(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - if (!con->current.children->length) { +static void render_containers_tabbed(struct sway_output *output, + pixman_region32_t *damage, struct parent_data *parent) { + if (!parent->children->length) { return; } - struct sway_container_state *pstate = &con->current; - struct sway_container *current = pstate->focused_inactive_child; + struct sway_container *current = parent->active_child; struct border_colors *current_colors = &config->border_colors.unfocused; - - int tab_width = (pstate->swayc_width) / pstate->children->length; + int tab_width = parent->box.width / parent->children->length; // Render tabs - for (int i = 0; i < pstate->children->length; ++i) { - struct sway_container *child = pstate->children->items[i]; - struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + for (int i = 0; i < parent->children->length; ++i) { + struct sway_container *child = parent->children->items[i]; + struct sway_view *view = child->view; struct sway_container_state *cstate = &child->current; struct border_colors *colors; struct wlr_texture *title_texture; @@ -637,11 +643,11 @@ static void render_container_tabbed(struct sway_output *output, colors = &config->border_colors.urgent; title_texture = child->title_urgent; marks_texture = view ? view->marks_urgent : NULL; - } else if (cstate->focused || parent_focused) { + } else if (cstate->focused || parent->focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; - } else if (child == pstate->focused_inactive_child) { + } else if (child == parent->active_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view ? view->marks_focused_inactive : NULL; @@ -651,14 +657,14 @@ static void render_container_tabbed(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int x = cstate->swayc_x + tab_width * i; + int x = cstate->con_x + tab_width * i; // Make last tab use the remaining width of the parent - if (i == pstate->children->length - 1) { - tab_width = pstate->swayc_width - tab_width * i; + if (i == parent->children->length - 1) { + tab_width = parent->box.width - tab_width * i; } - render_titlebar(output, damage, child, x, pstate->swayc_y, tab_width, + render_titlebar(output, damage, child, x, parent->box.y, tab_width, colors, title_texture, marks_texture); if (child == current) { @@ -667,33 +673,30 @@ static void render_container_tabbed(struct sway_output *output, } // Render surface and left/right/bottom borders - if (current->type == C_VIEW) { + if (current->view) { render_view(output, damage, current, current_colors); } else { render_container(output, damage, current, - parent_focused || current->current.focused); + parent->focused || current->current.focused); } } /** * Render a container's children using the L_STACKED layout. */ -static void render_container_stacked(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - if (!con->current.children->length) { +static void render_containers_stacked(struct sway_output *output, + pixman_region32_t *damage, struct parent_data *parent) { + if (!parent->children->length) { return; } - struct sway_container_state *pstate = &con->current; - struct sway_container *current = pstate->focused_inactive_child; + struct sway_container *current = parent->active_child; struct border_colors *current_colors = &config->border_colors.unfocused; - size_t titlebar_height = container_titlebar_height(); // Render titles - for (int i = 0; i < pstate->children->length; ++i) { - struct sway_container *child = pstate->children->items[i]; - struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + for (int i = 0; i < parent->children->length; ++i) { + struct sway_container *child = parent->children->items[i]; + struct sway_view *view = child->view; struct sway_container_state *cstate = &child->current; struct border_colors *colors; struct wlr_texture *title_texture; @@ -705,11 +708,11 @@ static void render_container_stacked(struct sway_output *output, colors = &config->border_colors.urgent; title_texture = child->title_urgent; marks_texture = view ? view->marks_urgent : NULL; - } else if (cstate->focused || parent_focused) { + } else if (cstate->focused || parent->focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; - } else if (child == pstate->focused_inactive_child) { + } else if (child == parent->active_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view ? view->marks_focused_inactive : NULL; @@ -719,9 +722,9 @@ static void render_container_stacked(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int y = pstate->swayc_y + titlebar_height * i; - render_titlebar(output, damage, child, pstate->swayc_x, y, - pstate->swayc_width, colors, title_texture, marks_texture); + int y = parent->box.y + titlebar_height * i; + render_titlebar(output, damage, child, parent->box.x, y, + parent->box.width, colors, title_texture, marks_texture); if (child == current) { current_colors = colors; @@ -729,36 +732,69 @@ static void render_container_stacked(struct sway_output *output, } // Render surface and left/right/bottom borders - if (current->type == C_VIEW) { + if (current->view) { render_view(output, damage, current, current_colors); } else { render_container(output, damage, current, - parent_focused || current->current.focused); + parent->focused || current->current.focused); + } +} + +static void render_containers(struct sway_output *output, + pixman_region32_t *damage, struct parent_data *parent) { + switch (parent->layout) { + case L_NONE: + case L_HORIZ: + case L_VERT: + render_containers_linear(output, damage, parent); + break; + case L_STACKED: + render_containers_stacked(output, damage, parent); + break; + case L_TABBED: + render_containers_tabbed(output, damage, parent); + break; } } static void render_container(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - switch (con->current.layout) { - case L_NONE: - case L_HORIZ: - case L_VERT: - render_container_simple(output, damage, con, parent_focused); - break; - case L_STACKED: - render_container_stacked(output, damage, con, parent_focused); - break; - case L_TABBED: - render_container_tabbed(output, damage, con, parent_focused); - break; - } + pixman_region32_t *damage, struct sway_container *con, bool focused) { + struct parent_data data = { + .layout = con->current.layout, + .box = { + .x = con->current.con_x, + .y = con->current.con_y, + .width = con->current.con_width, + .height = con->current.con_height, + }, + .children = con->current.children, + .focused = focused, + .active_child = con->current.focused_inactive_child, + }; + render_containers(output, damage, &data); +} + +static void render_workspace(struct sway_output *output, + pixman_region32_t *damage, struct sway_workspace *ws, bool focused) { + struct parent_data data = { + .layout = ws->current.layout, + .box = { + .x = ws->current.x, + .y = ws->current.y, + .width = ws->current.width, + .height = ws->current.height, + }, + .children = ws->current.tiling, + .focused = focused, + .active_child = ws->current.focused_inactive_child, + }; + render_containers(output, damage, &data); } static void render_floating_container(struct sway_output *soutput, pixman_region32_t *damage, struct sway_container *con) { - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; + if (con->view) { + struct sway_view *view = con->view; struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; @@ -777,10 +813,10 @@ static void render_floating_container(struct sway_output *soutput, marks_texture = view->marks_unfocused; } - if (!view->swayc->current.using_csd) { + if (!view->container->current.using_csd) { if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, con->current.swayc_x, - con->current.swayc_y, con->current.swayc_width, colors, + render_titlebar(soutput, damage, con, con->current.con_x, + con->current.con_y, con->current.con_width, colors, title_texture, marks_texture); } else if (con->current.border != B_NONE) { render_top_border(soutput, damage, con, colors); @@ -794,17 +830,15 @@ static void render_floating_container(struct sway_output *soutput, static void render_floating(struct sway_output *soutput, pixman_region32_t *damage) { - for (int i = 0; i < root_container.current.children->length; ++i) { - struct sway_container *output = - root_container.current.children->items[i]; - for (int j = 0; j < output->current.children->length; ++j) { - struct sway_container *ws = output->current.children->items[j]; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + for (int j = 0; j < output->current.workspaces->length; ++j) { + struct sway_workspace *ws = output->current.workspaces->items[j]; if (!workspace_is_visible(ws)) { continue; } - list_t *floating = ws->current.ws_floating; - for (int k = 0; k < floating->length; ++k) { - struct sway_container *floater = floating->items[k]; + for (int k = 0; k < ws->current.floating->length; ++k) { + struct sway_container *floater = ws->current.floating->items[k]; render_floating_container(soutput, damage, floater); } } @@ -837,8 +871,8 @@ void output_render(struct sway_output *output, struct timespec *when, pixman_region32_union_rect(damage, damage, 0, 0, width, height); } - struct sway_container *workspace = output_get_active_workspace(output); - struct sway_container *fullscreen_con = workspace->current.ws_fullscreen; + struct sway_workspace *workspace = output_get_active_workspace(output); + struct sway_container *fullscreen_con = workspace->current.fullscreen; if (output_has_opaque_overlay_layer_surface(output)) { goto render_overlay; @@ -855,12 +889,11 @@ void output_render(struct sway_output *output, struct timespec *when, } // TODO: handle views smaller than the output - if (fullscreen_con->type == C_VIEW) { - if (fullscreen_con->sway_view->saved_buffer) { - render_saved_view(fullscreen_con->sway_view, - output, damage, 1.0f); + if (fullscreen_con->view) { + if (fullscreen_con->view->saved_buffer) { + render_saved_view(fullscreen_con->view, output, damage, 1.0f); } else { - render_view_toplevels(fullscreen_con->sway_view, + render_view_toplevels(fullscreen_con->view, output, damage, 1.0f); } } else { @@ -868,8 +901,7 @@ void output_render(struct sway_output *output, struct timespec *when, fullscreen_con->current.focused); } #ifdef HAVE_XWAYLAND - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); + render_unmanaged(output, damage, &root->xwayland_unmanaged); #endif } else { float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; @@ -886,31 +918,30 @@ void output_render(struct sway_output *output, struct timespec *when, render_layer(output, damage, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - render_container(output, damage, workspace, workspace->current.focused); + render_workspace(output, damage, workspace, workspace->current.focused); render_floating(output, damage); #ifdef HAVE_XWAYLAND - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); + render_unmanaged(output, damage, &root->xwayland_unmanaged); #endif render_layer(output, damage, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); } struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - if (focus && focus->type == C_VIEW) { - render_view_popups(focus->sway_view, output, damage, focus->alpha); + struct sway_container *focus = seat_get_focused_container(seat); + if (focus && focus->view) { + render_view_popups(focus->view, output, damage, focus->alpha); } render_overlay: render_layer(output, damage, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_drag_icons(output, damage, &root_container.sway_root->drag_icons); + render_drag_icons(output, damage, &root->drag_icons); renderer_end: if (debug.render_tree) { wlr_renderer_scissor(renderer, NULL); - wlr_render_texture(renderer, root_container.sway_root->debug_tree, + wlr_render_texture(renderer, root->debug_tree, wlr_output->transform_matrix, 0, 40, 1); } if (debug.damage == DAMAGE_HIGHLIGHT) { diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 145c5f92f..b4eec933f 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -12,6 +12,7 @@ #include "sway/desktop/transaction.h" #include "sway/output.h" #include "sway/tree/container.h" +#include "sway/tree/node.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "list.h" @@ -27,8 +28,12 @@ struct sway_transaction { struct sway_transaction_instruction { struct sway_transaction *transaction; - struct sway_container *container; - struct sway_container_state state; + struct sway_node *node; + union { + struct sway_output_state *output_state; + struct sway_workspace_state *workspace_state; + struct sway_container_state *container_state; + }; uint32_t serial; }; @@ -47,26 +52,24 @@ static void transaction_destroy(struct sway_transaction *transaction) { for (int i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; - struct sway_container *con = instruction->container; - con->ntxnrefs--; - if (con->instruction == instruction) { - con->instruction = NULL; + struct sway_node *node = instruction->node; + node->ntxnrefs--; + if (node->instruction == instruction) { + node->instruction = NULL; } - if (con->destroying && con->ntxnrefs == 0) { - switch (con->type) { - case C_ROOT: + if (node->destroying && node->ntxnrefs == 0) { + switch (node->type) { + case N_ROOT: + sway_assert(false, "Never reached"); break; - case C_OUTPUT: - output_destroy(con); + case N_OUTPUT: + output_destroy(node->sway_output); break; - case C_WORKSPACE: - workspace_destroy(con); + case N_WORKSPACE: + workspace_destroy(node->sway_workspace); break; - case C_CONTAINER: - case C_VIEW: - container_destroy(con); - break; - case C_TYPES: + case N_CONTAINER: + container_destroy(node->sway_container); break; } } @@ -80,22 +83,79 @@ static void transaction_destroy(struct sway_transaction *transaction) { free(transaction); } -static void copy_pending_state(struct sway_container *container, - struct sway_container_state *state) { - state->layout = container->layout; - state->swayc_x = container->x; - state->swayc_y = container->y; - state->swayc_width = container->width; - state->swayc_height = container->height; - state->is_fullscreen = container->is_fullscreen; - state->has_gaps = container->has_gaps; - state->current_gaps = container->current_gaps; - state->gaps_inner = container->gaps_inner; - state->gaps_outer = container->gaps_outer; - state->parent = container->parent; +static void copy_output_state(struct sway_output *output, + struct sway_transaction_instruction *instruction) { + struct sway_output_state *state = + calloc(1, sizeof(struct sway_output_state)); + if (!state) { + wlr_log(WLR_ERROR, "Could not allocate output state"); + return; + } + instruction->output_state = state; - if (container->type == C_VIEW) { - struct sway_view *view = container->sway_view; + state->workspaces = create_list(); + list_cat(state->workspaces, output->workspaces); + + state->active_workspace = output_get_active_workspace(output); +} + +static void copy_workspace_state(struct sway_workspace *ws, + struct sway_transaction_instruction *instruction) { + struct sway_workspace_state *state = + calloc(1, sizeof(struct sway_workspace_state)); + if (!state) { + wlr_log(WLR_ERROR, "Could not allocate workspace state"); + return; + } + instruction->workspace_state = state; + + state->fullscreen = ws->fullscreen; + state->x = ws->x; + state->y = ws->y; + state->width = ws->width; + state->height = ws->height; + state->layout = ws->layout; + + state->output = ws->output; + state->floating = create_list(); + state->tiling = create_list(); + list_cat(state->floating, ws->floating); + list_cat(state->tiling, ws->tiling); + + struct sway_seat *seat = input_manager_current_seat(input_manager); + state->focused = seat_get_focus(seat) == &ws->node; + + // Set focused_inactive_child to the direct tiling child + struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws); + if (focus) { + while (focus->parent) { + focus = focus->parent; + } + } + state->focused_inactive_child = focus; +} + +static void copy_container_state(struct sway_container *container, + struct sway_transaction_instruction *instruction) { + struct sway_container_state *state = + calloc(1, sizeof(struct sway_container_state)); + if (!state) { + wlr_log(WLR_ERROR, "Could not allocate container state"); + return; + } + instruction->container_state = state; + + state->layout = container->layout; + state->con_x = container->x; + state->con_y = container->y; + state->con_width = container->width; + state->con_height = container->height; + state->is_fullscreen = container->is_fullscreen; + state->parent = container->parent; + state->workspace = container->workspace; + + if (container->view) { + struct sway_view *view = container->view; state->view_x = view->x; state->view_y = view->y; state->view_width = view->width; @@ -107,50 +167,111 @@ static void copy_pending_state(struct sway_container *container, state->border_right = view->border_right; state->border_bottom = view->border_bottom; state->using_csd = view->using_csd; - } else if (container->type == C_WORKSPACE) { - state->ws_fullscreen = container->sway_workspace->fullscreen; - state->ws_floating = create_list(); - state->children = create_list(); - list_cat(state->ws_floating, container->sway_workspace->floating); - list_cat(state->children, container->children); } else { state->children = create_list(); list_cat(state->children, container->children); } struct sway_seat *seat = input_manager_current_seat(input_manager); - state->focused = seat_get_focus(seat) == container; + state->focused = seat_get_focus(seat) == &container->node; - if (container->type == C_WORKSPACE) { - // Set focused_inactive_child to the direct tiling child - struct sway_container *focus = - seat_get_focus_inactive_tiling(seat, container); - if (focus && focus->type > C_WORKSPACE) { - while (focus->parent->type != C_WORKSPACE) { - focus = focus->parent; - } - } - state->focused_inactive_child = focus; - } else if (container->type != C_VIEW) { - state->focused_inactive_child = - seat_get_active_child(seat, container); + if (!container->view) { + struct sway_node *focus = seat_get_active_child(seat, &container->node); + state->focused_inactive_child = focus ? focus->sway_container : NULL; } } -static void transaction_add_container(struct sway_transaction *transaction, - struct sway_container *container) { +static void transaction_add_node(struct sway_transaction *transaction, + struct sway_node *node) { struct sway_transaction_instruction *instruction = calloc(1, sizeof(struct sway_transaction_instruction)); if (!sway_assert(instruction, "Unable to allocate instruction")) { return; } instruction->transaction = transaction; - instruction->container = container; + instruction->node = node; - copy_pending_state(container, &instruction->state); + switch (node->type) { + case N_ROOT: + break; + case N_OUTPUT: + copy_output_state(node->sway_output, instruction); + break; + case N_WORKSPACE: + copy_workspace_state(node->sway_workspace, instruction); + break; + case N_CONTAINER: + copy_container_state(node->sway_container, instruction); + break; + } list_add(transaction->instructions, instruction); - container->ntxnrefs++; + node->ntxnrefs++; +} + +static void apply_output_state(struct sway_output *output, + struct sway_output_state *state) { + output_damage_whole(output); + list_free(output->current.workspaces); + memcpy(&output->current, state, sizeof(struct sway_output_state)); + output_damage_whole(output); +} + +static void apply_workspace_state(struct sway_workspace *ws, + struct sway_workspace_state *state) { + output_damage_whole(ws->current.output); + list_free(ws->current.floating); + list_free(ws->current.tiling); + memcpy(&ws->current, state, sizeof(struct sway_workspace_state)); + output_damage_whole(ws->current.output); +} + +static void apply_container_state(struct sway_container *container, + struct sway_container_state *state) { + struct sway_view *view = container->view; + // Damage the old location + desktop_damage_whole_container(container); + if (view && view->saved_buffer) { + struct wlr_box box = { + .x = container->current.view_x - view->saved_geometry.x, + .y = container->current.view_y - view->saved_geometry.y, + .width = view->saved_buffer_width, + .height = view->saved_buffer_height, + }; + desktop_damage_box(&box); + } + + // There are separate children lists for each instruction state, the + // container's current state and the container's pending state + // (ie. con->children). The list itself needs to be freed here. + // Any child containers which are being deleted will be cleaned up in + // transaction_destroy(). + list_free(container->current.children); + + memcpy(&container->current, state, sizeof(struct sway_container_state)); + + if (view && view->saved_buffer) { + if (!container->node.destroying || container->node.ntxnrefs == 1) { + view_remove_saved_buffer(view); + } + } + + // Damage the new location + desktop_damage_whole_container(container); + if (view && view->surface) { + struct wlr_surface *surface = view->surface; + struct wlr_box box = { + .x = container->current.view_x - view->geometry.x, + .y = container->current.view_y - view->geometry.y, + .width = surface->current.width, + .height = surface->current.height, + }; + desktop_damage_box(&box); + } + + if (!container->node.destroying) { + container_discover_outputs(container); + } } /** @@ -168,67 +289,36 @@ static void transaction_apply(struct sway_transaction *transaction) { "(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60)); } - // Apply the instruction state to the container's current state + // Apply the instruction state to the node's current state for (int i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; - struct sway_container *container = instruction->container; + struct sway_node *node = instruction->node; - // Damage the old location - desktop_damage_whole_container(container); - if (container->type == C_VIEW && container->sway_view->saved_buffer) { - struct sway_view *view = container->sway_view; - struct wlr_box box = { - .x = container->current.view_x - view->saved_geometry.x, - .y = container->current.view_y - view->saved_geometry.y, - .width = view->saved_buffer_width, - .height = view->saved_buffer_height, - }; - desktop_damage_box(&box); + switch (node->type) { + case N_ROOT: + break; + case N_OUTPUT: + apply_output_state(node->sway_output, instruction->output_state); + break; + case N_WORKSPACE: + apply_workspace_state(node->sway_workspace, + instruction->workspace_state); + break; + case N_CONTAINER: + apply_container_state(node->sway_container, + instruction->container_state); + break; } - // There are separate children lists for each instruction state, the - // container's current state and the container's pending state - // (ie. con->children). The list itself needs to be freed here. - // Any child containers which are being deleted will be cleaned up in - // transaction_destroy(). - list_free(container->current.children); - list_free(container->current.ws_floating); - - memcpy(&container->current, &instruction->state, - sizeof(struct sway_container_state)); - - if (container->type == C_VIEW && container->sway_view->saved_buffer) { - if (!container->destroying || container->ntxnrefs == 1) { - view_remove_saved_buffer(container->sway_view); - } - } - - // Damage the new location - desktop_damage_whole_container(container); - if (container->type == C_VIEW && container->sway_view->surface) { - struct sway_view *view = container->sway_view; - struct wlr_surface *surface = view->surface; - struct wlr_box box = { - .x = container->current.view_x - view->geometry.x, - .y = container->current.view_y - view->geometry.y, - .width = surface->current.width, - .height = surface->current.height, - }; - desktop_damage_box(&box); - } - - container->instruction = NULL; - if (container->type == C_CONTAINER || container->type == C_VIEW) { - container_discover_outputs(container); - } + node->instruction = NULL; } } static void transaction_commit(struct sway_transaction *transaction); -// Return true if both transactions operate on the same containers -static bool transaction_same_containers(struct sway_transaction *a, +// Return true if both transactions operate on the same nodes +static bool transaction_same_nodes(struct sway_transaction *a, struct sway_transaction *b) { if (a->instructions->length != b->instructions->length) { return false; @@ -236,7 +326,7 @@ static bool transaction_same_containers(struct sway_transaction *a, for (int i = 0; i < a->instructions->length; ++i) { struct sway_transaction_instruction *a_inst = a->instructions->items[i]; struct sway_transaction_instruction *b_inst = b->instructions->items[i]; - if (a_inst->container != b_inst->container) { + if (a_inst->node != b_inst->node) { return false; } } @@ -267,7 +357,7 @@ static void transaction_progress_queue() { while (server.transactions->length >= 2) { struct sway_transaction *a = server.transactions->items[0]; struct sway_transaction *b = server.transactions->items[1]; - if (transaction_same_containers(a, b)) { + if (transaction_same_nodes(a, b)) { list_del(server.transactions, 0); transaction_destroy(a); } else { @@ -289,16 +379,18 @@ static int handle_timeout(void *data) { return 0; } -static bool should_configure(struct sway_container *con, +static bool should_configure(struct sway_node *node, struct sway_transaction_instruction *instruction) { - if (con->type != C_VIEW) { + if (!node_is_view(node)) { return false; } - if (con->destroying) { + if (node->destroying) { return false; } - if (con->current.view_width == instruction->state.view_width && - con->current.view_height == instruction->state.view_height) { + struct sway_container_state *cstate = &node->sway_container->current; + struct sway_container_state *istate = instruction->container_state; + if (cstate->view_width == istate->view_width && + cstate->view_height == istate->view_height) { return false; } return true; @@ -311,13 +403,13 @@ static void transaction_commit(struct sway_transaction *transaction) { for (int i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; - struct sway_container *con = instruction->container; - if (should_configure(con, instruction)) { - instruction->serial = view_configure(con->sway_view, - instruction->state.view_x, - instruction->state.view_y, - instruction->state.view_width, - instruction->state.view_height); + struct sway_node *node = instruction->node; + if (should_configure(node, instruction)) { + instruction->serial = view_configure(node->sway_container->view, + instruction->container_state->view_x, + instruction->container_state->view_y, + instruction->container_state->view_width, + instruction->container_state->view_height); ++transaction->num_waiting; // From here on we are rendering a saved buffer of the view, which @@ -325,14 +417,16 @@ static void transaction_commit(struct sway_transaction *transaction) { // as soon as possible. Additionally, this is required if a view is // mapping and its default geometry doesn't intersect an output. struct timespec when; - wlr_surface_send_frame_done(con->sway_view->surface, &when); + wlr_surface_send_frame_done( + node->sway_container->view->surface, &when); } - if (con->type == C_VIEW && !con->sway_view->saved_buffer) { - view_save_buffer(con->sway_view); - memcpy(&con->sway_view->saved_geometry, &con->sway_view->geometry, + if (node_is_view(node) && !node->sway_container->view->saved_buffer) { + view_save_buffer(node->sway_container->view); + memcpy(&node->sway_container->view->saved_geometry, + &node->sway_container->view->geometry, sizeof(struct wlr_box)); } - con->instruction = instruction; + node->instruction = instruction; } transaction->num_configures = transaction->num_waiting; if (debug.txn_timings) { @@ -381,7 +475,7 @@ static void set_instruction_ready( transaction, transaction->num_configures - transaction->num_waiting + 1, transaction->num_configures, ms, - instruction->container->name); + instruction->node->sway_container->title); } // If the transaction has timed out then its num_waiting will be 0 already. @@ -390,41 +484,43 @@ static void set_instruction_ready( wl_event_source_timer_update(transaction->timer, 0); } - instruction->container->instruction = NULL; + instruction->node->instruction = NULL; transaction_progress_queue(); } void transaction_notify_view_ready_by_serial(struct sway_view *view, uint32_t serial) { - struct sway_transaction_instruction *instruction = view->swayc->instruction; - if (view->swayc->instruction->serial == serial) { + struct sway_transaction_instruction *instruction = + view->container->node.instruction; + if (instruction->serial == serial) { set_instruction_ready(instruction); } } void transaction_notify_view_ready_by_size(struct sway_view *view, int width, int height) { - struct sway_transaction_instruction *instruction = view->swayc->instruction; - if (instruction->state.view_width == width && - instruction->state.view_height == height) { + struct sway_transaction_instruction *instruction = + view->container->node.instruction; + if (instruction->container_state->view_width == width && + instruction->container_state->view_height == height) { set_instruction_ready(instruction); } } void transaction_commit_dirty(void) { - if (!server.dirty_containers->length) { + if (!server.dirty_nodes->length) { return; } struct sway_transaction *transaction = transaction_create(); if (!transaction) { return; } - for (int i = 0; i < server.dirty_containers->length; ++i) { - struct sway_container *container = server.dirty_containers->items[i]; - transaction_add_container(transaction, container); - container->dirty = false; + for (int i = 0; i < server.dirty_nodes->length; ++i) { + struct sway_node *node = server.dirty_nodes->items[i]; + transaction_add_node(transaction, node); + node->dirty = false; } - server.dirty_containers->length = 0; + server.dirty_nodes->length = 0; list_add(server.transactions, transaction); diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 587deb0fb..e19d8e185 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -11,10 +11,12 @@ #include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" +#include "sway/output.h" #include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" static const struct sway_view_child_impl popup_impl; @@ -52,15 +54,15 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) { struct sway_view *view = popup->child.view; struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; - struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + struct sway_output *output = view->container->workspace->output; // the output box expressed in the coordinate system of the toplevel parent // of the popup struct wlr_box output_toplevel_sx_box = { - .x = output->x - view->x, - .y = output->y - view->y, - .width = output->width, - .height = output->height, + .x = output->wlr_output->lx - view->x, + .y = output->wlr_output->ly - view->y, + .width = output->wlr_output->width, + .height = output->wlr_output->height, }; wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); @@ -252,11 +254,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_view->view; struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; - if (!view->swayc) { - return; - } - - if (view->swayc->instruction) { + if (view->container->node.instruction) { wlr_xdg_surface_get_geometry(xdg_surface, &view->geometry); transaction_notify_view_ready_by_serial(view, xdg_surface->configure_serial); @@ -265,7 +263,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); if ((new_geo.width != view->width || new_geo.height != view->height) && - container_is_floating(view->swayc)) { + container_is_floating(view->container)) { // A floating view has unexpectedly sent a new size desktop_damage_view(view); view_update_size(view, new_geo.width, new_geo.height); @@ -319,10 +317,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) return; } - container_set_fullscreen(view->swayc, e->fullscreen); + container_set_fullscreen(view->container, e->fullscreen); - struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_windows(output); + arrange_workspace(view->container->workspace); transaction_commit_dirty(); } @@ -330,13 +327,13 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_move); struct sway_view *view = &xdg_shell_view->view; - if (!container_is_floating(view->swayc)) { + if (!container_is_floating(view->container)) { return; } struct wlr_xdg_toplevel_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seat_begin_move(seat, view->swayc, seat->last_button); + seat_begin_move(seat, view->container, seat->last_button); } } @@ -344,13 +341,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_resize); struct sway_view *view = &xdg_shell_view->view; - if (!container_is_floating(view->swayc)) { + if (!container_is_floating(view->container)) { return; } struct wlr_xdg_toplevel_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seat_begin_resize_floating(seat, view->swayc, + seat_begin_resize_floating(seat, view->container, seat->last_button, e->edges); } } @@ -399,11 +396,14 @@ static void handle_map(struct wl_listener *listener, void *data) { view_map(view, view->wlr_xdg_surface->surface); if (xdg_surface->toplevel->client_pending.fullscreen) { - container_set_fullscreen(view->swayc, true); - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_windows(ws); + container_set_fullscreen(view->container, true); + arrange_workspace(view->container->workspace); } else { - arrange_windows(view->swayc->parent); + if (view->container->parent) { + arrange_container(view->container->parent); + } else { + arrange_workspace(view->container->workspace); + } } transaction_commit_dirty(); @@ -440,8 +440,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, destroy); struct sway_view *view = &xdg_shell_view->view; - if (!sway_assert(view->swayc == NULL || view->swayc->destroying, - "Tried to destroy a mapped view")) { + if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { return; } wl_list_remove(&xdg_shell_view->destroy.link); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 175416f3c..b23d45777 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -10,10 +10,12 @@ #include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" +#include "sway/output.h" #include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" static const struct sway_view_child_impl popup_impl; @@ -51,15 +53,15 @@ static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { struct sway_view *view = popup->child.view; struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; - struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + struct sway_output *output = view->container->workspace->output; // the output box expressed in the coordinate system of the toplevel parent // of the popup struct wlr_box output_toplevel_sx_box = { - .x = output->x - view->x, - .y = output->y - view->y, - .width = output->width, - .height = output->height, + .x = output->wlr_output->lx - view->x, + .y = output->wlr_output->ly - view->y, + .width = output->wlr_output->width, + .height = output->wlr_output->height, }; wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); @@ -249,11 +251,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_v6_view->view; struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6; - if (!view->swayc) { - return; - } - - if (view->swayc->instruction) { + if (view->container->node.instruction) { wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &view->geometry); transaction_notify_view_ready_by_serial(view, xdg_surface_v6->configure_serial); @@ -262,7 +260,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &new_geo); if ((new_geo.width != view->width || new_geo.height != view->height) && - container_is_floating(view->swayc)) { + container_is_floating(view->container)) { // A floating view has unexpectedly sent a new size desktop_damage_view(view); view_update_size(view, new_geo.width, new_geo.height); @@ -316,10 +314,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) return; } - container_set_fullscreen(view->swayc, e->fullscreen); + container_set_fullscreen(view->container, e->fullscreen); - struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_windows(output); + arrange_workspace(view->container->workspace); transaction_commit_dirty(); } @@ -327,13 +324,13 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, request_move); struct sway_view *view = &xdg_shell_v6_view->view; - if (!container_is_floating(view->swayc)) { + if (!container_is_floating(view->container)) { return; } struct wlr_xdg_toplevel_v6_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seat_begin_move(seat, view->swayc, seat->last_button); + seat_begin_move(seat, view->container, seat->last_button); } } @@ -341,13 +338,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, request_resize); struct sway_view *view = &xdg_shell_v6_view->view; - if (!container_is_floating(view->swayc)) { + if (!container_is_floating(view->container)) { return; } struct wlr_xdg_toplevel_v6_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seat_begin_resize_floating(seat, view->swayc, + seat_begin_resize_floating(seat, view->container, seat->last_button, e->edges); } } @@ -396,11 +393,14 @@ static void handle_map(struct wl_listener *listener, void *data) { view_map(view, view->wlr_xdg_surface_v6->surface); if (xdg_surface->toplevel->client_pending.fullscreen) { - container_set_fullscreen(view->swayc, true); - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_windows(ws); + container_set_fullscreen(view->container, true); + arrange_workspace(view->container->workspace); } else { - arrange_windows(view->swayc->parent); + if (view->container->parent) { + arrange_container(view->container->parent); + } else { + arrange_workspace(view->container->workspace); + } } transaction_commit_dirty(); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 94a30239d..0d192b76e 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -59,8 +59,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { wl_container_of(listener, surface, map); struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - wl_list_insert(root_container.sway_root->xwayland_unmanaged.prev, - &surface->link); + wl_list_insert(root->xwayland_unmanaged.prev, &surface->link); wl_signal_add(&xsurface->surface->events.commit, &surface->commit); surface->commit.notify = unmanaged_handle_commit; @@ -90,11 +89,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { // Restore focus - struct sway_container *previous = - seat_get_focus_inactive(seat, &root_container); + struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); if (previous) { // Hack to get seat to re-focus the return value of get_focus - seat_set_focus(seat, previous->parent); + seat_set_focus(seat, NULL); seat_set_focus(seat, previous); } } @@ -299,7 +297,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; struct wlr_surface_state *state = &xsurface->surface->current; - if (view->swayc->instruction) { + if (view->container->node.instruction) { get_geometry(view, &view->geometry); transaction_notify_view_ready_by_size(view, state->width, state->height); @@ -308,7 +306,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { get_geometry(view, &new_geo); if ((new_geo.width != view->width || new_geo.height != view->height) && - container_is_floating(view->swayc)) { + container_is_floating(view->container)) { // A floating view has unexpectedly sent a new size // eg. The Firefox "Save As" dialog when downloading a file desktop_damage_view(view); @@ -391,11 +389,14 @@ static void handle_map(struct wl_listener *listener, void *data) { view_map(view, xsurface->surface); if (xsurface->fullscreen) { - container_set_fullscreen(view->swayc, true); - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_windows(ws); + container_set_fullscreen(view->container, true); + arrange_workspace(view->container->workspace); } else { - arrange_windows(view->swayc->parent); + if (view->container->parent) { + arrange_container(view->container->parent); + } else { + arrange_workspace(view->container->workspace); + } } transaction_commit_dirty(); } @@ -411,13 +412,14 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { ev->width, ev->height); return; } - if (container_is_floating(view->swayc)) { - configure(view, view->swayc->current.view_x, - view->swayc->current.view_y, ev->width, ev->height); + if (container_is_floating(view->container)) { + configure(view, view->container->current.view_x, + view->container->current.view_y, ev->width, ev->height); } else { - configure(view, view->swayc->current.view_x, - view->swayc->current.view_y, view->swayc->current.view_width, - view->swayc->current.view_height); + configure(view, view->container->current.view_x, + view->container->current.view_y, + view->container->current.view_width, + view->container->current.view_height); } } @@ -429,10 +431,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) if (!xsurface->mapped) { return; } - container_set_fullscreen(view->swayc, xsurface->fullscreen); + container_set_fullscreen(view->container, xsurface->fullscreen); - struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_windows(output); + arrange_workspace(view->container->workspace); transaction_commit_dirty(); } @@ -444,11 +445,11 @@ static void handle_request_move(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } - if (!container_is_floating(view->swayc)) { + if (!container_is_floating(view->container)) { return; } struct sway_seat *seat = input_manager_current_seat(input_manager); - seat_begin_move(seat, view->swayc, seat->last_button); + seat_begin_move(seat, view->container, seat->last_button); } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -459,12 +460,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } - if (!container_is_floating(view->swayc)) { + if (!container_is_floating(view->container)) { return; } struct wlr_xwayland_resize_event *e = data; struct sway_seat *seat = input_manager_current_seat(input_manager); - seat_begin_resize_floating(seat, view->swayc, seat->last_button, e->edges); + seat_begin_resize_floating(seat, view->container, + seat->last_button, e->edges); } static void handle_request_activate(struct wl_listener *listener, void *data) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 00240e84a..159932651 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -20,6 +20,7 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/tree/arrange.h" +#include "sway/tree/container.h" #include "sway/tree/root.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -50,15 +51,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output, } /** - * Returns the container at the cursor's position. If there is a surface at that + * Returns the node at the cursor's position. If there is a surface at that * location, it is stored in **surface (it may not be a view). */ -static struct sway_container *container_at_coords( +static struct sway_node *node_at_coords( struct sway_seat *seat, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { // check for unmanaged views first #ifdef HAVE_XWAYLAND - struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; + struct wl_list *unmanaged = &root->xwayland_unmanaged; struct sway_xwayland_unmanaged *unmanaged_surface; wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { struct wlr_xwayland_surface *xsurface = @@ -75,67 +76,64 @@ static struct sway_container *container_at_coords( } #endif // find the output the cursor is on - struct wlr_output_layout *output_layout = - root_container.sway_root->output_layout; struct wlr_output *wlr_output = wlr_output_layout_output_at( - output_layout, lx, ly); + root->output_layout, lx, ly); if (wlr_output == NULL) { return NULL; } struct sway_output *output = wlr_output->data; double ox = lx, oy = ly; - wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); + wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy); // find the focused workspace on the output for this seat - struct sway_container *ws = seat_get_focus_inactive(seat, output->swayc); - if (ws && ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } - if (!ws) { - return output->swayc; - } + struct sway_workspace *ws = output_get_active_workspace(output); if ((*surface = layer_surface_at(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], ox, oy, sx, sy))) { - return ws; + return &ws->node; } - if (ws->sway_workspace->fullscreen) { - return tiling_container_at(ws->sway_workspace->fullscreen, lx, ly, - surface, sx, sy); + if (ws->fullscreen) { + struct sway_container *con = + tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); + if (con) { + return &con->node; + } + return NULL; } if ((*surface = layer_surface_at(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], ox, oy, sx, sy))) { - return ws; + return &ws->node; } struct sway_container *c; if ((c = container_at(ws, lx, ly, surface, sx, sy))) { - return c; + return &c->node; } if ((*surface = layer_surface_at(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], ox, oy, sx, sy))) { - return ws; + return &ws->node; } if ((*surface = layer_surface_at(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], ox, oy, sx, sy))) { - return ws; + return &ws->node; } - c = seat_get_active_child(seat, output->swayc); - if (c) { - return c; - } - if (!c && output->swayc->children->length) { - c = output->swayc->children->items[0]; - return c; - } + return &ws->node; +} - return output->swayc; +static struct sway_container *container_at_coords(struct sway_seat *seat, + double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy) { + struct sway_node *node = node_at_coords(seat, lx, ly, surface, sx, sy); + if (node && node->type == N_CONTAINER) { + return node->sway_container; + } + return NULL; } /** @@ -160,13 +158,14 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { // Iterate the parents until we find one with the layout we want, // then check if the child has siblings between it and the edge. - while (cont->type != C_OUTPUT) { - if (cont->parent->layout == layout) { - int index = list_find(cont->parent->children, cont); + while (cont) { + if (container_parent_layout(cont) == layout) { + list_t *siblings = container_get_siblings(cont); + int index = list_find(siblings, cont); if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { return false; } - if (index < cont->parent->children->length - 1 && + if (index < siblings->length - 1 && (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) { return false; } @@ -178,10 +177,10 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { static enum wlr_edges find_edge(struct sway_container *cont, struct sway_cursor *cursor) { - if (cont->type != C_VIEW) { + if (!cont->view) { return WLR_EDGE_NONE; } - struct sway_view *view = cont->sway_view; + struct sway_view *view = cont->view; if (view->border == B_NONE || !view->border_thickness || view->using_csd) { return WLR_EDGE_NONE; } @@ -219,7 +218,7 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont, static void handle_down_motion(struct sway_seat *seat, struct sway_cursor *cursor, uint32_t time_msec) { struct sway_container *con = seat->op_container; - if (seat_is_input_allowed(seat, con->sway_view->surface)) { + if (seat_is_input_allowed(seat, con->view->surface)) { double moved_x = cursor->cursor->x - seat->op_ref_lx; double moved_y = cursor->cursor->y - seat->op_ref_ly; double sx = seat->op_ref_con_lx + moved_x; @@ -260,8 +259,7 @@ static void calculate_floating_constraints(struct sway_container *con, if (config->floating_maximum_width == -1) { // no maximum *max_width = INT_MAX; } else if (config->floating_maximum_width == 0) { // automatic - struct sway_container *ws = container_parent(con, C_WORKSPACE); - *max_width = ws->width; + *max_width = con->workspace->width; } else { *max_width = config->floating_maximum_width; } @@ -269,8 +267,7 @@ static void calculate_floating_constraints(struct sway_container *con, if (config->floating_maximum_height == -1) { // no maximum *max_height = INT_MAX; } else if (config->floating_maximum_height == 0) { // automatic - struct sway_container *ws = container_parent(con, C_WORKSPACE); - *max_height = ws->height; + *max_height = con->workspace->height; } else { *max_height = config->floating_maximum_height; } @@ -314,9 +311,9 @@ static void handle_resize_floating_motion(struct sway_seat *seat, height = fmax(min_height, fmin(height, max_height)); // Apply the view's min/max size - if (con->type == C_VIEW) { + if (con->view) { double view_min_width, view_max_width, view_min_height, view_max_height; - view_get_constraints(con->sway_view, &view_min_width, &view_max_width, + view_get_constraints(con->view, &view_min_width, &view_max_width, &view_min_height, &view_max_height); width = fmax(view_min_width, fmin(width, view_max_width)); height = fmax(view_min_height, fmin(height, view_max_height)); @@ -357,15 +354,15 @@ static void handle_resize_floating_motion(struct sway_seat *seat, con->width += relative_grow_width; con->height += relative_grow_height; - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; + if (con->view) { + struct sway_view *view = con->view; view->x += relative_grow_x; view->y += relative_grow_y; view->width += relative_grow_width; view->height += relative_grow_height; } - arrange_windows(con); + arrange_container(con); } static void handle_resize_tiling_motion(struct sway_seat *seat, @@ -435,44 +432,40 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, struct wlr_surface *surface = NULL; double sx, sy; - // Find the container beneath the pointer's previous position - struct sway_container *prev_c = container_at_coords(seat, + // Find the node beneath the pointer's previous position + struct sway_node *prev_node = node_at_coords(seat, cursor->previous.x, cursor->previous.y, &surface, &sx, &sy); // Update the stored previous position cursor->previous.x = cursor->cursor->x; cursor->previous.y = cursor->cursor->y; - struct sway_container *c = container_at_coords(seat, + struct sway_node *node = node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - if (c && config->focus_follows_mouse && allow_refocusing) { - struct sway_container *focus = seat_get_focus(seat); - if (focus && c->type == C_WORKSPACE) { + if (node && config->focus_follows_mouse && allow_refocusing) { + struct sway_node *focus = seat_get_focus(seat); + if (focus && node->type == N_WORKSPACE) { // Only follow the mouse if it would move to a new output // Otherwise we'll focus the workspace, which is probably wrong - if (focus->type != C_OUTPUT) { - focus = container_parent(focus, C_OUTPUT); + struct sway_output *focused_output = node_get_output(focus); + struct sway_output *output = node_get_output(node); + if (output != focused_output) { + seat_set_focus_warp(seat, node, false, true); } - struct sway_container *output = c; - if (output->type != C_OUTPUT) { - output = container_parent(c, C_OUTPUT); - } - if (output != focus) { - seat_set_focus_warp(seat, c, false, true); - } - } else if (c->type == C_VIEW) { - // Focus c if the following are true: + } else if (node->type == N_CONTAINER && node->sway_container->view) { + // Focus node if the following are true: // - cursor is over a new view, i.e. entered a new window; and // - the new view is visible, i.e. not hidden in a stack or tab; and // - the seat does not have a keyboard grab if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && - c != prev_c && - view_is_visible(c->sway_view)) { - seat_set_focus_warp(seat, c, false, true); + node != prev_node && + view_is_visible(node->sway_container->view)) { + seat_set_focus_warp(seat, node, false, true); } else { - struct sway_container *next_focus = - seat_get_focus_inactive(seat, &root_container); - if (next_focus && next_focus->type == C_VIEW && - view_is_visible(next_focus->sway_view)) { + struct sway_node *next_focus = + seat_get_focus_inactive(seat, &root->node); + if (next_focus && next_focus->type == N_CONTAINER && + node->sway_container->view && + view_is_visible(next_focus->sway_container->view)) { seat_set_focus_warp(seat, next_focus, false, true); } } @@ -486,12 +479,12 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, if (client != cursor->image_client) { cursor_set_image(cursor, "left_ptr", client); } - } else if (c) { - // Try a container's resize edge - enum wlr_edges edge = find_resize_edge(c, cursor); + } else if (node && node->type == N_CONTAINER) { + // Try a node's resize edge + enum wlr_edges edge = find_resize_edge(node->sway_container, cursor); if (edge == WLR_EDGE_NONE) { cursor_set_image(cursor, "left_ptr", NULL); - } else if (container_is_floating(c)) { + } else if (container_is_floating(node->sway_container)) { cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); } else { if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { @@ -684,7 +677,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, // Handle tiling resize via border if (resize_edge && button == BTN_LEFT && state == WLR_BUTTON_PRESSED && !is_floating) { - seat_set_focus(seat, cont); + seat_set_focus(seat, &cont->node); seat_begin_resize_tiling(seat, cont, button, edge); return; } @@ -713,7 +706,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, image = "sw-resize"; } cursor_set_image(seat->cursor, image, NULL); - seat_set_focus(seat, cont); + seat_set_focus(seat, &cont->node); seat_begin_resize_tiling(seat, cont, button, edge); return; } @@ -725,7 +718,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; if (button == btn_move && state == WLR_BUTTON_PRESSED && (mod_pressed || on_titlebar)) { - while (cont->parent->type != C_WORKSPACE) { + while (cont->parent) { cont = cont->parent; } seat_begin_move(seat, cont, button); @@ -747,7 +740,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, BTN_LEFT : BTN_RIGHT; if (mod_pressed && button == btn_resize) { struct sway_container *floater = cont; - while (floater->parent->type != C_WORKSPACE) { + while (floater->parent) { floater = floater->parent; } edge = 0; @@ -762,7 +755,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, // Handle mousedown on a container surface if (surface && cont && state == WLR_BUTTON_PRESSED) { - seat_set_focus(seat, cont); + seat_set_focus(seat, &cont->node); seat_pointer_notify_button(seat, time_msec, button, state); seat_begin_down(seat, cont, button, sx, sy); return; @@ -770,7 +763,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, // Handle clicking a container surface if (cont) { - seat_set_focus(seat, cont); + seat_set_focus(seat, &cont->node); seat_pointer_notify_button(seat, time_msec, button, state); return; } @@ -1025,8 +1018,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { cursor->previous.y = wlr_cursor->y; cursor->seat = seat; - wlr_cursor_attach_output_layout(wlr_cursor, - root_container.sway_root->output_layout); + wlr_cursor_attach_output_layout(wlr_cursor, root->output_layout); // input events wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index c820e0321..b4352c6ae 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -293,12 +293,10 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data) struct sway_seat *seat; wl_list_for_each(seat, &input_manager->seats, link) { seat_set_exclusive_client(seat, NULL); - struct sway_container *previous = seat_get_focus(seat); + struct sway_node *previous = seat_get_focus(seat); if (previous) { - wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, - container_type_to_str(previous->type), previous->name); // Hack to get seat to re-focus the return value of get_focus - seat_set_focus(seat, previous->parent); + seat_set_focus(seat, NULL); seat_set_focus(seat, previous); } } @@ -369,10 +367,10 @@ struct sway_input_manager *input_manager_create( } bool input_manager_has_focus(struct sway_input_manager *input, - struct sway_container *container) { + struct sway_node *node) { struct sway_seat *seat = NULL; wl_list_for_each(seat, &input->seats, link) { - if (seat_get_focus(seat) == container) { + if (seat_get_focus(seat) == node) { return true; } } @@ -381,10 +379,10 @@ bool input_manager_has_focus(struct sway_input_manager *input, } void input_manager_set_focus(struct sway_input_manager *input, - struct sway_container *container) { + struct sway_node *node) { struct sway_seat *seat; wl_list_for_each(seat, &input->seats, link) { - seat_set_focus(seat, container); + seat_set_focus(seat, node); } } diff --git a/sway/input/seat.c b/sway/input/seat.c index 4b7c78934..2f7a33188 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -47,48 +47,36 @@ void seat_destroy(struct sway_seat *seat) { seat_device_destroy(seat_device); } sway_cursor_destroy(seat->cursor); - wl_list_remove(&seat->new_container.link); + wl_list_remove(&seat->new_node.link); wl_list_remove(&seat->new_drag_icon.link); wl_list_remove(&seat->link); wlr_seat_destroy(seat->wlr_seat); } -static struct sway_seat_container *seat_container_from_container( - struct sway_seat *seat, struct sway_container *con); +static struct sway_seat_node *seat_node_from_node( + struct sway_seat *seat, struct sway_node *node); -static void seat_container_destroy(struct sway_seat_container *seat_con) { - struct sway_container *con = seat_con->container; - struct sway_container *child = NULL; - - if (con->children != NULL) { - for (int i = 0; i < con->children->length; ++i) { - child = con->children->items[i]; - struct sway_seat_container *seat_child = - seat_container_from_container(seat_con->seat, child); - seat_container_destroy(seat_child); - } - } - - wl_list_remove(&seat_con->destroy.link); - wl_list_remove(&seat_con->link); - free(seat_con); +static void seat_node_destroy(struct sway_seat_node *seat_node) { + wl_list_remove(&seat_node->destroy.link); + wl_list_remove(&seat_node->link); + free(seat_node); } /** * Activate all views within this container recursively. */ -static void seat_send_activate(struct sway_container *con, - struct sway_seat *seat) { - if (con->type == C_VIEW) { - if (!seat_is_input_allowed(seat, con->sway_view->surface)) { +static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) { + if (node_is_view(node)) { + if (!seat_is_input_allowed(seat, node->sway_container->view->surface)) { wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited"); return; } - view_set_activated(con->sway_view, true); + view_set_activated(node->sway_container->view, true); } else { - for (int i = 0; i < con->children->length; ++i) { - struct sway_container *child = con->children->items[i]; - seat_send_activate(child, seat); + list_t *children = node_get_children(node); + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; + seat_send_activate(&child->node, seat); } } } @@ -98,14 +86,15 @@ static void seat_send_activate(struct sway_container *con, * If con is a container, set all child views as active and don't enable * keyboard input on any. */ -static void seat_send_focus(struct sway_container *con, - struct sway_seat *seat) { - seat_send_activate(con, seat); +static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) { + seat_send_activate(node, seat); - if (con->type == C_VIEW - && seat_is_input_allowed(seat, con->sway_view->surface)) { + struct sway_view *view = node->type == N_CONTAINER ? + node->sway_container->view : NULL; + + if (view && seat_is_input_allowed(seat, view->surface)) { #ifdef HAVE_XWAYLAND - if (con->sway_view->type == SWAY_VIEW_XWAYLAND) { + if (view->type == SWAY_VIEW_XWAYLAND) { struct wlr_xwayland *xwayland = seat->input->server->xwayland.wlr_xwayland; wlr_xwayland_set_seat(xwayland, seat->wlr_seat); @@ -114,71 +103,67 @@ static void seat_send_focus(struct sway_container *con, struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); if (keyboard) { wlr_seat_keyboard_notify_enter(seat->wlr_seat, - con->sway_view->surface, keyboard->keycodes, + view->surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); } else { wlr_seat_keyboard_notify_enter( - seat->wlr_seat, con->sway_view->surface, NULL, 0, NULL); + seat->wlr_seat, view->surface, NULL, 0, NULL); } } } -void seat_focus_inactive_children_for_each(struct sway_seat *seat, - struct sway_container *container, - void (*f)(struct sway_container *container, void *data), void *data) { - struct sway_seat_container *current = NULL; +void seat_for_each_node(struct sway_seat *seat, + void (*f)(struct sway_node *node, void *data), void *data) { + struct sway_seat_node *current = NULL; wl_list_for_each(current, &seat->focus_stack, link) { - if (current->container->parent == NULL) { - continue; - } - if (current->container->parent == container) { - f(current->container, data); - } + f(current->node, data); } } struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, - struct sway_container *ancestor) { - if (ancestor->type == C_VIEW) { - return ancestor; + struct sway_node *ancestor) { + if (ancestor->type == N_CONTAINER && ancestor->sway_container->view) { + return ancestor->sway_container; } - struct sway_seat_container *current; + struct sway_seat_node *current; wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_container *con = current->container; - if (con->type == C_VIEW && container_has_ancestor(con, ancestor)) { - return con; + struct sway_node *node = current->node; + if (node->type == N_CONTAINER && node->sway_container->view && + node_has_ancestor(node, ancestor)) { + return node->sway_container; } } return NULL; } -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; - struct sway_container *con = seat_con->container; - struct sway_container *parent = con->parent; - struct sway_container *focus = seat_get_focus(seat); +static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { + struct sway_seat_node *seat_node = + wl_container_of(listener, seat_node, destroy); + struct sway_seat *seat = seat_node->seat; + struct sway_node *node = seat_node->node; + struct sway_node *parent = node_get_parent(node); + struct sway_node *focus = seat_get_focus(seat); bool set_focus = focus != NULL && - (focus == con || container_has_ancestor(focus, con)) && - con->type != C_WORKSPACE; + (focus == node || node_has_ancestor(focus, node)) && + node->type == N_CONTAINER; - seat_container_destroy(seat_con); + seat_node_destroy(seat_node); if (set_focus) { - struct sway_container *next_focus = NULL; + struct sway_node *next_focus = NULL; while (next_focus == NULL) { - next_focus = seat_get_focus_inactive_view(seat, parent); + struct sway_container *con = + seat_get_focus_inactive_view(seat, parent); + next_focus = con ? &con->node : NULL; - if (next_focus == NULL && parent->type == C_WORKSPACE) { + if (next_focus == NULL && parent->type == N_WORKSPACE) { next_focus = parent; break; } - parent = parent->parent; + parent = node_get_parent(parent); } // the structure change might have caused it to move up to the top of @@ -191,39 +176,39 @@ static void handle_seat_container_destroy(struct wl_listener *listener, } } -static struct sway_seat_container *seat_container_from_container( - struct sway_seat *seat, struct sway_container *con) { - if (con->type == C_ROOT || con->type == C_OUTPUT) { - // these don't get seat containers ever +static struct sway_seat_node *seat_node_from_node( + struct sway_seat *seat, struct sway_node *node) { + if (node->type == N_ROOT || node->type == N_OUTPUT) { + // these don't get seat nodes 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; + struct sway_seat_node *seat_node = NULL; + wl_list_for_each(seat_node, &seat->focus_stack, link) { + if (seat_node->node == node) { + return seat_node; } } - seat_con = calloc(1, sizeof(struct sway_seat_container)); - if (seat_con == NULL) { - wlr_log(WLR_ERROR, "could not allocate seat container"); + seat_node = calloc(1, sizeof(struct sway_seat_node)); + if (seat_node == NULL) { + wlr_log(WLR_ERROR, "could not allocate seat node"); 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; + seat_node->node = node; + seat_node->seat = seat; + wl_list_insert(seat->focus_stack.prev, &seat_node->link); + wl_signal_add(&node->events.destroy, &seat_node->destroy); + seat_node->destroy.notify = handle_seat_node_destroy; - return seat_con; + return seat_node; } -static void handle_new_container(struct wl_listener *listener, void *data) { - struct sway_seat *seat = wl_container_of(listener, seat, new_container); - struct sway_container *con = data; - seat_container_from_container(seat, con); +static void handle_new_node(struct wl_listener *listener, void *data) { + struct sway_seat *seat = wl_container_of(listener, seat, new_node); + struct sway_node *node = data; + seat_node_from_node(seat, node); } static void drag_icon_damage_whole(struct sway_drag_icon *icon) { @@ -272,8 +257,7 @@ static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) { drag_icon_damage_whole(icon); } -static void drag_icon_handle_destroy(struct wl_listener *listener, - void *data) { +static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) { struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy); icon->wlr_drag_icon->data = NULL; wl_list_remove(&icon->link); @@ -305,20 +289,29 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) { icon->destroy.notify = drag_icon_handle_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); - wl_list_insert(&root_container.sway_root->drag_icons, &icon->link); + wl_list_insert(&root->drag_icons, &icon->link); drag_icon_update_position(icon); } -static void collect_focus_iter(struct sway_container *con, void *data) { +static void collect_focus_iter(struct sway_node *node, void *data) { struct sway_seat *seat = data; - struct sway_seat_container *seat_con = - seat_container_from_container(seat, con); - if (!seat_con) { + struct sway_seat_node *seat_node = seat_node_from_node(seat, node); + if (!seat_node) { return; } - wl_list_remove(&seat_con->link); - wl_list_insert(&seat->focus_stack, &seat_con->link); + wl_list_remove(&seat_node->link); + wl_list_insert(&seat->focus_stack, &seat_node->link); +} + +static void collect_focus_workspace_iter(struct sway_workspace *workspace, + void *data) { + collect_focus_iter(&workspace->node, data); +} + +static void collect_focus_container_iter(struct sway_container *container, + void *data) { + collect_focus_iter(&container->node, data); } struct sway_seat *seat_create(struct sway_input_manager *input, @@ -345,12 +338,11 @@ struct sway_seat *seat_create(struct sway_input_manager *input, // init the focus stack wl_list_init(&seat->focus_stack); - root_for_each_workspace(collect_focus_iter, seat); - root_for_each_container(collect_focus_iter, seat); + root_for_each_workspace(collect_focus_workspace_iter, seat); + root_for_each_container(collect_focus_container_iter, seat); - wl_signal_add(&root_container.sway_root->events.new_container, - &seat->new_container); - seat->new_container.notify = handle_new_container; + wl_signal_add(&root->events.new_node, &seat->new_node); + seat->new_node.notify = handle_new_node; wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon); seat->new_drag_icon.notify = handle_new_drag_icon; @@ -388,19 +380,11 @@ static void seat_apply_input_config(struct sway_seat *seat, if (mapped_to_output != NULL) { wlr_log(WLR_DEBUG, "Mapping input device %s to output %s", sway_device->input_device->identifier, mapped_to_output); - struct sway_container *output = NULL; - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *_output = root_container.children->items[i]; - if (strcasecmp(_output->name, mapped_to_output) == 0) { - output = _output; - break; - } - } + struct sway_output *output = output_by_name(mapped_to_output); if (output) { wlr_cursor_map_input_to_output(seat->cursor->cursor, - sway_device->input_device->wlr_device, - output->sway_output->wlr_output); - wlr_log(WLR_DEBUG, "Mapped to output %s", output->name); + sway_device->input_device->wlr_device, output->wlr_output); + wlr_log(WLR_DEBUG, "Mapped to output %s", output->wlr_output->name); } } } @@ -423,12 +407,12 @@ static void seat_configure_keyboard(struct sway_seat *seat, sway_keyboard_configure(seat_device->keyboard); wlr_seat_set_keyboard(seat->wlr_seat, seat_device->input_device->wlr_device); - struct sway_container *focus = seat_get_focus(seat); - if (focus && focus->type == C_VIEW) { + struct sway_node *focus = seat_get_focus(seat); + if (focus && node_is_view(focus)) { // force notify reenter to pick up the new configuration wlr_seat_keyboard_clear_focus(seat->wlr_seat); wlr_seat_keyboard_notify_enter(seat->wlr_seat, - focus->sway_view->surface, wlr_keyboard->keycodes, + focus->sway_container->view->surface, wlr_keyboard->keycodes, wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); } } @@ -461,8 +445,7 @@ static struct sway_seat_device *seat_get_device(struct sway_seat *seat, void seat_configure_device(struct sway_seat *seat, struct sway_input_device *input_device) { - struct sway_seat_device *seat_device = - seat_get_device(seat, input_device); + struct sway_seat_device *seat_device = seat_get_device(seat, input_device); if (!seat_device) { return; } @@ -512,8 +495,7 @@ void seat_add_device(struct sway_seat *seat, void seat_remove_device(struct sway_seat *seat, struct sway_input_device *input_device) { - struct sway_seat_device *seat_device = - seat_get_device(seat, input_device); + struct sway_seat_device *seat_device = seat_get_device(seat, input_device); if (!seat_device) { return; @@ -539,11 +521,9 @@ void seat_configure_xcursor(struct sway_seat *seat) { } } - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output_container = - root_container.children->items[i]; - struct wlr_output *output = - output_container->sway_output->wlr_output; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *sway_output = root->outputs->items[i]; + struct wlr_output *output = sway_output->wlr_output; bool result = wlr_xcursor_manager_load(seat->cursor->xcursor_manager, output->scale); @@ -566,17 +546,20 @@ bool seat_is_input_allowed(struct sway_seat *seat, return !seat->exclusive_client || seat->exclusive_client == client; } +static void send_unfocus(struct sway_container *con, void *data) { + if (con->view) { + view_set_activated(con->view, false); + } +} + // Unfocus the container and any children (eg. when leaving `focus parent`) -static void seat_send_unfocus(struct sway_container *container, - struct sway_seat *seat) { - if (container->type == C_VIEW) { - wlr_seat_keyboard_clear_focus(seat->wlr_seat); - view_set_activated(container->sway_view, false); +static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) { + wlr_seat_keyboard_clear_focus(seat->wlr_seat); + if (node->type == N_WORKSPACE) { + workspace_for_each_container(node->sway_workspace, send_unfocus, seat); } else { - for (int i = 0; i < container->children->length; ++i) { - struct sway_container *child = container->children->items[i]; - seat_send_unfocus(child, seat); - } + send_unfocus(node->sway_container, seat); + container_for_each_child(node->sway_container, send_unfocus, seat); } } @@ -586,26 +569,23 @@ static int handle_urgent_timeout(void *data) { return 0; } -void seat_set_focus_warp(struct sway_seat *seat, - struct sway_container *container, bool warp, bool notify) { +void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, + bool warp, bool notify) { if (seat->focused_layer) { return; } - struct sway_container *last_focus = seat_get_focus(seat); - if (last_focus == container) { + struct sway_node *last_focus = seat_get_focus(seat); + if (last_focus == node) { return; } - struct sway_container *last_workspace = last_focus; - if (last_workspace && last_workspace->type != C_WORKSPACE) { - last_workspace = container_parent(last_workspace, C_WORKSPACE); - } + struct sway_workspace *last_workspace = seat_get_focused_workspace(seat); - if (container == NULL) { + if (node == NULL) { // Close any popups on the old focus - if (last_focus->type == C_VIEW) { - view_close_popups(last_focus->sway_view); + if (node_is_view(last_focus)) { + view_close_popups(last_focus->sway_container->view); } seat_send_unfocus(last_focus, seat); seat->has_focus = false; @@ -613,69 +593,70 @@ void seat_set_focus_warp(struct sway_seat *seat, return; } - struct sway_container *new_workspace = container; - if (new_workspace->type != C_WORKSPACE) { - new_workspace = container_parent(new_workspace, C_WORKSPACE); - } + struct sway_workspace *new_workspace = node->type == N_WORKSPACE ? + node->sway_workspace : node->sway_container->workspace; + struct sway_container *container = node->type == N_CONTAINER ? + node->sway_container : NULL; - if (last_workspace == new_workspace - && last_workspace->sway_workspace->fullscreen - && !container_is_fullscreen_or_child(container)) { + // Deny setting focus to a view which is hidden by a fullscreen container + if (new_workspace && new_workspace->fullscreen && container && + !container_is_fullscreen_or_child(container)) { return; } - struct sway_container *last_output = last_focus; - if (last_output && last_output->type != C_OUTPUT) { - last_output = container_parent(last_output, C_OUTPUT); - } - struct sway_container *new_output = container; - if (new_output->type != C_OUTPUT) { - new_output = container_parent(new_output, C_OUTPUT); - } + struct sway_output *last_output = last_workspace ? + last_workspace->output : NULL; + struct sway_output *new_output = new_workspace->output; // find new output's old workspace, which might have to be removed if empty - struct sway_container *new_output_last_ws = NULL; + struct sway_workspace *new_output_last_ws = NULL; if (new_output && last_output != new_output) { - new_output_last_ws = seat_get_active_child(seat, new_output); + new_output_last_ws = output_get_active_workspace(new_output); } - if (container->parent) { - struct sway_seat_container *seat_con = - seat_container_from_container(seat, container); - if (seat_con == NULL) { - return; - } - - // put all the ancestors of this container on top of the focus stack - struct sway_seat_container *parent = - seat_container_from_container(seat, container->parent); + // Put the container parents on the focus stack, then the workspace, then + // the focused container. + if (container) { + struct sway_container *parent = container->parent; while (parent) { - wl_list_remove(&parent->link); - wl_list_insert(&seat->focus_stack, &parent->link); - container_set_dirty(parent->container); - - parent = seat_container_from_container(seat, - parent->container->parent); + struct sway_seat_node *seat_node = + seat_node_from_node(seat, &parent->node); + wl_list_remove(&seat_node->link); + wl_list_insert(&seat->focus_stack, &seat_node->link); + node_set_dirty(&parent->node); + parent = parent->parent; } - - wl_list_remove(&seat_con->link); - wl_list_insert(&seat->focus_stack, &seat_con->link); + } + if (new_workspace) { + struct sway_seat_node *seat_node = + seat_node_from_node(seat, &new_workspace->node); + wl_list_remove(&seat_node->link); + wl_list_insert(&seat->focus_stack, &seat_node->link); + node_set_dirty(&new_workspace->node); + } + if (container) { + struct sway_seat_node *seat_node = + seat_node_from_node(seat, &container->node); + wl_list_remove(&seat_node->link); + wl_list_insert(&seat->focus_stack, &seat_node->link); + node_set_dirty(&container->node); if (last_focus) { seat_send_unfocus(last_focus, seat); - container_set_dirty(last_focus); + node_set_dirty(last_focus); + struct sway_node *last_parent = node_get_parent(last_focus); + if (last_parent) { + node_set_dirty(last_parent); + } } - seat_send_focus(container, seat); - - container_set_dirty(container); - container_set_dirty(container->parent); // for focused_inactive_child + seat_send_focus(&container->node, seat); } // emit ipc events if (notify && new_workspace && last_workspace != new_workspace) { ipc_event_workspace(last_workspace, new_workspace, "focus"); } - if (container->type == C_VIEW) { + if (container && container->view) { ipc_event_window(container, "focus"); } @@ -684,14 +665,14 @@ void seat_set_focus_warp(struct sway_seat *seat, } // Close any popups on the old focus - if (last_focus && last_focus->type == C_VIEW) { - view_close_popups(last_focus->sway_view); + if (last_focus && node_is_view(last_focus)) { + view_close_popups(last_focus->sway_container->view); } // If urgent, either unset the urgency or start a timer to unset it - if (container->type == C_VIEW && view_is_urgent(container->sway_view) && - !container->sway_view->urgent_timer) { - struct sway_view *view = container->sway_view; + if (container && container->view && view_is_urgent(container->view) && + !container->view->urgent_timer) { + struct sway_view *view = container->view; if (last_workspace && last_workspace != new_workspace && config->urgent_timeout > 0) { view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, @@ -711,12 +692,15 @@ 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. - struct sway_container *floater = container; - while (floater->parent && floater->parent->type != C_WORKSPACE) { - floater = floater->parent; - } - if (container_is_floating(floater)) { - list_move_to_end(floater->parent->sway_workspace->floating, floater); + if (container) { + struct sway_container *floater = container; + while (floater->parent) { + floater = floater->parent; + } + if (container_is_floating(floater)) { + list_move_to_end(floater->workspace->floating, floater); + node_set_dirty(&floater->workspace->node); + } } if (last_focus) { @@ -727,11 +711,8 @@ void seat_set_focus_warp(struct sway_seat *seat, if (config->mouse_warping && warp && new_output != last_output) { double x = container->x + container->width / 2.0; double y = container->y + container->height / 2.0; - struct wlr_output *wlr_output = - new_output->sway_output->wlr_output; - if (!wlr_output_layout_contains_point( - root_container.sway_root->output_layout, - wlr_output, seat->cursor->cursor->x, + if (!wlr_output_layout_contains_point(root->output_layout, + new_output->wlr_output, seat->cursor->cursor->x, seat->cursor->cursor->y)) { wlr_cursor_warp(seat->cursor->cursor, NULL, x, y); cursor_send_pointer_motion(seat->cursor, 0, true); @@ -744,9 +725,8 @@ void seat_set_focus_warp(struct sway_seat *seat, update_debug_tree(); } -void seat_set_focus(struct sway_seat *seat, - struct sway_container *container) { - seat_set_focus_warp(seat, container, true, true); +void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { + seat_set_focus_warp(seat, node, true, true); } void seat_set_focus_surface(struct sway_seat *seat, @@ -755,12 +735,11 @@ void seat_set_focus_surface(struct sway_seat *seat, return; } if (seat->has_focus && unfocus) { - struct sway_container *focus = seat_get_focus(seat); + struct sway_node *focus = seat_get_focus(seat); seat_send_unfocus(focus, seat); seat->has_focus = false; } - struct wlr_keyboard *keyboard = - wlr_seat_get_keyboard(seat->wlr_seat); + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); if (keyboard) { wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); @@ -773,11 +752,8 @@ void seat_set_focus_layer(struct sway_seat *seat, struct wlr_layer_surface *layer) { if (!layer && seat->focused_layer) { seat->focused_layer = NULL; - struct sway_container *previous = - seat_get_focus_inactive(seat, &root_container); + struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); if (previous) { - wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, - container_type_to_str(previous->type), previous->name); // Hack to get seat to re-focus the return value of get_focus seat_set_focus(seat, NULL); seat_set_focus(seat, previous); @@ -798,13 +774,9 @@ void seat_set_exclusive_client(struct sway_seat *seat, seat->exclusive_client = client; // Triggers a refocus of the topmost surface layer if necessary // TODO: Make layer surface focus per-output based on cursor position - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - if (!sway_assert(output->type == C_OUTPUT, - "root container has non-output child")) { - continue; - } - arrange_layers(output->sway_output); + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + arrange_layers(output); } return; } @@ -814,9 +786,9 @@ void seat_set_exclusive_client(struct sway_seat *seat, } } if (seat->has_focus) { - struct sway_container *focus = seat_get_focus(seat); - if (focus->type == C_VIEW && wl_resource_get_client( - focus->sway_view->surface->resource) != client) { + struct sway_node *focus = seat_get_focus(seat); + if (node_is_view(focus) && wl_resource_get_client( + focus->sway_container->view->surface->resource) != client) { seat_set_focus(seat, NULL); } } @@ -837,79 +809,101 @@ void seat_set_exclusive_client(struct sway_seat *seat, seat->exclusive_client = client; } -struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, - struct sway_container *con) { - if (con->type == C_WORKSPACE && !con->children->length && - !con->sway_workspace->floating->length) { - return con; +struct sway_node *seat_get_focus_inactive(struct sway_seat *seat, + struct sway_node *node) { + if (node_is_view(node)) { + return node; } - if (con->type == C_VIEW) { - return con; - } - struct sway_seat_container *current; + struct sway_seat_node *current; wl_list_for_each(current, &seat->focus_stack, link) { - if (container_has_ancestor(current->container, con)) { - return current->container; + if (node_has_ancestor(current->node, node)) { + return current->node; } } + if (node->type == N_WORKSPACE) { + return node; + } return NULL; } struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, - struct sway_container *ancestor) { - if (ancestor->type == C_WORKSPACE && !ancestor->children->length) { - return ancestor; + struct sway_workspace *workspace) { + if (!workspace->tiling->length) { + return NULL; } - struct sway_seat_container *current; + struct sway_seat_node *current; wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_container *con = current->container; - if (!container_is_floating_or_child(con) && - container_has_ancestor(current->container, ancestor)) { - return con; + struct sway_node *node = current->node; + if (node->type == N_CONTAINER && + !container_is_floating_or_child(node->sway_container) && + node->sway_container->workspace == workspace) { + return node->sway_container; } } return NULL; } struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, - struct sway_container *ancestor) { - if (ancestor->type == C_WORKSPACE && - !ancestor->sway_workspace->floating->length) { + struct sway_workspace *workspace) { + if (!workspace->floating->length) { return NULL; } - struct sway_seat_container *current; + struct sway_seat_node *current; wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_container *con = current->container; - if (container_is_floating_or_child(con) && - container_has_ancestor(current->container, ancestor)) { - return con; + struct sway_node *node = current->node; + if (node->type == N_CONTAINER && + container_is_floating_or_child(node->sway_container) && + node->sway_container->workspace == workspace) { + return node->sway_container; } } return NULL; } -struct sway_container *seat_get_active_child(struct sway_seat *seat, - struct sway_container *parent) { - if (parent->type == C_VIEW) { +struct sway_node *seat_get_active_child(struct sway_seat *seat, + struct sway_node *parent) { + if (node_is_view(parent)) { return parent; } - struct sway_seat_container *current; + struct sway_seat_node *current; wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_container *con = current->container; - if (con->parent == parent) { - return con; + struct sway_node *node = current->node; + if (node_get_parent(node) == parent) { + return node; } } return NULL; } -struct sway_container *seat_get_focus(struct sway_seat *seat) { +struct sway_node *seat_get_focus(struct sway_seat *seat) { if (!seat->has_focus) { return NULL; } - struct sway_seat_container *current = + struct sway_seat_node *current = wl_container_of(seat->focus_stack.next, current, link); - return current->container; + return current->node; +} + +struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) { + struct sway_node *focus = seat_get_focus(seat); + if (!focus) { + return NULL; + } + if (focus->type == N_CONTAINER) { + return focus->sway_container->workspace; + } + if (focus->type == N_WORKSPACE) { + return focus->sway_workspace; + } + return NULL; // unreachable +} + +struct sway_container *seat_get_focused_container(struct sway_seat *seat) { + struct sway_node *focus = seat_get_focus(seat); + if (focus && focus->type == N_CONTAINER) { + return focus->sway_container; + } + return NULL; } void seat_apply_config(struct sway_seat *seat, diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 06cb7e11c..9a9559916 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -46,18 +46,18 @@ json_object *ipc_json_get_version() { return version; } -static json_object *ipc_json_create_rect(struct sway_container *c) { +static json_object *ipc_json_create_rect(struct wlr_box *box) { json_object *rect = json_object_new_object(); - json_object_object_add(rect, "x", json_object_new_int((int32_t)c->x)); - json_object_object_add(rect, "y", json_object_new_int((int32_t)c->y)); - json_object_object_add(rect, "width", json_object_new_int((int32_t)c->width)); - json_object_object_add(rect, "height", json_object_new_int((int32_t)c->height)); + json_object_object_add(rect, "x", json_object_new_int(box->x)); + json_object_object_add(rect, "y", json_object_new_int(box->y)); + json_object_object_add(rect, "width", json_object_new_int(box->width)); + json_object_object_add(rect, "height", json_object_new_int(box->height)); return rect; } -static void ipc_json_describe_root(struct sway_container *root, json_object *object) { +static void ipc_json_describe_root(struct sway_root *root, json_object *object) { json_object_object_add(object, "type", json_object_new_string("root")); json_object_object_add(object, "layout", json_object_new_string("splith")); } @@ -84,17 +84,13 @@ static const char *ipc_json_get_output_transform(enum wl_output_transform transf return NULL; } -static void ipc_json_describe_output(struct sway_container *container, +static void ipc_json_describe_output(struct sway_output *output, json_object *object) { - struct wlr_output *wlr_output = container->sway_output->wlr_output; - json_object_object_add(object, "type", - json_object_new_string("output")); - json_object_object_add(object, "active", - json_object_new_boolean(true)); - json_object_object_add(object, "primary", - json_object_new_boolean(false)); - json_object_object_add(object, "layout", - json_object_new_string("output")); + struct wlr_output *wlr_output = output->wlr_output; + json_object_object_add(object, "type", json_object_new_string("output")); + json_object_object_add(object, "active", json_object_new_boolean(true)); + json_object_object_add(object, "primary", json_object_new_boolean(false)); + json_object_object_add(object, "layout", json_object_new_string("output")); json_object_object_add(object, "make", json_object_new_string(wlr_output->make)); json_object_object_add(object, "model", @@ -109,20 +105,9 @@ static void ipc_json_describe_output(struct sway_container *container, json_object_new_string( ipc_json_get_output_transform(wlr_output->transform))); - struct sway_seat *seat = input_manager_get_default_seat(input_manager); - const char *ws = NULL; - if (seat) { - struct sway_container *focus = - seat_get_focus_inactive(seat, container); - if (focus && focus->type != C_WORKSPACE) { - focus = container_parent(focus, C_WORKSPACE); - } - if (focus) { - ws = focus->name; - } - } + struct sway_workspace *ws = output_get_active_workspace(output); json_object_object_add(object, "current_workspace", - json_object_new_string(ws)); + json_object_new_string(ws->name)); json_object *modes_array = json_object_new_array(); struct wlr_output_mode *mode; @@ -161,60 +146,57 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) { return object; } -static void ipc_json_describe_workspace(struct sway_container *workspace, +static void ipc_json_describe_workspace(struct sway_workspace *workspace, json_object *object) { int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1; json_object_object_add(object, "num", json_object_new_int(num)); - json_object_object_add(object, "output", workspace->parent ? - json_object_new_string(workspace->parent->name) : NULL); + json_object_object_add(object, "output", workspace->output ? + json_object_new_string(workspace->output->wlr_output->name) : NULL); json_object_object_add(object, "type", json_object_new_string("workspace")); json_object_object_add(object, "urgent", - json_object_new_boolean(workspace->sway_workspace->urgent)); - json_object_object_add(object, "representation", workspace->formatted_title ? - json_object_new_string(workspace->formatted_title) : NULL); + json_object_new_boolean(workspace->urgent)); + json_object_object_add(object, "representation", workspace->representation ? + json_object_new_string(workspace->representation) : NULL); const char *layout = ipc_json_layout_description(workspace->layout); json_object_object_add(object, "layout", json_object_new_string(layout)); // Floating json_object *floating_array = json_object_new_array(); - list_t *floating = workspace->sway_workspace->floating; - for (int i = 0; i < floating->length; ++i) { - struct sway_container *floater = floating->items[i]; + for (int i = 0; i < workspace->floating->length; ++i) { + struct sway_container *floater = workspace->floating->items[i]; json_object_array_add(floating_array, - ipc_json_describe_container_recursive(floater)); + ipc_json_describe_node_recursive(&floater->node)); } json_object_object_add(object, "floating_nodes", floating_array); } static void ipc_json_describe_view(struct sway_container *c, json_object *object) { json_object_object_add(object, "name", - c->name ? json_object_new_string(c->name) : NULL); + c->title ? json_object_new_string(c->title) : NULL); json_object_object_add(object, "type", json_object_new_string("con")); - if (c->type == C_VIEW) { - const char *app_id = view_get_app_id(c->sway_view); + if (c->view) { + const char *app_id = view_get_app_id(c->view); json_object_object_add(object, "app_id", app_id ? json_object_new_string(app_id) : NULL); - const char *class = view_get_class(c->sway_view); + const char *class = view_get_class(c->view); json_object_object_add(object, "class", class ? json_object_new_string(class) : NULL); } - if (c->parent) { - json_object_object_add(object, "layout", - json_object_new_string(ipc_json_layout_description(c->layout))); - } + json_object_object_add(object, "layout", + json_object_new_string(ipc_json_layout_description(c->layout))); - bool urgent = c->type == C_VIEW ? - view_is_urgent(c->sway_view) : container_has_urgent_child(c); + bool urgent = c->view ? + view_is_urgent(c->view) : container_has_urgent_child(c); json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); - if (c->type == C_VIEW) { + if (c->view) { json_object *marks = json_object_new_array(); - list_t *view_marks = c->sway_view->marks; + list_t *view_marks = c->view->marks; for (int i = 0; i < view_marks->length; ++i) { json_object_array_add(marks, json_object_new_string(view_marks->items[i])); } @@ -222,64 +204,97 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object } } -static void focus_inactive_children_iterator(struct sway_container *c, void *data) { - json_object *focus = data; - json_object_array_add(focus, json_object_new_int(c->id)); +struct focus_inactive_data { + struct sway_node *node; + json_object *object; +}; + +static void focus_inactive_children_iterator(struct sway_node *node, + void *_data) { + struct focus_inactive_data *data = _data; + if (node_get_parent(node) == data->node) { + json_object_array_add(data->object, json_object_new_int(node->id)); + } } -json_object *ipc_json_describe_container(struct sway_container *c) { - if (!(sway_assert(c, "Container must not be null."))) { - return NULL; - } - +json_object *ipc_json_describe_node(struct sway_node *node) { struct sway_seat *seat = input_manager_get_default_seat(input_manager); - bool focused = seat_get_focus(seat) == c; + bool focused = seat_get_focus(seat) == node; json_object *object = json_object_new_object(); + char *name = node_get_name(node); - json_object_object_add(object, "id", json_object_new_int((int)c->id)); + struct wlr_box box; + node_get_box(node, &box); + json_object_object_add(object, "id", json_object_new_int((int)node->id)); json_object_object_add(object, "name", - c->name ? json_object_new_string(c->name) : NULL); - json_object_object_add(object, "rect", ipc_json_create_rect(c)); - json_object_object_add(object, "focused", - json_object_new_boolean(focused)); + name ? json_object_new_string(name) : NULL); + json_object_object_add(object, "rect", ipc_json_create_rect(&box)); + json_object_object_add(object, "focused", json_object_new_boolean(focused)); json_object *focus = json_object_new_array(); - seat_focus_inactive_children_for_each(seat, c, - focus_inactive_children_iterator, focus); + struct focus_inactive_data data = { + .node = node, + .object = focus, + }; + seat_for_each_node(seat, focus_inactive_children_iterator, &data); json_object_object_add(object, "focus", focus); - switch (c->type) { - case C_ROOT: - ipc_json_describe_root(c, object); + switch (node->type) { + case N_ROOT: + ipc_json_describe_root(root, object); break; - case C_OUTPUT: - ipc_json_describe_output(c, object); + case N_OUTPUT: + ipc_json_describe_output(node->sway_output, object); break; - case C_CONTAINER: - case C_VIEW: - ipc_json_describe_view(c, object); + case N_CONTAINER: + ipc_json_describe_view(node->sway_container, object); break; - case C_WORKSPACE: - ipc_json_describe_workspace(c, object); - break; - case C_TYPES: - default: + case N_WORKSPACE: + ipc_json_describe_workspace(node->sway_workspace, object); break; } return object; } -json_object *ipc_json_describe_container_recursive(struct sway_container *c) { - json_object *object = ipc_json_describe_container(c); +json_object *ipc_json_describe_node_recursive(struct sway_node *node) { + json_object *object = ipc_json_describe_node(node); int i; json_object *children = json_object_new_array(); - if (c->type != C_VIEW && c->children) { - for (i = 0; i < c->children->length; ++i) { - json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); + switch (node->type) { + case N_ROOT: + for (i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + json_object_array_add(children, + ipc_json_describe_node_recursive(&output->node)); } + break; + case N_OUTPUT: + for (i = 0; i < node->sway_output->workspaces->length; ++i) { + struct sway_workspace *ws = node->sway_output->workspaces->items[i]; + json_object_array_add(children, + ipc_json_describe_node_recursive(&ws->node)); + } + break; + case N_WORKSPACE: + for (i = 0; i < node->sway_workspace->tiling->length; ++i) { + struct sway_container *con = node->sway_workspace->tiling->items[i]; + json_object_array_add(children, + ipc_json_describe_node_recursive(&con->node)); + } + break; + case N_CONTAINER: + if (node->sway_container->children) { + for (i = 0; i < node->sway_container->children->length; ++i) { + struct sway_container *child = + node->sway_container->children->items[i]; + json_object_array_add(children, + ipc_json_describe_node_recursive(&child->node)); + } + } + break; } json_object_object_add(object, "nodes", children); @@ -329,7 +344,7 @@ json_object *ipc_json_describe_seat(struct sway_seat *seat) { } json_object *object = json_object_new_object(); - struct sway_container *focus = seat_get_focus(seat); + struct sway_node *focus = seat_get_focus(seat); json_object_object_add(object, "name", json_object_new_string(seat->wlr_seat->name)); @@ -470,13 +485,13 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { json_object_object_add(json, "colors", colors); // Add outputs if defined + json_object *outputs = json_object_new_array(); if (bar->outputs && bar->outputs->length > 0) { - json_object *outputs = json_object_new_array(); for (int i = 0; i < bar->outputs->length; ++i) { const char *name = bar->outputs->items[i]; json_object_array_add(outputs, json_object_new_string(name)); } - json_object_object_add(json, "outputs", outputs); } + json_object_object_add(json, "outputs", outputs); return json; } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index fb5be27bc..8ae265f6d 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -33,6 +33,7 @@ #include "sway/input/seat.h" #include "sway/tree/root.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "list.h" #include "log.h" #include "util.h" @@ -291,8 +292,8 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event) } } -void ipc_event_workspace(struct sway_container *old, - struct sway_container *new, const char *change) { +void ipc_event_workspace(struct sway_workspace *old, + struct sway_workspace *new, const char *change) { if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) { return; } @@ -301,14 +302,14 @@ void ipc_event_workspace(struct sway_container *old, json_object_object_add(obj, "change", json_object_new_string(change)); if (old) { json_object_object_add(obj, "old", - ipc_json_describe_container_recursive(old)); + ipc_json_describe_node_recursive(&old->node)); } else { json_object_object_add(obj, "old", NULL); } if (new) { json_object_object_add(obj, "current", - ipc_json_describe_container_recursive(new)); + ipc_json_describe_node_recursive(&new->node)); } else { json_object_object_add(obj, "current", NULL); } @@ -325,7 +326,8 @@ void ipc_event_window(struct sway_container *window, const char *change) { wlr_log(WLR_DEBUG, "Sending window::%s event", change); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(change)); - json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); + json_object_object_add(obj, "container", + ipc_json_describe_node_recursive(&window->node)); const char *json_string = json_object_to_json_string(obj); ipc_send_event(json_string, IPC_EVENT_WINDOW); @@ -521,30 +523,20 @@ void ipc_client_disconnect(struct ipc_client *client) { free(client); } -static void ipc_get_workspaces_callback(struct sway_container *workspace, +static void ipc_get_workspaces_callback(struct sway_workspace *workspace, void *data) { - if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { - return; - } - json_object *workspace_json = ipc_json_describe_container(workspace); + json_object *workspace_json = ipc_json_describe_node(&workspace->node); // override the default focused indicator because // it's set differently for the get_workspaces reply - struct sway_seat *seat = - input_manager_get_default_seat(input_manager); - struct sway_container *focused_ws = seat_get_focus(seat); - if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) { - focused_ws = container_parent(focused_ws, C_WORKSPACE); - } + struct sway_seat *seat = input_manager_get_default_seat(input_manager); + struct sway_workspace *focused_ws = seat_get_focused_workspace(seat); bool focused = workspace == focused_ws; json_object_object_del(workspace_json, "focused"); json_object_object_add(workspace_json, "focused", json_object_new_boolean(focused)); json_object_array_add((json_object *)data, workspace_json); - focused_ws = seat_get_focus_inactive(seat, workspace->parent); - if (focused_ws->type != C_WORKSPACE) { - focused_ws = container_parent(focused_ws, C_WORKSPACE); - } + focused_ws = output_get_active_workspace(workspace->output); bool visible = workspace == focused_ws; json_object_object_add(workspace_json, "visible", json_object_new_boolean(visible)); @@ -552,9 +544,9 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace, static void ipc_get_marks_callback(struct sway_container *con, void *data) { json_object *marks = (json_object *)data; - if (con->type == C_VIEW && con->sway_view->marks) { - for (int i = 0; i < con->sway_view->marks->length; ++i) { - char *mark = (char *)con->sway_view->marks->items[i]; + if (con->view && con->view->marks) { + for (int i = 0; i < con->view->marks->length; ++i) { + char *mark = (char *)con->view->marks->items[i]; json_object_array_add(marks, json_object_new_string(mark)); } } @@ -608,16 +600,14 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_OUTPUTS: { json_object *outputs = json_object_new_array(); - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *container = root_container.children->items[i]; - if (container->type == C_OUTPUT) { - json_object_array_add(outputs, - ipc_json_describe_container(container)); - } + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + json_object_array_add(outputs, + ipc_json_describe_node(&output->node)); } struct sway_output *output; - wl_list_for_each(output, &root_container.sway_root->all_outputs, link) { - if (!output->swayc) { + wl_list_for_each(output, &root->all_outputs, link) { + if (!output->enabled) { json_object_array_add(outputs, ipc_json_describe_disabled_output(output)); } @@ -717,8 +707,7 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_TREE: { - json_object *tree = - ipc_json_describe_container_recursive(&root_container); + json_object *tree = ipc_json_describe_node_recursive(&root->node); const char *json_string = json_object_to_json_string(tree); client_valid = ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); diff --git a/sway/main.c b/sway/main.c index 2f05dc383..fb4f0d8c0 100644 --- a/sway/main.c +++ b/sway/main.c @@ -42,7 +42,6 @@ void sway_terminate(int exit_code) { } void sig_handler(int signal) { - //close_views(&root_container); sway_terminate(EXIT_SUCCESS); } @@ -395,7 +394,7 @@ int main(int argc, char **argv) { wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION); - root_create(); + root = root_create(); if (!server_init(&server)) { return 1; @@ -450,7 +449,8 @@ int main(int argc, char **argv) { wlr_log(WLR_INFO, "Shutting down sway"); server_fini(&server); - root_destroy(); + root_destroy(root); + root = NULL; if (config) { free_config(config); diff --git a/sway/meson.build b/sway/meson.build index c14e58dd0..8891ebc0b 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -151,6 +151,7 @@ sway_sources = files( 'tree/arrange.c', 'tree/container.c', + 'tree/node.c', 'tree/root.c', 'tree/view.c', 'tree/workspace.c', diff --git a/sway/server.c b/sway/server.c index 749365cb8..09ebe83ff 100644 --- a/sway/server.c +++ b/sway/server.c @@ -61,8 +61,7 @@ bool server_init(struct sway_server *server) { server->new_output.notify = handle_new_output; wl_signal_add(&server->backend->events.new_output, &server->new_output); - wlr_xdg_output_manager_create(server->wl_display, - root_container.sway_root->output_layout); + wlr_xdg_output_manager_create(server->wl_display, root->output_layout); server->idle = wlr_idle_create(server->wl_display); server->idle_inhibit_manager_v1 = @@ -131,7 +130,7 @@ bool server_init(struct sway_server *server) { server->txn_timeout_ms = 200; } - server->dirty_containers = create_list(); + server->dirty_nodes = create_list(); server->transactions = create_list(); input_manager = input_manager_create(server); @@ -145,7 +144,7 @@ void server_fini(struct sway_server *server) { #endif wl_display_destroy_clients(server->wl_display); wl_display_destroy(server->wl_display); - list_free(server->dirty_containers); + list_free(server->dirty_nodes); list_free(server->transactions); } diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 92f20fccc..f86d4a743 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -166,29 +166,23 @@ void arrange_container(struct sway_container *container) { if (config->reloading) { return; } - if (container->type == C_VIEW) { - view_autoconfigure(container->sway_view); - container_set_dirty(container); - return; - } - if (!sway_assert(container->type == C_CONTAINER, "Expected a container")) { + if (container->view) { + view_autoconfigure(container->view); + node_set_dirty(&container->node); return; } struct wlr_box box; container_get_box(container, &box); arrange_children(container->children, container->layout, &box); - container_set_dirty(container); + node_set_dirty(&container->node); } -void arrange_workspace(struct sway_container *workspace) { +void arrange_workspace(struct sway_workspace *workspace) { if (config->reloading) { return; } - if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { - return; - } - struct sway_container *output = workspace->parent; - struct wlr_box *area = &output->sway_output->usable_area; + struct sway_output *output = workspace->output; + struct wlr_box *area = &output->usable_area; wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", area->width, area->height, area->x, area->y); workspace_remove_gaps(workspace); @@ -197,21 +191,20 @@ void arrange_workspace(struct sway_container *workspace) { double prev_y = workspace->y; workspace->width = area->width; workspace->height = area->height; - workspace->x = output->x + area->x; - workspace->y = output->y + area->y; + workspace->x = output->wlr_output->lx + area->x; + workspace->y = output->wlr_output->ly + area->y; // Adjust any floating containers double diff_x = workspace->x - prev_x; double diff_y = workspace->y - prev_y; if (diff_x != 0 || diff_y != 0) { - for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) { - struct sway_container *floater = - workspace->sway_workspace->floating->items[i]; + for (int i = 0; i < workspace->floating->length; ++i) { + struct sway_container *floater = workspace->floating->items[i]; container_floating_translate(floater, diff_x, diff_y); double center_x = floater->x + floater->width / 2; double center_y = floater->y + floater->height / 2; struct wlr_box workspace_box; - container_get_box(workspace, &workspace_box); + workspace_get_box(workspace, &workspace_box); if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { container_floating_move_to_center(floater); } @@ -219,43 +212,32 @@ void arrange_workspace(struct sway_container *workspace) { } workspace_add_gaps(workspace); - container_set_dirty(workspace); + node_set_dirty(&workspace->node); wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, workspace->x, workspace->y); - if (workspace->sway_workspace->fullscreen) { - struct sway_container *fs = workspace->sway_workspace->fullscreen; - fs->x = workspace->parent->x; - fs->y = workspace->parent->y; - fs->width = workspace->parent->width; - fs->height = workspace->parent->height; + if (workspace->fullscreen) { + struct sway_container *fs = workspace->fullscreen; + fs->x = output->wlr_output->lx; + fs->y = output->wlr_output->ly; + fs->width = output->wlr_output->width; + fs->height = output->wlr_output->height; arrange_container(fs); } else { struct wlr_box box; - container_get_box(workspace, &box); - arrange_children(workspace->children, workspace->layout, &box); - arrange_floating(workspace->sway_workspace->floating); + workspace_get_box(workspace, &box); + arrange_children(workspace->tiling, workspace->layout, &box); + arrange_floating(workspace->floating); } } -void arrange_output(struct sway_container *output) { +void arrange_output(struct sway_output *output) { if (config->reloading) { return; } - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return; - } - const struct wlr_box *output_box = wlr_output_layout_get_box( - root_container.sway_root->output_layout, - output->sway_output->wlr_output); - output->x = output_box->x; - output->y = output_box->y; - output->width = output_box->width; - output->height = output_box->height; - container_set_dirty(output); - wlr_log(WLR_DEBUG, "Arranging output '%s' at %f,%f", - output->name, output->x, output->y); - for (int i = 0; i < output->children->length; ++i) { - struct sway_container *workspace = output->children->items[i]; + // Outputs have no pending x/y/width/height, + // so all we do here is arrange the workspaces. + for (int i = 0; i < output->workspaces->length; ++i) { + struct sway_workspace *workspace = output->workspaces->items[i]; arrange_workspace(workspace); } } @@ -264,37 +246,31 @@ void arrange_root(void) { if (config->reloading) { return; } - struct wlr_output_layout *output_layout = - root_container.sway_root->output_layout; const struct wlr_box *layout_box = - wlr_output_layout_get_box(output_layout, NULL); - root_container.x = layout_box->x; - root_container.y = layout_box->y; - root_container.width = layout_box->width; - root_container.height = layout_box->height; - container_set_dirty(&root_container); - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; + wlr_output_layout_get_box(root->output_layout, NULL); + root->x = layout_box->x; + root->y = layout_box->y; + root->width = layout_box->width; + root->height = layout_box->height; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; arrange_output(output); } } -void arrange_windows(struct sway_container *container) { - switch (container->type) { - case C_ROOT: +void arrange_node(struct sway_node *node) { + switch (node->type) { + case N_ROOT: arrange_root(); break; - case C_OUTPUT: - arrange_output(container); + case N_OUTPUT: + arrange_output(node->sway_output); break; - case C_WORKSPACE: - arrange_workspace(container); + case N_WORKSPACE: + arrange_workspace(node->sway_workspace); break; - case C_CONTAINER: - case C_VIEW: - arrange_container(container); - break; - case C_TYPES: + case N_CONTAINER: + arrange_container(node->sway_container); break; } } diff --git a/sway/tree/container.c b/sway/tree/container.c index 520b45667..0cb8d0a51 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -24,97 +24,39 @@ #include "log.h" #include "stringop.h" -const char *container_type_to_str(enum sway_container_type type) { - switch (type) { - case C_ROOT: - return "C_ROOT"; - case C_OUTPUT: - return "C_OUTPUT"; - case C_WORKSPACE: - return "C_WORKSPACE"; - case C_CONTAINER: - return "C_CONTAINER"; - case C_VIEW: - return "C_VIEW"; - default: - return "C_UNKNOWN"; - } -} - -void container_create_notify(struct sway_container *container) { - if (container->type == C_VIEW) { - ipc_event_window(container, "new"); - } else if (container->type == C_WORKSPACE) { - ipc_event_workspace(NULL, container, "init"); - } - wl_signal_emit(&root_container.sway_root->events.new_container, container); -} - -void container_update_textures_recursive(struct sway_container *con) { - if (con->type == C_CONTAINER || con->type == C_VIEW) { - container_update_title_textures(con); - } - - if (con->type == C_VIEW) { - view_update_marks_textures(con->sway_view); - } else { - for (int i = 0; i < con->children->length; ++i) { - struct sway_container *child = con->children->items[i]; - container_update_textures_recursive(child); - } - - if (con->type == C_WORKSPACE) { - for (int i = 0; i < con->sway_workspace->floating->length; ++i) { - struct sway_container *floater = - con->sway_workspace->floating->items[i]; - container_update_textures_recursive(floater); - } - } - } -} - -struct sway_container *container_create(enum sway_container_type type) { - // next id starts at 1 because 0 is assigned to root_container in layout.c - static size_t next_id = 1; +struct sway_container *container_create(struct sway_view *view) { struct sway_container *c = calloc(1, sizeof(struct sway_container)); if (!c) { + wlr_log(WLR_ERROR, "Unable to allocate sway_container"); return NULL; } - c->id = next_id++; + node_init(&c->node, N_CONTAINER, c); c->layout = L_NONE; - c->type = type; + c->view = view; c->alpha = 1.0f; - if (type != C_VIEW) { + if (!view) { c->children = create_list(); c->current.children = create_list(); } c->outputs = create_list(); wl_signal_init(&c->events.destroy); - - c->has_gaps = false; - c->gaps_inner = 0; - c->gaps_outer = 0; - c->current_gaps = 0; + wl_signal_emit(&root->events.new_node, &c->node); return c; } void container_destroy(struct sway_container *con) { - if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, - "Expected a container or view")) { - return; - } - if (!sway_assert(con->destroying, + if (!sway_assert(con->node.destroying, "Tried to free container which wasn't marked as destroying")) { return; } - if (!sway_assert(con->ntxnrefs == 0, "Tried to free container " + if (!sway_assert(con->node.ntxnrefs == 0, "Tried to free container " "which is still referenced by transactions")) { return; } - free(con->name); + free(con->title); free(con->formatted_title); wlr_texture_destroy(con->title_focused); wlr_texture_destroy(con->title_focused_inactive); @@ -124,14 +66,14 @@ void container_destroy(struct sway_container *con) { list_free(con->current.children); list_free(con->outputs); - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; - view->swayc = NULL; + if (con->view) { + struct sway_view *view = con->view; + view->container = NULL; free(view->title_format); view->title_format = NULL; if (view->destroying) { - view_destroy(view); + view_destroy(con->view); } } @@ -139,115 +81,57 @@ void container_destroy(struct sway_container *con) { } void container_begin_destroy(struct sway_container *con) { - if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, - "Expected a container or view")) { - return; - } - - if (con->type == C_VIEW) { + if (con->view) { ipc_event_window(con, "close"); } - wl_signal_emit(&con->events.destroy, con); + wl_signal_emit(&con->node.events.destroy, &con->node); container_end_mouse_operation(con); - con->destroying = true; - container_set_dirty(con); + con->node.destroying = true; + node_set_dirty(&con->node); if (con->scratchpad) { root_scratchpad_remove_container(con); } - if (con->parent) { - container_remove_child(con); + if (con->parent || con->workspace) { + container_detach(con); } } -struct sway_container *container_reap_empty(struct sway_container *con) { - while (con && con->type == C_CONTAINER) { - struct sway_container *next = con->parent; - if (con->children->length == 0) { - container_begin_destroy(con); - } - con = next; +void container_reap_empty(struct sway_container *con) { + if (con->view) { + return; } - if (con && con->type == C_WORKSPACE) { - workspace_consider_destroy(con); - if (con->destroying) { - con = con->parent; + struct sway_workspace *ws = con->workspace; + while (con) { + if (con->children->length) { + return; } + struct sway_container *parent = con->parent; + container_begin_destroy(con); + con = parent; } - return con; + workspace_consider_destroy(ws); } struct sway_container *container_flatten(struct sway_container *container) { - while (container->type == C_CONTAINER && container->children->length == 1) { + if (container->view) { + return NULL; + } + while (container && container->children->length == 1) { struct sway_container *child = container->children->items[0]; struct sway_container *parent = container->parent; - container_replace_child(container, child); + container_replace(container, child); container_begin_destroy(container); container = parent; } return container; } -static void container_close_func(struct sway_container *container, void *data) { - if (container->type == C_VIEW) { - view_close(container->sway_view); - } -} - -struct sway_container *container_close(struct sway_container *con) { - if (!sway_assert(con != NULL, - "container_close called with a NULL container")) { - return NULL; - } - - struct sway_container *parent = con->parent; - - if (con->type == C_VIEW) { - view_close(con->sway_view); - } else if (con->type == C_CONTAINER) { - container_for_each_child(con, container_close_func, NULL); - } else if (con->type == C_WORKSPACE) { - workspace_for_each_container(con, container_close_func, NULL); - } - - return parent; -} - -struct sway_container *container_view_create(struct sway_container *sibling, - struct sway_view *sway_view) { - if (!sway_assert(sibling, - "container_view_create called with NULL sibling/parent")) { - return NULL; - } - const char *title = view_get_title(sway_view); - struct sway_container *swayc = container_create(C_VIEW); - wlr_log(WLR_DEBUG, "Adding new view %p:%s to container %p %d %s", - swayc, title, sibling, sibling ? sibling->type : 0, sibling->name); - // Setup values - swayc->sway_view = sway_view; - swayc->width = 0; - swayc->height = 0; - - if (sibling->type == C_WORKSPACE) { - // Case of focused workspace, just create as child of it - container_add_child(sibling, swayc); - } else { - // Regular case, create as sibling of current container - container_add_sibling(sibling, swayc); - } - container_create_notify(swayc); - return swayc; -} - struct sway_container *container_find_child(struct sway_container *container, - bool (*test)(struct sway_container *view, void *data), void *data) { - if (!sway_assert(container->type == C_CONTAINER || - container->type == C_VIEW, "Expected a container or view")) { - return NULL; - } + bool (*test)(struct sway_container *con, void *data), void *data) { if (!container->children) { return NULL; } @@ -264,46 +148,32 @@ struct sway_container *container_find_child(struct sway_container *container, return NULL; } -struct sway_container *container_parent(struct sway_container *container, - enum sway_container_type type) { - if (!sway_assert(container, "container is NULL")) { - return NULL; - } - if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) { - return NULL; - } - do { - container = container->parent; - } while (container && container->type != type); - return container; -} - -static void surface_at_view(struct sway_container *swayc, double lx, double ly, +static void surface_at_view(struct sway_container *con, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { + if (!sway_assert(con->view, "Expected a view")) { return; } - struct sway_view *sview = swayc->sway_view; - double view_sx = lx - sview->x + sview->geometry.x; - double view_sy = ly - sview->y + sview->geometry.y; + struct sway_view *view = con->view; + double view_sx = lx - view->x + view->geometry.x; + double view_sy = ly - view->y + view->geometry.y; double _sx, _sy; struct wlr_surface *_surface = NULL; - switch (sview->type) { + switch (view->type) { #ifdef HAVE_XWAYLAND case SWAY_VIEW_XWAYLAND: - _surface = wlr_surface_surface_at(sview->surface, + _surface = wlr_surface_surface_at(view->surface, view_sx, view_sy, &_sx, &_sy); break; #endif case SWAY_VIEW_XDG_SHELL_V6: _surface = wlr_xdg_surface_v6_surface_at( - sview->wlr_xdg_surface_v6, + view->wlr_xdg_surface_v6, view_sx, view_sy, &_sx, &_sy); break; case SWAY_VIEW_XDG_SHELL: _surface = wlr_xdg_surface_surface_at( - sview->wlr_xdg_surface, + view->wlr_xdg_surface, view_sx, view_sy, &_sx, &_sy); break; } @@ -317,65 +187,72 @@ static void surface_at_view(struct sway_container *swayc, double lx, double ly, /** * container_at for a container with layout L_TABBED. */ -static struct sway_container *container_at_tabbed(struct sway_container *parent, +static struct sway_container *container_at_tabbed(struct sway_node *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - if (ly < parent->y || ly > parent->y + parent->height) { + struct wlr_box box; + node_get_box(parent, &box); + if (ly < box.y || ly > box.y + box.height) { return NULL; } struct sway_seat *seat = input_manager_current_seat(input_manager); + list_t *children = node_get_children(parent); // Tab titles int title_height = container_titlebar_height(); - if (ly < parent->y + title_height) { - int tab_width = parent->width / parent->children->length; - int child_index = (lx - parent->x) / tab_width; - if (child_index >= parent->children->length) { - child_index = parent->children->length - 1; + if (ly < box.y + title_height) { + int tab_width = box.width / children->length; + int child_index = (lx - box.x) / tab_width; + if (child_index >= children->length) { + child_index = children->length - 1; } - struct sway_container *child = parent->children->items[child_index]; - return seat_get_focus_inactive(seat, child); + struct sway_container *child = children->items[child_index]; + struct sway_node *node = seat_get_focus_inactive(seat, &child->node); + return node->sway_container; } // Surfaces - struct sway_container *current = seat_get_active_child(seat, parent); - + struct sway_node *current = seat_get_active_child(seat, parent); return tiling_container_at(current, lx, ly, surface, sx, sy); } /** * container_at for a container with layout L_STACKED. */ -static struct sway_container *container_at_stacked( - struct sway_container *parent, double lx, double ly, +static struct sway_container *container_at_stacked(struct sway_node *parent, + double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - if (ly < parent->y || ly > parent->y + parent->height) { + struct wlr_box box; + node_get_box(parent, &box); + if (ly < box.y || ly > box.y + box.height) { return NULL; } struct sway_seat *seat = input_manager_current_seat(input_manager); + list_t *children = node_get_children(parent); // Title bars int title_height = container_titlebar_height(); - int child_index = (ly - parent->y) / title_height; - if (child_index < parent->children->length) { - struct sway_container *child = parent->children->items[child_index]; - return seat_get_focus_inactive(seat, child); + int child_index = (ly - box.y) / title_height; + if (child_index < children->length) { + struct sway_container *child = children->items[child_index]; + struct sway_node *node = seat_get_focus_inactive(seat, &child->node); + return node->sway_container; } // Surfaces - struct sway_container *current = seat_get_active_child(seat, parent); - + struct sway_node *current = seat_get_active_child(seat, parent); return tiling_container_at(current, lx, ly, surface, sx, sy); } /** * container_at for a container with layout L_HORIZ or L_VERT. */ -static struct sway_container *container_at_linear(struct sway_container *parent, +static struct sway_container *container_at_linear(struct sway_node *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - for (int i = 0; i < parent->children->length; ++i) { - struct sway_container *child = parent->children->items[i]; + list_t *children = node_get_children(parent); + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; struct wlr_box box = { .x = child->x, .y = child->y, @@ -383,7 +260,7 @@ static struct sway_container *container_at_linear(struct sway_container *parent, .height = child->height, }; if (wlr_box_contains_point(&box, lx, ly)) { - return tiling_container_at(child, lx, ly, surface, sx, sy); + return tiling_container_at(&child->node, lx, ly, surface, sx, sy); } } return NULL; @@ -391,12 +268,11 @@ static struct sway_container *container_at_linear(struct sway_container *parent, static struct sway_container *floating_container_at(double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - for (int j = 0; j < output->children->length; ++j) { - struct sway_container *workspace = output->children->items[j]; - struct sway_workspace *ws = workspace->sway_workspace; - if (!workspace_is_visible(workspace)) { + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + for (int j = 0; j < output->workspaces->length; ++j) { + struct sway_workspace *ws = output->workspaces->items[j]; + if (!workspace_is_visible(ws)) { continue; } // Items at the end of the list are on top, so iterate the list in @@ -410,7 +286,7 @@ static struct sway_container *floating_container_at(double lx, double ly, .height = floater->height, }; if (wlr_box_contains_point(&box, lx, ly)) { - return tiling_container_at(floater, lx, ly, + return tiling_container_at(&floater->node, lx, ly, surface, sx, sy); } } @@ -419,25 +295,24 @@ static struct sway_container *floating_container_at(double lx, double ly, return NULL; } -struct sway_container *tiling_container_at( - struct sway_container *con, double lx, double ly, +struct sway_container *tiling_container_at(struct sway_node *parent, + double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - if (con->type == C_VIEW) { - surface_at_view(con, lx, ly, surface, sx, sy); - return con; + if (node_is_view(parent)) { + surface_at_view(parent->sway_container, lx, ly, surface, sx, sy); + return parent->sway_container; } - if (!con->children->length) { + if (!node_get_children(parent)) { return NULL; } - - switch (con->layout) { + switch (node_get_layout(parent)) { case L_HORIZ: case L_VERT: - return container_at_linear(con, lx, ly, surface, sx, sy); + return container_at_linear(parent, lx, ly, surface, sx, sy); case L_TABBED: - return container_at_tabbed(con, lx, ly, surface, sx, sy); + return container_at_tabbed(parent, lx, ly, surface, sx, sy); case L_STACKED: - return container_at_stacked(con, lx, ly, surface, sx, sy); + return container_at_stacked(parent, lx, ly, surface, sx, sy); case L_NONE: return NULL; } @@ -472,19 +347,16 @@ static bool surface_is_popup(struct wlr_surface *surface) { return false; } -struct sway_container *container_at(struct sway_container *workspace, +struct sway_container *container_at(struct sway_workspace *workspace, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { - return NULL; - } struct sway_container *c; + // Focused view's popups struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = - seat_get_focus_inactive(seat, &root_container); + struct sway_container *focus = seat_get_focused_container(seat); bool is_floating = focus && container_is_floating_or_child(focus); // Focused view's popups - if (focus && focus->type == C_VIEW) { + if (focus && focus->view) { surface_at_view(focus, lx, ly, surface, sx, sy); if (*surface && surface_is_popup(*surface)) { return focus; @@ -492,7 +364,7 @@ struct sway_container *container_at(struct sway_container *workspace, *surface = NULL; } // If focused is floating, focused view's non-popups - if (focus && focus->type == C_VIEW && is_floating) { + if (focus && focus->view && is_floating) { surface_at_view(focus, lx, ly, surface, sx, sy); if (*surface) { return focus; @@ -504,7 +376,7 @@ struct sway_container *container_at(struct sway_container *workspace, return c; } // If focused is tiling, focused view's non-popups - if (focus && focus->type == C_VIEW && !is_floating) { + if (focus && focus->view && !is_floating) { surface_at_view(focus, lx, ly, surface, sx, sy); if (*surface) { return focus; @@ -512,7 +384,7 @@ struct sway_container *container_at(struct sway_container *workspace, *surface = NULL; } // Tiling (non-focused) - if ((c = tiling_container_at(workspace, lx, ly, surface, sx, sy))) { + if ((c = tiling_container_at(&workspace->node, lx, ly, surface, sx, sy))) { return c; } return NULL; @@ -521,10 +393,6 @@ struct sway_container *container_at(struct sway_container *workspace, void container_for_each_child(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data) { - if (!sway_assert(container->type == C_CONTAINER || - container->type == C_VIEW, "Expected a container or view")) { - return; - } if (container->children) { for (int i = 0; i < container->children->length; ++i) { struct sway_container *child = container->children->items[i]; @@ -536,7 +404,7 @@ void container_for_each_child(struct sway_container *container, bool container_has_ancestor(struct sway_container *descendant, struct sway_container *ancestor) { - while (descendant && descendant->type != C_ROOT) { + while (descendant) { descendant = descendant->parent; if (descendant == ancestor) { return true; @@ -545,27 +413,10 @@ bool container_has_ancestor(struct sway_container *descendant, return false; } -int container_count_descendants_of_type(struct sway_container *con, - enum sway_container_type type) { - int children = 0; - if (con->type == type) { - children++; - } - if (con->children) { - for (int i = 0; i < con->children->length; i++) { - struct sway_container *child = con->children->items[i]; - children += container_count_descendants_of_type(child, type); - } - } - return children; -} - void container_damage_whole(struct sway_container *container) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT) { - output_damage_whole_container(cont->sway_output, container); - } + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_whole_container(output, container); } } @@ -582,10 +433,6 @@ struct sway_output *container_get_effective_output(struct sway_container *con) { static void update_title_texture(struct sway_container *con, struct wlr_texture **texture, struct border_colors *class) { - if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, - "Unexpected type %s", container_type_to_str(con->type))) { - return; - } struct sway_output *output = container_get_effective_output(con); if (!output) { return; @@ -664,9 +511,10 @@ void container_calculate_title_height(struct sway_container *container) { * An example tree representation is: V[Terminal, Firefox] * If buffer is not NULL, also populate the buffer with the representation. */ -static size_t get_tree_representation(struct sway_container *parent, char *buffer) { +size_t container_build_representation(enum sway_container_layout layout, + list_t *children, char *buffer) { size_t len = 2; - switch (parent->layout) { + switch (layout) { case L_VERT: lenient_strcat(buffer, "V["); break; @@ -683,17 +531,17 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe lenient_strcat(buffer, "D["); break; } - for (int i = 0; i < parent->children->length; ++i) { + for (int i = 0; i < children->length; ++i) { if (i != 0) { ++len; lenient_strcat(buffer, " "); } - struct sway_container *child = parent->children->items[i]; + struct sway_container *child = children->items[i]; const char *identifier = NULL; - if (child->type == C_VIEW) { - identifier = view_get_class(child->sway_view); + if (child->view) { + identifier = view_get_class(child->view); if (!identifier) { - identifier = view_get_app_id(child->sway_view); + identifier = view_get_app_id(child->view); } } else { identifier = child->formatted_title; @@ -711,25 +559,25 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe return len; } -void container_notify_subtree_changed(struct sway_container *container) { - if (!container || container->type < C_WORKSPACE) { - return; +void container_update_representation(struct sway_container *con) { + if (!con->view) { + size_t len = container_build_representation(con->layout, + con->children, NULL); + free(con->formatted_title); + con->formatted_title = calloc(len + 1, sizeof(char)); + if (!sway_assert(con->formatted_title, + "Unable to allocate title string")) { + return; + } + container_build_representation(con->layout, con->children, + con->formatted_title); + container_calculate_title_height(con); + container_update_title_textures(con); } - free(container->formatted_title); - container->formatted_title = NULL; - - size_t len = get_tree_representation(container, NULL); - char *buffer = calloc(len + 1, sizeof(char)); - if (!sway_assert(buffer, "Unable to allocate title string")) { - return; - } - get_tree_representation(container, buffer); - - container->formatted_title = buffer; - if (container->type != C_WORKSPACE) { - container_calculate_title_height(container); - container_update_title_textures(container); - container_notify_subtree_changed(container->parent); + if (con->parent) { + container_update_representation(con->parent); + } else if (con->workspace) { + workspace_update_representation(con->workspace); } } @@ -738,11 +586,7 @@ size_t container_titlebar_height() { } void container_init_floating(struct sway_container *con) { - if (!sway_assert(con->type == C_VIEW || con->type == C_CONTAINER, - "Expected a view or container")) { - return; - } - struct sway_container *ws = container_parent(con, C_WORKSPACE); + struct sway_workspace *ws = con->workspace; int min_width, min_height; int max_width, max_height; @@ -778,13 +622,13 @@ void container_init_floating(struct sway_container *con) { max_height = config->floating_maximum_height; } - if (con->type == C_CONTAINER) { + if (!con->view) { con->width = max_width; con->height = max_height; con->x = ws->x + (ws->width - con->width) / 2; con->y = ws->y + (ws->height - con->height) / 2; } else { - struct sway_view *view = con->sway_view; + struct sway_view *view = con->view; view->width = fmax(min_width, fmin(view->natural_width, max_width)); view->height = fmax(min_height, fmin(view->natural_height, max_height)); view->x = ws->x + (ws->width - view->width) / 2; @@ -794,7 +638,7 @@ void container_init_floating(struct sway_container *con) { view->border_top = view->border_bottom = true; view->border_left = view->border_right = true; - container_set_geometry_from_floating_view(view->swayc); + container_set_geometry_from_floating_view(con); } } @@ -804,32 +648,41 @@ void container_set_floating(struct sway_container *container, bool enable) { } struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *workspace = container_parent(container, C_WORKSPACE); + struct sway_workspace *workspace = container->workspace; if (enable) { - struct sway_container *old_parent = container_remove_child(container); + struct sway_container *old_parent = container->parent; + container_detach(container); workspace_add_floating(workspace, container); container_init_floating(container); - if (container->type == C_VIEW) { - view_set_tiled(container->sway_view, false); + if (container->view) { + view_set_tiled(container->view, false); + } + if (old_parent) { + container_reap_empty(old_parent); } - container_reap_empty(old_parent); } else { // Returning to tiled if (container->scratchpad) { root_scratchpad_remove_container(container); } - container_remove_child(container); + container_detach(container); struct sway_container *reference = seat_get_focus_inactive_tiling(seat, workspace); - if (reference->type == C_VIEW) { + if (reference && reference->view) { reference = reference->parent; } - container_add_child(reference, container); - container->width = container->parent->width; - container->height = container->parent->height; - if (container->type == C_VIEW) { - view_set_tiled(container->sway_view, true); + if (reference) { + container_add_child(reference, container); + container->width = reference->width; + container->height = reference->height; + } else { + workspace_add_tiling(workspace, container); + container->width = workspace->width; + container->height = workspace->height; + } + if (container->view) { + view_set_tiled(container->view, true); } container->is_sticky = false; } @@ -840,14 +693,13 @@ void container_set_floating(struct sway_container *container, bool enable) { } void container_set_geometry_from_floating_view(struct sway_container *con) { - if (!sway_assert(con->type == C_VIEW, "Expected a view")) { + if (!sway_assert(con->view, "Expected a view")) { return; } - if (!sway_assert(container_is_floating(con), - "Expected a floating view")) { + if (!sway_assert(container_is_floating(con), "Expected a floating view")) { return; } - struct sway_view *view = con->sway_view; + struct sway_view *view = con->view; size_t border_width = 0; size_t top = 0; @@ -861,12 +713,12 @@ void container_set_geometry_from_floating_view(struct sway_container *con) { con->y = view->y - top; con->width = view->width + border_width * 2; con->height = top + view->height + border_width; - container_set_dirty(con); + node_set_dirty(&con->node); } bool container_is_floating(struct sway_container *container) { - return container->parent && container->parent->type == C_WORKSPACE && - list_find(container->parent->sway_workspace->floating, container) != -1; + return !container->parent && container->workspace && + list_find(container->workspace->floating, container) != -1; } void container_get_box(struct sway_container *container, struct wlr_box *box) { @@ -883,16 +735,16 @@ void container_floating_translate(struct sway_container *con, double x_amount, double y_amount) { con->x += x_amount; con->y += y_amount; - if (con->type == C_VIEW) { - con->sway_view->x += x_amount; - con->sway_view->y += y_amount; + if (con->view) { + con->view->x += x_amount; + con->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); + node_set_dirty(&con->node); } /** @@ -902,17 +754,16 @@ void container_floating_translate(struct sway_container *con, * one, otherwise we'll choose whichever output is closest to the container's * center. */ -struct sway_container *container_floating_find_output( - struct sway_container *con) { +struct sway_output *container_floating_find_output(struct sway_container *con) { double center_x = con->x + con->width / 2; double center_y = con->y + con->height / 2; - struct sway_container *closest_output = NULL; + struct sway_output *closest_output = NULL; double closest_distance = DBL_MAX; - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; struct wlr_box output_box; double closest_x, closest_y; - container_get_box(output, &output_box); + output_get_box(output, &output_box); wlr_box_closest_point(&output_box, center_x, center_y, &closest_x, &closest_y); if (center_x == closest_x && center_y == closest_y) { @@ -937,18 +788,18 @@ void container_floating_move_to(struct sway_container *con, return; } container_floating_translate(con, lx - con->x, ly - con->y); - struct sway_container *old_workspace = container_parent(con, C_WORKSPACE); - struct sway_container *new_output = container_floating_find_output(con); + struct sway_workspace *old_workspace = con->workspace; + struct sway_output *new_output = container_floating_find_output(con); if (!sway_assert(new_output, "Unable to find any output")) { return; } - struct sway_container *new_workspace = - output_get_active_workspace(new_output->sway_output); + struct sway_workspace *new_workspace = + output_get_active_workspace(new_output); if (old_workspace != new_workspace) { - container_remove_child(con); + container_detach(con); workspace_add_floating(new_workspace, con); - arrange_windows(old_workspace); - arrange_windows(new_workspace); + arrange_workspace(old_workspace); + arrange_workspace(new_workspace); workspace_detect_urgent(old_workspace); workspace_detect_urgent(new_workspace); } @@ -959,22 +810,14 @@ void container_floating_move_to_center(struct sway_container *con) { "Expected a floating container")) { return; } - struct sway_container *ws = container_parent(con, C_WORKSPACE); + struct sway_workspace *ws = con->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; - } - container->dirty = true; - list_add(server.dirty_containers, container); -} - static bool find_urgent_iterator(struct sway_container *con, void *data) { - return con->type == C_VIEW && view_is_urgent(con->sway_view); + return con->view && view_is_urgent(con->view); } bool container_has_urgent_child(struct sway_container *container) { @@ -991,12 +834,12 @@ void container_end_mouse_operation(struct sway_container *container) { } static void set_fullscreen_iterator(struct sway_container *con, void *data) { - if (con->type != C_VIEW) { + if (!con->view) { return; } - if (con->sway_view->impl->set_fullscreen) { + if (con->view->impl->set_fullscreen) { bool *enable = data; - con->sway_view->impl->set_fullscreen(con->sway_view, *enable); + con->view->impl->set_fullscreen(con->view, *enable); } } @@ -1005,9 +848,9 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { return; } - struct sway_container *workspace = container_parent(container, C_WORKSPACE); - if (enable && workspace->sway_workspace->fullscreen) { - container_set_fullscreen(workspace->sway_workspace->fullscreen, false); + struct sway_workspace *workspace = container->workspace; + if (enable && workspace->fullscreen) { + container_set_fullscreen(workspace->fullscreen, false); } set_fullscreen_iterator(container, &enable); @@ -1016,36 +859,32 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { container->is_fullscreen = enable; if (enable) { - workspace->sway_workspace->fullscreen = container; + workspace->fullscreen = container; container->saved_x = container->x; container->saved_y = container->y; container->saved_width = container->width; container->saved_height = container->height; struct sway_seat *seat; - struct sway_container *focus, *focus_ws; + struct sway_workspace *focus_ws; wl_list_for_each(seat, &input_manager->seats, link) { - focus = seat_get_focus(seat); - if (focus) { - focus_ws = focus; - if (focus_ws->type != C_WORKSPACE) { - focus_ws = container_parent(focus_ws, C_WORKSPACE); - } + focus_ws = seat_get_focused_workspace(seat); + if (focus_ws) { if (focus_ws == workspace) { - seat_set_focus(seat, container); + seat_set_focus(seat, &container->node); } } } } else { - workspace->sway_workspace->fullscreen = NULL; + workspace->fullscreen = NULL; if (container_is_floating(container)) { container->x = container->saved_x; container->y = container->saved_y; container->width = container->saved_width; container->height = container->saved_height; - struct sway_container *output = + struct sway_output *output = container_floating_find_output(container); - if (!container_has_ancestor(container, output)) { + if (workspace->output != output) { container_floating_move_to_center(container); } } else { @@ -1060,7 +899,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { } bool container_is_floating_or_child(struct sway_container *container) { - while (container->parent && container->parent->type != C_WORKSPACE) { + while (container->parent) { container = container->parent; } return container_is_floating(container); @@ -1072,7 +911,7 @@ bool container_is_fullscreen_or_child(struct sway_container *container) { return true; } container = container->parent; - } while (container && container->type != C_WORKSPACE); + } while (container); return false; } @@ -1090,42 +929,37 @@ static void surface_send_leave_iterator(struct wlr_surface *surface, } void container_discover_outputs(struct sway_container *con) { - if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, - "Expected a container or view")) { - return; - } struct wlr_box con_box = { - .x = con->current.swayc_x, - .y = con->current.swayc_y, - .width = con->current.swayc_width, - .height = con->current.swayc_height, + .x = con->current.con_x, + .y = con->current.con_y, + .width = con->current.con_width, + .height = con->current.con_height, }; struct sway_output *old_output = container_get_effective_output(con); - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - struct sway_output *sway_output = output->sway_output; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; struct wlr_box output_box; - container_get_box(output, &output_box); + output_get_box(output, &output_box); struct wlr_box intersection; bool intersects = wlr_box_intersection(&con_box, &output_box, &intersection); - int index = list_find(con->outputs, sway_output); + int index = list_find(con->outputs, output); if (intersects && index == -1) { // Send enter - wlr_log(WLR_DEBUG, "Con %p entered output %p", con, sway_output); - if (con->type == C_VIEW) { - view_for_each_surface(con->sway_view, - surface_send_enter_iterator, sway_output->wlr_output); + wlr_log(WLR_DEBUG, "Container %p entered output %p", con, output); + if (con->view) { + view_for_each_surface(con->view, + surface_send_enter_iterator, output->wlr_output); } - list_add(con->outputs, sway_output); + list_add(con->outputs, output); } else if (!intersects && index != -1) { // Send leave - wlr_log(WLR_DEBUG, "Con %p left output %p", con, sway_output); - if (con->type == C_VIEW) { - view_for_each_surface(con->sway_view, - surface_send_leave_iterator, sway_output->wlr_output); + wlr_log(WLR_DEBUG, "Container %p left output %p", con, output); + if (con->view) { + view_for_each_surface(con->view, + surface_send_leave_iterator, output->wlr_output); } list_del(con->outputs, index); } @@ -1135,17 +969,13 @@ void container_discover_outputs(struct sway_container *con) { double new_scale = new_output ? new_output->wlr_output->scale : -1; if (old_scale != new_scale) { container_update_title_textures(con); - if (con->type == C_VIEW) { - view_update_marks_textures(con->sway_view); + if (con->view) { + view_update_marks_textures(con->view); } } } void container_remove_gaps(struct sway_container *c) { - if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW, - "Expected a container or view")) { - return; - } if (c->current_gaps == 0) { return; } @@ -1158,25 +988,20 @@ void container_remove_gaps(struct sway_container *c) { } void container_add_gaps(struct sway_container *c) { - if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW, - "Expected a container or view")) { - return; - } if (c->current_gaps > 0) { return; } // Linear containers don't have gaps because it'd create double gaps - if (c->type == C_CONTAINER && - c->layout != L_TABBED && c->layout != L_STACKED) { + if (!c->view && c->layout != L_TABBED && c->layout != L_STACKED) { return; } // Children of tabbed/stacked containers re-use the gaps of the container - enum sway_container_layout layout = c->parent->layout; + enum sway_container_layout layout = container_parent_layout(c); if (layout == L_TABBED || layout == L_STACKED) { return; } - struct sway_container *ws = container_parent(c, C_WORKSPACE); + struct sway_workspace *ws = c->workspace; c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner; c->x += c->current_gaps; @@ -1185,222 +1010,154 @@ void container_add_gaps(struct sway_container *c) { c->height -= 2 * c->current_gaps; } -int container_sibling_index(const struct sway_container *child) { - return list_find(child->parent->children, child); +enum sway_container_layout container_parent_layout(struct sway_container *con) { + if (con->parent) { + return con->parent->layout; + } + return con->workspace->layout; } -void container_handle_fullscreen_reparent(struct sway_container *con, - struct sway_container *old_parent) { - if (!con->is_fullscreen) { +enum sway_container_layout container_current_parent_layout( + struct sway_container *con) { + if (con->current.parent) { + return con->current.parent->current.layout; + } + return con->current.workspace->current.layout; +} + +list_t *container_get_siblings(const struct sway_container *container) { + if (container->parent) { + return container->parent->children; + } + if (!container->workspace) { + return NULL; + } + if (list_find(container->workspace->tiling, container) != -1) { + return container->workspace->tiling; + } + return container->workspace->floating; +} + +int container_sibling_index(const struct sway_container *child) { + return list_find(container_get_siblings(child), child); +} + +list_t *container_get_current_siblings(struct sway_container *container) { + if (container->current.parent) { + return container->current.parent->current.children; + } + return container->current.workspace->current.tiling; +} + +void container_handle_fullscreen_reparent(struct sway_container *con) { + if (!con->is_fullscreen || con->workspace->fullscreen == con) { return; } - struct sway_container *old_workspace = old_parent; - if (old_workspace && old_workspace->type != C_WORKSPACE) { - old_workspace = container_parent(old_workspace, C_WORKSPACE); - } - struct sway_container *new_workspace = container_parent(con, C_WORKSPACE); - if (old_workspace == new_workspace) { - return; - } - // Unmark the old workspace as fullscreen - if (old_workspace) { - old_workspace->sway_workspace->fullscreen = NULL; + if (con->workspace->fullscreen) { + container_set_fullscreen(con->workspace->fullscreen, false); } + con->workspace->fullscreen = con; - // Mark the new workspace as fullscreen - if (new_workspace->sway_workspace->fullscreen) { - container_set_fullscreen( - new_workspace->sway_workspace->fullscreen, false); - } - new_workspace->sway_workspace->fullscreen = con; + arrange_workspace(con->workspace); +} - // Resize container to new output dimensions - struct sway_container *output = new_workspace->parent; - con->x = output->x; - con->y = output->y; - con->width = output->width; - con->height = output->height; - - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; - view->x = output->x; - view->y = output->y; - view->width = output->width; - view->height = output->height; - } else { - arrange_windows(new_workspace); - } +static void set_workspace(struct sway_container *container, void *data) { + container->workspace = container->parent->workspace; } void container_insert_child(struct sway_container *parent, struct sway_container *child, int i) { - struct sway_container *old_parent = child->parent; - if (old_parent) { - container_remove_child(child); + if (child->workspace) { + container_detach(child); } - wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i); list_insert(parent->children, i, child); child->parent = parent; - container_handle_fullscreen_reparent(child, old_parent); + child->workspace = parent->workspace; + container_for_each_child(child, set_workspace, NULL); + container_handle_fullscreen_reparent(child); + container_update_representation(parent); } -struct sway_container *container_add_sibling(struct sway_container *fixed, - struct sway_container *active) { - // TODO handle floating - struct sway_container *old_parent = NULL; - if (active->parent) { - old_parent = active->parent; - container_remove_child(active); +void container_add_sibling(struct sway_container *fixed, + struct sway_container *active, int offset) { + if (active->workspace) { + container_detach(active); } - struct sway_container *parent = fixed->parent; - int i = container_sibling_index(fixed); - list_insert(parent->children, i + 1, active); - active->parent = parent; - container_handle_fullscreen_reparent(active, old_parent); - return active->parent; + list_t *siblings = container_get_siblings(fixed); + int index = list_find(siblings, fixed); + list_insert(siblings, index + offset, active); + active->parent = fixed->parent; + active->workspace = fixed->workspace; + container_for_each_child(active, set_workspace, NULL); + container_handle_fullscreen_reparent(active); + container_update_representation(active); } void container_add_child(struct sway_container *parent, struct sway_container *child) { - wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", - child, child->type, child->width, child->height, - parent, parent->type, parent->width, parent->height); - struct sway_container *old_parent = child->parent; + if (child->workspace) { + container_detach(child); + } list_add(parent->children, child); child->parent = parent; - container_handle_fullscreen_reparent(child, old_parent); - if (old_parent) { - container_set_dirty(old_parent); - } - container_set_dirty(child); + child->workspace = parent->workspace; + container_for_each_child(child, set_workspace, NULL); + container_handle_fullscreen_reparent(child); + container_update_representation(parent); + node_set_dirty(&child->node); + node_set_dirty(&parent->node); } -struct sway_container *container_remove_child(struct sway_container *child) { +void container_detach(struct sway_container *child) { if (child->is_fullscreen) { - struct sway_container *workspace = container_parent(child, C_WORKSPACE); - workspace->sway_workspace->fullscreen = NULL; + child->workspace->fullscreen = NULL; } - struct sway_container *parent = child->parent; - list_t *list = container_is_floating(child) ? - parent->sway_workspace->floating : parent->children; - int index = list_find(list, child); + struct sway_container *old_parent = child->parent; + struct sway_workspace *old_workspace = child->workspace; + list_t *siblings = container_get_siblings(child); + int index = list_find(siblings, child); if (index != -1) { - list_del(list, index); + list_del(siblings, index); } child->parent = NULL; - container_notify_subtree_changed(parent); + child->workspace = NULL; + container_for_each_child(child, set_workspace, NULL); - container_set_dirty(parent); - container_set_dirty(child); - - return parent; -} - -enum sway_container_layout container_get_default_layout( - struct sway_container *con) { - if (con->type != C_OUTPUT) { - con = container_parent(con, C_OUTPUT); - } - - if (!sway_assert(con != NULL, - "container_get_default_layout must be called on an attached" - " container below the root container")) { - return 0; - } - - if (config->default_layout != L_NONE) { - return config->default_layout; - } else if (config->default_orientation != L_NONE) { - return config->default_orientation; - } else if (con->width >= con->height) { - return L_HORIZ; + if (old_parent) { + container_update_representation(old_parent); + node_set_dirty(&old_parent->node); } else { - return L_VERT; + workspace_update_representation(old_workspace); + node_set_dirty(&old_workspace->node); } + node_set_dirty(&child->node); } -struct sway_container *container_replace_child(struct sway_container *child, - struct sway_container *new_child) { - struct sway_container *parent = child->parent; - if (parent == NULL) { - return NULL; - } - - list_t *list = container_is_floating(child) ? - parent->sway_workspace->floating : parent->children; - int i = list_find(list, child); - - if (new_child->parent) { - container_remove_child(new_child); - } - list->items[i] = new_child; - new_child->parent = parent; - child->parent = NULL; - - // Set geometry for new child - new_child->x = child->x; - new_child->y = child->y; - new_child->width = child->width; - new_child->height = child->height; - - // reset geometry for child - child->width = 0; - child->height = 0; - - return parent; +void container_replace(struct sway_container *container, + struct sway_container *replacement) { + container_add_sibling(container, replacement, 1); + container_detach(container); } struct sway_container *container_split(struct sway_container *child, enum sway_container_layout layout) { - // TODO floating: cannot split a floating container - if (!sway_assert(child, "child cannot be null")) { - return NULL; - } - if (child->type == C_WORKSPACE && child->children->length == 0) { - // Special case: this just behaves like splitt - child->prev_split_layout = child->layout; - child->layout = layout; - return child; - } + struct sway_seat *seat = input_manager_get_default_seat(input_manager); + bool set_focus = (seat_get_focus(seat) == &child->node); - struct sway_container *cont = container_create(C_CONTAINER); - - wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child); - - cont->prev_split_layout = L_NONE; + struct sway_container *cont = container_create(NULL); cont->width = child->width; cont->height = child->height; - cont->x = child->x; - cont->y = child->y; cont->current_gaps = child->current_gaps; + cont->layout = layout; - struct sway_seat *seat = input_manager_get_default_seat(input_manager); - bool set_focus = (seat_get_focus(seat) == child); - - if (child->type == C_WORKSPACE) { - struct sway_container *workspace = child; - while (workspace->children->length) { - struct sway_container *ws_child = workspace->children->items[0]; - container_remove_child(ws_child); - container_add_child(cont, ws_child); - } - - container_add_child(workspace, cont); - enum sway_container_layout old_layout = workspace->layout; - workspace->layout = layout; - cont->layout = old_layout; - } else { - cont->layout = layout; - container_replace_child(child, cont); - container_add_child(cont, child); - } + container_replace(child, cont); + container_add_child(cont, child); if (set_focus) { - seat_set_focus(seat, cont); - seat_set_focus(seat, child); + seat_set_focus(seat, &cont->node); + seat_set_focus(seat, &child->node); } - container_notify_subtree_changed(cont); return cont; } diff --git a/sway/tree/node.c b/sway/tree/node.c new file mode 100644 index 000000000..74661c1ab --- /dev/null +++ b/sway/tree/node.c @@ -0,0 +1,151 @@ +#define _POSIX_C_SOURCE 200809L +#include "sway/output.h" +#include "sway/server.h" +#include "sway/tree/container.h" +#include "sway/tree/node.h" +#include "sway/tree/root.h" +#include "sway/tree/workspace.h" +#include "log.h" + +void node_init(struct sway_node *node, enum sway_node_type type, void *thing) { + static size_t next_id = 1; + node->id = next_id++; + node->type = type; + node->sway_root = thing; + wl_signal_init(&node->events.destroy); +} + +const char *node_type_to_str(enum sway_node_type type) { + switch (type) { + case N_ROOT: + return "N_ROOT"; + case N_OUTPUT: + return "N_OUTPUT"; + case N_WORKSPACE: + return "N_WORKSPACE"; + case N_CONTAINER: + return "N_CONTAINER"; + } + return ""; +} + +void node_set_dirty(struct sway_node *node) { + if (node->dirty) { + return; + } + node->dirty = true; + list_add(server.dirty_nodes, node); +} + +bool node_is_view(struct sway_node *node) { + return node->type == N_CONTAINER && node->sway_container->view; +} + +char *node_get_name(struct sway_node *node) { + switch (node->type) { + case N_ROOT: + return "root"; + case N_OUTPUT: + return node->sway_output->wlr_output->name; + case N_WORKSPACE: + return node->sway_workspace->name; + case N_CONTAINER: + return node->sway_container->title; + } + return NULL; +} + +void node_get_box(struct sway_node *node, struct wlr_box *box) { + switch (node->type) { + case N_ROOT: + root_get_box(root, box); + break; + case N_OUTPUT: + output_get_box(node->sway_output, box); + break; + case N_WORKSPACE: + workspace_get_box(node->sway_workspace, box); + break; + case N_CONTAINER: + container_get_box(node->sway_container, box); + break; + } +} + +struct sway_output *node_get_output(struct sway_node *node) { + switch (node->type) { + case N_CONTAINER: + return node->sway_container->workspace->output; + case N_WORKSPACE: + return node->sway_workspace->output; + case N_OUTPUT: + return node->sway_output; + case N_ROOT: + return NULL; + } + return NULL; +} + +enum sway_container_layout node_get_layout(struct sway_node *node) { + switch (node->type) { + case N_CONTAINER: + return node->sway_container->layout; + case N_WORKSPACE: + return node->sway_workspace->layout; + case N_OUTPUT: + case N_ROOT: + return L_NONE; + } + return L_NONE; +} + +struct sway_node *node_get_parent(struct sway_node *node) { + switch (node->type) { + case N_CONTAINER: { + struct sway_container *con = node->sway_container; + if (con->parent) { + return &con->parent->node; + } + if (con->workspace) { + return &con->workspace->node; + } + } + return NULL; + case N_WORKSPACE: { + struct sway_workspace *ws = node->sway_workspace; + if (ws->output) { + return &ws->output->node; + } + } + return NULL; + case N_OUTPUT: + return &root->node; + case N_ROOT: + return NULL; + } + return NULL; +} + +list_t *node_get_children(struct sway_node *node) { + switch (node->type) { + case N_CONTAINER: + return node->sway_container->children; + case N_WORKSPACE: + return node->sway_workspace->tiling; + case N_OUTPUT: + case N_ROOT: + return NULL; + } + return NULL; +} + +bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { + struct sway_node *parent = node_get_parent(node); + while (parent) { + if (parent == ancestor) { + return true; + } + parent = node_get_parent(parent); + } + return false; +} diff --git a/sway/tree/output.c b/sway/tree/output.c index 6601220bf..d72eb1a1d 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -2,28 +2,31 @@ #include #include #include +#include #include "sway/ipc-server.h" +#include "sway/layers.h" #include "sway/output.h" #include "sway/tree/arrange.h" #include "sway/tree/output.h" #include "sway/tree/workspace.h" #include "log.h" +#include "util.h" -static void restore_workspaces(struct sway_container *output) { +static void restore_workspaces(struct sway_output *output) { // Workspace output priority - for (int i = 0; i < root_container.children->length; i++) { - struct sway_container *other = root_container.children->items[i]; + for (int i = 0; i < root->outputs->length; i++) { + struct sway_output *other = root->outputs->items[i]; if (other == output) { continue; } - for (int j = 0; j < other->children->length; j++) { - struct sway_container *ws = other->children->items[j]; - struct sway_container *highest = + for (int j = 0; j < other->workspaces->length; j++) { + struct sway_workspace *ws = other->workspaces->items[j]; + struct sway_output *highest = workspace_output_get_highest_available(ws, NULL); if (highest == output) { - container_remove_child(ws); - container_add_child(output, ws); + workspace_detach(ws); + output_add_workspace(output, ws); ipc_event_workspace(NULL, ws, "move"); j--; } @@ -31,22 +34,197 @@ static void restore_workspaces(struct sway_container *output) { } // Saved workspaces - list_t *saved = root_container.sway_root->saved_workspaces; - for (int i = 0; i < saved->length; ++i) { - struct sway_container *ws = saved->items[i]; - container_add_child(output, ws); + for (int i = 0; i < root->saved_workspaces->length; ++i) { + struct sway_workspace *ws = root->saved_workspaces->items[i]; + output_add_workspace(output, ws); ipc_event_workspace(NULL, ws, "move"); } - saved->length = 0; + root->saved_workspaces->length = 0; output_sort_workspaces(output); } -struct sway_container *output_create( - struct sway_output *sway_output) { - const char *name = sway_output->wlr_output->name; +struct sway_output *output_create(struct wlr_output *wlr_output) { + struct sway_output *output = calloc(1, sizeof(struct sway_output)); + node_init(&output->node, N_OUTPUT, output); + output->wlr_output = wlr_output; + wlr_output->data = output; + + wl_signal_add(&wlr_output->events.destroy, &output->destroy); + + wl_list_insert(&root->all_outputs, &output->link); + + if (!wl_list_empty(&wlr_output->modes)) { + struct wlr_output_mode *mode = + wl_container_of(wlr_output->modes.prev, mode, link); + wlr_output_set_mode(wlr_output, mode); + } + + output->workspaces = create_list(); + output->current.workspaces = create_list(); + + return output; +} + +void output_enable(struct sway_output *output, struct output_config *oc) { + if (!sway_assert(!output->enabled, "output is already enabled")) { + return; + } + struct wlr_output *wlr_output = output->wlr_output; + output->enabled = true; + apply_output_config(oc, output); + list_add(root->outputs, output); + + restore_workspaces(output); + + if (!output->workspaces->length) { + // Create workspace + char *ws_name = workspace_next_name(wlr_output->name); + wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); + struct sway_workspace *ws = workspace_create(output, ws_name); + // Set each seat's focus if not already set + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input_manager->seats, link) { + if (!seat->has_focus) { + seat_set_focus(seat, &ws->node); + } + } + free(ws_name); + } + + size_t len = sizeof(output->layers) / sizeof(output->layers[0]); + for (size_t i = 0; i < len; ++i) { + wl_list_init(&output->layers[i]); + } + wl_signal_init(&output->events.destroy); + + input_manager_configure_xcursor(input_manager); + + wl_signal_add(&wlr_output->events.mode, &output->mode); + wl_signal_add(&wlr_output->events.transform, &output->transform); + wl_signal_add(&wlr_output->events.scale, &output->scale); + wl_signal_add(&output->damage->events.frame, &output->damage_frame); + wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); + + output_add_listeners(output); + + wl_signal_emit(&root->events.new_node, &output->node); + + load_swaybars(); + + arrange_layers(output); + arrange_root(); +} + +static void output_evacuate(struct sway_output *output) { + if (!output->workspaces->length) { + return; + } + struct sway_output *fallback_output = NULL; + if (root->outputs->length > 1) { + fallback_output = root->outputs->items[0]; + if (fallback_output == output) { + fallback_output = root->outputs->items[1]; + } + } + + while (output->workspaces->length) { + struct sway_workspace *workspace = output->workspaces->items[0]; + + workspace_detach(workspace); + + if (workspace_is_empty(workspace)) { + workspace_begin_destroy(workspace); + continue; + } + + struct sway_output *new_output = + workspace_output_get_highest_available(workspace, output); + if (!new_output) { + new_output = fallback_output; + } + + if (new_output) { + workspace_output_add_priority(workspace, new_output); + output_add_workspace(new_output, workspace); + output_sort_workspaces(new_output); + ipc_event_workspace(NULL, workspace, "move"); + } else { + list_add(root->saved_workspaces, workspace); + } + } +} + +void output_destroy(struct sway_output *output) { + if (!sway_assert(output->node.destroying, + "Tried to free output which wasn't marked as destroying")) { + return; + } + if (!sway_assert(output->wlr_output == NULL, + "Tried to free output which still had a wlr_output")) { + return; + } + if (!sway_assert(output->node.ntxnrefs == 0, "Tried to free output " + "which is still referenced by transactions")) { + return; + } + list_free(output->workspaces); + list_free(output->current.workspaces); + free(output); +} + +static void untrack_output(struct sway_container *con, void *data) { + struct sway_output *output = data; + int index = list_find(con->outputs, output); + if (index != -1) { + list_del(con->outputs, index); + } +} + +void output_disable(struct sway_output *output) { + if (!sway_assert(output->enabled, "Expected an enabled output")) { + return; + } + wlr_log(WLR_DEBUG, "Disabling output '%s'", output->wlr_output->name); + wl_signal_emit(&output->events.destroy, output); + + output_evacuate(output); + + root_for_each_container(untrack_output, output); + + int index = list_find(root->outputs, output); + list_del(root->outputs, index); + + wl_list_remove(&output->mode.link); + wl_list_remove(&output->transform.link); + wl_list_remove(&output->scale.link); + wl_list_remove(&output->damage_destroy.link); + wl_list_remove(&output->damage_frame.link); + + output->enabled = false; + + arrange_root(); +} + +void output_begin_destroy(struct sway_output *output) { + if (!sway_assert(!output->enabled, "Expected a disabled output")) { + return; + } + wlr_log(WLR_DEBUG, "Destroying output '%s'", output->wlr_output->name); + + output->node.destroying = true; + node_set_dirty(&output->node); + + wl_list_remove(&output->link); + wl_list_remove(&output->destroy.link); + output->wlr_output->data = NULL; + output->wlr_output = NULL; +} + +struct output_config *output_find_config(struct sway_output *output) { + const char *name = output->wlr_output->name; char identifier[128]; - output_get_identifier(identifier, sizeof(identifier), sway_output); + output_get_identifier(identifier, sizeof(identifier), output); struct output_config *oc = NULL, *all = NULL; for (int i = 0; i < config->output_configs->length; ++i) { @@ -73,189 +251,61 @@ struct sway_container *output_create( if (oc && !oc->enabled) { return NULL; } + return oc; +} - struct sway_container *output = container_create(C_OUTPUT); - output->sway_output = sway_output; - output->name = strdup(name); - if (output->name == NULL) { - output_begin_destroy(output); +struct sway_output *output_from_wlr_output(struct wlr_output *output) { + return output->data; +} + +struct sway_output *output_get_in_direction(struct sway_output *reference, + enum movement_direction direction) { + enum wlr_direction wlr_dir = 0; + if (!sway_assert(sway_dir_to_wlr(direction, &wlr_dir), + "got invalid direction: %d", direction)) { return NULL; } - - apply_output_config(oc, output); - container_add_child(&root_container, output); - load_swaybars(); - - struct wlr_box size; - wlr_output_effective_resolution(sway_output->wlr_output, &size.width, - &size.height); - output->width = size.width; - output->height = size.height; - - restore_workspaces(output); - - if (!output->children->length) { - // Create workspace - char *ws_name = workspace_next_name(output->name); - wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); - struct sway_container *ws = workspace_create(output, ws_name); - // Set each seat's focus if not already set - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &input_manager->seats, link) { - if (!seat->has_focus) { - seat_set_focus(seat, ws); - } - } - free(ws_name); - } - - container_create_notify(output); - return output; -} - -static void output_evacuate(struct sway_container *output) { - if (!output->children->length) { - return; - } - struct sway_container *fallback_output = NULL; - if (root_container.children->length > 1) { - fallback_output = root_container.children->items[0]; - if (fallback_output == output) { - fallback_output = root_container.children->items[1]; - } - } - - while (output->children->length) { - struct sway_container *workspace = output->children->items[0]; - - container_remove_child(workspace); - - if (workspace_is_empty(workspace)) { - workspace_begin_destroy(workspace); - continue; - } - - struct sway_container *new_output = - workspace_output_get_highest_available(workspace, output); - if (!new_output) { - new_output = fallback_output; - } - - if (new_output) { - workspace_output_add_priority(workspace, new_output); - container_add_child(new_output, workspace); - output_sort_workspaces(new_output); - ipc_event_workspace(NULL, workspace, "move"); - } else { - list_add(root_container.sway_root->saved_workspaces, workspace); - } - } -} - -void output_destroy(struct sway_container *output) { - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return; - } - if (!sway_assert(output->destroying, - "Tried to free output which wasn't marked as destroying")) { - return; - } - if (!sway_assert(output->ntxnrefs == 0, "Tried to free output " - "which is still referenced by transactions")) { - return; - } - free(output->name); - free(output->formatted_title); - wlr_texture_destroy(output->title_focused); - wlr_texture_destroy(output->title_focused_inactive); - wlr_texture_destroy(output->title_unfocused); - wlr_texture_destroy(output->title_urgent); - list_free(output->children); - list_free(output->current.children); - list_free(output->outputs); - free(output); - - // NOTE: We don't actually destroy the sway_output here -} - -static void untrack_output(struct sway_container *con, void *data) { - struct sway_output *output = data; - int index = list_find(con->outputs, output); - if (index != -1) { - list_del(con->outputs, index); - } -} - -void output_begin_destroy(struct sway_container *output) { - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return; - } - wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); - wl_signal_emit(&output->events.destroy, output); - - output_evacuate(output); - - output->destroying = true; - container_set_dirty(output); - - root_for_each_container(untrack_output, output->sway_output); - - wl_list_remove(&output->sway_output->mode.link); - wl_list_remove(&output->sway_output->transform.link); - wl_list_remove(&output->sway_output->scale.link); - wl_list_remove(&output->sway_output->damage_destroy.link); - wl_list_remove(&output->sway_output->damage_frame.link); - - output->sway_output->swayc = NULL; - output->sway_output = NULL; - - if (output->parent) { - container_remove_child(output); - } -} - -struct sway_container *output_from_wlr_output(struct wlr_output *output) { - if (output == NULL) { + int lx = reference->wlr_output->lx + reference->wlr_output->width / 2; + int ly = reference->wlr_output->ly + reference->wlr_output->height / 2; + struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output( + root->output_layout, wlr_dir, reference->wlr_output, lx, ly); + if (!wlr_adjacent) { return NULL; } - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *o = root_container.children->items[i]; - if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) { - return o; - } - } - return NULL; + return output_from_wlr_output(wlr_adjacent); } -void output_for_each_workspace(struct sway_container *output, - void (*f)(struct sway_container *con, void *data), void *data) { - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return; +void output_add_workspace(struct sway_output *output, + struct sway_workspace *workspace) { + if (workspace->output) { + workspace_detach(workspace); } - for (int i = 0; i < output->children->length; ++i) { - struct sway_container *workspace = output->children->items[i]; + list_add(output->workspaces, workspace); + workspace->output = output; + node_set_dirty(&output->node); + node_set_dirty(&workspace->node); +} + +void output_for_each_workspace(struct sway_output *output, + void (*f)(struct sway_workspace *ws, void *data), void *data) { + for (int i = 0; i < output->workspaces->length; ++i) { + struct sway_workspace *workspace = output->workspaces->items[i]; f(workspace, data); } } -void output_for_each_container(struct sway_container *output, +void output_for_each_container(struct sway_output *output, void (*f)(struct sway_container *con, void *data), void *data) { - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return; - } - for (int i = 0; i < output->children->length; ++i) { - struct sway_container *workspace = output->children->items[i]; + for (int i = 0; i < output->workspaces->length; ++i) { + struct sway_workspace *workspace = output->workspaces->items[i]; workspace_for_each_container(workspace, f, data); } } -struct sway_container *output_find_workspace(struct sway_container *output, - bool (*test)(struct sway_container *con, void *data), void *data) { - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return NULL; - } - for (int i = 0; i < output->children->length; ++i) { - struct sway_container *workspace = output->children->items[i]; +struct sway_workspace *output_find_workspace(struct sway_output *output, + bool (*test)(struct sway_workspace *ws, void *data), void *data) { + for (int i = 0; i < output->workspaces->length; ++i) { + struct sway_workspace *workspace = output->workspaces->items[i]; if (test(workspace, data)) { return workspace; } @@ -263,14 +313,11 @@ struct sway_container *output_find_workspace(struct sway_container *output, return NULL; } -struct sway_container *output_find_container(struct sway_container *output, +struct sway_container *output_find_container(struct sway_output *output, bool (*test)(struct sway_container *con, void *data), void *data) { - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return NULL; - } struct sway_container *result = NULL; - for (int i = 0; i < output->children->length; ++i) { - struct sway_container *workspace = output->children->items[i]; + for (int i = 0; i < output->workspaces->length; ++i) { + struct sway_workspace *workspace = output->workspaces->items[i]; if ((result = workspace_find_container(workspace, test, data))) { return result; } @@ -279,8 +326,8 @@ struct sway_container *output_find_container(struct sway_container *output, } static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { - struct sway_container *a = *(void **)_a; - struct sway_container *b = *(void **)_b; + struct sway_workspace *a = *(void **)_a; + struct sway_workspace *b = *(void **)_b; if (isdigit(a->name[0]) && isdigit(b->name[0])) { int a_num = strtol(a->name, NULL, 10); @@ -294,6 +341,27 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { return 0; } -void output_sort_workspaces(struct sway_container *output) { - list_stable_sort(output->children, sort_workspace_cmp_qsort); +void output_sort_workspaces(struct sway_output *output) { + list_stable_sort(output->workspaces, sort_workspace_cmp_qsort); +} + +void output_get_box(struct sway_output *output, struct wlr_box *box) { + box->x = output->wlr_output->lx; + box->y = output->wlr_output->ly; + box->width = output->wlr_output->width; + box->height = output->wlr_output->height; +} + +enum sway_container_layout output_get_default_layout( + struct sway_output *output) { + if (config->default_layout != L_NONE) { + return config->default_layout; + } + if (config->default_orientation != L_NONE) { + return config->default_orientation; + } + if (output->wlr_output->height > output->wlr_output->width) { + return L_VERT; + } + return L_HORIZ; } diff --git a/sway/tree/root.c b/sway/tree/root.c index b42371dec..ecc04ddbb 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -14,54 +14,45 @@ #include "log.h" #include "util.h" -struct sway_container root_container; +struct sway_root *root; static void output_layout_handle_change(struct wl_listener *listener, void *data) { - arrange_windows(&root_container); + arrange_root(); transaction_commit_dirty(); } -void root_create(void) { - root_container.id = 0; // normally assigned in new_swayc() - root_container.type = C_ROOT; - root_container.layout = L_NONE; - root_container.name = strdup("root"); - root_container.children = create_list(); - root_container.current.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->output_layout = wlr_output_layout_create(); - wl_list_init(&root_container.sway_root->all_outputs); +struct sway_root *root_create(void) { + struct sway_root *root = calloc(1, sizeof(struct sway_root)); + if (!root) { + wlr_log(WLR_ERROR, "Unable to allocate sway_root"); + return NULL; + } + node_init(&root->node, N_ROOT, root); + root->output_layout = wlr_output_layout_create(); + wl_list_init(&root->all_outputs); #ifdef HAVE_XWAYLAND - wl_list_init(&root_container.sway_root->xwayland_unmanaged); + wl_list_init(&root->xwayland_unmanaged); #endif - wl_list_init(&root_container.sway_root->drag_icons); - wl_signal_init(&root_container.sway_root->events.new_container); - root_container.sway_root->scratchpad = create_list(); - root_container.sway_root->saved_workspaces = create_list(); + wl_list_init(&root->drag_icons); + wl_signal_init(&root->events.new_node); + root->outputs = create_list(); + root->scratchpad = create_list(); + root->saved_workspaces = create_list(); - root_container.sway_root->output_layout_change.notify = - output_layout_handle_change; - wl_signal_add(&root_container.sway_root->output_layout->events.change, - &root_container.sway_root->output_layout_change); + root->output_layout_change.notify = output_layout_handle_change; + wl_signal_add(&root->output_layout->events.change, + &root->output_layout_change); + return root; } -void root_destroy(void) { - // sway_root - wl_list_remove(&root_container.sway_root->output_layout_change.link); - list_free(root_container.sway_root->scratchpad); - list_free(root_container.sway_root->saved_workspaces); - wlr_output_layout_destroy(root_container.sway_root->output_layout); - free(root_container.sway_root); - - // root_container - list_free(root_container.children); - list_free(root_container.current.children); - free(root_container.name); - - memset(&root_container, 0, sizeof(root_container)); +void root_destroy(struct sway_root *root) { + wl_list_remove(&root->output_layout_change.link); + list_free(root->scratchpad); + list_free(root->saved_workspaces); + list_free(root->outputs); + wlr_output_layout_destroy(root->output_layout); + free(root); } void root_scratchpad_add_container(struct sway_container *con) { @@ -69,15 +60,21 @@ void root_scratchpad_add_container(struct sway_container *con) { return; } con->scratchpad = true; - list_add(root_container.sway_root->scratchpad, con); + list_add(root->scratchpad, con); struct sway_container *parent = con->parent; + struct sway_workspace *workspace = con->workspace; container_set_floating(con, true); - container_remove_child(con); - arrange_windows(parent); + container_detach(con); struct sway_seat *seat = input_manager_current_seat(input_manager); - seat_set_focus(seat, seat_get_focus_inactive(seat, parent)); + if (parent) { + arrange_container(parent); + seat_set_focus(seat, seat_get_focus_inactive(seat, &parent->node)); + } else { + arrange_workspace(workspace); + seat_set_focus(seat, seat_get_focus_inactive(seat, &workspace->node)); + } } void root_scratchpad_remove_container(struct sway_container *con) { @@ -85,28 +82,25 @@ void root_scratchpad_remove_container(struct sway_container *con) { return; } con->scratchpad = false; - int index = list_find(root_container.sway_root->scratchpad, con); + int index = list_find(root->scratchpad, con); if (index != -1) { - list_del(root_container.sway_root->scratchpad, index); + list_del(root->scratchpad, index); } } void root_scratchpad_show(struct sway_container *con) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *ws = seat_get_focus(seat); - if (ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } + struct sway_workspace *ws = seat_get_focused_workspace(seat); // If the current con or any of its parents are in fullscreen mode, we // first need to disable it before showing the scratchpad con. - if (ws->sway_workspace->fullscreen) { - container_set_fullscreen(ws->sway_workspace->fullscreen, false); + if (ws->fullscreen) { + container_set_fullscreen(ws->fullscreen, false); } // Show the container - if (con->parent) { - container_remove_child(con); + if (con->workspace) { + container_detach(con); } workspace_add_floating(ws, con); @@ -115,7 +109,7 @@ void root_scratchpad_show(struct sway_container *con) { double center_ly = con->y + con->height / 2; struct wlr_box workspace_box; - container_get_box(ws, &workspace_box); + workspace_get_box(ws, &workspace_box); if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { // Maybe resize it if (con->width > ws->width || con->height > ws->height) { @@ -128,23 +122,21 @@ void root_scratchpad_show(struct sway_container *con) { container_floating_move_to(con, new_lx, new_ly); } - arrange_windows(ws); - seat_set_focus(seat, seat_get_focus_inactive(seat, con)); - - container_set_dirty(con->parent); + arrange_workspace(ws); + seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node)); } void root_scratchpad_hide(struct sway_container *con) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *ws = container_parent(con, C_WORKSPACE); + struct sway_node *focus = seat_get_focus(seat); + struct sway_workspace *ws = con->workspace; - container_remove_child(con); - arrange_windows(ws); - if (con == focus) { - seat_set_focus(seat, seat_get_focus_inactive(seat, ws)); + container_detach(con); + arrange_workspace(ws); + if (&con->node == focus) { + seat_set_focus(seat, seat_get_focus_inactive(seat, &ws->node)); } - list_move_to_end(root_container.sway_root->scratchpad, con); + list_move_to_end(root->scratchpad, con); } struct pid_workspace { @@ -152,7 +144,7 @@ struct pid_workspace { char *workspace; struct timespec time_added; - struct sway_container *output; + struct sway_output *output; struct wl_listener output_destroy; struct wl_list link; @@ -160,13 +152,13 @@ struct pid_workspace { static struct wl_list pid_workspaces; -struct sway_container *root_workspace_for_pid(pid_t pid) { +struct sway_workspace *root_workspace_for_pid(pid_t pid) { if (!pid_workspaces.prev && !pid_workspaces.next) { wl_list_init(&pid_workspaces); return NULL; } - struct sway_container *ws = NULL; + struct sway_workspace *ws = NULL; struct pid_workspace *pw = NULL; wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); @@ -219,16 +211,12 @@ void root_record_workspace_pid(pid_t pid) { } struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *ws = - seat_get_focus_inactive(seat, &root_container); - if (ws && ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } + struct sway_workspace *ws = seat_get_focused_workspace(seat); if (!ws) { wlr_log(WLR_DEBUG, "Bailing out, no workspace"); return; } - struct sway_container *output = ws->parent; + struct sway_output *output = ws->output; if (!output) { wlr_log(WLR_DEBUG, "Bailing out, no output"); return; @@ -255,30 +243,28 @@ void root_record_workspace_pid(pid_t pid) { pw->pid = pid; memcpy(&pw->time_added, &now, sizeof(struct timespec)); pw->output_destroy.notify = pw_handle_output_destroy; - wl_signal_add(&output->sway_output->wlr_output->events.destroy, - &pw->output_destroy); + wl_signal_add(&output->wlr_output->events.destroy, &pw->output_destroy); wl_list_insert(&pid_workspaces, &pw->link); } -void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), +void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), void *data) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; output_for_each_workspace(output, f, data); } } void root_for_each_container(void (*f)(struct sway_container *con, void *data), void *data) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; output_for_each_container(output, f, data); } // Scratchpad - for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { - struct sway_container *container = - root_container.sway_root->scratchpad->items[i]; + for (int i = 0; i < root->scratchpad->length; ++i) { + struct sway_container *container = root->scratchpad->items[i]; // If the container has a parent then it's visible on a workspace // and will have been iterated in the previous for loop. So we only // iterate the hidden scratchpad containers here. @@ -289,10 +275,10 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data), } } -struct sway_container *root_find_output( - bool (*test)(struct sway_container *con, void *data), void *data) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; +struct sway_output *root_find_output( + bool (*test)(struct sway_output *output, void *data), void *data) { + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; if (test(output, data)) { return output; } @@ -300,11 +286,11 @@ struct sway_container *root_find_output( return NULL; } -struct sway_container *root_find_workspace( - bool (*test)(struct sway_container *con, void *data), void *data) { - struct sway_container *result = NULL; - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; +struct sway_workspace *root_find_workspace( + bool (*test)(struct sway_workspace *ws, void *data), void *data) { + struct sway_workspace *result = NULL; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; if ((result = output_find_workspace(output, test, data))) { return result; } @@ -315,17 +301,16 @@ struct sway_container *root_find_workspace( struct sway_container *root_find_container( bool (*test)(struct sway_container *con, void *data), void *data) { struct sway_container *result = NULL; - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; if ((result = output_find_container(output, test, data))) { return result; } } // Scratchpad - for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { - struct sway_container *container = - root_container.sway_root->scratchpad->items[i]; + for (int i = 0; i < root->scratchpad->length; ++i) { + struct sway_container *container = root->scratchpad->items[i]; if (!container->parent) { if (test(container, data)) { return container; @@ -337,3 +322,10 @@ struct sway_container *root_find_container( } return NULL; } + +void root_get_box(struct sway_root *root, struct wlr_box *box) { + box->x = root->x; + box->y = root->y; + box->width = root->width; + box->height = root->height; +} diff --git a/sway/tree/view.c b/sway/tree/view.c index 6bd0ef670..452c2bd1b 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -33,6 +33,8 @@ void view_init(struct sway_view *view, enum sway_view_type type, view->marks = create_list(); view->allow_request_urgent = true; wl_signal_init(&view->events.unmap); + + view->container = container_create(view); } void view_destroy(struct sway_view *view) { @@ -43,8 +45,8 @@ void view_destroy(struct sway_view *view) { "Tried to free view which wasn't marked as destroying")) { return; } - if (!sway_assert(view->swayc == NULL, - "Tried to free view which still has a swayc " + if (!sway_assert(view->container == NULL, + "Tried to free view which still has a container " "(might have a pending transaction?)")) { return; } @@ -57,6 +59,7 @@ void view_destroy(struct sway_view *view) { wlr_texture_destroy(view->marks_focused_inactive); wlr_texture_destroy(view->marks_unfocused); wlr_texture_destroy(view->marks_urgent); + free(view->title_format); if (view->impl->destroy) { view->impl->destroy(view); @@ -65,23 +68,13 @@ void view_destroy(struct sway_view *view) { } } -/** - * The view may or may not be involved in a transaction. For example, a view may - * unmap then attempt to destroy itself before we've applied the new layout. If - * an unmapping view is still involved in a transaction then it'll still have a - * swayc. - * - * If there's no transaction we can simply free the view. Otherwise the - * destroying flag will make the view get freed when the transaction is - * finished. - */ void view_begin_destroy(struct sway_view *view) { if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { return; } view->destroying = true; - if (!view->swayc) { + if (!view->container) { view_destroy(view); } } @@ -171,30 +164,27 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, } void view_autoconfigure(struct sway_view *view) { - if (!sway_assert(view->swayc, - "Called view_autoconfigure() on a view without a swayc")) { + struct sway_output *output = view->container->workspace->output; + + if (view->container->is_fullscreen) { + view->x = output->wlr_output->lx; + view->y = output->wlr_output->ly; + view->width = output->wlr_output->width; + view->height = output->wlr_output->height; return; } - struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + struct sway_workspace *ws = view->container->workspace; - if (view->swayc->is_fullscreen) { - view->x = output->x; - view->y = output->y; - view->width = output->width; - view->height = output->height; - return; - } - - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - - int other_views = 0; + bool other_views = false; if (config->hide_edge_borders == E_SMART) { - struct sway_container *con = view->swayc; - while (con != output) { - if (con->layout != L_TABBED && con->layout != L_STACKED) { - other_views += con->children ? con->children->length - 1 : 0; - if (other_views > 0) { + struct sway_container *con = view->container; + while (con) { + enum sway_container_layout layout = container_parent_layout(con); + if (layout != L_TABBED && layout != L_STACKED) { + list_t *siblings = container_get_siblings(con); + if (siblings && siblings->length > 1) { + other_views = true; break; } } @@ -202,7 +192,7 @@ void view_autoconfigure(struct sway_view *view) { } } - struct sway_container *con = view->swayc; + struct sway_container *con = view->container; view->border_top = view->border_bottom = true; view->border_left = view->border_right = true; @@ -228,7 +218,8 @@ void view_autoconfigure(struct sway_view *view) { // In a tabbed or stacked container, the swayc's y is the bottom of the // title area. We have to disable any top border because the title bar is // rendered by the parent. - if (con->parent->layout == L_TABBED || con->parent->layout == L_STACKED) { + enum sway_container_layout layout = container_parent_layout(con); + if (layout == L_TABBED || layout == L_STACKED) { view->border_top = false; } else { y_offset = container_titlebar_height(); @@ -281,13 +272,16 @@ void view_set_activated(struct sway_view *view, bool activated) { } void view_request_activate(struct sway_view *view) { - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + struct sway_workspace *ws = view->container->workspace; + if (!ws) { // hidden scratchpad container + return; + } struct sway_seat *seat = input_manager_current_seat(input_manager); switch (config->focus_on_window_activation) { case FOWA_SMART: if (workspace_is_visible(ws)) { - seat_set_focus(seat, view->swayc); + seat_set_focus(seat, &view->container->node); } else { view_set_urgent(view, true); } @@ -296,7 +290,7 @@ void view_request_activate(struct sway_view *view) { view_set_urgent(view, true); break; case FOWA_FOCUS: - seat_set_focus(seat, view->swayc); + seat_set_focus(seat, &view->container->node); break; case FOWA_NONE: break; @@ -331,23 +325,12 @@ void view_close_popups(struct sway_view *view) { } void view_damage_from(struct sway_view *view) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT) { - output_damage_from_view(cont->sway_output, view); - } + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_from_view(output, view); } } -static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { - struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - - box->x = output->x + view->swayc->x; - box->y = output->y + view->swayc->y; - box->width = view->width; - box->height = view->height; -} - void view_for_each_surface(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data) { if (!view->surface) { @@ -396,11 +379,8 @@ static bool view_has_executed_criteria(struct sway_view *view, } void view_execute_criteria(struct sway_view *view) { - if (!view->swayc) { - return; - } struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *prior_focus = seat_get_focus(seat); + struct sway_node *prior_focus = seat_get_focus(seat); list_t *criterias = criteria_for_view(view, CT_COMMAND); for (int i = 0; i < criterias->length; i++) { struct criteria *criteria = criterias->items[i]; @@ -411,7 +391,7 @@ void view_execute_criteria(struct sway_view *view) { } wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", criteria->raw, view, criteria->cmdlist); - seat_set_focus(seat, view->swayc); + seat_set_focus(seat, &view->container->node); list_add(view->executed_criteria, criteria); struct cmd_results *res = execute_command(criteria->cmdlist, NULL); if (res->status != CMD_SUCCESS) { @@ -423,19 +403,19 @@ void view_execute_criteria(struct sway_view *view) { seat_set_focus(seat, prior_focus); } -static struct sway_container *select_workspace(struct sway_view *view) { +static struct sway_workspace *select_workspace(struct sway_view *view) { struct sway_seat *seat = input_manager_current_seat(input_manager); // Check if there's any `assign` criteria for the view list_t *criterias = criteria_for_view(view, CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT); - struct sway_container *ws = NULL; + struct sway_workspace *ws = NULL; for (int i = 0; i < criterias->length; ++i) { struct criteria *criteria = criterias->items[i]; if (criteria->type == CT_ASSIGN_OUTPUT) { - struct sway_container *output = output_by_name(criteria->target); + struct sway_output *output = output_by_name(criteria->target); if (output) { - ws = seat_get_active_child(seat, output); + ws = output_get_active_workspace(output); break; } } else { @@ -484,20 +464,14 @@ static struct sway_container *select_workspace(struct sway_view *view) { } // Use the focused workspace - ws = seat_get_focus_inactive(seat, &root_container); - if (ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } - return ws; + return seat_get_focused_workspace(seat); } static bool should_focus(struct sway_view *view) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *prev_focus = - seat_get_focus_inactive(seat, &root_container); - struct sway_container *prev_ws = prev_focus->type == C_WORKSPACE ? - prev_focus : container_parent(prev_focus, C_WORKSPACE); - struct sway_container *map_ws = container_parent(view->swayc, C_WORKSPACE); + struct sway_container *prev_con = seat_get_focused_container(seat); + struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); + struct sway_workspace *map_ws = view->container->workspace; // Views can only take focus if they are mapped into the active workspace if (prev_ws != map_ws) { @@ -506,10 +480,9 @@ static bool should_focus(struct sway_view *view) { // If the view is the only one in the focused workspace, it'll get focus // regardless of any no_focus criteria. - struct sway_container *parent = view->swayc->parent; - if (parent->type == C_WORKSPACE && prev_focus == parent) { - size_t num_children = parent->children->length + - parent->sway_workspace->floating->length; + if (!view->container->parent && !prev_con) { + size_t num_children = view->container->workspace->tiling->length + + view->container->workspace->floating->length; if (num_children == 1) { return true; } @@ -529,16 +502,24 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view->surface = wlr_surface; struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *ws = select_workspace(view); - struct sway_container *target_sibling = seat_get_focus_inactive(seat, ws); + struct sway_workspace *ws = select_workspace(view); + struct sway_node *node = seat_get_focus_inactive(seat, &ws->node); + struct sway_container *target_sibling = node->type == N_CONTAINER ? + node->sway_container : NULL; // If we're about to launch the view into the floating container, then // launch it as a tiled view in the root of the workspace instead. - if (container_is_floating(target_sibling)) { - target_sibling = target_sibling->parent; + if (target_sibling && container_is_floating(target_sibling)) { + target_sibling = NULL; } - view->swayc = container_view_create(target_sibling, view); + view->container = container_create(view); + if (target_sibling) { + container_add_sibling(target_sibling, view->container, 1); + } else { + workspace_add_tiling(ws, view->container); + } + ipc_event_window(view->container, "new"); view_init_subsurfaces(view, wlr_surface); wl_signal_add(&wlr_surface->events.new_subsurface, @@ -548,7 +529,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { if (view->impl->wants_floating && view->impl->wants_floating(view)) { view->border = config->floating_border; view->border_thickness = config->floating_border_thickness; - container_set_floating(view->swayc, true); + container_set_floating(view->container, true); } else { view->border = config->border; view->border_thickness = config->border_thickness; @@ -556,11 +537,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { } if (should_focus(view)) { - input_manager_set_focus(input_manager, view->swayc); + input_manager_set_focus(input_manager, &view->container->node); } view_update_title(view, false); - container_notify_subtree_changed(view->swayc->parent); + container_update_representation(view->container); view_execute_criteria(view); } @@ -574,17 +555,17 @@ void view_unmap(struct sway_view *view) { view->urgent_timer = NULL; } - bool was_fullscreen = view->swayc->is_fullscreen; - struct sway_container *parent = view->swayc->parent; - container_begin_destroy(view->swayc); - struct sway_container *surviving_ancestor = container_reap_empty(parent); + struct sway_container *parent = view->container->parent; + struct sway_workspace *ws = view->container->workspace; + container_begin_destroy(view->container); + if (parent) { + container_reap_empty(parent); + } else { + workspace_consider_destroy(ws); + } - // If the workspace wasn't reaped - if (surviving_ancestor && surviving_ancestor->type >= C_WORKSPACE) { - struct sway_container *ws = surviving_ancestor->type == C_WORKSPACE ? - surviving_ancestor : - container_parent(surviving_ancestor, C_WORKSPACE); - arrange_windows(was_fullscreen ? ws : surviving_ancestor); + if (!ws->node.destroying) { + arrange_workspace(ws); workspace_detect_urgent(ws); } @@ -593,15 +574,15 @@ void view_unmap(struct sway_view *view) { } void view_update_size(struct sway_view *view, int width, int height) { - if (!sway_assert(container_is_floating(view->swayc), + if (!sway_assert(container_is_floating(view->container), "Expected a floating container")) { return; } view->width = width; view->height = height; - view->swayc->current.view_width = width; - view->swayc->current.view_height = height; - container_set_geometry_from_floating_view(view->swayc); + view->container->current.view_width = width; + view->container->current.view_height = height; + container_set_geometry_from_floating_view(view->container); } static void view_subsurface_create(struct sway_view *view, @@ -670,27 +651,18 @@ void view_child_init(struct sway_view_child *child, wl_signal_add(&view->events.unmap, &child->view_unmap); child->view_unmap.notify = view_child_handle_view_unmap; - struct sway_container *output = child->view->swayc->parent; - if (output != NULL) { - if (output->type != C_OUTPUT) { - output = container_parent(output, C_OUTPUT); - } - wlr_surface_send_enter(child->surface, output->sway_output->wlr_output); - } + struct sway_output *output = child->view->container->workspace->output; + wlr_surface_send_enter(child->surface, output->wlr_output); view_init_subsurfaces(child->view, surface); // TODO: only damage the whole child - if (child->view->swayc) { - container_damage_whole(child->view->swayc); - } + container_damage_whole(child->view->container); } void view_child_destroy(struct sway_view_child *child) { // TODO: only damage the whole child - if (child->view->swayc) { - container_damage_whole(child->view->swayc); - } + container_damage_whole(child->view->container); wl_list_remove(&child->surface_commit.link); wl_list_remove(&child->surface_destroy.link); @@ -808,22 +780,20 @@ static char *escape_title(char *buffer) { } void view_update_title(struct sway_view *view, bool force) { - if (!view->swayc) { - return; - } const char *title = view_get_title(view); if (!force) { - if (title && view->swayc->name && strcmp(title, view->swayc->name) == 0) { + if (title && view->container->title && + strcmp(title, view->container->title) == 0) { return; } - if (!title && !view->swayc->name) { + if (!title && !view->container->title) { return; } } - free(view->swayc->name); - free(view->swayc->formatted_title); + free(view->container->title); + free(view->container->formatted_title); if (title) { size_t len = parse_title_format(view, NULL); char *buffer = calloc(len + 1, sizeof(char)); @@ -836,25 +806,25 @@ void view_update_title(struct sway_view *view, bool force) { buffer = escape_title(buffer); } - view->swayc->name = strdup(title); - view->swayc->formatted_title = buffer; + view->container->title = strdup(title); + view->container->formatted_title = buffer; } else { - view->swayc->name = NULL; - view->swayc->formatted_title = NULL; + view->container->title = NULL; + view->container->formatted_title = NULL; } - container_calculate_title_height(view->swayc); + container_calculate_title_height(view->container); config_update_font_height(false); // Update title after the global font height is updated - container_update_title_textures(view->swayc); + container_update_title_textures(view->container); - ipc_event_window(view->swayc, "title"); + ipc_event_window(view->container, "title"); } static bool find_by_mark_iterator(struct sway_container *con, void *data) { char *mark = data; - return con->type == C_VIEW && view_has_mark(con->sway_view, mark); + return con->view && view_has_mark(con->view, mark); } struct sway_view *view_find_mark(char *mark) { @@ -863,7 +833,7 @@ struct sway_view *view_find_mark(char *mark) { if (!container) { return NULL; } - return container->sway_view; + return container->view; } bool view_find_and_unmark(char *mark) { @@ -872,7 +842,7 @@ bool view_find_and_unmark(char *mark) { if (!container) { return false; } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; for (int i = 0; i < view->marks->length; ++i) { char *view_mark = view->marks->items[i]; @@ -888,10 +858,9 @@ bool view_find_and_unmark(char *mark) { } void view_clear_marks(struct sway_view *view) { - while (view->marks->length) { - list_del(view->marks, 0); - ipc_event_window(view->swayc, "mark"); - } + list_foreach(view->marks, free); + view->marks->length = 0; + ipc_event_window(view->container, "mark"); } bool view_has_mark(struct sway_view *view, char *mark) { @@ -906,12 +875,13 @@ bool view_has_mark(struct sway_view *view, char *mark) { void view_add_mark(struct sway_view *view, char *mark) { list_add(view->marks, strdup(mark)); - ipc_event_window(view->swayc, "mark"); + ipc_event_window(view->container, "mark"); } static void update_marks_texture(struct sway_view *view, struct wlr_texture **texture, struct border_colors *class) { - struct sway_output *output = container_get_effective_output(view->swayc); + struct sway_output *output = + container_get_effective_output(view->container); if (!output) { return; } @@ -949,7 +919,7 @@ static void update_marks_texture(struct sway_view *view, double scale = output->wlr_output->scale; int width = 0; - int height = view->swayc->title_height * scale; + int height = view->container->title_height * scale; cairo_t *c = cairo_create(NULL); get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); @@ -994,44 +964,40 @@ void view_update_marks_textures(struct sway_view *view) { &config->border_colors.unfocused); update_marks_texture(view, &view->marks_urgent, &config->border_colors.urgent); - container_damage_whole(view->swayc); + container_damage_whole(view->container); } bool view_is_visible(struct sway_view *view) { - if (!view->swayc || view->swayc->destroying) { + if (view->container->node.destroying) { return false; } - struct sway_container *workspace = - container_parent(view->swayc, C_WORKSPACE); + struct sway_workspace *workspace = view->container->workspace; if (!workspace) { return false; } - // Determine if view is nested inside a floating container which is sticky. - // A simple floating view will have this ancestry: - // C_VIEW -> floating -> workspace - // A more complex ancestry could be: - // C_VIEW -> C_CONTAINER (tabbed) -> floating -> workspace - struct sway_container *floater = view->swayc; - while (floater->parent->type != C_WORKSPACE - && floater->parent->parent->type != C_WORKSPACE) { + // Determine if view is nested inside a floating container which is sticky + struct sway_container *floater = view->container; + while (floater->parent) { floater = floater->parent; } bool is_sticky = container_is_floating(floater) && floater->is_sticky; // Check view isn't in a tabbed or stacked container on an inactive tab struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *container = view->swayc; - while (container->type != C_WORKSPACE) { - if (container->parent->layout == L_TABBED || - container->parent->layout == L_STACKED) { - if (seat_get_active_child(seat, container->parent) != container) { + struct sway_container *container = view->container; + while (container) { + enum sway_container_layout layout = container_parent_layout(container); + if (layout == L_TABBED || layout == L_STACKED) { + struct sway_node *parent = container->parent ? + &container->parent->node : &container->workspace->node; + if (seat_get_active_child(seat, parent) != &container->node) { return false; } } container = container->parent; } // Check view isn't hidden by another fullscreen view - if (workspace->sway_workspace->fullscreen && - !container_is_fullscreen_or_child(view->swayc)) { + if (workspace->fullscreen && + !container_is_fullscreen_or_child(view->container)) { return false; } // Check the workspace is visible @@ -1047,7 +1013,7 @@ void view_set_urgent(struct sway_view *view, bool enable) { } if (enable) { struct sway_seat *seat = input_manager_current_seat(input_manager); - if (seat_get_focus(seat) == view->swayc) { + if (seat_get_focused_container(seat) == view->container) { return; } clock_gettime(CLOCK_MONOTONIC, &view->urgent); @@ -1058,12 +1024,11 @@ void view_set_urgent(struct sway_view *view, bool enable) { view->urgent_timer = NULL; } } - container_damage_whole(view->swayc); + container_damage_whole(view->container); - ipc_event_window(view->swayc, "urgent"); + ipc_event_window(view->container, "urgent"); - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - workspace_detect_urgent(ws); + workspace_detect_urgent(view->container->workspace); } bool view_is_urgent(struct sway_view *view) { diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 1957d94fc..38ee478e9 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -12,128 +12,105 @@ #include "sway/output.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" +#include "sway/tree/node.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "list.h" #include "log.h" #include "util.h" -struct sway_container *workspace_get_initial_output(const char *name) { - struct sway_container *parent; +struct sway_output *workspace_get_initial_output(const char *name) { // Search for workspace<->output pair - int e = config->workspace_outputs->length; for (int i = 0; i < config->workspace_outputs->length; ++i) { struct workspace_output *wso = config->workspace_outputs->items[i]; if (strcasecmp(wso->workspace, name) == 0) { // Find output to use if it exists - e = root_container.children->length; - for (i = 0; i < e; ++i) { - parent = root_container.children->items[i]; - if (strcmp(parent->name, wso->output) == 0) { - return parent; - } + struct sway_output *output = output_by_name(wso->output); + if (output) { + return output; } break; } } // Otherwise put it on the focused output struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = - seat_get_focus_inactive(seat, &root_container); - parent = focus; - parent = container_parent(parent, C_OUTPUT); - return parent; + struct sway_workspace *focus = seat_get_focused_workspace(seat); + return focus->output; } -struct sway_container *workspace_create(struct sway_container *output, +struct sway_workspace *workspace_create(struct sway_output *output, const char *name) { if (output == NULL) { output = workspace_get_initial_output(name); } - wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); - struct sway_container *workspace = container_create(C_WORKSPACE); + wlr_log(WLR_DEBUG, "Adding workspace %s for output %s", name, + output->wlr_output->name); - workspace->x = output->x; - workspace->y = output->y; - workspace->width = output->width; - workspace->height = output->height; - workspace->name = !name ? NULL : strdup(name); - workspace->prev_split_layout = L_NONE; - workspace->layout = container_get_default_layout(output); - - struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); - if (!swayws) { + struct sway_workspace *ws = calloc(1, sizeof(struct sway_workspace)); + if (!ws) { + wlr_log(WLR_ERROR, "Unable to allocate sway_workspace"); return NULL; } - swayws->swayc = workspace; - swayws->floating = create_list(); - swayws->output_priority = create_list(); - workspace->sway_workspace = swayws; - workspace_output_add_priority(workspace, output); + node_init(&ws->node, N_WORKSPACE, ws); + ws->x = output->wlr_output->lx; + ws->y = output->wlr_output->ly; + ws->width = output->wlr_output->width; + ws->height = output->wlr_output->height; + ws->name = name ? strdup(name) : NULL; + ws->prev_split_layout = L_NONE; + ws->layout = output_get_default_layout(output); + ws->floating = create_list(); + ws->tiling = create_list(); + ws->output_priority = create_list(); + workspace_output_add_priority(ws, output); - container_add_child(output, workspace); + output_add_workspace(output, ws); output_sort_workspaces(output); - container_create_notify(workspace); - return workspace; + ipc_event_workspace(NULL, ws, "init"); + wl_signal_emit(&root->events.new_node, &ws->node); + + return ws; } -void workspace_destroy(struct sway_container *workspace) { - if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { - return; - } - if (!sway_assert(workspace->destroying, +void workspace_destroy(struct sway_workspace *workspace) { + if (!sway_assert(workspace->node.destroying, "Tried to free workspace which wasn't marked as destroying")) { return; } - if (!sway_assert(workspace->ntxnrefs == 0, "Tried to free workspace " + if (!sway_assert(workspace->node.ntxnrefs == 0, "Tried to free workspace " "which is still referenced by transactions")) { return; } - // sway_workspace - struct sway_workspace *ws = workspace->sway_workspace; - list_foreach(ws->output_priority, free); - list_free(ws->output_priority); - list_free(ws->floating); - free(ws); - // swayc free(workspace->name); - free(workspace->formatted_title); - wlr_texture_destroy(workspace->title_focused); - wlr_texture_destroy(workspace->title_focused_inactive); - wlr_texture_destroy(workspace->title_unfocused); - wlr_texture_destroy(workspace->title_urgent); - list_free(workspace->children); - list_free(workspace->current.children); - list_free(workspace->outputs); + free(workspace->representation); + list_foreach(workspace->output_priority, free); + list_free(workspace->output_priority); + list_free(workspace->floating); + list_free(workspace->tiling); + list_free(workspace->current.floating); + list_free(workspace->current.tiling); free(workspace); } -void workspace_begin_destroy(struct sway_container *workspace) { - if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { - return; - } +void workspace_begin_destroy(struct sway_workspace *workspace) { wlr_log(WLR_DEBUG, "Destroying workspace '%s'", workspace->name); - wl_signal_emit(&workspace->events.destroy, workspace); ipc_event_workspace(NULL, workspace, "empty"); // intentional + wl_signal_emit(&workspace->node.events.destroy, &workspace->node); - workspace->destroying = true; - container_set_dirty(workspace); - - if (workspace->parent) { - container_remove_child(workspace); + if (workspace->output) { + workspace_detach(workspace); } + + workspace->node.destroying = true; + node_set_dirty(&workspace->node); } -void workspace_consider_destroy(struct sway_container *ws) { - if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { - return; - } - struct sway_seat *seat = input_manager_current_seat(input_manager); - if (ws->children->length == 0 && ws->sway_workspace->floating->length == 0 - && seat_get_active_child(seat, ws->parent) != ws) { +void workspace_consider_destroy(struct sway_workspace *ws) { + if (ws->tiling->length == 0 && ws->floating->length == 0 + && output_get_active_workspace(ws->output) != ws) { workspace_begin_destroy(ws); } } @@ -272,59 +249,49 @@ char *workspace_next_name(const char *output_name) { } // As a fall back, get the current number of active workspaces // and return that + 1 for the next workspace's name - int ws_num = root_container.children->length; + int ws_num = root->outputs->length; int l = snprintf(NULL, 0, "%d", ws_num); char *name = malloc(l + 1); - if (!sway_assert(name, "Cloud not allocate workspace name")) { + if (!sway_assert(name, "Could not allocate workspace name")) { return NULL; } sprintf(name, "%d", ws_num++); return name; } -static bool _workspace_by_number(struct sway_container *view, void *data) { - if (view->type != C_WORKSPACE) { - return false; - } +static bool _workspace_by_number(struct sway_workspace *ws, void *data) { char *name = data; - char *view_name = view->name; + char *ws_name = ws->name; while (isdigit(*name)) { - if (*name++ != *view_name++) { + if (*name++ != *ws_name++) { return false; } } - return !isdigit(*view_name); + return !isdigit(*ws_name); } -struct sway_container *workspace_by_number(const char* name) { +struct sway_workspace *workspace_by_number(const char* name) { return root_find_workspace(_workspace_by_number, (void *) name); } -static bool _workspace_by_name(struct sway_container *view, void *data) { - return (view->type == C_WORKSPACE) && - (strcasecmp(view->name, (char *) data) == 0); +static bool _workspace_by_name(struct sway_workspace *ws, void *data) { + return strcasecmp(ws->name, data) == 0; } -struct sway_container *workspace_by_name(const char *name) { +struct sway_workspace *workspace_by_name(const char *name) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *current_workspace = NULL, *current_output = NULL; - struct sway_container *focus = seat_get_focus(seat); - if (focus) { - current_workspace = focus->type == C_WORKSPACE ? - focus : container_parent(focus, C_WORKSPACE); - current_output = container_parent(focus, C_OUTPUT); - } + struct sway_workspace *current = seat_get_focused_workspace(seat); if (strcmp(name, "prev") == 0) { - return workspace_prev(current_workspace); + return workspace_prev(current); } else if (strcmp(name, "prev_on_output") == 0) { - return workspace_output_prev(current_output); + return workspace_output_prev(current); } else if (strcmp(name, "next") == 0) { - return workspace_next(current_workspace); + return workspace_next(current); } else if (strcmp(name, "next_on_output") == 0) { - return workspace_output_next(current_output); + return workspace_output_next(current); } else if (strcmp(name, "current") == 0) { - return current_workspace; + return current; } else if (strcasecmp(name, "back_and_forth") == 0) { return prev_workspace_name ? root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) @@ -339,97 +306,68 @@ struct sway_container *workspace_by_name(const char *name) { * the end and beginning. If next is false, the previous workspace is returned, * otherwise the next one is returned. */ -static struct sway_container *workspace_output_prev_next_impl( - struct sway_container *output, int dir) { - if (!output) { - return NULL; - } - if (!sway_assert(output->type == C_OUTPUT, - "Argument must be an output, is %d", output->type)) { - return NULL; - } - +static struct sway_workspace *workspace_output_prev_next_impl( + struct sway_output *output, int dir) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, output); - struct sway_container *workspace = (focus->type == C_WORKSPACE ? - focus : - container_parent(focus, C_WORKSPACE)); + struct sway_workspace *workspace = seat_get_focused_workspace(seat); - int index = list_find(output->children, workspace); - size_t new_index = wrap(index + dir, output->children->length); - return output->children->items[new_index]; + int index = list_find(output->workspaces, workspace); + size_t new_index = wrap(index + dir, output->workspaces->length); + return output->workspaces->items[new_index]; } /** * Get the previous or next workspace. If the first/last workspace on an output * is active, proceed to the previous/next output's previous/next workspace. */ -static struct sway_container *workspace_prev_next_impl( - struct sway_container *workspace, int dir) { - if (!workspace) { - return NULL; - } - if (!sway_assert(workspace->type == C_WORKSPACE, - "Argument must be a workspace, is %d", workspace->type)) { - return NULL; - } - - struct sway_container *output = workspace->parent; - int index = list_find(output->children, workspace); +static struct sway_workspace *workspace_prev_next_impl( + struct sway_workspace *workspace, int dir) { + struct sway_output *output = workspace->output; + int index = list_find(output->workspaces, workspace); int new_index = index + dir; - if (new_index >= 0 && new_index < output->children->length) { - return output->children->items[index + dir]; + if (new_index >= 0 && new_index < output->workspaces->length) { + return output->workspaces->items[new_index]; } // Look on a different output - int output_index = list_find(root_container.children, output); - new_index = wrap(output_index + dir, root_container.children->length); - output = root_container.children->items[new_index]; + int output_index = list_find(root->outputs, output); + new_index = wrap(output_index + dir, root->outputs->length); + output = root->outputs->items[new_index]; if (dir == 1) { - return output->children->items[0]; + return output->workspaces->items[0]; } else { - return output->children->items[output->children->length - 1]; + return output->workspaces->items[output->workspaces->length - 1]; } } -struct sway_container *workspace_output_next(struct sway_container *current) { - return workspace_output_prev_next_impl(current, 1); +struct sway_workspace *workspace_output_next(struct sway_workspace *current) { + return workspace_output_prev_next_impl(current->output, 1); } -struct sway_container *workspace_next(struct sway_container *current) { +struct sway_workspace *workspace_next(struct sway_workspace *current) { return workspace_prev_next_impl(current, 1); } -struct sway_container *workspace_output_prev(struct sway_container *current) { - return workspace_output_prev_next_impl(current, -1); +struct sway_workspace *workspace_output_prev(struct sway_workspace *current) { + return workspace_output_prev_next_impl(current->output, -1); } -struct sway_container *workspace_prev(struct sway_container *current) { +struct sway_workspace *workspace_prev(struct sway_workspace *current) { return workspace_prev_next_impl(current, -1); } -bool workspace_switch(struct sway_container *workspace, +bool workspace_switch(struct sway_workspace *workspace, bool no_auto_back_and_forth) { - if (!workspace) { - return false; - } struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = - seat_get_focus_inactive(seat, &root_container); - if (!seat || !focus) { - return false; - } - struct sway_container *active_ws = focus; - if (active_ws->type != C_WORKSPACE) { - active_ws = container_parent(focus, C_WORKSPACE); - } + struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); + struct sway_workspace *active_ws = seat_get_focused_workspace(seat); 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); + struct sway_workspace *new_ws = workspace_by_name(prev_workspace_name); workspace = new_ws ? new_ws : workspace_create(NULL, prev_workspace_name); @@ -447,21 +385,21 @@ bool workspace_switch(struct sway_container *workspace, } // Move sticky containers to new workspace - struct sway_container *next_output = workspace->parent; - struct sway_container *next_output_prev_ws = - seat_get_active_child(seat, next_output); - list_t *floating = next_output_prev_ws->sway_workspace->floating; + struct sway_output *next_output = workspace->output; + struct sway_workspace *next_output_prev_ws = + output_get_active_workspace(next_output); bool has_sticky = false; if (workspace != next_output_prev_ws) { - for (int i = 0; i < floating->length; ++i) { - struct sway_container *floater = floating->items[i]; + for (int i = 0; i < next_output_prev_ws->floating->length; ++i) { + struct sway_container *floater = + next_output_prev_ws->floating->items[i]; if (floater->is_sticky) { has_sticky = true; - container_remove_child(floater); + container_detach(floater); workspace_add_floating(workspace, floater); - if (floater == focus) { + if (&floater->node == focus) { seat_set_focus(seat, NULL); - seat_set_focus(seat, floater); + seat_set_focus(seat, &floater->node); } --i; } @@ -470,9 +408,9 @@ bool workspace_switch(struct sway_container *workspace, wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); - struct sway_container *next = seat_get_focus_inactive(seat, workspace); + struct sway_node *next = seat_get_focus_inactive(seat, &workspace->node); if (next == NULL) { - next = workspace; + next = &workspace->node; } if (has_sticky) { // If there's a sticky container, we might be setting focus to the same @@ -483,35 +421,24 @@ bool workspace_switch(struct sway_container *workspace, workspace_consider_destroy(active_ws); } seat_set_focus(seat, next); - struct sway_container *output = container_parent(workspace, C_OUTPUT); - arrange_windows(output); + arrange_workspace(workspace); return true; } -bool workspace_is_visible(struct sway_container *ws) { - if (ws->destroying) { +bool workspace_is_visible(struct sway_workspace *ws) { + if (ws->node.destroying) { return false; } - struct sway_container *output = container_parent(ws, C_OUTPUT); - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, output); - if (focus->type != C_WORKSPACE) { - focus = container_parent(focus, C_WORKSPACE); - } - return focus == ws; + return output_get_active_workspace(ws->output) == ws; } -bool workspace_is_empty(struct sway_container *ws) { - if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { - return false; - } - if (ws->children->length) { +bool workspace_is_empty(struct sway_workspace *ws) { + if (ws->tiling->length) { return false; } // Sticky views are not considered to be part of this workspace - list_t *floating = ws->sway_workspace->floating; - for (int i = 0; i < floating->length; ++i) { - struct sway_container *floater = floating->items[i]; + for (int i = 0; i < ws->floating->length; ++i) { + struct sway_container *floater = ws->floating->items[i]; if (!floater->is_sticky) { return false; } @@ -523,20 +450,19 @@ static int find_output(const void *id1, const void *id2) { return strcmp(id1, id2) ? 0 : 1; } -void workspace_output_raise_priority(struct sway_container *workspace, - struct sway_container *old_output, struct sway_container *output) { - struct sway_workspace *ws = workspace->sway_workspace; - +void workspace_output_raise_priority(struct sway_workspace *ws, + struct sway_output *old_output, struct sway_output *output) { int old_index = list_seq_find(ws->output_priority, find_output, - old_output->name); + old_output->wlr_output->name); if (old_index < 0) { return; } int new_index = list_seq_find(ws->output_priority, find_output, - output->name); + output->wlr_output->name); if (new_index < 0) { - list_insert(ws->output_priority, old_index, strdup(output->name)); + list_insert(ws->output_priority, old_index, + strdup(output->wlr_output->name)); } else if (new_index > old_index) { char *name = ws->output_priority->items[new_index]; list_del(ws->output_priority, new_index); @@ -544,29 +470,24 @@ void workspace_output_raise_priority(struct sway_container *workspace, } } -void workspace_output_add_priority(struct sway_container *workspace, - struct sway_container *output) { - int index = list_seq_find(workspace->sway_workspace->output_priority, - find_output, output->name); +void workspace_output_add_priority(struct sway_workspace *workspace, + struct sway_output *output) { + int index = list_seq_find(workspace->output_priority, + find_output, output->wlr_output->name); if (index < 0) { - list_add(workspace->sway_workspace->output_priority, - strdup(output->name)); + list_add(workspace->output_priority, strdup(output->wlr_output->name)); } } -static bool _output_by_name(struct sway_container *output, void *data) { - return output->type == C_OUTPUT && strcasecmp(output->name, data) == 0; -} - -struct sway_container *workspace_output_get_highest_available( - struct sway_container *ws, struct sway_container *exclude) { - for (int i = 0; i < ws->sway_workspace->output_priority->length; i++) { - char *name = ws->sway_workspace->output_priority->items[i]; - if (exclude && strcasecmp(name, exclude->name) == 0) { +struct sway_output *workspace_output_get_highest_available( + struct sway_workspace *ws, struct sway_output *exclude) { + for (int i = 0; i < ws->output_priority->length; i++) { + char *name = ws->output_priority->items[i]; + if (exclude && strcasecmp(name, exclude->wlr_output->name) == 0) { continue; } - struct sway_container *output = root_find_output(_output_by_name, name); + struct sway_output *output = output_by_name(name); if (output) { return output; } @@ -576,49 +497,42 @@ struct sway_container *workspace_output_get_highest_available( } static bool find_urgent_iterator(struct sway_container *con, void *data) { - return con->type == C_VIEW && view_is_urgent(con->sway_view); + return con->view && view_is_urgent(con->view); } -void workspace_detect_urgent(struct sway_container *workspace) { +void workspace_detect_urgent(struct sway_workspace *workspace) { bool new_urgent = (bool)workspace_find_container(workspace, find_urgent_iterator, NULL); - if (workspace->sway_workspace->urgent != new_urgent) { - workspace->sway_workspace->urgent = new_urgent; + if (workspace->urgent != new_urgent) { + workspace->urgent = new_urgent; ipc_event_workspace(NULL, workspace, "urgent"); - container_damage_whole(workspace); + output_damage_whole(workspace->output); } } -void workspace_for_each_container(struct sway_container *ws, +void workspace_for_each_container(struct sway_workspace *ws, void (*f)(struct sway_container *con, void *data), void *data) { - if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { - return; - } // Tiling - for (int i = 0; i < ws->children->length; ++i) { - struct sway_container *container = ws->children->items[i]; + for (int i = 0; i < ws->tiling->length; ++i) { + struct sway_container *container = ws->tiling->items[i]; f(container, data); container_for_each_child(container, f, data); } // Floating - for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { - struct sway_container *container = - ws->sway_workspace->floating->items[i]; + for (int i = 0; i < ws->floating->length; ++i) { + struct sway_container *container = ws->floating->items[i]; f(container, data); container_for_each_child(container, f, data); } } -struct sway_container *workspace_find_container(struct sway_container *ws, +struct sway_container *workspace_find_container(struct sway_workspace *ws, bool (*test)(struct sway_container *con, void *data), void *data) { - if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { - return NULL; - } struct sway_container *result = NULL; // Tiling - for (int i = 0; i < ws->children->length; ++i) { - struct sway_container *child = ws->children->items[i]; + for (int i = 0; i < ws->tiling->length; ++i) { + struct sway_container *child = ws->tiling->items[i]; if (test(child, data)) { return child; } @@ -627,8 +541,8 @@ struct sway_container *workspace_find_container(struct sway_container *ws, } } // Floating - for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { - struct sway_container *child = ws->sway_workspace->floating->items[i]; + for (int i = 0; i < ws->floating->length; ++i) { + struct sway_container *child = ws->floating->items[i]; if (test(child, data)) { return child; } @@ -639,37 +553,76 @@ struct sway_container *workspace_find_container(struct sway_container *ws, return NULL; } -struct sway_container *workspace_wrap_children(struct sway_container *ws) { - struct sway_container *middle = container_create(C_CONTAINER); +struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { + struct sway_container *middle = container_create(NULL); middle->layout = ws->layout; - while (ws->children->length) { - struct sway_container *child = ws->children->items[0]; - container_remove_child(child); + while (ws->tiling->length) { + struct sway_container *child = ws->tiling->items[0]; + container_detach(child); container_add_child(middle, child); } - container_add_child(ws, middle); + workspace_add_tiling(ws, middle); return middle; } -void workspace_add_floating(struct sway_container *workspace, - struct sway_container *con) { - if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { - return; - } - if (!sway_assert(con->parent == NULL, "Expected an orphan container")) { - return; +void workspace_detach(struct sway_workspace *workspace) { + struct sway_output *output = workspace->output; + int index = list_find(output->workspaces, workspace); + if (index != -1) { + list_del(output->workspaces, index); } + workspace->output = NULL; - list_add(workspace->sway_workspace->floating, con); - con->parent = workspace; - container_set_dirty(workspace); - container_set_dirty(con); + node_set_dirty(&workspace->node); + node_set_dirty(&output->node); } -void workspace_remove_gaps(struct sway_container *ws) { - if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { - return; +static void set_workspace(struct sway_container *container, void *data) { + container->workspace = container->parent->workspace; +} + +void workspace_add_tiling(struct sway_workspace *workspace, + struct sway_container *con) { + if (con->workspace) { + container_detach(con); } + list_add(workspace->tiling, con); + con->workspace = workspace; + container_for_each_child(con, set_workspace, NULL); + container_handle_fullscreen_reparent(con); + workspace_update_representation(workspace); + node_set_dirty(&workspace->node); + node_set_dirty(&con->node); +} + +void workspace_add_floating(struct sway_workspace *workspace, + struct sway_container *con) { + if (con->workspace) { + container_detach(con); + } + list_add(workspace->floating, con); + con->workspace = workspace; + container_for_each_child(con, set_workspace, NULL); + container_handle_fullscreen_reparent(con); + node_set_dirty(&workspace->node); + node_set_dirty(&con->node); +} + +void workspace_insert_tiling(struct sway_workspace *workspace, + struct sway_container *con, int index) { + if (con->workspace) { + container_detach(con); + } + list_insert(workspace->tiling, index, con); + con->workspace = workspace; + container_for_each_child(con, set_workspace, NULL); + container_handle_fullscreen_reparent(con); + workspace_update_representation(workspace); + node_set_dirty(&workspace->node); + node_set_dirty(&con->node); +} + +void workspace_remove_gaps(struct sway_workspace *ws) { if (ws->current_gaps == 0) { return; } @@ -681,15 +634,12 @@ void workspace_remove_gaps(struct sway_container *ws) { ws->current_gaps = 0; } -void workspace_add_gaps(struct sway_container *ws) { - if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { - return; - } +void workspace_add_gaps(struct sway_workspace *ws) { if (ws->current_gaps > 0) { return; } bool should_apply = - config->edge_gaps || (config->smart_gaps && ws->children->length > 1); + config->edge_gaps || (config->smart_gaps && ws->tiling->length > 1); if (!should_apply) { return; } @@ -708,3 +658,36 @@ void workspace_add_gaps(struct sway_container *ws) { ws->width -= 2 * ws->current_gaps; ws->height -= 2 * ws->current_gaps; } + +struct sway_container *workspace_split(struct sway_workspace *workspace, + enum sway_container_layout layout) { + if (workspace->tiling->length == 0) { + workspace->prev_split_layout = workspace->layout; + workspace->layout = layout; + return NULL; + } + + enum sway_container_layout old_layout = workspace->layout; + struct sway_container *middle = workspace_wrap_children(workspace); + workspace->layout = layout; + middle->layout = old_layout; + + return middle; +} + +void workspace_update_representation(struct sway_workspace *ws) { + size_t len = container_build_representation(ws->layout, ws->tiling, NULL); + free(ws->representation); + ws->representation = calloc(len + 1, sizeof(char)); + if (!sway_assert(ws->representation, "Unable to allocate title string")) { + return; + } + container_build_representation(ws->layout, ws->tiling, ws->representation); +} + +void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box) { + box->x = workspace->x; + box->y = workspace->y; + box->width = workspace->width; + box->height = workspace->height; +}