aboutsummaryrefslogtreecommitdiff
path: root/sway/tree/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/output.c')
-rw-r--r--sway/tree/output.c348
1 files changed, 209 insertions, 139 deletions
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 6601220b..35589032 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -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,111 +34,116 @@ 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;
- char identifier[128];
- output_get_identifier(identifier, sizeof(identifier), sway_output);
+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;
- 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];
+ wl_signal_add(&wlr_output->events.destroy, &output->destroy);
- if (strcasecmp(name, cur->name) == 0 ||
- strcasecmp(identifier, cur->name) == 0) {
- wlr_log(WLR_DEBUG, "Matched output config for %s", name);
- oc = cur;
- }
- if (strcasecmp("*", cur->name) == 0) {
- wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
- all = cur;
- }
+ wl_list_insert(&root->all_outputs, &output->link);
- if (oc && all) {
- break;
- }
- }
- if (!oc) {
- oc = all;
+ 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);
}
- if (oc && !oc->enabled) {
- return NULL;
- }
+ output->workspaces = create_list();
+ output->current.workspaces = create_list();
- 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);
- return NULL;
- }
+ 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);
- container_add_child(&root_container, output);
- load_swaybars();
+ list_add(root->outputs, output);
- struct wlr_box size;
- wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
- &size.height);
- output->width = size.width;
- output->height = size.height;
+ 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->children->length) {
+ if (!output->workspaces->length) {
// Create workspace
- char *ws_name = workspace_next_name(output->name);
+ char *ws_name = workspace_next_name(wlr_output->name);
wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name);
- struct sway_container *ws = workspace_create(output, 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);
+ seat_set_focus(seat, &ws->node);
}
}
free(ws_name);
}
- container_create_notify(output);
- return output;
+ 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_container *output) {
- if (!output->children->length) {
+static void output_evacuate(struct sway_output *output) {
+ if (!output->workspaces->length) {
return;
}
- struct sway_container *fallback_output = NULL;
- if (root_container.children->length > 1) {
- fallback_output = root_container.children->items[0];
+ struct sway_output *fallback_output = NULL;
+ if (root->outputs->length > 1) {
+ fallback_output = root->outputs->items[0];
if (fallback_output == output) {
- fallback_output = root_container.children->items[1];
+ fallback_output = root->outputs->items[1];
}
}
- while (output->children->length) {
- struct sway_container *workspace = output->children->items[0];
+ while (output->workspaces->length) {
+ struct sway_workspace *workspace = output->workspaces->items[0];
- container_remove_child(workspace);
+ workspace_detach(workspace);
if (workspace_is_empty(workspace)) {
workspace_begin_destroy(workspace);
continue;
}
- struct sway_container *new_output =
+ struct sway_output *new_output =
workspace_output_get_highest_available(workspace, output);
if (!new_output) {
new_output = fallback_output;
@@ -143,39 +151,31 @@ static void output_evacuate(struct sway_container *output) {
if (new_output) {
workspace_output_add_priority(workspace, new_output);
- container_add_child(new_output, workspace);
+ output_add_workspace(new_output, workspace);
output_sort_workspaces(new_output);
ipc_event_workspace(NULL, workspace, "move");
} else {
- list_add(root_container.sway_root->saved_workspaces, workspace);
+ list_add(root->saved_workspaces, workspace);
}
}
}
-void output_destroy(struct sway_container *output) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
+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->destroying,
- "Tried to free output which wasn't marked as destroying")) {
+ if (!sway_assert(output->wlr_output == NULL,
+ "Tried to free output which still had a wlr_output")) {
return;
}
- if (!sway_assert(output->ntxnrefs == 0, "Tried to free output "
+ if (!sway_assert(output->node.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);
+ list_free(output->workspaces);
+ list_free(output->current.workspaces);
free(output);
-
- // NOTE: We don't actually destroy the sway_output here
}
static void untrack_output(struct sway_container *con, void *data) {
@@ -186,76 +186,128 @@ static void untrack_output(struct sway_container *con, void *data) {
}
}
-void output_begin_destroy(struct sway_container *output) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
+void output_disable(struct sway_output *output) {
+ if (!sway_assert(output->enabled, "Expected an enabled output")) {
return;
}
- wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
+ wlr_log(WLR_DEBUG, "Disabling output '%s'", output->wlr_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);
+
+ 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;
+}
- root_for_each_container(untrack_output, output->sway_output);
+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), 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);
+ 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];
- output->sway_output->swayc = NULL;
- output->sway_output = NULL;
+ if (strcasecmp(name, cur->name) == 0 ||
+ strcasecmp(identifier, cur->name) == 0) {
+ wlr_log(WLR_DEBUG, "Matched output config for %s", name);
+ oc = cur;
+ }
+ if (strcasecmp("*", cur->name) == 0) {
+ wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
+ all = cur;
+ }
- if (output->parent) {
- container_remove_child(output);
+ if (oc && all) {
+ break;
+ }
+ }
+ if (!oc) {
+ oc = all;
}
+
+ return oc;
}
-struct sway_container *output_from_wlr_output(struct wlr_output *output) {
- if (output == NULL) {
+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;
}
- 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;
- }
+ 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;
}
- return NULL;
+ return output_from_wlr_output(wlr_adjacent);
}
-void output_for_each_workspace(struct sway_container *output,
- void (*f)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return;
+void output_add_workspace(struct sway_output *output,
+ struct sway_workspace *workspace) {
+ if (workspace->output) {
+ workspace_detach(workspace);
}
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+ list_add(output->workspaces, workspace);
+ workspace->output = output;
+ node_set_dirty(&output->node);
+ node_set_dirty(&workspace->node);
+}
+
+void output_for_each_workspace(struct sway_output *output,
+ void (*f)(struct sway_workspace *ws, void *data), void *data) {
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
f(workspace, data);
}
}
-void output_for_each_container(struct sway_container *output,
+void output_for_each_container(struct sway_output *output,
void (*f)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return;
- }
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
workspace_for_each_container(workspace, f, data);
}
}
-struct sway_container *output_find_workspace(struct sway_container *output,
- bool (*test)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return NULL;
- }
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+struct sway_workspace *output_find_workspace(struct sway_output *output,
+ bool (*test)(struct sway_workspace *ws, void *data), void *data) {
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
if (test(workspace, data)) {
return workspace;
}
@@ -263,14 +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;
}