This commit is contained in:
aouelete 2015-08-22 21:56:43 -04:00
commit af872be2cf
19 changed files with 1017 additions and 559 deletions

View file

@ -22,6 +22,12 @@ struct sway_mode {
list_t *bindings; list_t *bindings;
}; };
struct output_config {
char *name;
int width, height;
int x, y;
};
struct workspace_output { struct workspace_output {
char *output; char *output;
char *workspace; char *workspace;
@ -32,6 +38,7 @@ struct sway_config {
list_t *modes; list_t *modes;
list_t *cmd_queue; list_t *cmd_queue;
list_t *workspace_outputs; list_t *workspace_outputs;
list_t *output_configs;
struct sway_mode *current_mode; struct sway_mode *current_mode;
uint32_t floating_mod; uint32_t floating_mod;

View file

@ -81,13 +81,22 @@ swayc_t *destroy_view(swayc_t *view);
// Container Lookup // Container Lookup
swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
swayc_t *swayc_by_handle(wlc_handle handle);
swayc_t *swayc_active_output(void);
swayc_t *swayc_active_workspace(void);
swayc_t *swayc_active_workspace_for(swayc_t *view);
// Container information
bool swayc_is_fullscreen(swayc_t *view);
// Mapping functions
swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
// Mappings // Mappings
void set_view_visibility(swayc_t *view, void *data); void set_view_visibility(swayc_t *view, void *data);
void reset_gaps(swayc_t *view, void *data); void reset_gaps(swayc_t *view, void *data);

View file

@ -5,6 +5,7 @@
#include <wlc/wlc.h> #include <wlc/wlc.h>
extern struct wlc_interface interface; extern struct wlc_interface interface;
extern struct wlc_origin mouse_origin;
extern uint32_t keys_pressed[32]; extern uint32_t keys_pressed[32];
// set focus to current pointer location and return focused container // set focus to current pointer location and return focused container

View file

@ -37,13 +37,19 @@ extern struct pointer_state {
struct pointer_tiling { struct pointer_tiling {
bool resize; bool resize;
swayc_t *init_view; swayc_t *init_view;
struct wlc_origin *lock_pos; struct wlc_origin lock_pos;
} tiling; } tiling;
struct pointer_lock { struct pointer_lock {
// Lock movement for certain edges
bool left; bool left;
bool right; bool right;
bool top; bool top;
bool bottom; bool bottom;
// Lock movement in certain directions
bool temp_left;
bool temp_right;
bool temp_up;
bool temp_down;
} lock; } lock;
} pointer_state; } pointer_state;

View file

@ -8,6 +8,9 @@
extern swayc_t root_container; extern swayc_t root_container;
extern int min_sane_w;
extern int min_sane_h;
void init_layout(void); void init_layout(void);
void add_child(swayc_t *parent, swayc_t *child); void add_child(swayc_t *parent, swayc_t *child);
@ -19,17 +22,10 @@ swayc_t *remove_child(swayc_t *child);
void move_container(swayc_t* container,swayc_t* root,enum movement_direction direction); void move_container(swayc_t* container,swayc_t* root,enum movement_direction direction);
// Layout // Layout
void arrange_windows(swayc_t *container, double width, double height); void arrange_windows(swayc_t *container, double width, double height);
// Focus
void unfocus_all(swayc_t *container);
void focus_view(swayc_t *view);
void focus_view_for(swayc_t *ancestor, swayc_t *container);
swayc_t *get_focused_container(swayc_t *parent); swayc_t *get_focused_container(swayc_t *parent);
swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent);
swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir); swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir);
void recursive_resize(swayc_t *container, double amount, enum wlc_resize_edge edge); void recursive_resize(swayc_t *container, double amount, enum wlc_resize_edge edge);

8
include/resize.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef _SWAY_RESIZE_H
#define _SWAY_RESIZE_H
bool mouse_resize_tiled(struct wlc_origin prev_pos);
bool resize_floating(struct wlc_origin prev_pos);
bool resize_tiled(int amount, bool use_width);
#endif

View file

@ -5,11 +5,9 @@
#include "list.h" #include "list.h"
#include "layout.h" #include "layout.h"
extern swayc_t *active_workspace;
char *workspace_next_name(void); char *workspace_next_name(void);
swayc_t *workspace_create(const char*); swayc_t *workspace_create(const char*);
swayc_t *workspace_find_by_name(const char*); swayc_t *workspace_by_name(const char*);
void workspace_switch(swayc_t*); void workspace_switch(swayc_t*);
void workspace_output_next(); void workspace_output_next();
void workspace_next(); void workspace_next();

View file

@ -41,6 +41,11 @@ Commands
**floating** toggle:: **floating** toggle::
Toggles the "floating" status of the focused view. Toggles the "floating" status of the focused view.
**floating_modifier** <modifier>::
When the _modifier_ key is held down, you may use left click to drag floating
windows, and right click to resize them. Unlike i3, this modifier may also be
used to resize and move windows that are tiled.
**focus** <direction>:: **focus** <direction>::
Direction may be one of _up_, _down_, _left_, _right_, or _parent_. The Direction may be one of _up_, _down_, _left_, _right_, or _parent_. The
directional focus commands will move the focus in that direction. The parent directional focus commands will move the focus in that direction. The parent
@ -55,34 +60,6 @@ Commands
If set to _yes_, the currently focused view will change as you move your If set to _yes_, the currently focused view will change as you move your
mouse around the screen to the view that ends up underneath your mouse. mouse around the screen to the view that ends up underneath your mouse.
**kill**::
Closes the currently focused view.
**layout** <mode>::
Sets the layout mode of the focused container. _mode_ can be one of _splith_,
_splitv_, or _toggle split_.
**reload**::
Reloads the sway config file without restarting sway.
**set** <name> <value>::
Creates a substitution for _value_ that can be used with $_name_ in other
commands.
**split** <vertical|horizontal>::
Splits the current container, vertically or horiziontally. The letters "h" and
"v" can be used instead of the full words "vertical" or "horizontal".
**splith**::
Equivalent to **split horizontal**.
**splitv**::
Equivalent to **split vertical**.
**floating_modifier** <modifier>::
When the _modifier_ key is held down, you may use left click to drag floating
windows, and right click to resize them.
**fullscreen**:: **fullscreen**::
Toggles fullscreen status for the focused view. Toggles fullscreen status for the focused view.
@ -93,6 +70,41 @@ Commands
Adds _amount_ pixels as an _inner_ or _outer_ gap, where the former affects Adds _amount_ pixels as an _inner_ or _outer_ gap, where the former affects
spacing between views and the latter affects the space around each output. spacing between views and the latter affects the space around each output.
**kill**::
Closes the currently focused view.
**layout** <mode>::
Sets the layout mode of the focused container. _mode_ can be one of _splith_,
_splitv_, or _toggle split_.
**move** <left|right|up|down>::
Moves the focused container _left_, _right_, _up_, or _down_.
**output** <name> <resolution|res WIDTHxHEIGHT> <position|pos X,Y>::
Configures the specified output. It will use the given resolution and be
arranged at the given position in the layout tree. You may omit either of
these parameters if you only want to set one of them.
**reload**::
Reloads the sway config file without restarting sway.
**resize** <shrink|grow> <width|height> <amount>::
Resizes the currently focused container or view by _amount_. _amount_ can be
specified as "n px" or "n ppt" or "n px or n ppt".
**set** <name> <value>::
Creates a substitution for _value_ that can be used with $_name_ in other
commands.
**split** <vertical|v|horizontal|h>::
Splits the current container, vertically or horiziontally.
**splith**::
Equivalent to **split horizontal**.
**splitv**::
Equivalent to **split vertical**.
**workspace** <name>:: **workspace** <name>::
Switches to the specified workspace. Switches to the specified workspace.

View file

@ -16,6 +16,7 @@
#include "container.h" #include "container.h"
#include "handlers.h" #include "handlers.h"
#include "sway.h" #include "sway.h"
#include "resize.h"
struct modifier_key { struct modifier_key {
char *name; char *name;
@ -208,16 +209,16 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
destroy_container(remove_child(view)); destroy_container(remove_child(view));
// and move it into workspace floating // and move it into workspace floating
add_floating(active_workspace,view); add_floating(swayc_active_workspace(),view);
view->x = (active_workspace->width - view->width)/2; view->x = (swayc_active_workspace()->width - view->width)/2;
view->y = (active_workspace->height - view->height)/2; view->y = (swayc_active_workspace()->height - view->height)/2;
if (view->desired_width != -1) { if (view->desired_width != -1) {
view->width = view->desired_width; view->width = view->desired_width;
} }
if (view->desired_height != -1) { if (view->desired_height != -1) {
view->height = view->desired_height; view->height = view->desired_height;
} }
arrange_windows(active_workspace, -1, -1); arrange_windows(swayc_active_workspace(), -1, -1);
} else { } else {
// Delete the view from the floating list and unset its is_floating flag // Delete the view from the floating list and unset its is_floating flag
// Using length-1 as the index is safe because the view must be the currently // Using length-1 as the index is safe because the view must be the currently
@ -228,7 +229,7 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
swayc_t *focused = container_under_pointer(); swayc_t *focused = container_under_pointer();
// If focused is null, it's because the currently focused container is a workspace // If focused is null, it's because the currently focused container is a workspace
if (focused == NULL) { if (focused == NULL) {
focused = active_workspace; focused = swayc_active_workspace();
} }
set_focused_container(focused); set_focused_container(focused);
@ -244,7 +245,7 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
} }
// Refocus on the view once its been put back into the layout // Refocus on the view once its been put back into the layout
view->width = view->height = 0; view->width = view->height = 0;
arrange_windows(active_workspace, -1, -1); arrange_windows(swayc_active_workspace(), -1, -1);
} }
set_focused_container(view); set_focused_container(view);
} }
@ -293,37 +294,38 @@ static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
return move_focus(MOVE_PARENT); return move_focus(MOVE_PARENT);
} else if (strcasecmp(argv[0], "mode_toggle") == 0) { } else if (strcasecmp(argv[0], "mode_toggle") == 0) {
int i; int i;
swayc_t *focused = get_focused_view(active_workspace); swayc_t *workspace = swayc_active_workspace();
swayc_t *focused = get_focused_view(workspace);
if (focused->is_floating) { if (focused->is_floating) {
if (active_workspace->children->length > 0) { if (workspace->children->length > 0) {
for (i = 0;i < active_workspace->floating->length; i++) { for (i = 0;i < workspace->floating->length; i++) {
if (active_workspace->floating->items[i] == focused) { if (workspace->floating->items[i] == focused) {
floating_toggled_index = i; floating_toggled_index = i;
break; break;
} }
} }
if (active_workspace->children->length > tiled_toggled_index) { if (workspace->children->length > tiled_toggled_index) {
set_focused_container(get_focused_view(active_workspace->children->items[tiled_toggled_index])); set_focused_container(get_focused_view(workspace->children->items[tiled_toggled_index]));
} else { } else {
set_focused_container(get_focused_view(active_workspace->children->items[0])); set_focused_container(get_focused_view(workspace->children->items[0]));
tiled_toggled_index = 0; tiled_toggled_index = 0;
} }
} }
} else { } else {
if (active_workspace->floating->length > 0) { if (workspace->floating->length > 0) {
for (i = 0;i < active_workspace->children->length; i++) { for (i = 0;i < workspace->children->length; i++) {
if (active_workspace->children->items[i] == focused) { if (workspace->children->items[i] == focused) {
tiled_toggled_index = i; tiled_toggled_index = i;
break; break;
} }
} }
if (active_workspace->floating->length > floating_toggled_index) { if (workspace->floating->length > floating_toggled_index) {
swayc_t *floating = active_workspace->floating->items[floating_toggled_index]; swayc_t *floating = workspace->floating->items[floating_toggled_index];
set_focused_container(get_focused_view(floating)); set_focused_container(get_focused_view(floating));
} else { } else {
swayc_t *floating = active_workspace->floating->items[active_workspace->floating->length - 1]; swayc_t *floating = workspace->floating->items[workspace->floating->length - 1];
set_focused_container(get_focused_view(floating)); set_focused_container(get_focused_view(floating));
tiled_toggled_index = active_workspace->floating->length - 1; tiled_toggled_index = workspace->floating->length - 1;
} }
} }
} }
@ -362,6 +364,66 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) {
return true; return true;
} }
static bool cmd_output(struct sway_config *config, int argc, char **argv) {
if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
return false;
}
struct output_config *output = calloc(1, sizeof(struct output_config));
output->x = output->y = output->width = output->height = -1;
output->name = strdup(argv[0]);
// TODO: atoi doesn't handle invalid numbers
int i;
for (i = 1; i < argc; ++i) {
if (strcasecmp(argv[i], "resolution") == 0 || strcasecmp(argv[i], "res") == 0) {
char *res = argv[++i];
char *x = strchr(res, 'x');
int width = -1, height = -1;
if (x != NULL) {
// Format is 1234x4321
*x = '\0';
width = atoi(res);
height = atoi(x + 1);
*x = 'x';
} else {
// Format is 1234 4321
width = atoi(res);
res = argv[++i];
height = atoi(res);
}
output->width = width;
output->height = height;
} else if (strcasecmp(argv[i], "position") == 0 || strcasecmp(argv[i], "pos") == 0) {
char *res = argv[++i];
char *c = strchr(res, ',');
int x = -1, y = -1;
if (c != NULL) {
// Format is 1234,4321
*c = '\0';
x = atoi(res);
y = atoi(c + 1);
*c = ',';
} else {
// Format is 1234 4321
x = atoi(res);
res = argv[++i];
y = atoi(res);
}
output->x = x;
output->y = y;
}
}
list_add(config->output_configs, output);
sway_log(L_DEBUG, "Configured output %s to %d x %d @ %d, %d",
output->name, output->width, output->height, output->x, output->y);
return true;
}
static bool cmd_gaps(struct sway_config *config, int argc, char **argv) { static bool cmd_gaps(struct sway_config *config, int argc, char **argv) {
if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) { if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
return false; return false;
@ -452,147 +514,21 @@ static bool cmd_resize(struct sway_config *config, int argc, char **argv) {
errno = 0; errno = 0;
return false; return false;
} }
if (strcmp(argv[0], "shrink") != 0 && strcmp(argv[0], "grow") != 0) { if (strcmp(argv[0], "shrink") != 0 && strcmp(argv[0], "grow") != 0) {
return false; return false;
} }
if (strcmp(argv[0], "shrink") == 0) { if (strcmp(argv[0], "shrink") == 0) {
amount *= -1; amount *= -1;
} }
swayc_t *parent = get_focused_view(active_workspace);
swayc_t *focused = parent;
swayc_t *sibling;
if (!parent) {
return true;
}
// Find the closest parent container which has siblings of the proper layout.
// Then apply the resize to all of them.
int i;
if (strcmp(argv[1], "width") == 0) { if (strcmp(argv[1], "width") == 0) {
int lnumber = 0; return resize_tiled(amount, true);
int rnumber = 0;
while (parent->parent) {
if (parent->parent->layout == L_HORIZ) {
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->x != focused->x) {
if (sibling->x < parent->x) {
lnumber++;
} else if (sibling->x > parent->x) {
rnumber++;
}
}
}
if (rnumber || lnumber) {
break;
}
}
parent = parent->parent;
}
if (parent == &root_container) {
return true;
}
sway_log(L_DEBUG, "Found the proper parent: %p. It has %d l conts, and %d r conts", parent->parent, lnumber, rnumber);
//TODO: Ensure rounding is done in such a way that there are NO pixel leaks
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->x != focused->x) {
if (sibling->x < parent->x) {
double pixels = -1 * amount;
pixels /= lnumber;
if (rnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_RIGHT);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_RIGHT);
}
} else if (sibling->x > parent->x) {
double pixels = -1 * amount;
pixels /= rnumber;
if (lnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_LEFT);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_LEFT);
}
}
} else {
if (rnumber != 0 && lnumber != 0) {
double pixels = amount;
pixels /= 2;
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_LEFT);
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_RIGHT);
} else if (rnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_RIGHT);
} else if (lnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_LEFT);
}
}
}
// Recursive resize does not handle positions, let arrange_windows
// take care of that.
arrange_windows(active_workspace, -1, -1);
return true;
} else if (strcmp(argv[1], "height") == 0) { } else if (strcmp(argv[1], "height") == 0) {
int tnumber = 0; return resize_tiled(amount, false);
int bnumber = 0;
while (parent->parent) {
if (parent->parent->layout == L_VERT) {
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->y != focused->y) {
if (sibling->y < parent->y) {
bnumber++;
} else if (sibling->y > parent->y) {
tnumber++;
} }
} return false;
}
if (bnumber || tnumber) {
break;
}
}
parent = parent->parent;
}
if (parent == &root_container) {
return true;
}
sway_log(L_DEBUG, "Found the proper parent: %p. It has %d b conts, and %d t conts", parent->parent, bnumber, tnumber);
//TODO: Ensure rounding is done in such a way that there are NO pixel leaks
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->y != focused->y) {
if (sibling->y < parent->y) {
double pixels = -1 * amount;
pixels /= bnumber;
if (tnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_BOTTOM);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_BOTTOM);
}
} else if (sibling->x > parent->x) {
double pixels = -1 * amount;
pixels /= tnumber;
if (bnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_TOP);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_TOP);
}
}
} else {
if (bnumber != 0 && tnumber != 0) {
double pixels = amount/2;
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_TOP);
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_BOTTOM);
} else if (tnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_TOP);
} else if (bnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_BOTTOM);
}
}
}
arrange_windows(active_workspace, -1, -1);
return true;
}
return true;
} }
static bool cmd_set(struct sway_config *config, int argc, char **argv) { static bool cmd_set(struct sway_config *config, int argc, char **argv) {
@ -616,8 +552,12 @@ static bool _do_split(struct sway_config *config, int argc, char **argv, int lay
} }
swayc_t *focused = get_focused_container(&root_container); swayc_t *focused = get_focused_container(&root_container);
if (focused->type == C_WORKSPACE && focused->children->length <= 1) { // Case of floating window, dont split
if (focused->is_floating) {
return true;
}
/* Case that focus is on an workspace with 0/1 children.change its layout */ /* Case that focus is on an workspace with 0/1 children.change its layout */
if (focused->type == C_WORKSPACE && focused->children->length <= 1) {
sway_log(L_DEBUG, "changing workspace layout"); sway_log(L_DEBUG, "changing workspace layout");
focused->layout = layout; focused->layout = layout;
} else if (focused->type != C_WORKSPACE && focused->parent->children->length == 1) { } else if (focused->type != C_WORKSPACE && focused->parent->children->length == 1) {
@ -632,7 +572,6 @@ static bool _do_split(struct sway_config *config, int argc, char **argv, int lay
set_focused_container(focused); set_focused_container(focused);
arrange_windows(parent, -1, -1); arrange_windows(parent, -1, -1);
} }
return true; return true;
} }
@ -680,7 +619,7 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
} }
swayc_t *container = get_focused_view(&root_container); swayc_t *container = get_focused_view(&root_container);
bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0; bool current = swayc_is_fullscreen(container);
wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current);
// Resize workspace if going from fullscreen -> notfullscreen // Resize workspace if going from fullscreen -> notfullscreen
// otherwise just resize container // otherwise just resize container
@ -721,7 +660,7 @@ static bool cmd_workspace(struct sway_config *config, int argc, char **argv) {
return true; return true;
} }
swayc_t *workspace = workspace_find_by_name(argv[0]); swayc_t *workspace = workspace_by_name(argv[0]);
if (!workspace) { if (!workspace) {
workspace = workspace_create(argv[0]); workspace = workspace_create(argv[0]);
} }
@ -758,6 +697,7 @@ static struct cmd_handler handlers[] = {
{ "layout", cmd_layout }, { "layout", cmd_layout },
{ "log_colors", cmd_log_colors }, { "log_colors", cmd_log_colors },
{ "move", cmd_move}, { "move", cmd_move},
{ "output", cmd_output},
{ "reload", cmd_reload }, { "reload", cmd_reload },
{ "resize", cmd_resize }, { "resize", cmd_resize },
{ "set", cmd_set }, { "set", cmd_set },

View file

@ -22,6 +22,7 @@ void config_defaults(struct sway_config *config) {
config->modes = create_list(); config->modes = create_list();
config->cmd_queue = create_list(); config->cmd_queue = create_list();
config->workspace_outputs = create_list(); config->workspace_outputs = create_list();
config->output_configs = create_list();
config->current_mode = malloc(sizeof(struct sway_mode)); config->current_mode = malloc(sizeof(struct sway_mode));
config->current_mode->name = NULL; config->current_mode->name = NULL;
config->current_mode->bindings = create_list(); config->current_mode->bindings = create_list();
@ -60,6 +61,7 @@ void free_config(struct sway_config *config) {
free(sym->value); free(sym->value);
} }
free_flat_list(config->symbols); free_flat_list(config->symbols);
free_flat_list(config->output_configs);
} }
static const char *search_paths[] = { static const char *search_paths[] = {

View file

@ -26,14 +26,11 @@ static void free_swayc(swayc_t *cont) {
if (!ASSERT_NONNULL(cont)) { if (!ASSERT_NONNULL(cont)) {
return; return;
} }
// TODO does not properly handle containers with children,
// TODO but functions that call this usually check for that
if (cont->children) { if (cont->children) {
if (cont->children->length) { // remove children until there are no more, free_swayc calls
int i; // remove_child, which removes child from this container
for (i = 0; i < cont->children->length; ++i) { while (cont->children->length) {
free_swayc(cont->children->items[i]); free_swayc(cont->children->items[0]);
}
} }
list_free(cont->children); list_free(cont->children);
} }
@ -57,34 +54,65 @@ static void free_swayc(swayc_t *cont) {
// New containers // New containers
static bool workspace_test(swayc_t *view, void *name) {
return strcasecmp(view->name, (char *)name) == 0;
}
swayc_t *new_output(wlc_handle handle) { swayc_t *new_output(wlc_handle handle) {
const struct wlc_size *size = wlc_output_get_resolution(handle); const struct wlc_size *size = wlc_output_get_resolution(handle);
const char *name = wlc_output_get_name(handle); const char *name = wlc_output_get_name(handle);
sway_log(L_DEBUG, "Added output %lu:%s", handle, name); sway_log(L_DEBUG, "Added 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;
}
swayc_t *output = new_swayc(C_OUTPUT); swayc_t *output = new_swayc(C_OUTPUT);
if (oc && oc->width != -1 && oc->height != -1) {
output->width = oc->width;
output->height = oc->height;
struct wlc_size new_size = { .w = oc->width, .h = oc->height };
wlc_output_set_resolution(handle, &new_size);
} else {
output->width = size->w; output->width = size->w;
output->height = size->h; output->height = size->h;
}
output->handle = handle; output->handle = handle;
output->name = name ? strdup(name) : NULL; output->name = name ? strdup(name) : NULL;
output->gaps = config->gaps_outer + config->gaps_inner / 2; output->gaps = config->gaps_outer + config->gaps_inner / 2;
// Find position for it
if (oc && oc->x != -1 && oc->y != -1) {
sway_log(L_DEBUG, "Set %s position to %d, %d", name, oc->x, oc->y);
output->x = oc->x;
output->y = oc->y;
} else {
int x = 0;
for (i = 0; i < root_container.children->length; ++i) {
swayc_t *c = root_container.children->items[i];
if (c->type == C_OUTPUT) {
if (c->width + c->x > x) {
x = c->width + c->x;
}
}
}
output->x = x;
}
add_child(&root_container, output); add_child(&root_container, output);
// Create workspace // Create workspace
char *ws_name = NULL; char *ws_name = NULL;
if (name) { if (name) {
int i;
for (i = 0; i < config->workspace_outputs->length; ++i) { for (i = 0; i < config->workspace_outputs->length; ++i) {
struct workspace_output *wso = config->workspace_outputs->items[i]; struct workspace_output *wso = config->workspace_outputs->items[i];
if (strcasecmp(wso->output, name) == 0) { if (strcasecmp(wso->output, name) == 0) {
sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output);
// Check if any other workspaces are using this name // Check if any other workspaces are using this name
if (find_container(&root_container, workspace_test, wso->workspace)) { if (workspace_by_name(wso->workspace)) {
sway_log(L_DEBUG, "But it's already taken"); sway_log(L_DEBUG, "But it's already taken");
break; break;
} }
@ -128,7 +156,8 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
} }
swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
if (!ASSERT_NONNULL(child)) { if (!ASSERT_NONNULL(child)
&& !sway_assert(!child->is_floating, "cannot create container around floating window")) {
return NULL; return NULL;
} }
swayc_t *cont = new_swayc(C_CONTAINER); swayc_t *cont = new_swayc(C_CONTAINER);
@ -207,6 +236,9 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
} }
swayc_t *new_floating_view(wlc_handle handle) { swayc_t *new_floating_view(wlc_handle handle) {
if (swayc_active_workspace() == NULL) {
return NULL;
}
const char *title = wlc_view_get_title(handle); const char *title = wlc_view_get_title(handle);
swayc_t *view = new_swayc(C_VIEW); swayc_t *view = new_swayc(C_VIEW);
sway_log(L_DEBUG, "Adding new view %lu:%x:%s as a floating view", sway_log(L_DEBUG, "Adding new view %lu:%x:%s as a floating view",
@ -220,8 +252,8 @@ swayc_t *new_floating_view(wlc_handle handle) {
const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
// give it requested geometry, but place in center // give it requested geometry, but place in center
view->x = (active_workspace->width - geometry->size.w) / 2; view->x = (swayc_active_workspace()->width - geometry->size.w) / 2;
view->y = (active_workspace->height- geometry->size.h) / 2; view->y = (swayc_active_workspace()->height- geometry->size.h) / 2;
view->width = geometry->size.w; view->width = geometry->size.w;
view->height = geometry->size.h; view->height = geometry->size.h;
@ -231,10 +263,10 @@ swayc_t *new_floating_view(wlc_handle handle) {
view->is_floating = true; view->is_floating = true;
// Case of focused workspace, just create as child of it // Case of focused workspace, just create as child of it
list_add(active_workspace->floating, view); list_add(swayc_active_workspace()->floating, view);
view->parent = active_workspace; view->parent = swayc_active_workspace();
if (active_workspace->focused == NULL) { if (swayc_active_workspace()->focused == NULL) {
set_focused_container_for(active_workspace, view); set_focused_container_for(swayc_active_workspace(), view);
} }
return view; return view;
} }
@ -267,7 +299,8 @@ swayc_t *destroy_workspace(swayc_t *workspace) {
return NULL; return NULL;
} }
if (workspace->children->length == 0) { // Do not destroy if there are children
if (workspace->children->length == 0 && workspace->floating->length == 0) {
sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name); sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name);
swayc_t *parent = workspace->parent; swayc_t *parent = workspace->parent;
free_swayc(workspace); free_swayc(workspace);
@ -306,6 +339,35 @@ swayc_t *destroy_view(swayc_t *view) {
// Container lookup // 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;
}
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
if (!ASSERT_NONNULL(container)) { if (!ASSERT_NONNULL(container)) {
return NULL; return NULL;
@ -332,27 +394,30 @@ swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts layout) {
return container; return container;
} }
swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { static swayc_t *_swayc_by_handle_helper(wlc_handle handle, swayc_t *parent) {
if (!container->children) { if (!parent || !parent->children) {
return NULL; return NULL;
} }
// Special case for checking floating stuff int i, len;
int i; swayc_t **child;
if (container->type == C_WORKSPACE) { if (parent->type == C_WORKSPACE) {
for (i = 0; i < container->floating->length; ++i) { len = parent->floating->length;
swayc_t *child = container->floating->items[i]; child = (swayc_t **)parent->floating->items;
if (test(child, data)) { for (i = 0; i < len; ++i, ++child) {
return child; if ((*child)->handle == handle) {
return *child;
} }
} }
} }
for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i]; len = parent->children->length;
if (test(child, data)) { child = (swayc_t**)parent->children->items;
return child; for (i = 0; i < len; ++i, ++child) {
if ((*child)->handle == handle) {
return *child;
} else { } else {
swayc_t *res = find_container(child, test, data); swayc_t *res;
if (res) { if ((res = _swayc_by_handle_helper(handle, *child))) {
return res; return res;
} }
} }
@ -360,15 +425,58 @@ swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *da
return NULL; 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->focused;
/* 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);
}
// Mapping
void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
if (container && container->children && container->children->length) { if (container) {
int i; int i;
if (container->children) {
for (i = 0; i < container->children->length; ++i) { for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i]; swayc_t *child = container->children->items[i];
f(child, data); f(child, data);
container_map(child, f, data); container_map(child, f, data);
} }
if (container->type == C_WORKSPACE) { }
if (container->floating) {
for (i = 0; i < container->floating->length; ++i) { for (i = 0; i < container->floating->length; ++i) {
swayc_t *child = container->floating->items[i]; swayc_t *child = container->floating->items[i];
f(child, data); f(child, data);

View file

@ -21,8 +21,6 @@ static void update_focus(swayc_t *c) {
// Case where output changes // Case where output changes
case C_OUTPUT: case C_OUTPUT:
wlc_output_focus(c->handle); wlc_output_focus(c->handle);
// Set new workspace to the outputs focused workspace
active_workspace = c->focused;
break; break;
// Case where workspace changes // Case where workspace changes
@ -36,10 +34,8 @@ static void update_focus(swayc_t *c) {
mask = 2; mask = 2;
container_map(c, set_view_visibility, &mask); container_map(c, set_view_visibility, &mask);
wlc_output_set_mask(parent->handle, 2); wlc_output_set_mask(parent->handle, 2);
c->parent->focused = c;
destroy_workspace(ws); destroy_workspace(ws);
} }
active_workspace = c;
break; break;
default: default:
@ -54,8 +50,8 @@ static void update_focus(swayc_t *c) {
} }
bool move_focus(enum movement_direction direction) { bool move_focus(enum movement_direction direction) {
swayc_t *view = get_swayc_in_direction( swayc_t *view = get_focused_container(&root_container);
get_focused_container(&root_container), direction); view = get_swayc_in_direction(view, direction);
if (view) { if (view) {
if (direction == MOVE_PARENT) { if (direction == MOVE_PARENT) {
set_focused_container(view); set_focused_container(view);
@ -68,13 +64,12 @@ bool move_focus(enum movement_direction direction) {
} }
swayc_t *get_focused_container(swayc_t *parent) { swayc_t *get_focused_container(swayc_t *parent) {
while (parent && !parent->is_focused) { if (!parent) {
parent = parent->focused; return swayc_active_workspace();
} }
// just incase // get focusde container
if (parent == NULL) { while (!parent->is_focused && parent->focused) {
sway_log(L_DEBUG, "get_focused_container unable to find container"); parent = parent->focused;
return active_workspace;
} }
return parent; return parent;
} }
@ -85,9 +80,13 @@ void set_focused_container(swayc_t *c) {
} }
sway_log(L_DEBUG, "Setting focus to %p:%ld", c, c->handle); sway_log(L_DEBUG, "Setting focus to %p:%ld", c, c->handle);
// Find previous focused view, and the new focused view, if they are the same return // Get workspace for c, get that workspaces current focused container.
swayc_t *focused = get_focused_view(&root_container); swayc_t *workspace = swayc_active_workspace_for(c);
swayc_t *workspace = active_workspace; swayc_t *focused = get_focused_view(workspace);
// if the workspace we are changing focus to has a fullscreen view return
if (swayc_is_fullscreen(focused) && focused != c) {
return;
}
// update container focus from here to root, making necessary changes along // update container focus from here to root, making necessary changes along
// the way // the way
@ -101,13 +100,6 @@ void set_focused_container(swayc_t *c) {
p->is_focused = false; p->is_focused = false;
} }
// if the workspace is the same, and previous focus is fullscreen, dont
// change focus
if (workspace == active_workspace
&& wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) {
return;
}
// get new focused view and set focus to it. // get new focused view and set focus to it.
p = get_focused_view(c); p = get_focused_view(c);
if (p->type == C_VIEW && !(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) { if (p->type == C_VIEW && !(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) {
@ -137,6 +129,15 @@ void set_focused_container_for(swayc_t *a, swayc_t *c) {
return; return;
} }
} }
// Get workspace for c, get that workspaces current focused container.
swayc_t *workspace = swayc_active_workspace_for(c);
swayc_t *focused = get_focused_view(workspace);
// if the workspace we are changing focus to has a fullscreen view return
if (swayc_is_fullscreen(focused) && c != focused) {
return;
}
// Check if we changing a parent container that will see chnage // Check if we changing a parent container that will see chnage
bool effective = true; bool effective = true;
while (find != &root_container) { while (find != &root_container) {
@ -171,7 +172,7 @@ swayc_t *get_focused_view(swayc_t *parent) {
parent = parent->focused; parent = parent->focused;
} }
if (parent == NULL) { if (parent == NULL) {
return active_workspace; return swayc_active_workspace_for(parent);
} }
return parent; return parent;
} }

View file

@ -15,8 +15,9 @@
#include "container.h" #include "container.h"
#include "focus.h" #include "focus.h"
#include "input_state.h" #include "input_state.h"
#include "resize.h"
static struct wlc_origin mouse_origin; struct wlc_origin mouse_origin;
static bool pointer_test(swayc_t *view, void *_origin) { static bool pointer_test(swayc_t *view, void *_origin) {
const struct wlc_origin *origin = _origin; const struct wlc_origin *origin = _origin;
@ -86,7 +87,7 @@ static bool handle_output_created(wlc_handle output) {
swayc_t *op = new_output(output); swayc_t *op = new_output(output);
// Switch to workspace if we need to // Switch to workspace if we need to
if (active_workspace == NULL) { if (swayc_active_workspace() == NULL) {
swayc_t *ws = op->children->items[0]; swayc_t *ws = op->children->items[0];
workspace_switch(ws); workspace_switch(ws);
} }
@ -104,9 +105,7 @@ static void handle_output_destroyed(wlc_handle output) {
if (i < list->length) { if (i < list->length) {
destroy_output(list->items[i]); destroy_output(list->items[i]);
} }
if (list->length == 0) { if (list->length > 0) {
active_workspace = NULL;
} else {
// switch to other outputs active workspace // switch to other outputs active workspace
workspace_switch(((swayc_t *)root_container.children->items[0])->focused); workspace_switch(((swayc_t *)root_container.children->items[0])->focused);
} }
@ -114,7 +113,7 @@ static void handle_output_destroyed(wlc_handle output) {
static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) {
sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h);
swayc_t *c = get_swayc_for_handle(output, &root_container); swayc_t *c = swayc_by_handle(output);
if (!c) return; if (!c) return;
c->width = to->w; c->width = to->w;
c->height = to->h; c->height = to->h;
@ -122,7 +121,7 @@ static void handle_output_resolution_change(wlc_handle output, const struct wlc_
} }
static void handle_output_focused(wlc_handle output, bool focus) { static void handle_output_focused(wlc_handle output, bool focus) {
swayc_t *c = get_swayc_for_handle(output, &root_container); swayc_t *c = swayc_by_handle(output);
// if for some reason this output doesnt exist, create it. // if for some reason this output doesnt exist, create it.
if (!c) { if (!c) {
handle_output_created(output); handle_output_created(output);
@ -140,7 +139,7 @@ static bool handle_view_created(wlc_handle handle) {
// Get parent container, to add view in // Get parent container, to add view in
if (parent) { if (parent) {
focused = get_swayc_for_handle(parent, &root_container); focused = swayc_by_handle(parent);
} }
if (!focused || focused->type == C_OUTPUT) { if (!focused || focused->type == C_OUTPUT) {
focused = get_focused_container(&root_container); focused = get_focused_container(&root_container);
@ -197,7 +196,7 @@ static bool handle_view_created(wlc_handle handle) {
static void handle_view_destroyed(wlc_handle handle) { static void handle_view_destroyed(wlc_handle handle) {
sway_log(L_DEBUG, "Destroying window %lu", handle); sway_log(L_DEBUG, "Destroying window %lu", handle);
swayc_t *view = get_swayc_for_handle(handle, &root_container); swayc_t *view = swayc_by_handle(handle);
switch (wlc_view_get_type(handle)) { switch (wlc_view_get_type(handle)) {
// regular view created regularly // regular view created regularly
@ -231,7 +230,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
// If the view is floating, then apply the geometry. // If the view is floating, then apply the geometry.
// Otherwise save the desired width/height for the view. // Otherwise save the desired width/height for the view.
// This will not do anything for the time being as WLC improperly sends geometry requests // This will not do anything for the time being as WLC improperly sends geometry requests
swayc_t *view = get_swayc_for_handle(handle, &root_container); swayc_t *view = swayc_by_handle(handle);
if (view) { if (view) {
view->desired_width = geometry->size.w; view->desired_width = geometry->size.w;
view->desired_height = geometry->size.h; view->desired_height = geometry->size.h;
@ -247,7 +246,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
} }
static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) {
swayc_t *c = get_swayc_for_handle(view, &root_container); swayc_t *c = swayc_by_handle(view);
switch (state) { switch (state) {
case WLC_BIT_FULLSCREEN: case WLC_BIT_FULLSCREEN:
// i3 just lets it become fullscreen // i3 just lets it become fullscreen
@ -340,198 +339,17 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
mouse_origin = *origin; mouse_origin = *origin;
bool changed_floating = false; bool changed_floating = false;
bool changed_tiling = false; bool changed_tiling = false;
int min_sane_w = 100; if (!swayc_active_workspace()) {
int min_sane_h = 60;
if (!active_workspace) {
return false; return false;
} }
// Do checks to determine if proper keys are being held // Do checks to determine if proper keys are being held
swayc_t *view = container_under_pointer(); swayc_t *view = container_under_pointer();
uint32_t edge = 0;
if (pointer_state.floating.drag && view) { if (pointer_state.floating.drag && view) {
if (view->is_floating) { if (view->is_floating) {
int dx = mouse_origin.x - prev_pos.x; int dx = mouse_origin.x - prev_pos.x;
int dy = mouse_origin.y - prev_pos.y; int dy = mouse_origin.y - prev_pos.y;
view->x += dx; view->x += dx;
view->y += dy; view->y += dy;
changed_floating = true;
}
} else if (pointer_state.floating.resize && view) {
if (view->is_floating) {
int dx = mouse_origin.x - prev_pos.x;
int dy = mouse_origin.y - prev_pos.y;
// Move and resize the view based on the dx/dy and mouse position
int midway_x = view->x + view->width/2;
int midway_y = view->y + view->height/2;
if (dx < 0) {
if (!pointer_state.lock.right) {
if (view->width > min_sane_w) {
changed_floating = true;
view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT;
}
} else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
changed_floating = true;
view->x += dx;
view->width -= dx;
edge += WLC_RESIZE_EDGE_LEFT;
}
} else if (dx > 0) {
if (mouse_origin.x > midway_x && !pointer_state.lock.right) {
changed_floating = true;
view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT;
} else if (!pointer_state.lock.left) {
if (view->width > min_sane_w) {
changed_floating = true;
view->x += dx;
view->width -= dx;
edge += WLC_RESIZE_EDGE_LEFT;
}
}
}
if (dy < 0) {
if (!pointer_state.lock.bottom) {
if (view->height > min_sane_h) {
changed_floating = true;
view->height += dy;
edge += WLC_RESIZE_EDGE_BOTTOM;
}
} else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
changed_floating = true;
view->y += dy;
view->height -= dy;
edge += WLC_RESIZE_EDGE_TOP;
}
} else if (dy > 0) {
if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) {
changed_floating = true;
view->height += dy;
edge += WLC_RESIZE_EDGE_BOTTOM;
} else if (!pointer_state.lock.top) {
if (view->height > min_sane_h) {
changed_floating = true;
view->y += dy;
view->height -= dy;
edge += WLC_RESIZE_EDGE_TOP;
}
}
}
}
} else if (pointer_state.tiling.resize && view) {
if (view != pointer_state.tiling.init_view) {
// Quit out of the resize
//pointer_state.tiling.init_view = NULL;
}
if (!view->is_floating && view == pointer_state.tiling.init_view) {
// Handle layout resizes -- Find the biggest parent container then apply resizes to that
// and its bordering siblings
swayc_t *parent = view;
double dx = mouse_origin.x - prev_pos.x;
double dy = mouse_origin.y - prev_pos.y;
if (!pointer_state.lock.bottom) {
while (parent->type != C_WORKSPACE) {
// TODO: Absolute value is a bad hack here to compensate for rounding. Find a better
// way of doing this.
if (fabs(parent->parent->y + parent->parent->height - (view->y + view->height)) <= 1) {
parent = parent->parent;
} else {
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) {
sway_log(L_DEBUG, "Top is locked, found biggest valid parent at: %p", parent);
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_DOWN);
if (sibling) {
sway_log(L_DEBUG, "Found sibling at: %p", sibling);
if ((parent->height > min_sane_h || dy > 0) && (sibling->height > min_sane_h || dy < 0)) {
recursive_resize(parent, dy, WLC_RESIZE_EDGE_BOTTOM);
recursive_resize(sibling, -1 * dy, WLC_RESIZE_EDGE_TOP);
changed_tiling = true;
}
}
}
} else if (!pointer_state.lock.top) {
while (parent->type != C_WORKSPACE) {
if (fabs(parent->parent->y - view->y) <= 1) {
parent = parent->parent;
} else {
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) {
sway_log(L_DEBUG, "Bot is locked, found biggest valid parent at: %p", parent);
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_UP);
if (sibling) {
sway_log(L_DEBUG, "Found sibling at: %p", sibling);
if ((parent->height > min_sane_h || dy < 0) && (sibling->height > min_sane_h || dy > 0)) {
recursive_resize(parent, -1 * dy, WLC_RESIZE_EDGE_TOP);
recursive_resize(sibling, dy, WLC_RESIZE_EDGE_BOTTOM);
changed_tiling = true;
}
}
}
}
parent = view;
if (!pointer_state.lock.right) {
while (parent->type != C_WORKSPACE) {
if (fabs(parent->parent->x + parent->parent->width - (view->x + view->width)) <= 1) {
parent = parent->parent;
} else {
sway_log(L_DEBUG, "view: %f vs parent: %f", view->x + view->width, parent->parent->x + parent->parent->width);
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) {
sway_log(L_DEBUG, "Left is locked, found biggest valid parent at: %p", parent);
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_RIGHT);
if (sibling) {
sway_log(L_DEBUG, "Found sibling at: %p", sibling);
if ((parent->width > min_sane_w || dx > 0) && (sibling->width > min_sane_w || dx < 0)) {
recursive_resize(parent, dx, WLC_RESIZE_EDGE_RIGHT);
recursive_resize(sibling, -1 * dx, WLC_RESIZE_EDGE_LEFT);
changed_tiling = true;
}
}
}
} else if (!pointer_state.lock.left) {
while (parent->type != C_WORKSPACE) {
if (fabs(parent->parent->x - view->x) <= 1 && parent->parent) {
parent = parent->parent;
} else {
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) {
sway_log(L_DEBUG, "Right is locked, found biggest valid parent at: %p", parent);
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_LEFT);
if (sibling) {
sway_log(L_DEBUG, "Found sibling at: %p", sibling);
if ((parent->width > min_sane_w || dx < 0) && (sibling->width > min_sane_w || dx > 0)) {
recursive_resize(parent, -1 * dx, WLC_RESIZE_EDGE_LEFT);
recursive_resize(sibling, dx, WLC_RESIZE_EDGE_RIGHT);
changed_tiling = true;
}
}
}
}
arrange_windows(active_workspace, -1, -1);
}
}
if (config->focus_follows_mouse && prev_handle != handle) {
// Dont change focus if fullscreen
swayc_t *focused = get_focused_view(view);
if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)
&& !(pointer_state.l_held || pointer_state.r_held)) {
set_focused_container(container_under_pointer());
}
}
prev_handle = handle;
prev_pos = mouse_origin;
if (changed_floating) {
struct wlc_geometry geometry = { struct wlc_geometry geometry = {
.origin = { .origin = {
.x = view->x, .x = view->x,
@ -542,10 +360,56 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
.h = view->height .h = view->height
} }
}; };
wlc_view_set_geometry(view->handle, edge, &geometry); wlc_view_set_geometry(view->handle, 0, &geometry);
return true; changed_floating = true;
} else {
swayc_t *init_view = pointer_state.tiling.init_view;
if (view != init_view && view->type == C_VIEW) {
changed_tiling = true;
int i, j;
for (i = 0; i < view->parent->children->length; i++) {
if (view->parent->children->items[i] == view) {
for (j = 0; j < init_view->parent->children->length; j++) {
if (init_view->parent->children->items[j] == init_view) {
double temp_w = view->width;
double temp_h = view->height;
view->width = init_view->width;
view->height = init_view->height;
init_view->width = temp_w;
init_view->height = temp_h;
init_view->parent->children->items[j] = view;
view->parent->children->items[i] = init_view;
swayc_t *temp = view->parent;
view->parent = init_view->parent;
init_view->parent = temp;
arrange_windows(&root_container, -1, -1);
break;
} }
if (changed_tiling) { }
break;
}
}
}
}
} else if (pointer_state.floating.resize && view) {
changed_floating = resize_floating(prev_pos);
} else if (pointer_state.tiling.resize && view) {
changed_tiling = mouse_resize_tiled(prev_pos);
}
if (config->focus_follows_mouse && prev_handle != handle) {
// Dont change focus if fullscreen
swayc_t *focused = get_focused_view(view);
if (!swayc_is_fullscreen(focused)
&& !(pointer_state.l_held || pointer_state.r_held)) {
set_focused_container(container_under_pointer());
}
}
prev_handle = handle;
prev_pos = mouse_origin;
if (changed_tiling || changed_floating) {
return true; return true;
} }
return false; return false;
@ -556,7 +420,7 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) { uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) {
swayc_t *focused = get_focused_container(&root_container); swayc_t *focused = get_focused_container(&root_container);
// dont change focus if fullscreen // dont change focus if fullscreen
if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { if (swayc_is_fullscreen(focused)) {
return false; return false;
} }
if (state == WLC_BUTTON_STATE_PRESSED) { if (state == WLC_BUTTON_STATE_PRESSED) {
@ -596,8 +460,13 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
// Dont want pointer sent to window while dragging or resizing // Dont want pointer sent to window while dragging or resizing
return (pointer_state.floating.drag || pointer_state.floating.resize); return (pointer_state.floating.drag || pointer_state.floating.resize);
} else { } else {
if (modifiers->mods & config->floating_mod) {
pointer_state.floating.drag = pointer_state.l_held;
pointer_state.tiling.resize = pointer_state.r_held; pointer_state.tiling.resize = pointer_state.r_held;
pointer_state.tiling.init_view = pointer; pointer_state.tiling.init_view = pointer;
// Dont want pointer sent when resizing
return (pointer_state.tiling.resize);
}
} }
return (pointer && pointer != focused); return (pointer && pointer != focused);
} else { } else {
@ -605,13 +474,14 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
if (button == M_LEFT_CLICK) { if (button == M_LEFT_CLICK) {
pointer_state.l_held = false; pointer_state.l_held = false;
pointer_state.floating.drag = false; pointer_state.floating.drag = false;
pointer_state.tiling.init_view = NULL;
} }
if (button == M_RIGHT_CLICK) { if (button == M_RIGHT_CLICK) {
pointer_state.r_held = false; pointer_state.r_held = false;
pointer_state.floating.resize = false; pointer_state.floating.resize = false;
pointer_state.tiling.resize = false; pointer_state.tiling.resize = false;
pointer_state.tiling.init_view = NULL; pointer_state.tiling.init_view = NULL;
pointer_state.lock = (struct pointer_lock){false ,false ,false ,false}; pointer_state.lock = (struct pointer_lock){false ,false ,false ,false, false, false, false, false};
} }
} }
return false; return false;

View file

@ -48,7 +48,7 @@ void release_key(keycode key) {
} }
} }
struct pointer_state pointer_state = {0, 0, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}}; struct pointer_state pointer_state;
static struct wlc_geometry saved_floating; static struct wlc_geometry saved_floating;
@ -70,5 +70,5 @@ void reset_floating(swayc_t *view) {
arrange_windows(view->parent, -1, -1); arrange_windows(view->parent, -1, -1);
} }
pointer_state.floating = (struct pointer_floating){0, 0}; pointer_state.floating = (struct pointer_floating){0, 0};
pointer_state.lock = (struct pointer_lock){0,0,0,0}; pointer_state.lock = (struct pointer_lock){0, 0, 0, 0, 0, 0, 0, 0};
} }

View file

@ -10,6 +10,8 @@
#include "focus.h" #include "focus.h"
swayc_t root_container; swayc_t root_container;
int min_sane_h = 60;
int min_sane_w = 100;
void init_layout(void) { void init_layout(void) {
root_container.type = C_ROOT; root_container.type = C_ROOT;
@ -35,7 +37,7 @@ void add_child(swayc_t *parent, swayc_t *child) {
child->parent = parent; child->parent = parent;
// set focus for this container // set focus for this container
if (parent->children->length == 1) { if (parent->children->length == 1) {
set_focused_container_for(parent, child); parent->focused = child;
} }
} }
@ -46,7 +48,7 @@ void add_floating(swayc_t *ws, swayc_t *child) {
child->parent = ws; child->parent = ws;
child->is_floating = true; child->is_floating = true;
if (!ws->focused) { if (!ws->focused) {
set_focused_container_for(ws, child); ws->focused = child;
} }
} }
@ -71,7 +73,7 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) {
new_child->parent = child->parent; new_child->parent = child->parent;
if (child->parent->focused == child) { if (child->parent->focused == child) {
set_focused_container_for(child->parent, new_child); child->parent->focused = new_child;
} }
child->parent = NULL; child->parent = NULL;
return parent; return parent;
@ -100,7 +102,7 @@ swayc_t *remove_child(swayc_t *child) {
// Set focused to new container // Set focused to new container
if (parent->focused == child) { if (parent->focused == child) {
if (parent->children->length > 0) { if (parent->children->length > 0) {
set_focused_container_for(parent, parent->children->items[i?i-1:0]); parent->focused = parent->children->items[i?i-1:0];
} else { } else {
parent->focused = NULL; parent->focused = NULL;
} }
@ -167,21 +169,14 @@ void arrange_windows(swayc_t *container, double width, double height) {
for (i = 0; i < container->children->length; ++i) { for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i]; swayc_t *child = container->children->items[i];
sway_log(L_DEBUG, "Arranging output at %d", x); sway_log(L_DEBUG, "Arranging output at %d", x);
child->x = x;
child->y = y;
arrange_windows(child, -1, -1); arrange_windows(child, -1, -1);
// Removed for now because wlc works with relative positions x += child->width;
// Addition can be reconsidered once wlc positions are changed
// x += child->width;
} }
return; return;
case C_OUTPUT: case C_OUTPUT:
container->width = width; container->width = width;
container->height = height; container->height = height;
// These lines make x/y negative and result in stuff glitching out x = 0, y = 0;
// Their addition can be reconsidered once wlc positions are changed
// x -= container->x;
// y -= container->y;
for (i = 0; i < container->children->length; ++i) { for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i]; swayc_t *child = container->children->items[i];
child->x = x + container->gaps; child->x = x + container->gaps;
@ -204,7 +199,7 @@ void arrange_windows(swayc_t *container, double width, double height) {
.h = height - container->gaps .h = height - container->gaps
} }
}; };
if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { if (swayc_is_fullscreen(container)) {
swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT); swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
geometry.origin.x = 0; geometry.origin.x = 0;
geometry.origin.y = 0; geometry.origin.y = 0;
@ -303,7 +298,7 @@ void arrange_windows(swayc_t *container, double width, double height) {
.h = view->height .h = view->height
} }
}; };
if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { if (swayc_is_fullscreen(view)) {
swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT); swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
geometry.origin.x = 0; geometry.origin.x = 0;
geometry.origin.y = 0; geometry.origin.y = 0;
@ -318,7 +313,7 @@ void arrange_windows(swayc_t *container, double width, double height) {
// have higher indexes // have higher indexes
// This is conditional on there not being a fullscreen view in the workspace // This is conditional on there not being a fullscreen view in the workspace
if (!container->focused if (!container->focused
|| !(wlc_view_get_state(container->focused->handle) & WLC_BIT_FULLSCREEN)) { || !swayc_is_fullscreen(container->focused)) {
wlc_view_bring_to_front(view->handle); wlc_view_bring_to_front(view->handle);
} }
} }
@ -328,35 +323,6 @@ void arrange_windows(swayc_t *container, double width, double height) {
layout_log(&root_container, 0); layout_log(&root_container, 0);
} }
swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) {
if (parent->children == NULL) {
return NULL;
}
// Search for floating workspaces
int i;
if (parent->type == C_WORKSPACE) {
for (i = 0; i < parent->floating->length; ++i) {
swayc_t *child = parent->floating->items[i];
if (child->handle == handle) {
return child;
}
}
}
for (i = 0; i < parent->children->length; ++i) {
swayc_t *child = parent->children->items[i];
if (child->handle == handle) {
return child;
} else {
swayc_t *res;
if ((res = get_swayc_for_handle(handle, child))) {
return res;
}
}
}
return NULL;
}
swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) { swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) {
swayc_t *parent = container->parent; swayc_t *parent = container->parent;
@ -372,8 +338,63 @@ swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir)
// Test if we can even make a difference here // Test if we can even make a difference here
bool can_move = false; bool can_move = false;
int diff = 0; int diff = 0;
int i;
if (parent->type == C_ROOT) {
// Find the next output
int target = -1, max_x = 0, max_y = 0, self = -1;
sway_log(L_DEBUG, "Moving between outputs");
for (i = 0; i < parent->children->length; ++i) {
swayc_t *next = parent->children->items[i];
if (next == container) {
self = i;
sway_log(L_DEBUG, "self is %p %d", next, self);
continue;
}
if (next->type == C_OUTPUT) {
sway_log(L_DEBUG, "Testing with %p %d (dir %d)", next, i, dir);
// Check if it's more extreme
if (dir == MOVE_RIGHT) {
if (container->x + container->width <= next->x) {
if (target == -1 || next->x < max_x) {
target = i;
max_x = next->x;
}
}
} else if (dir == MOVE_LEFT) {
if (container->x >= next->x + next->width) {
if (target == -1 || max_x < next->x) {
target = i;
max_x = next->x;
}
}
} else if (dir == MOVE_DOWN) {
if (container->y + container->height <= next->y) {
if (target == -1 || next->y < max_y) {
target = i;
max_y = next->y;
}
}
} else if (dir == MOVE_UP) {
if (container->y >= next->y + next->height) {
if (target == -1 || max_y < next->y) {
target = i;
max_y = next->y;
}
}
}
}
}
if (target == -1) {
can_move = false;
} else {
can_move = true;
diff = target - self;
}
} else {
if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
if (parent->layout == L_HORIZ || parent->type == C_ROOT) { if (parent->layout == L_HORIZ) {
can_move = true; can_move = true;
diff = dir == MOVE_LEFT ? -1 : 1; diff = dir == MOVE_LEFT ? -1 : 1;
} }
@ -383,8 +404,9 @@ swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir)
diff = dir == MOVE_UP ? -1 : 1; diff = dir == MOVE_UP ? -1 : 1;
} }
} }
}
if (can_move) { if (can_move) {
int i;
for (i = 0; i < parent->children->length; ++i) { for (i = 0; i < parent->children->length; ++i) {
swayc_t *child = parent->children->items[i]; swayc_t *child = parent->children->items[i];
if (child == container) { if (child == container) {

View file

@ -119,8 +119,9 @@ bool sway_assert(bool condition, const char* format, ...) {
/* XXX:DEBUG:XXX */ /* XXX:DEBUG:XXX */
static void container_log(const swayc_t *c) { static void container_log(const swayc_t *c) {
fprintf(stderr, "focus:%c|", fprintf(stderr, "focus:%c|",
c->is_focused ? 'F' : // Focused c == get_focused_view(&root_container) ? 'K':
c == active_workspace ? 'W' : // active workspace c == get_focused_container(&root_container) ? 'F' : // Focused
c == swayc_active_workspace() ? 'W' : // active workspace
c == &root_container ? 'R' : // root c == &root_container ? 'R' : // root
'X');// not any others 'X');// not any others
fprintf(stderr,"(%p)",c); fprintf(stderr,"(%p)",c);

View file

@ -38,12 +38,6 @@ int main(int argc, char **argv) {
setenv("WLC_DIM", "0", 0); setenv("WLC_DIM", "0", 0);
FILE *devnull = fopen("/dev/null", "w");
if (devnull) {
// NOTE: Does not work, see wlc issue #54
wlc_set_log_file(devnull);
}
/* Changing code earlier than this point requires detailed review */ /* Changing code earlier than this point requires detailed review */
if (!wlc_init(&interface, argc, argv)) { if (!wlc_init(&interface, argc, argv)) {
return 1; return 1;
@ -85,9 +79,6 @@ int main(int argc, char **argv) {
if (debug) { if (debug) {
init_log(L_DEBUG); init_log(L_DEBUG);
wlc_set_log_file(stderr);
fclose(devnull);
devnull = NULL;
} else if (verbose || validate) { } else if (verbose || validate) {
init_log(L_INFO); init_log(L_INFO);
} else { } else {
@ -114,10 +105,6 @@ int main(int argc, char **argv) {
wlc_run(); wlc_run();
} }
if (devnull) {
fclose(devnull);
}
ipc_terminate(); ipc_terminate();
return 0; return 0;

491
sway/resize.c Normal file
View file

@ -0,0 +1,491 @@
#include <wlc/wlc.h>
#include <math.h>
#include "layout.h"
#include "focus.h"
#include "log.h"
#include "input_state.h"
#include "handlers.h"
bool mouse_resize_tiled(struct wlc_origin prev_pos) {
swayc_t *view = container_under_pointer();
bool valid = true;
bool changed_tiling = false;
double dx = mouse_origin.x - prev_pos.x;
double dy = mouse_origin.y - prev_pos.y;
if (view != pointer_state.tiling.init_view) {
changed_tiling = true;
valid = false;
if (view->type != C_WORKSPACE) {
if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_LEFT) == view) {
pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + 20;
pointer_state.lock.temp_left = true;
} else if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_RIGHT) == view) {
pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + pointer_state.tiling.init_view->width - 20;
pointer_state.lock.temp_right = true;
} else if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_UP) == view) {
pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
pointer_state.lock.temp_up = true;
} else if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_DOWN) == view) {
pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
pointer_state.lock.temp_down = true;
}
}
}
if ((dx < 0 || mouse_origin.x < pointer_state.tiling.lock_pos.x) && pointer_state.lock.temp_left) {
changed_tiling = true;
valid = false;
} else if (dx > 0 && pointer_state.lock.temp_left) {
pointer_state.lock.temp_left = false;
pointer_state.tiling.lock_pos.x = 0;
}
if ((dx > 0 || mouse_origin.x > pointer_state.tiling.lock_pos.x) && pointer_state.lock.temp_right) {
changed_tiling = true;
valid = false;
} else if (dx < 0 && pointer_state.lock.temp_right) {
pointer_state.lock.temp_right = false;
pointer_state.tiling.lock_pos.x = 0;
}
if ((dy < 0 || mouse_origin.y < pointer_state.tiling.lock_pos.y) && pointer_state.lock.temp_up) {
changed_tiling = true;
valid = false;
} else if (dy > 0 && pointer_state.lock.temp_up) {
pointer_state.lock.temp_up = false;
pointer_state.tiling.lock_pos.y = 0;
}
if ((dy > 0 || mouse_origin.y > pointer_state.tiling.lock_pos.y) && pointer_state.lock.temp_down) {
changed_tiling = true;
valid = false;
} else if (dy < 0 && pointer_state.lock.temp_down) {
pointer_state.lock.temp_down = false;
pointer_state.tiling.lock_pos.y = 0;
}
if (!view->is_floating && valid) {
// Handle layout resizes -- Find the biggest parent container then apply resizes to that
// and its bordering siblings
swayc_t *parent = view;
if (!pointer_state.lock.bottom) {
while (parent->type != C_WORKSPACE) {
// TODO: Absolute value is a bad hack here to compensate for rounding. Find a better
// way of doing this.
if (fabs(parent->parent->y + parent->parent->height - (view->y + view->height)) <= 1) {
parent = parent->parent;
} else {
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) {
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_DOWN);
if (sibling) {
if ((parent->height > min_sane_h || dy > 0) && (sibling->height > min_sane_h || dy < 0)) {
recursive_resize(parent, dy, WLC_RESIZE_EDGE_BOTTOM);
recursive_resize(sibling, -1 * dy, WLC_RESIZE_EDGE_TOP);
changed_tiling = true;
} else {
if (parent->height < min_sane_h) {
//pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
pointer_state.lock.temp_up = true;
} else if (sibling->height < min_sane_h) {
pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
pointer_state.lock.temp_down = true;
}
}
}
}
} else if (!pointer_state.lock.top) {
while (parent->type != C_WORKSPACE) {
if (fabs(parent->parent->y - view->y) <= 1) {
parent = parent->parent;
} else {
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) {
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_UP);
if (sibling) {
if ((parent->height > min_sane_h || dy < 0) && (sibling->height > min_sane_h || dy > 0)) {
recursive_resize(parent, -1 * dy, WLC_RESIZE_EDGE_TOP);
recursive_resize(sibling, dy, WLC_RESIZE_EDGE_BOTTOM);
changed_tiling = true;
} else {
if (parent->height < min_sane_h) {
//pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
pointer_state.lock.temp_down = true;
} else if (sibling->height < min_sane_h) {
pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
pointer_state.lock.temp_up = true;
}
}
}
}
}
parent = view;
if (!pointer_state.lock.right) {
while (parent->type != C_WORKSPACE) {
if (fabs(parent->parent->x + parent->parent->width - (view->x + view->width)) <= 1) {
parent = parent->parent;
} else {
sway_log(L_DEBUG, "view: %f vs parent: %f", view->x + view->width, parent->parent->x + parent->parent->width);
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) {
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_RIGHT);
if (sibling) {
if ((parent->width > min_sane_w || dx > 0) && (sibling->width > min_sane_w || dx < 0)) {
recursive_resize(parent, dx, WLC_RESIZE_EDGE_RIGHT);
recursive_resize(sibling, -1 * dx, WLC_RESIZE_EDGE_LEFT);
changed_tiling = true;
} else {
if (parent->width < min_sane_w) {
pointer_state.lock.temp_left = true;
pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + pointer_state.tiling.init_view->width - 20;
} else if (sibling->width < min_sane_w) {
pointer_state.lock.temp_right = true;
pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + pointer_state.tiling.init_view->width - 20;
}
}
}
}
} else if (!pointer_state.lock.left) {
while (parent->type != C_WORKSPACE) {
if (fabs(parent->parent->x - view->x) <= 1 && parent->parent) {
parent = parent->parent;
} else {
break;
}
}
if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) {
swayc_t *sibling = get_swayc_in_direction(parent, MOVE_LEFT);
if (sibling) {
if ((parent->width > min_sane_w || dx < 0) && (sibling->width > min_sane_w || dx > 0)) {
recursive_resize(parent, -1 * dx, WLC_RESIZE_EDGE_LEFT);
recursive_resize(sibling, dx, WLC_RESIZE_EDGE_RIGHT);
changed_tiling = true;
} else {
if (parent->width < min_sane_w) {
pointer_state.lock.temp_right = true;
pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + 20;
} else if (sibling->width < min_sane_w) {
pointer_state.lock.temp_left = true;
pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + 20;
}
}
}
}
}
arrange_windows(swayc_active_workspace(), -1, -1);
}
return changed_tiling;
}
bool resize_floating(struct wlc_origin prev_pos) {
bool changed = false;
swayc_t *view = container_under_pointer();
uint32_t edge = 0;
int dx = mouse_origin.x - prev_pos.x;
int dy = mouse_origin.y - prev_pos.y;
// Move and resize the view based on the dx/dy and mouse position
int midway_x = view->x + view->width/2;
int midway_y = view->y + view->height/2;
if (dx < 0) {
if (!pointer_state.lock.right) {
if (view->width > min_sane_w) {
changed = true;
view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT;
}
} else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
changed = true;
view->x += dx;
view->width -= dx;
edge += WLC_RESIZE_EDGE_LEFT;
}
} else if (dx > 0) {
if (mouse_origin.x > midway_x && !pointer_state.lock.right) {
changed = true;
view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT;
} else if (!pointer_state.lock.left) {
if (view->width > min_sane_w) {
changed = true;
view->x += dx;
view->width -= dx;
edge += WLC_RESIZE_EDGE_LEFT;
}
}
}
if (dy < 0) {
if (!pointer_state.lock.bottom) {
if (view->height > min_sane_h) {
changed = true;
view->height += dy;
edge += WLC_RESIZE_EDGE_BOTTOM;
}
} else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
changed = true;
view->y += dy;
view->height -= dy;
edge += WLC_RESIZE_EDGE_TOP;
}
} else if (dy > 0) {
if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) {
changed = true;
view->height += dy;
edge += WLC_RESIZE_EDGE_BOTTOM;
} else if (!pointer_state.lock.top) {
if (view->height > min_sane_h) {
changed = true;
view->y += dy;
view->height -= dy;
edge += WLC_RESIZE_EDGE_TOP;
}
}
}
if (changed) {
struct wlc_geometry geometry = {
.origin = {
.x = view->x,
.y = view->y
},
.size = {
.w = view->width,
.h = view->height
}
};
wlc_view_set_geometry(view->handle, edge, &geometry);
}
return changed;
}
bool resize_tiled(int amount, bool use_width) {
swayc_t *parent = get_focused_view(swayc_active_workspace());
swayc_t *focused = parent;
swayc_t *sibling;
if (!parent) {
return true;
}
// Find the closest parent container which has siblings of the proper layout.
// Then apply the resize to all of them.
int i;
if (use_width) {
int lnumber = 0;
int rnumber = 0;
while (parent->parent) {
if (parent->parent->layout == L_HORIZ) {
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->x != focused->x) {
if (sibling->x < parent->x) {
lnumber++;
} else if (sibling->x > parent->x) {
rnumber++;
}
}
}
if (rnumber || lnumber) {
break;
}
}
parent = parent->parent;
}
if (parent == &root_container) {
return true;
}
sway_log(L_DEBUG, "Found the proper parent: %p. It has %d l conts, and %d r conts", parent->parent, lnumber, rnumber);
//TODO: Ensure rounding is done in such a way that there are NO pixel leaks
bool valid = true;
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->x != focused->x) {
if (sibling->x < parent->x) {
double pixels = -1 * amount;
pixels /= lnumber;
if (rnumber) {
if ((sibling->width + pixels/2) < min_sane_w) {
valid = false;
break;
}
} else {
if ((sibling->width + pixels) < min_sane_w) {
valid = false;
break;
}
}
} else if (sibling->x > parent->x) {
double pixels = -1 * amount;
pixels /= rnumber;
if (lnumber) {
if ((sibling->width + pixels/2) < min_sane_w) {
valid = false;
break;
}
} else {
if ((sibling->width + pixels) < min_sane_w) {
valid = false;
break;
}
}
}
} else {
double pixels = amount;
if (parent->width + pixels < min_sane_w) {
valid = false;
break;
}
}
}
if (valid) {
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->x != focused->x) {
if (sibling->x < parent->x) {
double pixels = -1 * amount;
pixels /= lnumber;
if (rnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_RIGHT);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_RIGHT);
}
} else if (sibling->x > parent->x) {
double pixels = -1 * amount;
pixels /= rnumber;
if (lnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_LEFT);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_LEFT);
}
}
} else {
if (rnumber != 0 && lnumber != 0) {
double pixels = amount;
pixels /= 2;
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_LEFT);
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_RIGHT);
} else if (rnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_RIGHT);
} else if (lnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_LEFT);
}
}
}
// Recursive resize does not handle positions, let arrange_windows
// take care of that.
arrange_windows(swayc_active_workspace(), -1, -1);
}
return true;
} else {
int tnumber = 0;
int bnumber = 0;
while (parent->parent) {
if (parent->parent->layout == L_VERT) {
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->y != focused->y) {
if (sibling->y < parent->y) {
bnumber++;
} else if (sibling->y > parent->y) {
tnumber++;
}
}
}
if (bnumber || tnumber) {
break;
}
}
parent = parent->parent;
}
if (parent == &root_container) {
return true;
}
sway_log(L_DEBUG, "Found the proper parent: %p. It has %d b conts, and %d t conts", parent->parent, bnumber, tnumber);
//TODO: Ensure rounding is done in such a way that there are NO pixel leaks
bool valid = true;
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->y != focused->y) {
if (sibling->y < parent->y) {
double pixels = -1 * amount;
pixels /= bnumber;
if (tnumber) {
if ((sibling->height + pixels/2) < min_sane_h) {
valid = false;
break;
}
} else {
if ((sibling->height + pixels) < min_sane_h) {
valid = false;
break;
}
}
} else if (sibling->y > parent->y) {
double pixels = -1 * amount;
pixels /= tnumber;
if (bnumber) {
if ((sibling->height + pixels/2) < min_sane_h) {
valid = false;
break;
}
} else {
if ((sibling->height + pixels) < min_sane_h) {
valid = false;
break;
}
}
}
} else {
double pixels = amount;
if (parent->height + pixels < min_sane_h) {
valid = false;
break;
}
}
}
if (valid) {
for (i = 0; i < parent->parent->children->length; i++) {
sibling = parent->parent->children->items[i];
if (sibling->y != focused->y) {
if (sibling->y < parent->y) {
double pixels = -1 * amount;
pixels /= bnumber;
if (tnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_BOTTOM);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_BOTTOM);
}
} else if (sibling->x > parent->x) {
double pixels = -1 * amount;
pixels /= tnumber;
if (bnumber) {
recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_TOP);
} else {
recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_TOP);
}
}
} else {
if (bnumber != 0 && tnumber != 0) {
double pixels = amount/2;
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_TOP);
recursive_resize(parent, pixels, WLC_RESIZE_EDGE_BOTTOM);
} else if (tnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_TOP);
} else if (bnumber) {
recursive_resize(parent, amount, WLC_RESIZE_EDGE_BOTTOM);
}
}
}
arrange_windows(swayc_active_workspace(), -1, -1);
}
return true;
}
return true;
}

View file

@ -1,6 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <wlc/wlc.h> #include <wlc/wlc.h>
#include <string.h>
#include "workspace.h" #include "workspace.h"
#include "layout.h" #include "layout.h"
#include "list.h" #include "list.h"
@ -11,8 +12,6 @@
#include "stringop.h" #include "stringop.h"
#include "focus.h" #include "focus.h"
swayc_t *active_workspace = NULL;
char *workspace_next_name(void) { char *workspace_next_name(void) {
sway_log(L_DEBUG, "Workspace: Generating new name"); sway_log(L_DEBUG, "Workspace: Generating new name");
int i; int i;
@ -48,7 +47,7 @@ char *workspace_next_name(void) {
} }
// Make sure that the workspace doesn't already exist // Make sure that the workspace doesn't already exist
if (workspace_find_by_name(target)) { if (workspace_by_name(target)) {
list_free(args); list_free(args);
continue; continue;
} }
@ -79,22 +78,22 @@ swayc_t *workspace_create(const char* name) {
return new_workspace(parent, name); return new_workspace(parent, name);
} }
bool workspace_by_name(swayc_t *view, void *data) { static bool _workspace_by_name(swayc_t *view, void *data) {
return (view->type == C_WORKSPACE) && return (view->type == C_WORKSPACE) &&
(strcasecmp(view->name, (char *) data) == 0); (strcasecmp(view->name, (char *) data) == 0);
} }
swayc_t *workspace_find_by_name(const char* name) { swayc_t *workspace_by_name(const char* name) {
return find_container(&root_container, workspace_by_name, (void *) name); return swayc_by_test(&root_container, _workspace_by_name, (void *) name);
} }
void workspace_output_next() { void workspace_output_next() {
// Get the index of the workspace in the current output, and change the view to index+1 workspace. // Get the index of the workspace in the current output, and change the view to index+1 workspace.
// if we're currently focused on the last workspace in the output, switch to the first // if we're currently focused on the last workspace in the output, switch to the first
swayc_t *current_output = active_workspace->parent; swayc_t *current_output = swayc_active_workspace()->parent;
int i; int i;
for (i = 0; i < current_output->children->length - 1; i++) { for (i = 0; i < current_output->children->length - 1; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), active_workspace->name) == 0) { if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) {
workspace_switch(current_output->children->items[i + 1]); workspace_switch(current_output->children->items[i + 1]);
return; return;
} }
@ -106,10 +105,10 @@ void workspace_next() {
// Get the index of the workspace in the current output, and change the view to index+1 workspace. // Get the index of the workspace in the current output, and change the view to index+1 workspace.
// if we're currently focused on the last workspace in the output, change focus to there // if we're currently focused on the last workspace in the output, change focus to there
// and call workspace_output_next(), as long as another output actually exists // and call workspace_output_next(), as long as another output actually exists
swayc_t *current_output = active_workspace->parent; swayc_t *current_output = swayc_active_workspace()->parent;
int i; int i;
for (i = 0; i < current_output->children->length - 1; i++) { for (i = 0; i < current_output->children->length - 1; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), active_workspace->name) == 0) { if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) {
workspace_switch(current_output->children->items[i + 1]); workspace_switch(current_output->children->items[i + 1]);
return; return;
} }
@ -134,10 +133,10 @@ void workspace_next() {
void workspace_output_prev() { void workspace_output_prev() {
// Get the index of the workspace in the current output, and change the view to index+1 workspace // Get the index of the workspace in the current output, and change the view to index+1 workspace
// if we're currently focused on the first workspace in the output, do nothing and return false // if we're currently focused on the first workspace in the output, do nothing and return false
swayc_t *current_output = active_workspace->parent; swayc_t *current_output = swayc_active_workspace()->parent;
int i; int i;
for (i = 1; i < current_output->children->length; i++) { for (i = 1; i < current_output->children->length; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), active_workspace->name) == 0) { if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) {
workspace_switch(current_output->children->items[i - 1]); workspace_switch(current_output->children->items[i - 1]);
return; return;
} }
@ -150,10 +149,10 @@ void workspace_prev() {
// if we're currently focused on the last workspace in the output, change focus to there // if we're currently focused on the last workspace in the output, change focus to there
// and call workspace_output_next(), as long as another output actually exists // and call workspace_output_next(), as long as another output actually exists
swayc_t *current_output = active_workspace->parent; swayc_t *current_output = swayc_active_workspace()->parent;
int i; int i;
for (i = 1; i < current_output->children->length; i++) { for (i = 1; i < current_output->children->length; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), active_workspace->name) == 0) { if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) {
workspace_switch(current_output->children->items[i - 1]); workspace_switch(current_output->children->items[i - 1]);
return; return;
} }