mirror of
https://github.com/swaywm/sway.git
synced 2026-04-29 06:46:22 -04:00
container: Add neighbours struct (for output containers). In order to move the mouse between the outputs this struct is added to keep track of each outputs' neighbours. Neighbour relationships are updated during output creation/destruction and output command invocation (e.g. via config reload).
689 lines
18 KiB
C
689 lines
18 KiB
C
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <strings.h>
|
|
#include <string.h>
|
|
#include "config.h"
|
|
#include "stringop.h"
|
|
#include "container.h"
|
|
#include "workspace.h"
|
|
#include "focus.h"
|
|
#include "layout.h"
|
|
#include "log.h"
|
|
|
|
#define ASSERT_NONNULL(PTR) \
|
|
sway_assert (PTR, #PTR "must be non-null")
|
|
|
|
static swayc_t *new_swayc(enum swayc_types type) {
|
|
swayc_t *c = calloc(1, sizeof(swayc_t));
|
|
c->handle = -1;
|
|
c->gaps = -1;
|
|
c->layout = L_NONE;
|
|
c->type = type;
|
|
|
|
if (type != C_VIEW) {
|
|
c->children = create_list();
|
|
}
|
|
if (type == C_OUTPUT) {
|
|
c->neighbours = malloc(sizeof(struct swayc_neighbours));
|
|
c->neighbours->top = NULL;
|
|
c->neighbours->right = NULL;
|
|
c->neighbours->bottom = NULL;
|
|
c->neighbours->left = NULL;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
static void free_swayc(swayc_t *cont) {
|
|
if (!ASSERT_NONNULL(cont)) {
|
|
return;
|
|
}
|
|
if (cont->children) {
|
|
// remove children until there are no more, free_swayc calls
|
|
// remove_child, which removes child from this container
|
|
while (cont->children->length) {
|
|
free_swayc(cont->children->items[0]);
|
|
}
|
|
list_free(cont->children);
|
|
}
|
|
if (cont->floating) {
|
|
while (cont->floating->length) {
|
|
free_swayc(cont->floating->items[0]);
|
|
}
|
|
list_free(cont->floating);
|
|
}
|
|
if (cont->parent) {
|
|
remove_child(cont);
|
|
}
|
|
if (cont->name) {
|
|
free(cont->name);
|
|
}
|
|
if (cont->neighbours) {
|
|
free(cont->neighbours);
|
|
}
|
|
free(cont);
|
|
}
|
|
|
|
// New containers
|
|
|
|
swayc_t *new_output(wlc_handle handle) {
|
|
const struct wlc_size *size = wlc_output_get_resolution(handle);
|
|
const char *name = wlc_output_get_name(handle);
|
|
// Find current outputs to see if this already exists
|
|
{
|
|
int i, len = root_container.children->length;
|
|
for (i = 0; i < len; ++i) {
|
|
swayc_t *op = root_container.children->items[i];
|
|
const char *op_name = op->name;
|
|
if (op_name && name && strcmp(op_name, name) == 0) {
|
|
sway_log(L_DEBUG, "restoring output %lu:%s", handle, op_name);
|
|
return op;
|
|
}
|
|
}
|
|
}
|
|
|
|
sway_log(L_DEBUG, "New output %lu:%s", handle, name);
|
|
|
|
struct output_config *oc = NULL;
|
|
int i;
|
|
for (i = 0; i < config->output_configs->length; ++i) {
|
|
oc = config->output_configs->items[i];
|
|
if (strcasecmp(name, oc->name) == 0) {
|
|
sway_log(L_DEBUG, "Matched output config for %s", name);
|
|
break;
|
|
}
|
|
oc = NULL;
|
|
}
|
|
|
|
if (oc && !oc->enabled) {
|
|
return NULL;
|
|
}
|
|
|
|
swayc_t *output = new_swayc(C_OUTPUT);
|
|
output->handle = handle;
|
|
output->name = name ? strdup(name) : NULL;
|
|
output->width = size->w;
|
|
output->height = size->h;
|
|
|
|
apply_output_config(oc, output);
|
|
add_child(&root_container, output);
|
|
|
|
// Create workspace
|
|
char *ws_name = NULL;
|
|
if (name) {
|
|
for (i = 0; i < config->workspace_outputs->length; ++i) {
|
|
struct workspace_output *wso = config->workspace_outputs->items[i];
|
|
if (strcasecmp(wso->output, name) == 0) {
|
|
sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output);
|
|
// Check if any other workspaces are using this name
|
|
if (workspace_by_name(wso->workspace)) {
|
|
sway_log(L_DEBUG, "But it's already taken");
|
|
break;
|
|
}
|
|
sway_log(L_DEBUG, "So we're going to use it");
|
|
ws_name = strdup(wso->workspace);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!ws_name) {
|
|
ws_name = workspace_next_name();
|
|
}
|
|
|
|
// create and initilize default workspace
|
|
swayc_t *ws = new_workspace(output, ws_name);
|
|
ws->is_focused = true;
|
|
|
|
free(ws_name);
|
|
|
|
return output;
|
|
}
|
|
|
|
swayc_t *new_workspace(swayc_t *output, const char *name) {
|
|
if (!ASSERT_NONNULL(output)) {
|
|
return NULL;
|
|
}
|
|
sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
|
|
swayc_t *workspace = new_swayc(C_WORKSPACE);
|
|
|
|
// TODO: default_layout
|
|
if (config->default_layout != L_NONE) {
|
|
workspace->layout = config->default_layout;
|
|
} else if (config->default_orientation != L_NONE) {
|
|
workspace->layout = config->default_orientation;
|
|
} else if (output->width >= output->height) {
|
|
workspace->layout = L_HORIZ;
|
|
} else {
|
|
workspace->layout = L_VERT;
|
|
}
|
|
workspace->x = output->x;
|
|
workspace->y = output->y;
|
|
workspace->width = output->width;
|
|
workspace->height = output->height;
|
|
workspace->name = strdup(name);
|
|
workspace->visible = false;
|
|
workspace->floating = create_list();
|
|
|
|
add_child(output, workspace);
|
|
return workspace;
|
|
}
|
|
|
|
swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
|
|
if (!ASSERT_NONNULL(child)
|
|
&& !sway_assert(!child->is_floating, "cannot create container around floating window")) {
|
|
return NULL;
|
|
}
|
|
swayc_t *cont = new_swayc(C_CONTAINER);
|
|
|
|
sway_log(L_DEBUG, "creating container %p around %p", cont, child);
|
|
|
|
cont->layout = layout;
|
|
cont->width = child->width;
|
|
cont->height = child->height;
|
|
cont->x = child->x;
|
|
cont->y = child->y;
|
|
cont->visible = child->visible;
|
|
|
|
/* Container inherits all of workspaces children, layout and whatnot */
|
|
if (child->type == C_WORKSPACE) {
|
|
swayc_t *workspace = child;
|
|
// reorder focus
|
|
cont->focused = workspace->focused;
|
|
workspace->focused = cont;
|
|
// set all children focu to container
|
|
int i;
|
|
for (i = 0; i < workspace->children->length; ++i) {
|
|
((swayc_t *)workspace->children->items[i])->parent = cont;
|
|
}
|
|
// Swap children
|
|
list_t *tmp_list = workspace->children;
|
|
workspace->children = cont->children;
|
|
cont->children = tmp_list;
|
|
// add container to workspace chidren
|
|
add_child(workspace, cont);
|
|
// give them proper layouts
|
|
cont->layout = workspace->layout;
|
|
workspace->layout = layout;
|
|
set_focused_container_for(workspace, get_focused_view(workspace));
|
|
} else { // Or is built around container
|
|
swayc_t *parent = replace_child(child, cont);
|
|
if (parent) {
|
|
add_child(cont, child);
|
|
}
|
|
}
|
|
return cont;
|
|
}
|
|
|
|
swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
|
|
if (!ASSERT_NONNULL(sibling)) {
|
|
return NULL;
|
|
}
|
|
const char *title = wlc_view_get_title(handle);
|
|
swayc_t *view = new_swayc(C_VIEW);
|
|
sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d",
|
|
handle, title, sibling, sibling ? sibling->type : 0);
|
|
// Setup values
|
|
view->handle = handle;
|
|
view->name = title ? strdup(title) : NULL;
|
|
view->visible = true;
|
|
view->is_focused = true;
|
|
// Setup geometry
|
|
const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
|
|
view->width = 0;
|
|
view->height = 0;
|
|
view->desired_width = geometry->size.w;
|
|
view->desired_height = geometry->size.h;
|
|
|
|
view->is_floating = false;
|
|
|
|
if (sibling->type == C_WORKSPACE) {
|
|
// Case of focused workspace, just create as child of it
|
|
add_child(sibling, view);
|
|
} else {
|
|
// Regular case, create as sibling of current container
|
|
add_sibling(sibling, view);
|
|
}
|
|
return view;
|
|
}
|
|
|
|
swayc_t *new_floating_view(wlc_handle handle) {
|
|
if (swayc_active_workspace() == NULL) {
|
|
return NULL;
|
|
}
|
|
const char *title = wlc_view_get_title(handle);
|
|
swayc_t *view = new_swayc(C_VIEW);
|
|
sway_log(L_DEBUG, "Adding new view %lu:%x:%s as a floating view",
|
|
handle, wlc_view_get_type(handle), title);
|
|
// Setup values
|
|
view->handle = handle;
|
|
view->name = title ? strdup(title) : NULL;
|
|
view->visible = true;
|
|
|
|
// Set the geometry of the floating view
|
|
const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
|
|
|
|
// give it requested geometry, but place in center
|
|
view->x = (swayc_active_workspace()->width - geometry->size.w) / 2;
|
|
view->y = (swayc_active_workspace()->height- geometry->size.h) / 2;
|
|
view->width = geometry->size.w;
|
|
view->height = geometry->size.h;
|
|
|
|
view->desired_width = view->width;
|
|
view->desired_height = view->height;
|
|
|
|
view->is_floating = true;
|
|
|
|
// Case of focused workspace, just create as child of it
|
|
list_add(swayc_active_workspace()->floating, view);
|
|
view->parent = swayc_active_workspace();
|
|
if (swayc_active_workspace()->focused == NULL) {
|
|
set_focused_container_for(swayc_active_workspace(), view);
|
|
}
|
|
return view;
|
|
}
|
|
|
|
// Destroy container
|
|
|
|
swayc_t *destroy_output(swayc_t *output) {
|
|
if (!ASSERT_NONNULL(output)) {
|
|
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) {
|
|
swayc_t *child = output->children->items[0];
|
|
remove_child(child);
|
|
add_child(root_container.children->items[p], child);
|
|
}
|
|
update_visibility(root_container.children->items[p]);
|
|
arrange_windows(root_container.children->items[p], -1, -1);
|
|
}
|
|
}
|
|
|
|
reset_neighbour_relations(output);
|
|
sway_log(L_DEBUG, "OUTPUT: Destroying output '%lu'", output->handle);
|
|
free_swayc(output);
|
|
return &root_container;
|
|
}
|
|
|
|
swayc_t *destroy_workspace(swayc_t *workspace) {
|
|
if (!ASSERT_NONNULL(workspace)) {
|
|
return NULL;
|
|
}
|
|
// NOTE: This is called from elsewhere without checking children length
|
|
// TODO move containers to other workspaces?
|
|
// for now just dont delete
|
|
|
|
// Do not destroy this if it's the last workspace on this output
|
|
swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
|
|
if (output && output->children->length == 1) {
|
|
return NULL;
|
|
}
|
|
|
|
// Do not destroy if there are children
|
|
if (workspace->children->length == 0 && workspace->floating->length == 0) {
|
|
sway_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
|
|
swayc_t *parent = workspace->parent;
|
|
free_swayc(workspace);
|
|
return parent;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
swayc_t *destroy_container(swayc_t *container) {
|
|
if (!ASSERT_NONNULL(container)) {
|
|
return NULL;
|
|
}
|
|
while (container->children->length == 0 && container->type == C_CONTAINER) {
|
|
sway_log(L_DEBUG, "Container: Destroying container '%p'", container);
|
|
swayc_t *parent = container->parent;
|
|
free_swayc(container);
|
|
container = parent;
|
|
}
|
|
return container;
|
|
}
|
|
|
|
swayc_t *destroy_view(swayc_t *view) {
|
|
if (!ASSERT_NONNULL(view)) {
|
|
return NULL;
|
|
}
|
|
sway_log(L_DEBUG, "Destroying view '%p'", view);
|
|
swayc_t *parent = view->parent;
|
|
free_swayc(view);
|
|
|
|
// Destroy empty containers
|
|
if (parent->type == C_CONTAINER) {
|
|
return destroy_container(parent);
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
// Modify container
|
|
|
|
// Make output inaccesible via its neighbours.
|
|
void reset_neighbour_relations(swayc_t *output) {
|
|
if (output->neighbours->top) {
|
|
output->neighbours->top->neighbours->bottom = NULL;
|
|
output->neighbours->top = NULL;
|
|
}
|
|
if (output->neighbours->right) {
|
|
output->neighbours->right->neighbours->left = NULL;
|
|
output->neighbours->right = NULL;
|
|
}
|
|
if (output->neighbours->bottom) {
|
|
output->neighbours->bottom->neighbours->top = NULL;
|
|
output->neighbours->bottom = NULL;
|
|
}
|
|
if (output->neighbours->left) {
|
|
output->neighbours->left->neighbours->right = NULL;
|
|
output->neighbours->left = NULL;
|
|
}
|
|
}
|
|
|
|
// Container lookup
|
|
|
|
swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) {
|
|
if (!container->children) {
|
|
return NULL;
|
|
}
|
|
// Special case for checking floating stuff
|
|
int i;
|
|
if (container->type == C_WORKSPACE) {
|
|
for (i = 0; i < container->floating->length; ++i) {
|
|
swayc_t *child = container->floating->items[i];
|
|
if (test(child, data)) {
|
|
return child;
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < container->children->length; ++i) {
|
|
swayc_t *child = container->children->items[i];
|
|
if (test(child, data)) {
|
|
return child;
|
|
} else {
|
|
swayc_t *res = swayc_by_test(child, test, data);
|
|
if (res) {
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool test_name(swayc_t *view, void *data) {
|
|
if (!view || !view->name) {
|
|
return false;
|
|
}
|
|
return strcmp(view->name, data) == 0;
|
|
}
|
|
|
|
swayc_t *swayc_by_name(const char *name) {
|
|
return swayc_by_test(&root_container, test_name, (void *)name);
|
|
}
|
|
|
|
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
|
|
if (!ASSERT_NONNULL(container)) {
|
|
return NULL;
|
|
}
|
|
if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) {
|
|
return NULL;
|
|
}
|
|
do {
|
|
container = container->parent;
|
|
} while (container && container->type != type);
|
|
return container;
|
|
}
|
|
|
|
swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts layout) {
|
|
if (!ASSERT_NONNULL(container)) {
|
|
return NULL;
|
|
}
|
|
if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "invalid layout")) {
|
|
return NULL;
|
|
}
|
|
do {
|
|
container = container->parent;
|
|
} while (container && container->layout != layout);
|
|
return container;
|
|
}
|
|
|
|
swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types type) {
|
|
if (!ASSERT_NONNULL(container)) {
|
|
return NULL;
|
|
}
|
|
if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) {
|
|
return NULL;
|
|
}
|
|
do {
|
|
container = container->focused;
|
|
} while (container && container->type != type);
|
|
return container;
|
|
}
|
|
|
|
swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts layout) {
|
|
if (!ASSERT_NONNULL(container)) {
|
|
return NULL;
|
|
}
|
|
if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "invalid layout")) {
|
|
return NULL;
|
|
}
|
|
do {
|
|
container = container->focused;
|
|
} while (container && container->layout != layout);
|
|
return container;
|
|
}
|
|
|
|
|
|
static swayc_t *_swayc_by_handle_helper(wlc_handle handle, swayc_t *parent) {
|
|
if (!parent || !parent->children) {
|
|
return NULL;
|
|
}
|
|
int i, len;
|
|
swayc_t **child;
|
|
if (parent->type == C_WORKSPACE) {
|
|
len = parent->floating->length;
|
|
child = (swayc_t **)parent->floating->items;
|
|
for (i = 0; i < len; ++i, ++child) {
|
|
if ((*child)->handle == handle) {
|
|
return *child;
|
|
}
|
|
}
|
|
}
|
|
|
|
len = parent->children->length;
|
|
child = (swayc_t**)parent->children->items;
|
|
for (i = 0; i < len; ++i, ++child) {
|
|
if ((*child)->handle == handle) {
|
|
return *child;
|
|
} else {
|
|
swayc_t *res;
|
|
if ((res = _swayc_by_handle_helper(handle, *child))) {
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
swayc_t *swayc_by_handle(wlc_handle handle) {
|
|
return _swayc_by_handle_helper(handle, &root_container);
|
|
}
|
|
|
|
swayc_t *swayc_active_output(void) {
|
|
return root_container.focused;
|
|
}
|
|
|
|
swayc_t *swayc_active_workspace(void) {
|
|
return root_container.focused ? root_container.focused->focused : NULL;
|
|
}
|
|
|
|
swayc_t *swayc_active_workspace_for(swayc_t *cont) {
|
|
if (!cont) {
|
|
return NULL;
|
|
}
|
|
switch (cont->type) {
|
|
case C_ROOT:
|
|
cont = cont->focused;
|
|
/* Fallthrough */
|
|
|
|
case C_OUTPUT:
|
|
cont = cont ? cont->focused : NULL;
|
|
/* Fallthrough */
|
|
|
|
case C_WORKSPACE:
|
|
return cont;
|
|
|
|
default:
|
|
return swayc_parent_by_type(cont, C_WORKSPACE);
|
|
}
|
|
}
|
|
|
|
// Container information
|
|
|
|
bool swayc_is_fullscreen(swayc_t *view) {
|
|
return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN);
|
|
}
|
|
|
|
bool swayc_is_active(swayc_t *view) {
|
|
return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED);
|
|
}
|
|
|
|
bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) {
|
|
while (child != &root_container) {
|
|
child = child->parent;
|
|
if (child == parent) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool swayc_is_child_of(swayc_t *child, swayc_t *parent) {
|
|
return swayc_is_parent_of(parent, child);
|
|
}
|
|
|
|
int swayc_gap(swayc_t *container) {
|
|
if (container->type == C_VIEW) {
|
|
return container->gaps >= 0 ? container->gaps : config->gaps_inner;
|
|
} else if (container->type == C_WORKSPACE) {
|
|
return container->gaps >= 0 ? container->gaps : config->gaps_outer;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Mapping
|
|
|
|
void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
|
|
if (container) {
|
|
f(container, data);
|
|
int i;
|
|
if (container->children) {
|
|
for (i = 0; i < container->children->length; ++i) {
|
|
swayc_t *child = container->children->items[i];
|
|
container_map(child, f, data);
|
|
}
|
|
}
|
|
if (container->floating) {
|
|
for (i = 0; i < container->floating->length; ++i) {
|
|
swayc_t *child = container->floating->items[i];
|
|
container_map(child, f, data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void update_visibility_output(swayc_t *container, wlc_handle output) {
|
|
// Inherit visibility
|
|
swayc_t *parent = container->parent;
|
|
container->visible = parent->visible;
|
|
// special cases where visibility depends on focus
|
|
if (parent->type == C_OUTPUT
|
|
|| parent->layout == L_TABBED
|
|
|| parent->layout == L_STACKED) {
|
|
container->visible = parent->focused == container;
|
|
}
|
|
// Set visibility and output for view
|
|
if (container->type == C_VIEW) {
|
|
wlc_view_set_output(container->handle, output);
|
|
wlc_view_set_mask(container->handle, container->visible ? VISIBLE : 0);
|
|
if (container->visible) {
|
|
wlc_view_bring_to_front(container->handle);
|
|
} else {
|
|
wlc_view_send_to_back(container->handle);
|
|
}
|
|
}
|
|
// Update visibility for children
|
|
else {
|
|
if (container->children) {
|
|
int i, len = container->children->length;
|
|
for (i = 0; i < len; ++i) {
|
|
update_visibility_output(container->children->items[i], output);
|
|
}
|
|
}
|
|
if (container->floating) {
|
|
int i, len = container->floating->length;
|
|
for (i = 0; i < len; ++i) {
|
|
update_visibility_output(container->floating->items[i], output);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void update_visibility(swayc_t *container) {
|
|
if (!container) return;
|
|
switch (container->type) {
|
|
case C_ROOT:
|
|
container->visible = true;
|
|
if (container->children) {
|
|
int i, len = container->children->length;
|
|
for (i = 0; i < len; ++i) {
|
|
update_visibility(container->children->items[i]);
|
|
}
|
|
}
|
|
return;
|
|
|
|
case C_OUTPUT:
|
|
container->visible = true;
|
|
if (container->children) {
|
|
int i, len = container->children->length;
|
|
for (i = 0; i < len; ++i) {
|
|
update_visibility_output(container->children->items[i], container->handle);
|
|
}
|
|
}
|
|
return;
|
|
|
|
default:
|
|
{
|
|
swayc_t *op = swayc_parent_by_type(container, C_OUTPUT);
|
|
update_visibility_output(container, op->handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
void set_gaps(swayc_t *view, void *_data) {
|
|
int *data = _data;
|
|
if (!ASSERT_NONNULL(view)) {
|
|
return;
|
|
}
|
|
if (view->type == C_WORKSPACE || view->type == C_VIEW) {
|
|
view->gaps = *data;
|
|
}
|
|
}
|
|
|
|
void add_gaps(swayc_t *view, void *_data) {
|
|
int *data = _data;
|
|
if (!ASSERT_NONNULL(view)) {
|
|
return;
|
|
}
|
|
if (view->type == C_WORKSPACE || view->type == C_VIEW) {
|
|
if ((view->gaps += *data) < 0) {
|
|
view->gaps = 0;
|
|
}
|
|
}
|
|
}
|