mirror of
https://github.com/swaywm/sway.git
synced 2024-11-29 19:31:29 +00:00
Merge pull request #1702 from acrisci/split-containers2
properly close container containers
This commit is contained in:
commit
dee71871d7
|
@ -91,13 +91,11 @@ struct sway_container {
|
|||
} events;
|
||||
};
|
||||
|
||||
// TODO make private and use the container-specific create functions
|
||||
struct sway_container *container_create(enum sway_container_type type);
|
||||
|
||||
const char *container_type_to_str(enum sway_container_type type);
|
||||
|
||||
// TODO only one container create function and pass the type?
|
||||
struct sway_container *container_output_create(
|
||||
struct sway_container *output_create(
|
||||
struct sway_output *sway_output);
|
||||
|
||||
/**
|
||||
|
@ -110,35 +108,26 @@ struct sway_container *container_container_create();
|
|||
* Create a new output. Outputs are children of the root container and have no
|
||||
* order in the tree structure.
|
||||
*/
|
||||
struct sway_container *container_output_create(struct sway_output *sway_output);
|
||||
struct sway_container *output_create(struct sway_output *sway_output);
|
||||
|
||||
/**
|
||||
* Create a new workspace container. Workspaces are children of an output
|
||||
* container and are ordered alphabetically by name.
|
||||
*/
|
||||
struct sway_container *container_workspace_create(struct sway_container *output, const char *name);
|
||||
struct sway_container *workspace_create(struct sway_container *output, const char *name);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// TODO view containers should be created in a detached state.
|
||||
struct sway_container *container_view_create(
|
||||
struct sway_container *sibling, struct sway_view *sway_view);
|
||||
|
||||
// TODO don't return the parent on destroy
|
||||
struct sway_container *container_destroy(struct sway_container *container);
|
||||
|
||||
struct sway_container *container_workspace_destroy(struct sway_container *container);
|
||||
struct sway_container *container_output_destroy(struct sway_container *container);
|
||||
struct sway_container *container_view_destroy(struct sway_container *container);
|
||||
struct sway_container *container_close(struct sway_container *container);
|
||||
|
||||
// TODO move to layout.c
|
||||
struct sway_container *container_set_layout(struct sway_container *container,
|
||||
enum sway_container_layout layout);
|
||||
|
||||
// TODO rename to container_descendants_for_each()
|
||||
void container_descendants(struct sway_container *root,
|
||||
enum sway_container_type type,
|
||||
void (*func)(struct sway_container *item, void *data), void *data);
|
||||
|
@ -153,7 +142,6 @@ struct sway_container *container_find(struct sway_container *container,
|
|||
/**
|
||||
* Finds a parent container with the given struct sway_containerype.
|
||||
*/
|
||||
// TODO rename to container_parent_of_type()
|
||||
struct sway_container *container_parent(struct sway_container *container,
|
||||
enum sway_container_type type);
|
||||
|
||||
|
@ -190,4 +178,6 @@ bool container_has_anscestor(struct sway_container *container,
|
|||
bool container_has_child(struct sway_container *con,
|
||||
struct sway_container *child);
|
||||
|
||||
void container_create_notify(struct sway_container *container);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,42 +29,37 @@ struct sway_root {
|
|||
|
||||
void layout_init(void);
|
||||
|
||||
// TODO move to tree.h
|
||||
void container_add_child(struct sway_container *parent,
|
||||
struct sway_container *child);
|
||||
|
||||
// TODO move to tree.h
|
||||
struct sway_container *container_add_sibling(struct sway_container *parent,
|
||||
struct sway_container *child);
|
||||
|
||||
// TODO move to tree.h
|
||||
struct sway_container *container_remove_child(struct sway_container *child);
|
||||
|
||||
// TODO PRIVATE in tree.h
|
||||
struct sway_container *container_reap_empty(struct sway_container *container);
|
||||
struct sway_container *container_replace_child(struct sway_container *child,
|
||||
struct sway_container *new_child);
|
||||
|
||||
struct sway_container *container_set_layout(struct sway_container *container,
|
||||
enum sway_container_layout layout);
|
||||
|
||||
// TODO move to tree.h
|
||||
void container_move_to(struct sway_container* container,
|
||||
struct sway_container* destination);
|
||||
|
||||
void container_move(struct sway_container *container,
|
||||
enum movement_direction dir, int move_amt);
|
||||
|
||||
// TODO move to output.c
|
||||
enum sway_container_layout container_get_default_layout(
|
||||
struct sway_container *output);
|
||||
struct sway_container *con);
|
||||
|
||||
// TODO move to output.c
|
||||
void container_sort_workspaces(struct sway_container *output);
|
||||
|
||||
void arrange_windows(struct sway_container *container,
|
||||
double width, double height);
|
||||
|
||||
// TODO move to container.h
|
||||
struct sway_container *container_get_in_direction(struct sway_container
|
||||
*container, struct sway_seat *seat, enum movement_direction dir);
|
||||
|
||||
// TODO move to tree.h
|
||||
struct sway_container *container_split(struct sway_container *child,
|
||||
enum sway_container_layout layout);
|
||||
|
||||
|
|
0
include/sway/tree/output.h
Normal file
0
include/sway/tree/output.h
Normal file
|
@ -7,8 +7,6 @@ extern char *prev_workspace_name;
|
|||
|
||||
char *workspace_next_name(const char *output_name);
|
||||
|
||||
struct sway_container *workspace_create(const char *name);
|
||||
|
||||
bool workspace_switch(struct sway_container *workspace);
|
||||
|
||||
struct sway_container *workspace_by_number(const char* name);
|
||||
|
|
|
@ -10,22 +10,7 @@ struct cmd_results *cmd_kill(int argc, char **argv) {
|
|||
struct sway_container *con =
|
||||
config->handler_context.current_container;
|
||||
|
||||
switch (con->type) {
|
||||
case C_ROOT:
|
||||
case C_OUTPUT:
|
||||
case C_WORKSPACE:
|
||||
case C_TYPES:
|
||||
return cmd_results_new(CMD_INVALID, NULL,
|
||||
"Can only kill views and containers with this command");
|
||||
break;
|
||||
case C_CONTAINER:
|
||||
con = container_destroy(con);
|
||||
arrange_windows(con, -1, -1);
|
||||
break;
|
||||
case C_VIEW:
|
||||
view_close(con->sway_view);
|
||||
break;
|
||||
}
|
||||
container_close(con);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
|
|||
if (strcasecmp(argv[0], "default") == 0) {
|
||||
container_set_layout(parent, parent->prev_layout);
|
||||
if (parent->layout == L_NONE) {
|
||||
struct sway_container *output = container_parent(parent, C_OUTPUT);
|
||||
container_set_layout(parent, container_get_default_layout(output));
|
||||
container_set_layout(parent, container_get_default_layout(parent));
|
||||
}
|
||||
} else {
|
||||
if (parent->layout != L_TABBED && parent->layout != L_STACKED) {
|
||||
|
|
|
@ -74,7 +74,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
|
|||
ws = workspace_by_name(ws_name);
|
||||
}
|
||||
if (!ws) {
|
||||
ws = workspace_create(ws_name ? ws_name : num_name);
|
||||
ws = workspace_create(NULL, ws_name ? ws_name : num_name);
|
||||
}
|
||||
free(ws_name);
|
||||
struct sway_container *old_parent = current->parent;
|
||||
|
|
|
@ -61,7 +61,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
|
|||
if (strcasecmp(argv[0], "number") == 0) {
|
||||
if (!(ws = workspace_by_number(argv[1]))) {
|
||||
char *name = join_args(argv + 1, argc - 1);
|
||||
ws = workspace_create(name);
|
||||
ws = workspace_create(NULL, name);
|
||||
free(name);
|
||||
}
|
||||
} else if (strcasecmp(argv[0], "next") == 0) {
|
||||
|
@ -80,12 +80,12 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
|
|||
ws = old_workspace;
|
||||
} else if (prev_workspace_name
|
||||
&& !(ws = workspace_by_name(prev_workspace_name))) {
|
||||
ws = workspace_create(prev_workspace_name);
|
||||
ws = workspace_create(NULL, prev_workspace_name);
|
||||
}
|
||||
} else {
|
||||
char *name = join_args(argv, argc);
|
||||
if (!(ws = workspace_by_name(name))) {
|
||||
ws = workspace_create(name);
|
||||
ws = workspace_create(NULL, name);
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
|
|
|
@ -128,8 +128,9 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
|
|||
struct wlr_output *wlr_output = output->sway_output->wlr_output;
|
||||
|
||||
if (oc && oc->enabled == 0) {
|
||||
container_output_destroy(output);
|
||||
wlr_output_layout_remove(output_layout, wlr_output);
|
||||
container_destroy(output);
|
||||
wlr_output_layout_remove(root_container.sway_root->output_layout,
|
||||
wlr_output);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <strings.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
|
@ -21,6 +22,16 @@
|
|||
#include "sway/tree/layout.h"
|
||||
#include "sway/tree/view.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) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate a child's position relative to a parent. The parent size is (pw, ph),
|
||||
* the child position is (*sx, *sy) and its size is (sw, sh).
|
||||
|
@ -334,12 +345,12 @@ void output_damage_whole_view(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);
|
||||
container_output_destroy(output->swayc);
|
||||
container_destroy(output->swayc);
|
||||
}
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_output *output = wl_container_of(listener, output, destroy);
|
||||
container_output_destroy(output->swayc);
|
||||
container_destroy(output->swayc);
|
||||
}
|
||||
|
||||
static void handle_mode(struct wl_listener *listener, void *data) {
|
||||
|
@ -381,7 +392,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
|||
|
||||
output->damage = wlr_output_damage_create(wlr_output);
|
||||
|
||||
output->swayc = container_output_create(output);
|
||||
output->swayc = output_create(output);
|
||||
if (!output->swayc) {
|
||||
free(output);
|
||||
return;
|
||||
|
|
|
@ -384,7 +384,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
|
|||
if (last_ws) {
|
||||
ipc_event_workspace(last_ws, container, "focus");
|
||||
if (last_ws->children->length == 0) {
|
||||
container_workspace_destroy(last_ws);
|
||||
container_destroy(last_ws);
|
||||
}
|
||||
}
|
||||
struct sway_container *last_output = last_focus;
|
||||
|
|
|
@ -86,9 +86,9 @@ sway_sources = files(
|
|||
'security.c',
|
||||
'tree/container.c',
|
||||
'tree/layout.c',
|
||||
'tree/output.c',
|
||||
'tree/view.c',
|
||||
'tree/workspace.c',
|
||||
'tree/output.c',
|
||||
)
|
||||
|
||||
sway_deps = [
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -6,7 +7,6 @@
|
|||
#include <wayland-server.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_wl_shell.h>
|
||||
#include "log.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/input/seat.h"
|
||||
|
@ -50,7 +50,7 @@ const char *container_type_to_str(enum sway_container_type type) {
|
|||
}
|
||||
}
|
||||
|
||||
static void notify_new_container(struct sway_container *container) {
|
||||
void container_create_notify(struct sway_container *container) {
|
||||
wl_signal_emit(&root_container.sway_root->events.new_container, container);
|
||||
ipc_event_window(container, "new");
|
||||
}
|
||||
|
@ -76,21 +76,21 @@ struct sway_container *container_create(enum sway_container_type type) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static struct sway_container *_container_destroy(struct sway_container *cont) {
|
||||
static void _container_destroy(struct sway_container *cont) {
|
||||
if (cont == NULL) {
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
wl_signal_emit(&cont->events.destroy, cont);
|
||||
|
||||
struct sway_container *parent = cont->parent;
|
||||
if (cont->children != NULL) {
|
||||
if (cont->children != NULL && cont->children->length) {
|
||||
// remove children until there are no more, container_destroy calls
|
||||
// container_remove_child, which removes child from this container
|
||||
while (cont->children != NULL && cont->children->length != 0) {
|
||||
while (cont->children != NULL) {
|
||||
struct sway_container *child = cont->children->items[0];
|
||||
container_remove_child(child);
|
||||
container_destroy(child);
|
||||
_container_destroy(child);
|
||||
}
|
||||
}
|
||||
if (cont->marks) {
|
||||
|
@ -106,106 +106,200 @@ static struct sway_container *_container_destroy(struct sway_container *cont) {
|
|||
list_free(cont->children);
|
||||
cont->children = NULL;
|
||||
free(cont);
|
||||
return parent;
|
||||
}
|
||||
|
||||
struct sway_container *container_destroy(struct sway_container *cont) {
|
||||
struct sway_container *parent = _container_destroy(cont);
|
||||
parent = container_reap_empty(parent);
|
||||
arrange_windows(&root_container, -1, -1);
|
||||
return parent;
|
||||
static struct sway_container *container_output_destroy(
|
||||
struct sway_container *output) {
|
||||
if (!sway_assert(output, "cannot destroy null output")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_container *container_output_create(
|
||||
struct sway_output *sway_output) {
|
||||
struct wlr_box size;
|
||||
wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
|
||||
&size.height);
|
||||
|
||||
const char *name = sway_output->wlr_output->name;
|
||||
char identifier[128];
|
||||
output_get_identifier(identifier, sizeof(identifier), sway_output);
|
||||
|
||||
struct output_config *oc = NULL, *all = NULL;
|
||||
for (int i = 0; i < config->output_configs->length; ++i) {
|
||||
struct output_config *cur = config->output_configs->items[i];
|
||||
|
||||
if (strcasecmp(name, cur->name) == 0 ||
|
||||
strcasecmp(identifier, cur->name) == 0) {
|
||||
wlr_log(L_DEBUG, "Matched output config for %s", name);
|
||||
oc = cur;
|
||||
if (output->children->length > 0) {
|
||||
// TODO save workspaces when there are no outputs.
|
||||
// TODO also check if there will ever be no outputs except for exiting
|
||||
// program
|
||||
if (root_container.children->length > 1) {
|
||||
int p = root_container.children->items[0] == output;
|
||||
// Move workspace from this output to another output
|
||||
while (output->children->length) {
|
||||
struct sway_container *child = output->children->items[0];
|
||||
container_remove_child(child);
|
||||
container_add_child(root_container.children->items[p], child);
|
||||
}
|
||||
container_sort_workspaces(root_container.children->items[p]);
|
||||
arrange_windows(root_container.children->items[p],
|
||||
-1, -1);
|
||||
}
|
||||
if (strcasecmp("*", cur->name) == 0) {
|
||||
wlr_log(L_DEBUG, "Matched wildcard output config for %s", name);
|
||||
all = cur;
|
||||
}
|
||||
|
||||
if (oc && all) {
|
||||
wl_list_remove(&output->sway_output->destroy.link);
|
||||
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);
|
||||
|
||||
wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
|
||||
_container_destroy(output);
|
||||
return &root_container;
|
||||
}
|
||||
|
||||
static struct sway_container *container_workspace_destroy(
|
||||
struct sway_container *workspace) {
|
||||
if (!sway_assert(workspace, "cannot destroy null workspace")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Do not destroy this if it's the last workspace on this output
|
||||
struct sway_container *output = container_parent(workspace, C_OUTPUT);
|
||||
if (output && output->children->length == 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_container *parent = workspace->parent;
|
||||
if (workspace->children->length == 0) {
|
||||
// destroy the WS if there are no children (TODO check for floating)
|
||||
wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
|
||||
ipc_event_workspace(workspace, NULL, "empty");
|
||||
} else {
|
||||
// Move children to a different workspace on this output
|
||||
struct sway_container *new_workspace = NULL;
|
||||
// TODO move floating
|
||||
for (int i = 0; i < output->children->length; i++) {
|
||||
if (output->children->items[i] != workspace) {
|
||||
new_workspace = output->children->items[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!oc) {
|
||||
oc = all;
|
||||
|
||||
wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'",
|
||||
workspace->name, new_workspace->name);
|
||||
for (int i = 0; i < workspace->children->length; i++) {
|
||||
container_move_to(workspace->children->items[i], new_workspace);
|
||||
}
|
||||
}
|
||||
|
||||
if (oc && !oc->enabled) {
|
||||
_container_destroy(workspace);
|
||||
|
||||
output_damage_whole(output->sway_output);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static void container_root_finish(struct sway_container *con) {
|
||||
wlr_log(L_ERROR, "TODO: destroy the root container");
|
||||
}
|
||||
|
||||
static bool container_reap_empty(struct sway_container *con) {
|
||||
switch (con->type) {
|
||||
case C_ROOT:
|
||||
case C_OUTPUT:
|
||||
// dont reap these
|
||||
break;
|
||||
case C_WORKSPACE:
|
||||
if (!workspace_is_visible(con) && con->children->length == 0) {
|
||||
container_workspace_destroy(con);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case C_CONTAINER:
|
||||
if (con->children->length == 0) {
|
||||
_container_destroy(con);
|
||||
return true;
|
||||
} else if (con->children->length == 1) {
|
||||
struct sway_container *child = con->children->items[0];
|
||||
if (child->type == C_CONTAINER) {
|
||||
container_remove_child(child);
|
||||
container_replace_child(con, child);
|
||||
_container_destroy(con);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case C_VIEW:
|
||||
break;
|
||||
case C_TYPES:
|
||||
sway_assert(false, "container_reap_empty called on an invalid "
|
||||
"container");
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sway_container *container_destroy(struct sway_container *con) {
|
||||
if (con == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_container *output = container_create(C_OUTPUT);
|
||||
output->sway_output = sway_output;
|
||||
output->name = strdup(name);
|
||||
if (output->name == NULL) {
|
||||
container_destroy(output);
|
||||
struct sway_container *parent = con->parent;
|
||||
|
||||
switch (con->type) {
|
||||
case C_ROOT:
|
||||
container_root_finish(con);
|
||||
break;
|
||||
case C_OUTPUT:
|
||||
// dont try to reap the root after this
|
||||
container_output_destroy(con);
|
||||
break;
|
||||
case C_WORKSPACE:
|
||||
// dont try to reap the output after this
|
||||
container_workspace_destroy(con);
|
||||
break;
|
||||
case C_CONTAINER:
|
||||
if (con->children->length) {
|
||||
for (int i = 0; i < con->children->length; ++i) {
|
||||
struct sway_container *child = con->children->items[0];
|
||||
container_remove_child(child);
|
||||
container_add_child(parent, child);
|
||||
}
|
||||
}
|
||||
_container_destroy(con);
|
||||
break;
|
||||
case C_VIEW:
|
||||
_container_destroy(con);
|
||||
break;
|
||||
case C_TYPES:
|
||||
wlr_log(L_ERROR, "container_destroy called on an invalid "
|
||||
"container");
|
||||
break;
|
||||
}
|
||||
|
||||
struct sway_container *tmp = parent;
|
||||
while (parent) {
|
||||
tmp = parent->parent;
|
||||
|
||||
if (!container_reap_empty(parent)) {
|
||||
break;
|
||||
}
|
||||
|
||||
parent = tmp;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static void container_close_func(struct sway_container *container, void *data) {
|
||||
if (container->type == C_VIEW) {
|
||||
view_close(container->sway_view);
|
||||
}
|
||||
}
|
||||
|
||||
struct sway_container *container_close(struct sway_container *con) {
|
||||
if (!sway_assert(con != NULL,
|
||||
"container_close called with a NULL container")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Insert the child before applying config so that the container coordinates
|
||||
// get updated
|
||||
container_add_child(&root_container, output);
|
||||
apply_output_config(oc, output);
|
||||
struct sway_container *parent = con->parent;
|
||||
|
||||
load_swaybars();
|
||||
|
||||
// Create workspace
|
||||
char *ws_name = workspace_next_name(output->name);
|
||||
wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
|
||||
struct sway_container *ws = container_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);
|
||||
}
|
||||
if (con->type == C_VIEW) {
|
||||
view_close(con->sway_view);
|
||||
} else {
|
||||
container_for_each_descendant_dfs(con, container_close_func, NULL);
|
||||
}
|
||||
|
||||
free(ws_name);
|
||||
notify_new_container(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
struct sway_container *container_workspace_create(
|
||||
struct sway_container *output, const char *name) {
|
||||
if (!sway_assert(output,
|
||||
"container_workspace_create called with null output")) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name);
|
||||
struct sway_container *workspace = container_create(C_WORKSPACE);
|
||||
|
||||
workspace->x = output->x;
|
||||
workspace->y = output->y;
|
||||
workspace->width = output->width;
|
||||
workspace->height = output->height;
|
||||
workspace->name = !name ? NULL : strdup(name);
|
||||
workspace->prev_layout = L_NONE;
|
||||
workspace->layout = container_get_default_layout(output);
|
||||
workspace->workspace_layout = container_get_default_layout(output);
|
||||
|
||||
container_add_child(output, workspace);
|
||||
container_sort_workspaces(output);
|
||||
notify_new_container(workspace);
|
||||
return workspace;
|
||||
return parent;
|
||||
}
|
||||
|
||||
struct sway_container *container_view_create(struct sway_container *sibling,
|
||||
|
@ -231,23 +325,10 @@ struct sway_container *container_view_create(struct sway_container *sibling,
|
|||
// Regular case, create as sibling of current container
|
||||
container_add_sibling(sibling, swayc);
|
||||
}
|
||||
notify_new_container(swayc);
|
||||
container_create_notify(swayc);
|
||||
return swayc;
|
||||
}
|
||||
|
||||
struct sway_container *container_set_layout(struct sway_container *container,
|
||||
enum sway_container_layout layout) {
|
||||
if (container->type == C_WORKSPACE) {
|
||||
container->workspace_layout = layout;
|
||||
if (layout == L_HORIZ || layout == L_VERT) {
|
||||
container->layout = layout;
|
||||
}
|
||||
} else {
|
||||
container->layout = layout;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
void container_descendants(struct sway_container *root,
|
||||
enum sway_container_type type,
|
||||
void (*func)(struct sway_container *item, void *data), void *data) {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -52,6 +51,19 @@ static void output_layout_handle_change(struct wl_listener *listener,
|
|||
arrange_windows(&root_container, -1, -1);
|
||||
}
|
||||
|
||||
struct sway_container *container_set_layout(struct sway_container *container,
|
||||
enum sway_container_layout layout) {
|
||||
if (container->type == C_WORKSPACE) {
|
||||
container->workspace_layout = layout;
|
||||
if (layout == L_HORIZ || layout == L_VERT) {
|
||||
container->layout = layout;
|
||||
}
|
||||
} else {
|
||||
container->layout = layout;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
void layout_init(void) {
|
||||
root_container.id = 0; // normally assigned in new_swayc()
|
||||
root_container.type = C_ROOT;
|
||||
|
@ -107,32 +119,6 @@ void container_add_child(struct sway_container *parent,
|
|||
child->parent = parent;
|
||||
}
|
||||
|
||||
struct sway_container *container_reap_empty(struct sway_container *container) {
|
||||
if (container == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_log(L_DEBUG, "Reaping %p %s '%s'", container,
|
||||
container_type_to_str(container->type), container->name);
|
||||
while (container->type != C_ROOT && container->type != C_OUTPUT
|
||||
&& container->children->length == 0) {
|
||||
if (container->type == C_WORKSPACE) {
|
||||
if (!workspace_is_visible(container)) {
|
||||
struct sway_container *parent = container->parent;
|
||||
container_workspace_destroy(container);
|
||||
return parent;
|
||||
}
|
||||
return container;
|
||||
} else if (container->type == C_CONTAINER) {
|
||||
struct sway_container *parent = container->parent;
|
||||
container_destroy(container);
|
||||
container = parent;
|
||||
} else {
|
||||
container = container->parent;
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
struct sway_container *container_remove_child(struct sway_container *child) {
|
||||
struct sway_container *parent = child->parent;
|
||||
for (int i = 0; i < parent->children->length; ++i) {
|
||||
|
@ -167,7 +153,7 @@ void container_move_to(struct sway_container *container,
|
|||
if (old_parent->children->length == 0) {
|
||||
char *ws_name = workspace_next_name(old_parent->name);
|
||||
struct sway_container *ws =
|
||||
container_workspace_create(old_parent, ws_name);
|
||||
workspace_create(old_parent, ws_name);
|
||||
free(ws_name);
|
||||
seat_set_focus(seat, ws);
|
||||
}
|
||||
|
@ -186,12 +172,22 @@ void container_move(struct sway_container *container,
|
|||
}
|
||||
|
||||
enum sway_container_layout container_get_default_layout(
|
||||
struct sway_container *output) {
|
||||
struct sway_container *con) {
|
||||
if (con->type != C_OUTPUT) {
|
||||
con = container_parent(con, C_OUTPUT);
|
||||
}
|
||||
|
||||
if (!sway_assert(con != NULL,
|
||||
"container_get_default_layout must be called on an attached"
|
||||
" container below the root container")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (config->default_layout != L_NONE) {
|
||||
return config->default_layout;
|
||||
} else if (config->default_orientation != L_NONE) {
|
||||
return config->default_orientation;
|
||||
} else if (output->width >= output->height) {
|
||||
} else if (con->width >= con->height) {
|
||||
return L_HORIZ;
|
||||
} else {
|
||||
return L_VERT;
|
||||
|
|
|
@ -1,51 +1,73 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/layout.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/tree/output.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "log.h"
|
||||
|
||||
struct sway_container *container_output_destroy(struct sway_container *output) {
|
||||
if (!sway_assert(output, "cannot destroy null output")) {
|
||||
struct sway_container *output_create(
|
||||
struct sway_output *sway_output) {
|
||||
struct wlr_box size;
|
||||
wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
|
||||
&size.height);
|
||||
|
||||
const char *name = sway_output->wlr_output->name;
|
||||
char identifier[128];
|
||||
output_get_identifier(identifier, sizeof(identifier), sway_output);
|
||||
|
||||
struct output_config *oc = NULL, *all = NULL;
|
||||
for (int i = 0; i < config->output_configs->length; ++i) {
|
||||
struct output_config *cur = config->output_configs->items[i];
|
||||
|
||||
if (strcasecmp(name, cur->name) == 0 ||
|
||||
strcasecmp(identifier, cur->name) == 0) {
|
||||
wlr_log(L_DEBUG, "Matched output config for %s", name);
|
||||
oc = cur;
|
||||
}
|
||||
if (strcasecmp("*", cur->name) == 0) {
|
||||
wlr_log(L_DEBUG, "Matched wildcard output config for %s", name);
|
||||
all = cur;
|
||||
}
|
||||
|
||||
if (oc && all) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!oc) {
|
||||
oc = all;
|
||||
}
|
||||
|
||||
if (oc && !oc->enabled) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (output->children->length > 0) {
|
||||
// TODO save workspaces when there are no outputs.
|
||||
// TODO also check if there will ever be no outputs except for exiting
|
||||
// program
|
||||
if (root_container.children->length > 1) {
|
||||
int p = root_container.children->items[0] == output;
|
||||
// Move workspace from this output to another output
|
||||
while (output->children->length) {
|
||||
struct sway_container *child = output->children->items[0];
|
||||
container_remove_child(child);
|
||||
container_add_child(root_container.children->items[p], child);
|
||||
}
|
||||
container_sort_workspaces(root_container.children->items[p]);
|
||||
arrange_windows(root_container.children->items[p],
|
||||
-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_remove(&output->sway_output->destroy.link);
|
||||
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);
|
||||
|
||||
wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
|
||||
struct sway_container *output = container_create(C_OUTPUT);
|
||||
output->sway_output = sway_output;
|
||||
output->name = strdup(name);
|
||||
if (output->name == NULL) {
|
||||
container_destroy(output);
|
||||
return &root_container;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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){
|
||||
apply_output_config(oc, output);
|
||||
container_add_child(&root_container, output);
|
||||
load_swaybars();
|
||||
|
||||
// Create workspace
|
||||
char *ws_name = workspace_next_name(output->name);
|
||||
wlr_log(L_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 NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,7 @@ void view_destroy(struct sway_view *view) {
|
|||
view_unmap(view);
|
||||
}
|
||||
|
||||
container_view_destroy(view->swayc);
|
||||
free(view);
|
||||
container_destroy(view->swayc);
|
||||
}
|
||||
|
||||
const char *view_get_title(struct sway_view *view) {
|
||||
|
@ -78,16 +77,6 @@ void view_close(struct sway_view *view) {
|
|||
}
|
||||
}
|
||||
|
||||
struct sway_container *container_view_destroy(struct sway_container *view) {
|
||||
if (!view) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_log(L_DEBUG, "Destroying view '%s'", view->name);
|
||||
struct sway_container *parent = container_destroy(view);
|
||||
arrange_windows(parent, -1, -1);
|
||||
return parent;
|
||||
}
|
||||
|
||||
void view_damage_whole(struct sway_view *view) {
|
||||
for (int i = 0; i < root_container.children->length; ++i) {
|
||||
struct sway_container *cont = root_container.children->items[i];
|
||||
|
@ -160,10 +149,12 @@ void view_unmap(struct sway_view *view) {
|
|||
|
||||
view_damage_whole(view);
|
||||
|
||||
container_view_destroy(view->swayc);
|
||||
struct sway_container *parent = container_destroy(view->swayc);
|
||||
|
||||
view->swayc = NULL;
|
||||
view->surface = NULL;
|
||||
|
||||
arrange_windows(parent, -1, -1);
|
||||
}
|
||||
|
||||
void view_update_position(struct sway_view *view, double ox, double oy) {
|
||||
|
|
|
@ -14,6 +14,58 @@
|
|||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
static struct sway_container *get_workspace_initial_output(const char *name) {
|
||||
struct sway_container *parent;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
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_container *workspace_create(struct sway_container *output,
|
||||
const char *name) {
|
||||
if (output == NULL) {
|
||||
output = get_workspace_initial_output(name);
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name);
|
||||
struct sway_container *workspace = container_create(C_WORKSPACE);
|
||||
|
||||
workspace->x = output->x;
|
||||
workspace->y = output->y;
|
||||
workspace->width = output->width;
|
||||
workspace->height = output->height;
|
||||
workspace->name = !name ? NULL : strdup(name);
|
||||
workspace->prev_layout = L_NONE;
|
||||
workspace->layout = container_get_default_layout(output);
|
||||
workspace->workspace_layout = workspace->layout;
|
||||
|
||||
container_add_child(output, workspace);
|
||||
container_sort_workspaces(output);
|
||||
container_create_notify(workspace);
|
||||
|
||||
return workspace;
|
||||
}
|
||||
|
||||
char *prev_workspace_name = NULL;
|
||||
struct workspace_by_number_data {
|
||||
int len;
|
||||
|
@ -197,74 +249,6 @@ struct sway_container *workspace_by_name(const char *name) {
|
|||
}
|
||||
}
|
||||
|
||||
struct sway_container *workspace_create(const char *name) {
|
||||
struct sway_container *parent;
|
||||
// Search for workspace<->output pair
|
||||
int i, e = config->workspace_outputs->length;
|
||||
for (i = 0; i < e; ++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 container_workspace_create(parent, name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Otherwise create a new one
|
||||
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);
|
||||
struct sway_container *new_ws = container_workspace_create(parent, name);
|
||||
ipc_event_workspace(NULL, new_ws, "init");
|
||||
return new_ws;
|
||||
}
|
||||
|
||||
struct sway_container *container_workspace_destroy(
|
||||
struct sway_container *workspace) {
|
||||
if (!sway_assert(workspace, "cannot destroy null workspace")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Do not destroy this if it's the last workspace on this output
|
||||
struct sway_container *output = container_parent(workspace, C_OUTPUT);
|
||||
if (output && output->children->length == 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_container *parent = workspace->parent;
|
||||
if (workspace->children->length == 0) {
|
||||
// destroy the WS if there are no children (TODO check for floating)
|
||||
wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
|
||||
ipc_event_workspace(workspace, NULL, "empty");
|
||||
} else {
|
||||
// Move children to a different workspace on this output
|
||||
struct sway_container *new_workspace = NULL;
|
||||
// TODO move floating
|
||||
for (int i = 0; i < output->children->length; i++) {
|
||||
if (output->children->items[i] != workspace) {
|
||||
new_workspace = output->children->items[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'",
|
||||
workspace->name, new_workspace->name);
|
||||
for (int i = 0; i < workspace->children->length; i++) {
|
||||
container_move_to(workspace->children->items[i], new_workspace);
|
||||
}
|
||||
}
|
||||
|
||||
container_destroy(workspace);
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previous or next workspace on the specified output. Wraps around at
|
||||
* the end and beginning. If next is false, the previous workspace is returned,
|
||||
|
@ -376,7 +360,9 @@ bool workspace_switch(struct sway_container *workspace) {
|
|||
&& active_ws == workspace
|
||||
&& prev_workspace_name) {
|
||||
struct sway_container *new_ws = workspace_by_name(prev_workspace_name);
|
||||
workspace = new_ws ? new_ws : workspace_create(prev_workspace_name);
|
||||
workspace = new_ws ?
|
||||
new_ws :
|
||||
workspace_create(NULL, prev_workspace_name);
|
||||
}
|
||||
|
||||
if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name)
|
||||
|
|
Loading…
Reference in a new issue