mirror of
https://github.com/swaywm/sway.git
synced 2024-11-23 00:11:28 +00:00
Merge pull request #2540 from RyanDwyer/typesafety
Implement type safe arguments and demote sway_container
This commit is contained in:
commit
610eb94617
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef _SWAY_TRANSACTION_H
|
||||
#define _SWAY_TRANSACTION_H
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include "sway/tree/container.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -6,14 +6,20 @@
|
|||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#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,18 @@ struct sway_output {
|
|||
struct timespec last_frame;
|
||||
struct wlr_output_damage *damage;
|
||||
|
||||
int lx, ly;
|
||||
int width, height;
|
||||
|
||||
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 +52,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 +83,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 +126,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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#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,
|
||||
void container_add_sibling(struct sway_container *parent,
|
||||
struct sway_container *child);
|
||||
|
||||
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);
|
||||
|
||||
|
|
74
include/sway/tree/node.h
Normal file
74
include/sway/tree/node.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
#ifndef _SWAY_NODE_H
|
||||
#define _SWAY_NODE_H
|
||||
#include <stdbool.h>
|
||||
#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
|
|
@ -5,12 +5,14 @@
|
|||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -3,66 +3,98 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -34,58 +34,49 @@ 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);
|
||||
}
|
||||
break;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case MOVE_UP:
|
||||
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;
|
||||
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 top child of new output
|
||||
container = ws->tiling->items[0];
|
||||
} else {
|
||||
container = seat_get_focus_inactive_tiling(seat, ws);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -94,151 +85,90 @@ static struct sway_container *get_swayc_in_output_direction(
|
|||
}
|
||||
}
|
||||
|
||||
return ws;
|
||||
if (container) {
|
||||
container = seat_get_focus_inactive_view(seat, &container->node);
|
||||
return &container->node;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (dir == MOVE_CHILD) {
|
||||
return seat_get_focus_inactive(seat, container);
|
||||
}
|
||||
static struct sway_node *node_get_in_direction(struct sway_container *container,
|
||||
struct sway_seat *seat, enum movement_direction dir) {
|
||||
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 +176,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 +185,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 <direction|name>'");
|
||||
}
|
||||
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 +202,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 +218,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 +253,34 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
|
|||
"or 'focus output <direction|name>'");
|
||||
}
|
||||
|
||||
struct sway_container *next_focus = container_get_in_direction(
|
||||
con, seat, direction);
|
||||
if (direction == MOVE_CHILD) {
|
||||
struct sway_node *focus = seat_get_active_child(seat, node);
|
||||
if (focus) {
|
||||
seat_set_focus(seat, focus);
|
||||
}
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
if (node->type == N_WORKSPACE) {
|
||||
if (direction == MOVE_PARENT) {
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
// Jump to the next output
|
||||
struct sway_output *new_output =
|
||||
output_get_in_direction(workspace->output, direction);
|
||||
if (!new_output) {
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 <math.h>
|
||||
|
@ -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 <amount>
|
||||
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 <amount>)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,129 @@ 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) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
|
|||
"Expected 'smart_gaps <on|off>' ");
|
||||
}
|
||||
|
||||
arrange_windows(&root_container);
|
||||
arrange_root();
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <strings.h>
|
||||
#include <signal.h>
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
@ -117,7 +118,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (criteria->con_mark) {
|
||||
bool exists = false;
|
||||
for (int i = 0; i < view->marks->length; ++i) {
|
||||
|
@ -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);
|
||||
|
|
|
@ -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->width,
|
||||
node->sway_output->height,
|
||||
node->sway_output->lx,
|
||||
node->sway_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->width > width) {
|
||||
width = output->width;
|
||||
}
|
||||
if (container->height > height) {
|
||||
height = container->height;
|
||||
if (output->height > height) {
|
||||
height = 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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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->width,
|
||||
.height = 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->width,
|
||||
.y2 = 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;
|
||||
}
|
||||
|
|
|
@ -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->width,
|
||||
.height = 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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,13 +54,13 @@ 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,
|
||||
.x = output->lx - view->x,
|
||||
.y = output->ly - view->y,
|
||||
.width = output->width,
|
||||
.height = output->height,
|
||||
};
|
||||
|
@ -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);
|
||||
|
|
|
@ -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,13 +53,13 @@ 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,
|
||||
.x = output->lx - view->x,
|
||||
.y = output->ly - view->y,
|
||||
.width = output->width,
|
||||
.height = output->height,
|
||||
};
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,54 @@ 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 NULL;
|
||||
}
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
if ((*surface = layer_surface_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
ox, oy, sx, sy))) {
|
||||
return ws;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 output->swayc;
|
||||
return &ws->node;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,13 +148,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 +167,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 +208,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 +249,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 +257,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 +301,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 +344,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 +422,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 &&
|
||||
next_focus->sway_container->view &&
|
||||
view_is_visible(next_focus->sway_container->view)) {
|
||||
seat_set_focus_warp(seat, next_focus, false, true);
|
||||
}
|
||||
}
|
||||
|
@ -486,12 +469,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)) {
|
||||
|
@ -637,8 +620,10 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
|
|||
// Determine what's under the cursor
|
||||
struct wlr_surface *surface = NULL;
|
||||
double sx, sy;
|
||||
struct sway_container *cont = container_at_coords(seat,
|
||||
struct sway_node *node = node_at_coords(seat,
|
||||
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
|
||||
struct sway_container *cont = node && node->type == N_CONTAINER ?
|
||||
node->sway_container : NULL;
|
||||
bool is_floating = cont && container_is_floating(cont);
|
||||
bool is_floating_or_child = cont && container_is_floating_or_child(cont);
|
||||
bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont);
|
||||
|
@ -670,6 +655,12 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
|
|||
return;
|
||||
}
|
||||
|
||||
// Handle clicking an empty workspace
|
||||
if (node && node->type == N_WORKSPACE) {
|
||||
seat_set_focus(seat, node);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle clicking a layer surface
|
||||
if (surface && wlr_surface_is_layer_surface(surface)) {
|
||||
struct wlr_layer_surface *layer =
|
||||
|
@ -684,7 +675,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 +704,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 +716,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 +738,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 +753,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 +761,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;
|
||||
}
|
||||
|
@ -808,7 +799,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
|
|||
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
|
||||
event->x, event->y, &lx, &ly);
|
||||
double sx, sy;
|
||||
container_at_coords(seat, lx, ly, &surface, &sx, &sy);
|
||||
node_at_coords(seat, lx, ly, &surface, &sx, &sy);
|
||||
|
||||
seat->touch_id = event->touch_id;
|
||||
seat->touch_x = lx;
|
||||
|
@ -850,7 +841,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
|
|||
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
|
||||
event->x, event->y, &lx, &ly);
|
||||
double sx, sy;
|
||||
container_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
|
||||
node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
|
||||
|
||||
if (seat->touch_id == event->touch_id) {
|
||||
seat->touch_x = lx;
|
||||
|
@ -1025,8 +1016,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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,71 @@ 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;
|
||||
// Unfocus the previous focus
|
||||
if (last_focus) {
|
||||
seat_send_unfocus(last_focus, seat);
|
||||
node_set_dirty(last_focus);
|
||||
struct sway_node *parent = node_get_parent(last_focus);
|
||||
if (parent) {
|
||||
node_set_dirty(parent);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (last_focus) {
|
||||
seat_send_unfocus(last_focus, seat);
|
||||
container_set_dirty(last_focus);
|
||||
}
|
||||
seat_send_focus(container, seat);
|
||||
|
||||
container_set_dirty(container);
|
||||
container_set_dirty(container->parent); // for focused_inactive_child
|
||||
}
|
||||
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);
|
||||
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 +666,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 +693,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) {
|
||||
|
@ -725,16 +710,20 @@ 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,
|
||||
seat->cursor->cursor->y)) {
|
||||
wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
|
||||
cursor_send_pointer_motion(seat->cursor, 0, true);
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (container) {
|
||||
x = container->x + container->width / 2.0;
|
||||
y = container->y + container->height / 2.0;
|
||||
} else {
|
||||
x = new_workspace->x + new_workspace->width / 2.0;
|
||||
y = new_workspace->y + new_workspace->height / 2.0;
|
||||
}
|
||||
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 +733,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 +743,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 +760,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 +782,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 +794,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 +817,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,
|
||||
|
|
187
sway/ipc-json.c
187
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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,37 @@ 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->lx;
|
||||
fs->y = output->ly;
|
||||
fs->width = output->width;
|
||||
fs->height = 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;
|
||||
root->output_layout, output->wlr_output);
|
||||
output->lx = output_box->x;
|
||||
output->ly = 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];
|
||||
|
||||
for (int i = 0; i < output->workspaces->length; ++i) {
|
||||
struct sway_workspace *workspace = output->workspaces->items[i];
|
||||
arrange_workspace(workspace);
|
||||
}
|
||||
}
|
||||
|
@ -264,37 +251,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;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
151
sway/tree/node.c
Normal file
151
sway/tree/node.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -2,28 +2,31 @@
|
|||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_output_damage.h>
|
||||
#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,202 @@ 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);
|
||||
|
||||
output->lx = wlr_output->lx;
|
||||
output->ly = wlr_output->ly;
|
||||
wlr_output_transformed_resolution(wlr_output,
|
||||
&output->width, &output->height);
|
||||
|
||||
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) {
|
||||
|
@ -70,192 +253,61 @@ struct sway_container *output_create(
|
|||
oc = all;
|
||||
}
|
||||
|
||||
if (oc && !oc->enabled) {
|
||||
return oc;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
int lx = reference->wlr_output->lx + reference->width / 2;
|
||||
int ly = reference->wlr_output->ly + reference->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;
|
||||
}
|
||||
|
||||
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;
|
||||
return output_from_wlr_output(wlr_adjacent);
|
||||
}
|
||||
|
||||
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_add_workspace(struct sway_output *output,
|
||||
struct sway_workspace *workspace) {
|
||||
if (workspace->output) {
|
||||
workspace_detach(workspace);
|
||||
}
|
||||
list_add(output->workspaces, workspace);
|
||||
workspace->output = output;
|
||||
node_set_dirty(&output->node);
|
||||
node_set_dirty(&workspace->node);
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
for (int i = 0; i < output->children->length; ++i) {
|
||||
struct sway_container *workspace = output->children->items[i];
|
||||
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 +315,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 +328,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 +343,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->lx;
|
||||
box->y = output->ly;
|
||||
box->width = output->width;
|
||||
box->height = 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->height > output->width) {
|
||||
return L_VERT;
|
||||
}
|
||||
return L_HORIZ;
|
||||
}
|
||||
|
|
184
sway/tree/root.c
184
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;
|
||||
}
|
||||
|
|
275
sway/tree/view.c
275
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,31 @@ 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")) {
|
||||
if (!view->container->workspace) {
|
||||
// Hidden in the scratchpad
|
||||
return;
|
||||
}
|
||||
struct sway_output *output = view->container->workspace->output;
|
||||
|
||||
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
|
||||
|
||||
if (view->swayc->is_fullscreen) {
|
||||
view->x = output->x;
|
||||
view->y = output->y;
|
||||
if (view->container->is_fullscreen) {
|
||||
view->x = output->lx;
|
||||
view->y = output->ly;
|
||||
view->width = output->width;
|
||||
view->height = output->height;
|
||||
return;
|
||||
}
|
||||
|
||||
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
|
||||
struct sway_workspace *ws = view->container->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 +196,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 +222,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 +276,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 +294,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 +329,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 +383,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 +395,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 +407,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 +468,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 +484,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 +506,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);
|
||||
} 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 +533,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 +541,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 +559,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 if (ws) {
|
||||
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 && !ws->node.destroying) {
|
||||
arrange_workspace(ws);
|
||||
workspace_detect_urgent(ws);
|
||||
}
|
||||
|
||||
|
@ -593,15 +578,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 +655,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 +784,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 +810,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 +837,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 +846,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 +862,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 +879,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 +923,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 +968,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 +1017,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 +1028,13 @@ 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);
|
||||
if (view->container->workspace) {
|
||||
workspace_detect_urgent(view->container->workspace);
|
||||
}
|
||||
}
|
||||
|
||||
bool view_is_urgent(struct sway_view *view) {
|
||||
|
|
|
@ -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->lx;
|
||||
ws->y = output->ly;
|
||||
ws->width = output->width;
|
||||
ws->height = 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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue