Merge pull request #1702 from acrisci/split-containers2

properly close container containers
master
emersion 7 years ago committed by GitHub
commit dee71871d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -91,13 +91,11 @@ struct sway_container {
} events; } events;
}; };
// TODO make private and use the container-specific create functions
struct sway_container *container_create(enum sway_container_type type); struct sway_container *container_create(enum sway_container_type type);
const char *container_type_to_str(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 *output_create(
struct sway_container *container_output_create(
struct sway_output *sway_output); 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 * Create a new output. Outputs are children of the root container and have no
* order in the tree structure. * 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 * Create a new workspace container. Workspaces are children of an output
* container and are ordered alphabetically by name. * 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 * 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 * or a container container and are rendered in the order and structure of
* how they are attached to the tree. * 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 *container_view_create(
struct sway_container *sibling, struct sway_view *sway_view); 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_destroy(struct sway_container *container);
struct sway_container *container_workspace_destroy(struct sway_container *container); struct sway_container *container_close(struct sway_container *container);
struct sway_container *container_output_destroy(struct sway_container *container);
struct sway_container *container_view_destroy(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, void container_descendants(struct sway_container *root,
enum sway_container_type type, enum sway_container_type type,
void (*func)(struct sway_container *item, void *data), void *data); 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. * 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, struct sway_container *container_parent(struct sway_container *container,
enum sway_container_type type); 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, bool container_has_child(struct sway_container *con,
struct sway_container *child); struct sway_container *child);
void container_create_notify(struct sway_container *container);
#endif #endif

@ -29,42 +29,37 @@ struct sway_root {
void layout_init(void); void layout_init(void);
// TODO move to tree.h
void container_add_child(struct sway_container *parent, void container_add_child(struct sway_container *parent,
struct sway_container *child); struct sway_container *child);
// TODO move to tree.h
struct sway_container *container_add_sibling(struct sway_container *parent, struct sway_container *container_add_sibling(struct sway_container *parent,
struct sway_container *child); struct sway_container *child);
// TODO move to tree.h
struct sway_container *container_remove_child(struct sway_container *child); struct sway_container *container_remove_child(struct sway_container *child);
// TODO PRIVATE in tree.h struct sway_container *container_replace_child(struct sway_container *child,
struct sway_container *container_reap_empty(struct sway_container *container); 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, void container_move_to(struct sway_container* container,
struct sway_container* destination); struct sway_container* destination);
void container_move(struct sway_container *container, void container_move(struct sway_container *container,
enum movement_direction dir, int move_amt); enum movement_direction dir, int move_amt);
// TODO move to output.c
enum sway_container_layout container_get_default_layout( 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 container_sort_workspaces(struct sway_container *output);
void arrange_windows(struct sway_container *container, void arrange_windows(struct sway_container *container,
double width, double height); double width, double height);
// TODO move to container.h
struct sway_container *container_get_in_direction(struct sway_container struct sway_container *container_get_in_direction(struct sway_container
*container, struct sway_seat *seat, enum movement_direction dir); *container, struct sway_seat *seat, enum movement_direction dir);
// TODO move to tree.h
struct sway_container *container_split(struct sway_container *child, struct sway_container *container_split(struct sway_container *child,
enum sway_container_layout layout); enum sway_container_layout layout);

@ -7,8 +7,6 @@ extern char *prev_workspace_name;
char *workspace_next_name(const char *output_name); char *workspace_next_name(const char *output_name);
struct sway_container *workspace_create(const char *name);
bool workspace_switch(struct sway_container *workspace); bool workspace_switch(struct sway_container *workspace);
struct sway_container *workspace_by_number(const char* name); 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 = struct sway_container *con =
config->handler_context.current_container; config->handler_context.current_container;
switch (con->type) { container_close(con);
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;
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL); 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) { if (strcasecmp(argv[0], "default") == 0) {
container_set_layout(parent, parent->prev_layout); container_set_layout(parent, parent->prev_layout);
if (parent->layout == L_NONE) { if (parent->layout == L_NONE) {
struct sway_container *output = container_parent(parent, C_OUTPUT); container_set_layout(parent, container_get_default_layout(parent));
container_set_layout(parent, container_get_default_layout(output));
} }
} else { } else {
if (parent->layout != L_TABBED && parent->layout != L_STACKED) { 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); ws = workspace_by_name(ws_name);
} }
if (!ws) { if (!ws) {
ws = workspace_create(ws_name ? ws_name : num_name); ws = workspace_create(NULL, ws_name ? ws_name : num_name);
} }
free(ws_name); free(ws_name);
struct sway_container *old_parent = current->parent; 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 (strcasecmp(argv[0], "number") == 0) {
if (!(ws = workspace_by_number(argv[1]))) { if (!(ws = workspace_by_number(argv[1]))) {
char *name = join_args(argv + 1, argc - 1); char *name = join_args(argv + 1, argc - 1);
ws = workspace_create(name); ws = workspace_create(NULL, name);
free(name); free(name);
} }
} else if (strcasecmp(argv[0], "next") == 0) { } else if (strcasecmp(argv[0], "next") == 0) {
@ -80,12 +80,12 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
ws = old_workspace; ws = old_workspace;
} else if (prev_workspace_name } else if (prev_workspace_name
&& !(ws = workspace_by_name(prev_workspace_name))) { && !(ws = workspace_by_name(prev_workspace_name))) {
ws = workspace_create(prev_workspace_name); ws = workspace_create(NULL, prev_workspace_name);
} }
} else { } else {
char *name = join_args(argv, argc); char *name = join_args(argv, argc);
if (!(ws = workspace_by_name(name))) { if (!(ws = workspace_by_name(name))) {
ws = workspace_create(name); ws = workspace_create(NULL, name);
} }
free(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; struct wlr_output *wlr_output = output->sway_output->wlr_output;
if (oc && oc->enabled == 0) { if (oc && oc->enabled == 0) {
container_output_destroy(output); container_destroy(output);
wlr_output_layout_remove(output_layout, wlr_output); wlr_output_layout_remove(root_container.sway_root->output_layout,
wlr_output);
return; return;
} }

@ -2,6 +2,7 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <strings.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_box.h> #include <wlr/types/wlr_box.h>
@ -21,6 +22,16 @@
#include "sway/tree/layout.h" #include "sway/tree/layout.h"
#include "sway/tree/view.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), * 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). * 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) { static void damage_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = struct sway_output *output =
wl_container_of(listener, output, damage_destroy); 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) { static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, destroy); 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) { 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->damage = wlr_output_damage_create(wlr_output);
output->swayc = container_output_create(output); output->swayc = output_create(output);
if (!output->swayc) { if (!output->swayc) {
free(output); free(output);
return; return;

@ -384,7 +384,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
if (last_ws) { if (last_ws) {
ipc_event_workspace(last_ws, container, "focus"); ipc_event_workspace(last_ws, container, "focus");
if (last_ws->children->length == 0) { if (last_ws->children->length == 0) {
container_workspace_destroy(last_ws); container_destroy(last_ws);
} }
} }
struct sway_container *last_output = last_focus; struct sway_container *last_output = last_focus;

@ -86,9 +86,9 @@ sway_sources = files(
'security.c', 'security.c',
'tree/container.c', 'tree/container.c',
'tree/layout.c', 'tree/layout.c',
'tree/output.c',
'tree/view.c', 'tree/view.c',
'tree/workspace.c', 'tree/workspace.c',
'tree/output.c',
) )
sway_deps = [ sway_deps = [

@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -6,7 +7,6 @@
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_wl_shell.h>
#include "log.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
#include "sway/input/seat.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); wl_signal_emit(&root_container.sway_root->events.new_container, container);
ipc_event_window(container, "new"); ipc_event_window(container, "new");
} }
@ -76,21 +76,21 @@ struct sway_container *container_create(enum sway_container_type type) {
return c; return c;
} }
static struct sway_container *_container_destroy(struct sway_container *cont) { static void _container_destroy(struct sway_container *cont) {
if (cont == NULL) { if (cont == NULL) {
return NULL; return;
} }
wl_signal_emit(&cont->events.destroy, cont); wl_signal_emit(&cont->events.destroy, cont);
struct sway_container *parent = cont->parent; 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 // remove children until there are no more, container_destroy calls
// container_remove_child, which removes child from this container // 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]; struct sway_container *child = cont->children->items[0];
container_remove_child(child); container_remove_child(child);
container_destroy(child); _container_destroy(child);
} }
} }
if (cont->marks) { if (cont->marks) {
@ -106,106 +106,200 @@ static struct sway_container *_container_destroy(struct sway_container *cont) {
list_free(cont->children); list_free(cont->children);
cont->children = NULL; cont->children = NULL;
free(cont); free(cont);
return parent;
} }
struct sway_container *container_destroy(struct sway_container *cont) { static struct sway_container *container_output_destroy(
struct sway_container *parent = _container_destroy(cont); struct sway_container *output) {
parent = container_reap_empty(parent); if (!sway_assert(output, "cannot destroy null output")) {
arrange_windows(&root_container, -1, -1); return NULL;
return parent; }
}
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);
}
}
struct sway_container *container_output_create( wl_list_remove(&output->sway_output->destroy.link);
struct sway_output *sway_output) { wl_list_remove(&output->sway_output->mode.link);
struct wlr_box size; wl_list_remove(&output->sway_output->transform.link);
wlr_output_effective_resolution(sway_output->wlr_output, &size.width, wl_list_remove(&output->sway_output->scale.link);
&size.height);
const char *name = sway_output->wlr_output->name; wl_list_remove(&output->sway_output->damage_destroy.link);
char identifier[128]; wl_list_remove(&output->sway_output->damage_frame.link);
output_get_identifier(identifier, sizeof(identifier), sway_output);
struct output_config *oc = NULL, *all = NULL; wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
for (int i = 0; i < config->output_configs->length; ++i) { _container_destroy(output);
struct output_config *cur = config->output_configs->items[i]; return &root_container;
}
if (strcasecmp(name, cur->name) == 0 || static struct sway_container *container_workspace_destroy(
strcasecmp(identifier, cur->name) == 0) { struct sway_container *workspace) {
wlr_log(L_DEBUG, "Matched output config for %s", name); if (!sway_assert(workspace, "cannot destroy null workspace")) {
oc = cur; return NULL;
} }
if (strcasecmp("*", cur->name) == 0) {
wlr_log(L_DEBUG, "Matched wildcard output config for %s", name); // Do not destroy this if it's the last workspace on this output
all = cur; 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 && all) { wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'",
break; 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 = all;
}
if (oc && !oc->enabled) { _container_destroy(workspace);
return NULL;
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;
} }
struct sway_container *output = container_create(C_OUTPUT); return false;
output->sway_output = sway_output; }
output->name = strdup(name);
if (output->name == NULL) { struct sway_container *container_destroy(struct sway_container *con) {
container_destroy(output); if (con == NULL) {
return NULL; return NULL;
} }
// Insert the child before applying config so that the container coordinates struct sway_container *parent = con->parent;
// get updated
container_add_child(&root_container, output); switch (con->type) {
apply_output_config(oc, output); 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;
}
load_swaybars(); struct sway_container *tmp = parent;
while (parent) {
tmp = parent->parent;
// Create workspace if (!container_reap_empty(parent)) {
char *ws_name = workspace_next_name(output->name); break;
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);
} }
parent = tmp;
} }
free(ws_name); return tmp;
notify_new_container(output); }
return output;
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_workspace_create( struct sway_container *container_close(struct sway_container *con) {
struct sway_container *output, const char *name) { if (!sway_assert(con != NULL,
if (!sway_assert(output, "container_close called with a NULL container")) {
"container_workspace_create called with null output")) {
return NULL; return NULL;
} }
wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name);
struct sway_container *workspace = container_create(C_WORKSPACE); struct sway_container *parent = con->parent;
workspace->x = output->x; if (con->type == C_VIEW) {
workspace->y = output->y; view_close(con->sway_view);
workspace->width = output->width; } else {
workspace->height = output->height; container_for_each_descendant_dfs(con, container_close_func, NULL);
workspace->name = !name ? NULL : strdup(name); }
workspace->prev_layout = L_NONE;
workspace->layout = container_get_default_layout(output); return parent;
workspace->workspace_layout = container_get_default_layout(output);
container_add_child(output, workspace);
container_sort_workspaces(output);
notify_new_container(workspace);
return workspace;
} }
struct sway_container *container_view_create(struct sway_container *sibling, 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 // Regular case, create as sibling of current container
container_add_sibling(sibling, swayc); container_add_sibling(sibling, swayc);
} }
notify_new_container(swayc); container_create_notify(swayc);
return 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, void container_descendants(struct sway_container *root,
enum sway_container_type type, enum sway_container_type type,
void (*func)(struct sway_container *item, void *data), void *data) { void (*func)(struct sway_container *item, void *data), void *data) {

@ -1,5 +1,4 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
@ -52,6 +51,19 @@ static void output_layout_handle_change(struct wl_listener *listener,
arrange_windows(&root_container, -1, -1); 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) { void layout_init(void) {
root_container.id = 0; // normally assigned in new_swayc() root_container.id = 0; // normally assigned in new_swayc()
root_container.type = C_ROOT; root_container.type = C_ROOT;
@ -107,32 +119,6 @@ void container_add_child(struct sway_container *parent,
child->parent = 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 *container_remove_child(struct sway_container *child) {
struct sway_container *parent = child->parent; struct sway_container *parent = child->parent;
for (int i = 0; i < parent->children->length; ++i) { 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) { if (old_parent->children->length == 0) {
char *ws_name = workspace_next_name(old_parent->name); char *ws_name = workspace_next_name(old_parent->name);
struct sway_container *ws = struct sway_container *ws =
container_workspace_create(old_parent, ws_name); workspace_create(old_parent, ws_name);
free(ws_name); free(ws_name);
seat_set_focus(seat, ws); seat_set_focus(seat, ws);
} }
@ -186,12 +172,22 @@ void container_move(struct sway_container *container,
} }
enum sway_container_layout container_get_default_layout( 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) { if (config->default_layout != L_NONE) {
return config->default_layout; return config->default_layout;
} else if (config->default_orientation != L_NONE) { } else if (config->default_orientation != L_NONE) {
return config->default_orientation; return config->default_orientation;
} else if (output->width >= output->height) { } else if (con->width >= con->height) {
return L_HORIZ; return L_HORIZ;
} else { } else {
return L_VERT; return L_VERT;

@ -1,51 +1,73 @@
#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <strings.h> #include <strings.h>
#include "sway/tree/container.h"
#include "sway/tree/layout.h"
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/output.h"
#include "sway/tree/workspace.h"
#include "log.h" #include "log.h"
struct sway_container *container_output_destroy(struct sway_container *output) { struct sway_container *output_create(
if (!sway_assert(output, "cannot destroy null output")) { struct sway_output *sway_output) {
return NULL; 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 (output->children->length > 0) { if (strcasecmp(name, cur->name) == 0 ||
// TODO save workspaces when there are no outputs. strcasecmp(identifier, cur->name) == 0) {
// TODO also check if there will ever be no outputs except for exiting wlr_log(L_DEBUG, "Matched output config for %s", name);
// program oc = cur;
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) {
break;
}
}
if (!oc) {
oc = all;
} }
wl_list_remove(&output->sway_output->destroy.link); if (oc && !oc->enabled) {
wl_list_remove(&output->sway_output->mode.link); return NULL;
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); struct sway_container *output = container_create(C_OUTPUT);
wl_list_remove(&output->sway_output->damage_frame.link); output->sway_output = sway_output;
output->name = strdup(name);
if (output->name == NULL) {
container_destroy(output);
return NULL;
}
wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); apply_output_config(oc, output);
container_destroy(output); container_add_child(&root_container, output);
return &root_container; load_swaybars();
}
struct sway_container *output_by_name(const char *name) { // Create workspace
for (int i = 0; i < root_container.children->length; ++i) { char *ws_name = workspace_next_name(output->name);
struct sway_container *output = root_container.children->items[i]; wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
if (strcasecmp(output->name, name) == 0){ struct sway_container *ws = workspace_create(output, ws_name);
return output; // 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);
} }
} }
return NULL;
free(ws_name);
container_create_notify(output);
return output;
} }

@ -27,8 +27,7 @@ void view_destroy(struct sway_view *view) {
view_unmap(view); view_unmap(view);
} }
container_view_destroy(view->swayc); container_destroy(view->swayc);
free(view);
} }
const char *view_get_title(struct sway_view *view) { 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) { void view_damage_whole(struct sway_view *view) {
for (int i = 0; i < root_container.children->length; ++i) { for (int i = 0; i < root_container.children->length; ++i) {
struct sway_container *cont = root_container.children->items[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); view_damage_whole(view);
container_view_destroy(view->swayc); struct sway_container *parent = container_destroy(view->swayc);
view->swayc = NULL; view->swayc = NULL;
view->surface = NULL; view->surface = NULL;
arrange_windows(parent, -1, -1);
} }
void view_update_position(struct sway_view *view, double ox, double oy) { void view_update_position(struct sway_view *view, double ox, double oy) {

@ -14,6 +14,58 @@
#include "log.h" #include "log.h"
#include "util.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; char *prev_workspace_name = NULL;
struct workspace_by_number_data { struct workspace_by_number_data {
int len; 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 * 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, * 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 && active_ws == workspace
&& prev_workspace_name) { && prev_workspace_name) {
struct sway_container *new_ws = workspace_by_name(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) if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name)

Loading…
Cancel
Save