aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c186
-rw-r--r--sway/config.c218
-rw-r--r--sway/container.c166
-rw-r--r--sway/focus.c87
-rw-r--r--sway/handlers.c326
-rw-r--r--sway/input_state.c68
-rw-r--r--sway/ipc.c321
-rw-r--r--sway/layout.c186
-rw-r--r--sway/log.c117
-rw-r--r--sway/main.c96
-rw-r--r--sway/readline.c12
-rw-r--r--sway/stringop.c39
-rw-r--r--sway/workspace.c77
13 files changed, 1356 insertions, 543 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 1ca5c17f..e39b781a 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -3,6 +3,7 @@
#include <wlc/wlc.h>
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
@@ -14,6 +15,7 @@
#include "commands.h"
#include "container.h"
#include "handlers.h"
+#include "sway.h"
struct modifier_key {
char *name;
@@ -75,6 +77,18 @@ static bool checkarg(int argc, char *name, enum expected_args type, int val) {
return false;
}
+static int bindsym_sort(const void *_lbind, const void *_rbind) {
+ const struct sway_binding *lbind = *(void **)_lbind;
+ const struct sway_binding *rbind = *(void **)_rbind;
+ unsigned int lmod = 0, rmod = 0, i;
+
+ // Count how any modifiers are pressed
+ for (i = 0; i < 8 * sizeof(lbind->modifiers); ++i) {
+ lmod += lbind->modifiers & 1 << i;
+ rmod += rbind->modifiers & 1 << i;
+ }
+ return (rbind->keys->length + rmod) - (lbind->keys->length + lmod);
+}
static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) {
@@ -104,6 +118,10 @@ static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], XKB_KEYSYM_CASE_INSENSITIVE);
if (!sym) {
sway_log(L_ERROR, "bindsym - unknown key %s", (char *)split->items[i]);
+ list_free(binding->keys);
+ free(binding->command);
+ free(binding);
+ list_free(split);
return false;
}
xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t));
@@ -113,7 +131,10 @@ static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
list_free(split);
// TODO: Check if there are other commands with this key binding
- list_add(config->current_mode->bindings, binding);
+ struct sway_mode *mode = config->current_mode;
+ list_add(mode->bindings, binding);
+ qsort(mode->bindings->items, mode->bindings->length,
+ sizeof(mode->bindings->items[0]), bindsym_sort);
sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command);
return true;
@@ -166,7 +187,7 @@ static bool cmd_exit(struct sway_config *config, int argc, char **argv) {
}
// Close all views
container_map(&root_container, kill_views, NULL);
- exit(0);
+ sway_terminate();
return true;
}
@@ -181,43 +202,28 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
if (view->type != C_VIEW) {
return true;
}
- int i;
// Change from nonfloating to floating
if (!view->is_floating) {
- view->is_floating = true;
- for (i = 0; i < view->parent->children->length; i++) {
- if (view->parent->children->items[i] == view) {
- // Try to use desired geometry to set w/h
- if (view->desired_width != -1) {
- view->width = view->desired_width;
- }
- if (view->desired_height != -1) {
- view->height = view->desired_height;
- }
-
- // Swap from the list of whatever container the view was in
- // to the workspace->floating list
- list_del(view->parent->children, i);
- list_add(active_workspace->floating, view);
- destroy_container(view->parent);
-
- // Set the new position of the container and arrange windows
- view->x = (active_workspace->width - view->width)/2;
- view->y = (active_workspace->height - view->height)/2;
- sway_log(L_INFO, "Setting container %p to floating at coordinates X:%d Y:%d, W:%d, H:%d", view, view->x, view->y, view->width, view->height);
- // Change parent to active_workspace
- view->parent = active_workspace;
- arrange_windows(active_workspace, -1, -1);
- return true;
- }
+ // Remove view from its current location
+ destroy_container(remove_child(view));
+
+ // and move it into workspace floating
+ add_floating(active_workspace,view);
+ view->x = (active_workspace->width - view->width)/2;
+ view->y = (active_workspace->height - view->height)/2;
+ if (view->desired_width != -1) {
+ view->width = view->desired_width;
+ }
+ if (view->desired_height != -1) {
+ view->height = view->desired_height;
}
+ arrange_windows(active_workspace, -1, -1);
} else {
// 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
// focused floating output
- list_del(active_workspace->floating, active_workspace->floating->length - 1);
+ remove_child(view);
view->is_floating = false;
- active_workspace->focused = NULL;
// Get the properly focused container, and add in the view there
swayc_t *focused = container_under_pointer();
// If focused is null, it's because the currently focused container is a workspace
@@ -228,21 +234,20 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
sway_log(L_DEBUG, "Non-floating focused container is %p", focused);
- //Case of focused workspace, just create as child of it
+ // Case of focused workspace, just create as child of it
if (focused->type == C_WORKSPACE) {
add_child(focused, view);
}
- //Regular case, create as sibling of current container
+ // Regular case, create as sibling of current container
else {
add_sibling(focused, view);
}
// Refocus on the view once its been put back into the layout
- set_focused_container(view);
+ view->width = view->height = 0;
arrange_windows(active_workspace, -1, -1);
- return true;
}
+ set_focused_container(view);
}
-
return true;
}
@@ -250,11 +255,29 @@ static bool cmd_floating_mod(struct sway_config *config, int argc, char **argv)
if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
return false;
}
- config->floating_mod = xkb_keysym_from_name(argv[0], XKB_KEYSYM_CASE_INSENSITIVE);
+ int i, j;
+ list_t *split = split_string(argv[0], "+");
+ config->floating_mod = 0;
+
+ // set modifer keys
+ for (i = 0; i < split->length; ++i) {
+ for (j = 0; j < sizeof(modifiers) / sizeof(struct modifier_key); ++j) {
+ if (strcasecmp(modifiers[j].name, split->items[i]) == 0) {
+ config->floating_mod |= modifiers[j].mod;
+ }
+ }
+ }
+ list_free(split);
+ if (!config->floating_mod) {
+ sway_log(L_ERROR, "bindsym - unknown keys %s", argv[0]);
+ return false;
+ }
return true;
}
static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
+ static int floating_toggled_index = 0;
+ static int tiled_toggled_index = 0;
if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
return false;
}
@@ -268,7 +291,44 @@ static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
return move_focus(MOVE_DOWN);
} else if (strcasecmp(argv[0], "parent") == 0) {
return move_focus(MOVE_PARENT);
+ } else if (strcasecmp(argv[0], "mode_toggle") == 0) {
+ int i;
+ swayc_t *focused = get_focused_view(active_workspace);
+ if (focused->is_floating) {
+ if (active_workspace->children->length > 0) {
+ for (i = 0;i < active_workspace->floating->length; i++) {
+ if (active_workspace->floating->items[i] == focused) {
+ floating_toggled_index = i;
+ break;
+ }
+ }
+ if (active_workspace->children->length > tiled_toggled_index) {
+ set_focused_container(get_focused_view(active_workspace->children->items[tiled_toggled_index]));
+ } else {
+ set_focused_container(get_focused_view(active_workspace->children->items[0]));
+ tiled_toggled_index = 0;
+ }
+ }
+ } else {
+ if (active_workspace->floating->length > 0) {
+ for (i = 0;i < active_workspace->children->length; i++) {
+ if (active_workspace->children->items[i] == focused) {
+ tiled_toggled_index = i;
+ break;
+ }
+ }
+ if (active_workspace->floating->length > floating_toggled_index) {
+ swayc_t *floating = active_workspace->floating->items[floating_toggled_index];
+ set_focused_container(get_focused_view(floating));
+ } else {
+ swayc_t *floating = active_workspace->floating->items[active_workspace->floating->length - 1];
+ set_focused_container(get_focused_view(floating));
+ tiled_toggled_index = active_workspace->floating->length - 1;
+ }
+ }
+ }
}
+
return true;
}
@@ -303,6 +363,42 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) {
return true;
+static bool cmd_gaps(struct sway_config *config, int argc, char **argv) {
+ if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
+ return false;
+ }
+
+ if (argc == 1) {
+ char *end;
+ int amount = (int)strtol(argv[0], &end, 10);
+ if (errno == ERANGE || amount == 0) {
+ errno = 0;
+ return false;
+ }
+ if (config->gaps_inner == 0) {
+ config->gaps_inner = amount;
+ }
+ if (config->gaps_outer == 0) {
+ config->gaps_outer = amount;
+ }
+ } else if (argc == 2) {
+ char *end;
+ int amount = (int)strtol(argv[1], &end, 10);
+ if (errno == ERANGE || amount == 0) {
+ errno = 0;
+ return false;
+ }
+ if (strcasecmp(argv[0], "inner") == 0) {
+ config->gaps_inner = amount;
+ } else if (strcasecmp(argv[0], "outer") == 0) {
+ config->gaps_outer = amount;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ return true;
}
static bool cmd_kill(struct sway_config *config, int argc, char **argv) {
@@ -316,7 +412,6 @@ static bool cmd_layout(struct sway_config *config, int argc, char **argv) {
return false;
}
swayc_t *parent = get_focused_container(&root_container);
-
while (parent->type == C_VIEW) {
parent = parent->parent;
}
@@ -341,7 +436,7 @@ static bool cmd_reload(struct sway_config *config, int argc, char **argv) {
if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) {
return false;
}
- if (!load_config()) {
+ if (!load_config(NULL)) { // TODO: Use config given from -c
return false;
}
arrange_windows(&root_container, -1, -1);
@@ -435,14 +530,12 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
swayc_t *container = get_focused_view(&root_container);
bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0;
wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current);
- //Resize workspace if going from fullscreen -> notfullscreen
- //otherwise just resize container
+ // Resize workspace if going from fullscreen -> notfullscreen
+ // otherwise just resize container
if (current) {
- while (container->type != C_WORKSPACE) {
- container = container->parent;
- }
+ container = swayc_parent_by_type(container, C_WORKSPACE);
}
- //Only resize container when going into fullscreen
+ // Only resize container when going into fullscreen
arrange_windows(container, -1, -1);
return true;
@@ -508,6 +601,7 @@ static struct cmd_handler handlers[] = {
{ "focus", cmd_focus },
{ "focus_follows_mouse", cmd_focus_follows_mouse },
{ "fullscreen", cmd_fullscreen },
+ { "gaps", cmd_gaps },
{ "kill", cmd_kill },
{ "layout", cmd_layout },
{ "log_colors", cmd_log_colors },
@@ -606,7 +700,7 @@ bool handle_command(struct sway_config *config, char *exec) {
char **argv = split_directive(exec + strlen(handler->command), &argc);
int i;
- //Perform var subs on all parts of the command
+ // Perform var subs on all parts of the command
for (i = 0; i < argc; ++i) {
argv[i] = do_var_replacement(config, argv[i]);
}
diff --git a/sway/config.c b/sway/config.c
index f1de6080..9f65e8a2 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -8,6 +8,7 @@
#include "log.h"
#include "commands.h"
#include "config.h"
+#include "layout.h"
struct sway_config *config;
@@ -15,121 +16,143 @@ static bool exists(const char *path) {
return access(path, R_OK) != -1;
}
-static char *get_config_path() {
- char *name = "/.sway/config";
- const char *home = getenv("HOME");
+void config_defaults(struct sway_config *config) {
+ config->symbols = create_list();
+ config->modes = create_list();
+ config->cmd_queue = create_list();
+ config->workspace_outputs = create_list();
+ config->current_mode = malloc(sizeof(struct sway_mode));
+ config->current_mode->name = NULL;
+ config->current_mode->bindings = create_list();
+ list_add(config->modes, config->current_mode);
+ // Flags
+ config->focus_follows_mouse = true;
+ config->mouse_warping = true;
+ config->reloading = false;
+ config->active = false;
+ config->failed = false;
+ config->gaps_inner = 0;
+ config->gaps_outer = 0;
+}
- // Check home dir
- sway_log(L_DEBUG, "Trying to find config in ~/.sway/config");
- char *temp = malloc(strlen(home) + strlen(name) + 1);
- strcpy(temp, home);
- strcat(temp, name);
- if (exists(temp)) {
- return temp;
- }
+void free_mode(struct sway_mode *mode) {
+ free(mode->name);
+ free_flat_list(mode->bindings);
+}
- // Check XDG_CONFIG_HOME with fallback to ~/.config/
- sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_HOME/sway/config");
- char *xdg_config_home = getenv("XDG_CONFIG_HOME");
- if (xdg_config_home == NULL) {
- sway_log(L_DEBUG, "Falling back to ~/.config/sway/config");
- name = "/.config/sway/config";
- temp = malloc(strlen(home) + strlen(name) + 1);
- strcpy(temp, home);
- strcat(temp, name);
- } else {
- name = "/sway/config";
- temp = malloc(strlen(xdg_config_home) + strlen(name) + 1);
- strcpy(xdg_config_home, home);
- strcat(temp, name);
+void free_config(struct sway_config *config) {
+ int i;
+ for (i = 0; i < config->modes->length; ++i) {
+ free_mode((struct sway_mode *)config->modes->items[i]);
}
- if (exists(temp)) {
- return temp;
+ free_flat_list(config->modes);
+ for (i = 0; i < config->workspace_outputs->length; ++i) {
+ struct workspace_output *wso = config->workspace_outputs->items[i];
+ free(wso->output);
+ free(wso->workspace);
}
-
- // Check /etc/
- sway_log(L_DEBUG, "Trying to find config in /etc/sway/config");
- strcpy(temp, "/etc/sway/config");
- if (exists(temp)) {
- return temp;
+ free_flat_list(config->workspace_outputs);
+ free_flat_list(config->cmd_queue);
+ for (i = 0; i < config->symbols->length; ++i) {
+ struct sway_variable *sym = config->symbols->items[i];
+ free(sym->name);
+ free(sym->value);
}
+ free_flat_list(config->symbols);
+}
- // Check XDG_CONFIG_DIRS
- sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
- char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS");
- if (xdg_config_dirs != NULL) {
- list_t *paths = split_string(xdg_config_dirs, ":");
- name = "/sway/config";
- int i;
- for (i = 0; i < paths->length; i++ ) {
- temp = malloc(strlen(paths->items[i]) + strlen(name) + 1);
- strcpy(temp, paths->items[i]);
- strcat(temp, name);
- if (exists(temp)) {
- free_flat_list(paths);
- return temp;
- }
- }
- free_flat_list(paths);
- }
+static const char *search_paths[] = {
+ "$home/.sway/config",
+ "$config/sway/config",
+ "/etc/sway/config",
+ "$home/.i3/config",
+ "$config/.i3/config",
+ "/etc/i3/config"
+};
- //Now fall back to i3 paths and try the same thing
- name = "/.i3/config";
- sway_log(L_DEBUG, "Trying to find config in ~/.i3/config");
- temp = malloc(strlen(home) + strlen(name) + 1);
- strcpy(temp, home);
- strcat(temp, name);
- if (exists(temp)) {
- return temp;
+static char *get_config_path() {
+ char *home = getenv("HOME");
+ if (home) {
+ home = strdup(getenv("HOME"));
}
-
- sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_HOME/i3/config");
- if (xdg_config_home == NULL) {
- sway_log(L_DEBUG, "Falling back to ~/.config/i3/config");
- name = "/.config/i3/config";
- temp = malloc(strlen(home) + strlen(name) + 1);
- strcpy(temp, home);
- strcat(temp, name);
+ char *config = getenv("XDG_CONFIG_HOME");
+ if (config) {
+ config = strdup(getenv("XDG_CONFIG_HOME"));
+ } else if (home) {
+ const char *def = "/.config";
+ config = malloc(strlen(home) + strlen(def) + 1);
+ strcpy(config, home);
+ strcat(config, def);
} else {
- name = "/i3/config";
- temp = malloc(strlen(xdg_config_home) + strlen(name) + 1);
- strcpy(xdg_config_home, home);
- strcat(temp, name);
- }
- if (exists(temp)) {
- return temp;
+ home = strdup("");
+ config = strdup("");
}
- sway_log(L_DEBUG, "Trying to find config in /etc/i3/config");
- strcpy(temp, "/etc/i3/config");
- if (exists(temp)) {
- return temp;
+ // Set up a temporary config for holding set variables
+ struct sway_config *temp_config = malloc(sizeof(struct sway_config));
+ config_defaults(temp_config);
+ const char *set_home = "set $home ";
+ char *_home = malloc(strlen(home) + strlen(set_home) + 1);
+ strcpy(_home, set_home);
+ strcat(_home, home);
+ handle_command(temp_config, _home);
+ free(_home);
+ const char *set_config = "set $config ";
+ char *_config = malloc(strlen(config) + strlen(set_config) + 1);
+ strcpy(_config, set_config);
+ strcat(_config, config);
+ handle_command(temp_config, _config);
+ free(_config);
+
+ char *test = NULL;
+ int i;
+ for (i = 0; i < sizeof(search_paths) / sizeof(char *); ++i) {
+ test = strdup(search_paths[i]);
+ test = do_var_replacement(temp_config, test);
+ sway_log(L_DEBUG, "Checking for config at %s", test);
+ if (exists(test)) {
+ goto _continue;
+ }
+ free(test);
+ test = NULL;
}
sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
+ char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS");
if (xdg_config_dirs != NULL) {
list_t *paths = split_string(xdg_config_dirs, ":");
- name = "/i3/config";
+ char *name = "/sway/config";
int i;
for (i = 0; i < paths->length; i++ ) {
- temp = malloc(strlen(paths->items[i]) + strlen(name) + 1);
- strcpy(temp, paths->items[i]);
- strcat(temp, name);
- if (exists(temp)) {
+ test = malloc(strlen(paths->items[i]) + strlen(name) + 1);
+ strcpy(test, paths->items[i]);
+ strcat(test, name);
+ if (exists(test)) {
free_flat_list(paths);
- return temp;
+ return test;
}
+ free(test);
+ test = NULL;
}
free_flat_list(paths);
}
- return NULL;
+_continue:
+ free_config(temp_config);
+ free(home);
+ free(config);
+ return test;
}
-bool load_config(void) {
+bool load_config(const char *file) {
sway_log(L_INFO, "Loading config");
- char *path = get_config_path();
+ char *path;
+ if (file != NULL) {
+ path = strdup(file);
+ } else {
+ path = get_config_path();
+ }
if (path == NULL) {
sway_log(L_ERROR, "Unable to find a config file!");
@@ -155,23 +178,6 @@ bool load_config(void) {
return config_load_success;
}
-void config_defaults(struct sway_config *config) {
- config->symbols = create_list();
- config->modes = create_list();
- config->cmd_queue = create_list();
- config->workspace_outputs = create_list();
- config->current_mode = malloc(sizeof(struct sway_mode));
- config->current_mode->name = NULL;
- config->current_mode->bindings = create_list();
- list_add(config->modes, config->current_mode);
- // Flags
- config->focus_follows_mouse = true;
- config->mouse_warping = true;
- config->reloading = false;
- config->active = false;
- config->failed = false;
-}
-
bool read_config(FILE *file, bool is_active) {
struct sway_config *temp_config = malloc(sizeof(struct sway_config));
config_defaults(temp_config);
@@ -188,8 +194,8 @@ bool read_config(FILE *file, bool is_active) {
while (!feof(file)) {
int _;
char *line = read_line(file);
- line = strip_comments(line);
line = strip_whitespace(line, &_);
+ line = strip_comments(line);
if (!line[0]) {
goto _continue;
}
@@ -225,6 +231,8 @@ _continue:
if (is_active) {
temp_config->reloading = false;
+ container_map(&root_container, reset_gaps, NULL);
+ arrange_windows(&root_container, -1, -1);
}
config = temp_config;
diff --git a/sway/container.c b/sway/container.c
index 62c5bda0..7ccc2e09 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -8,53 +8,57 @@
#include "layout.h"
#include "log.h"
+#define ASSERT_NONNULL(PTR) \
+ sway_assert (PTR, "%s: " #PTR "must be non-null", __func__)
static swayc_t *new_swayc(enum swayc_types type) {
swayc_t *c = calloc(1, sizeof(swayc_t));
c->handle = -1;
c->layout = L_NONE;
c->type = type;
- c->weight = 1;
if (type != C_VIEW) {
c->children = create_list();
}
return c;
}
-static void free_swayc(swayc_t *c) {
+static void free_swayc(swayc_t *cont) {
+ if (!ASSERT_NONNULL(cont)) {
+ return;
+ }
// TODO does not properly handle containers with children,
// TODO but functions that call this usually check for that
- if (c->children) {
- if (c->children->length) {
+ if (cont->children) {
+ if (cont->children->length) {
int i;
- for (i = 0; i < c->children->length; ++i) {
- free_swayc(c->children->items[i]);
+ for (i = 0; i < cont->children->length; ++i) {
+ free_swayc(cont->children->items[i]);
}
}
- list_free(c->children);
+ list_free(cont->children);
}
- if (c->floating) {
- if (c->floating->length) {
+ if (cont->floating) {
+ if (cont->floating->length) {
int i;
- for (i = 0; i < c->floating->length; ++i) {
- free_swayc(c->floating->items[i]);
+ for (i = 0; i < cont->floating->length; ++i) {
+ free_swayc(cont->floating->items[i]);
}
}
- list_free(c->floating);
+ list_free(cont->floating);
}
- if (c->parent) {
- remove_child(c);
+ if (cont->parent) {
+ remove_child(cont);
}
- if (c->name) {
- free(c->name);
+ if (cont->name) {
+ free(cont->name);
}
- free(c);
+ free(cont);
}
-/* New containers */
+// New containers
static bool workspace_test(swayc_t *view, void *name) {
- return strcasecmp(view->name, (char *)name);
+ return strcasecmp(view->name, (char *)name) == 0;
}
swayc_t *new_output(wlc_handle handle) {
@@ -67,6 +71,7 @@ swayc_t *new_output(wlc_handle handle) {
output->height = size->h;
output->handle = handle;
output->name = name ? strdup(name) : NULL;
+ output->gaps = config->gaps_outer + config->gaps_inner / 2;
add_child(&root_container, output);
@@ -80,8 +85,10 @@ swayc_t *new_output(wlc_handle handle) {
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 (find_container(&root_container, workspace_test, 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;
}
@@ -101,10 +108,15 @@ swayc_t *new_output(wlc_handle handle) {
}
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);
workspace->layout = L_HORIZ; // TODO: default layout
+ workspace->x = output->x;
+ workspace->y = output->y;
workspace->width = output->width;
workspace->height = output->height;
workspace->name = strdup(name);
@@ -116,6 +128,9 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
}
swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
+ if (!ASSERT_NONNULL(child)) {
+ return NULL;
+ }
swayc_t *cont = new_swayc(C_CONTAINER);
sway_log(L_DEBUG, "creating container %p around %p", cont, child);
@@ -147,6 +162,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
// 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) {
@@ -157,6 +173,9 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
}
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",
@@ -166,11 +185,15 @@ swayc_t *new_view(swayc_t *sibling, wlc_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->desired_width = -1;
- view->desired_height = -1;
+ view->gaps = config->gaps_inner;
- // TODO: properly set this
view->is_floating = false;
if (sibling->type == C_WORKSPACE) {
@@ -196,8 +219,9 @@ swayc_t *new_floating_view(wlc_handle handle) {
// Set the geometry of the floating view
const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
- view->x = geometry->origin.x;
- view->y = geometry->origin.y;
+ // give it requested geometry, but place in center
+ view->x = (active_workspace->width - geometry->size.w) / 2;
+ view->y = (active_workspace->height- geometry->size.h) / 2;
view->width = geometry->size.w;
view->height = geometry->size.h;
@@ -215,9 +239,12 @@ swayc_t *new_floating_view(wlc_handle handle) {
return view;
}
-/* Destroy container */
+// Destroy container
swayc_t *destroy_output(swayc_t *output) {
+ if (!ASSERT_NONNULL(output)) {
+ return NULL;
+ }
if (output->children->length == 0) {
// TODO move workspaces to other outputs
}
@@ -227,23 +254,21 @@ swayc_t *destroy_output(swayc_t *output) {
}
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 = workspace->parent;
- while (output && output->type != C_OUTPUT) {
- output = output->parent;
- }
- if (output) {
- if (output->children->length == 1) {
- return NULL;
- }
+ swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
+ if (output && output->children->length == 1) {
+ return NULL;
}
if (workspace->children->length == 0) {
- sway_log(L_DEBUG, "Workspace: Destroying workspace '%s'", workspace->name);
+ sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name);
swayc_t *parent = workspace->parent;
free_swayc(workspace);
return parent;
@@ -252,19 +277,20 @@ swayc_t *destroy_workspace(swayc_t *workspace) {
}
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 (view == NULL) {
- sway_log(L_DEBUG, "Warning: NULL passed into destroy_view");
+ if (!ASSERT_NONNULL(view)) {
return NULL;
}
sway_log(L_DEBUG, "Destroying view '%p'", view);
@@ -278,6 +304,34 @@ swayc_t *destroy_view(swayc_t *view) {
return parent;
}
+// Container lookup
+
+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, "%s: invalid type", __func__)) {
+ 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, "%s: invalid layout", __func__)) {
+ return NULL;
+ }
+ do {
+ container = container->parent;
+ } while (container && container->layout != layout);
+ return container;
+}
+
swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) {
if (!container->children) {
return NULL;
@@ -307,25 +361,27 @@ swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *da
}
void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
- if (!container || !container->children || !container->children->length) {
- return;
- }
- int i;
- for (i = 0; i < container->children->length; ++i) {
- swayc_t *child = container->children->items[i];
- f(child, data);
- container_map(child, f, data);
- }
- if (container->type == C_WORKSPACE) {
- for (i = 0; i < container->floating->length; ++i) {
- swayc_t *child = container->floating->items[i];
+ if (container && container->children && container->children->length) {
+ int i;
+ for (i = 0; i < container->children->length; ++i) {
+ swayc_t *child = container->children->items[i];
f(child, data);
container_map(child, f, data);
}
+ if (container->type == C_WORKSPACE) {
+ for (i = 0; i < container->floating->length; ++i) {
+ swayc_t *child = container->floating->items[i];
+ f(child, data);
+ container_map(child, f, data);
+ }
+ }
}
}
void set_view_visibility(swayc_t *view, void *data) {
+ if (!ASSERT_NONNULL(view)) {
+ return;
+ }
uint32_t *p = data;
if (view->type == C_VIEW) {
wlc_view_set_mask(view->handle, *p);
@@ -337,3 +393,15 @@ void set_view_visibility(swayc_t *view, void *data) {
}
view->visible = (*p == 2);
}
+
+void reset_gaps(swayc_t *view, void *data) {
+ if (!ASSERT_NONNULL(view)) {
+ return;
+ }
+ if (view->type == C_OUTPUT) {
+ view->gaps = config->gaps_outer;
+ }
+ if (view->type == C_VIEW) {
+ view->gaps = config->gaps_inner;
+ }
+}
diff --git a/sway/focus.c b/sway/focus.c
index 628316dd..5008dbbf 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -3,6 +3,7 @@
#include "focus.h"
#include "log.h"
#include "workspace.h"
+#include "layout.h"
bool locked_container_focus = false;
bool locked_view_focus = false;
@@ -20,6 +21,8 @@ static void update_focus(swayc_t *c) {
// Case where output changes
case C_OUTPUT:
wlc_output_focus(c->handle);
+ // Set new workspace to the outputs focused workspace
+ active_workspace = c->focused;
break;
// Case where workspace changes
@@ -51,74 +54,17 @@ static void update_focus(swayc_t *c) {
}
bool move_focus(enum movement_direction direction) {
- if (locked_container_focus) {
- return false;
- }
- swayc_t *current = get_focused_container(&root_container);
- if (current->type == C_VIEW
- && wlc_view_get_state(current->handle) & WLC_BIT_FULLSCREEN) {
- return false;
- }
- swayc_t *parent = current->parent;
-
- if (direction == MOVE_PARENT) {
- if (parent->type == C_OUTPUT) {
- sway_log(L_DEBUG, "Focus cannot move to parent");
- return false;
+ swayc_t *view = get_swayc_in_direction(
+ get_focused_container(&root_container), direction);
+ if (view) {
+ if (direction == MOVE_PARENT) {
+ set_focused_container(view);
} else {
- sway_log(L_DEBUG, "Moving focus from %p:%ld to %p:%ld",
- current, current->handle, parent, parent->handle);
- set_focused_container(parent);
- return true;
- }
- }
-
- while (true) {
- sway_log(L_DEBUG, "Moving focus away from %p", current);
-
- // Test if we can even make a difference here
- bool can_move = false;
- int diff = 0;
- if (direction == MOVE_LEFT || direction == MOVE_RIGHT) {
- if (parent->layout == L_HORIZ || parent->type == C_ROOT) {
- can_move = true;
- diff = direction == MOVE_LEFT ? -1 : 1;
- }
- } else {
- if (parent->layout == L_VERT) {
- can_move = true;
- diff = direction == MOVE_UP ? -1 : 1;
- }
- }
- sway_log(L_DEBUG, "Can move? %s", can_move ? "yes" : "no");
- if (can_move) {
- int i;
- for (i = 0; i < parent->children->length; ++i) {
- swayc_t *child = parent->children->items[i];
- if (child == current) {
- break;
- }
- }
- int desired = i + diff;
- sway_log(L_DEBUG, "Moving from %d to %d", i, desired);
- if (desired < 0 || desired >= parent->children->length) {
- can_move = false;
- } else {
- swayc_t *newview = parent->children->items[desired];
- set_focused_container(get_focused_view(newview));
- return true;
- }
- }
- if (!can_move) {
- sway_log(L_DEBUG, "Can't move at current level, moving up tree");
- current = parent;
- parent = parent->parent;
- if (!parent) {
- // Nothing we can do
- return false;
- }
+ set_focused_container(get_focused_view(view));
}
+ return true;
}
+ return false;
}
swayc_t *get_focused_container(swayc_t *parent) {
@@ -142,13 +88,13 @@ void set_focused_container(swayc_t *c) {
// Find previous focused view, and the new focused view, if they are the same return
swayc_t *focused = get_focused_view(&root_container);
swayc_t *workspace = active_workspace;
- if (focused == get_focused_view(c)) {
- return;
- }
// update container focus from here to root, making necessary changes along
// the way
swayc_t *p = c;
+ if (p->type != C_OUTPUT && p->type != C_ROOT) {
+ p->is_focused = true;
+ }
while (p != &root_container) {
update_focus(p);
p = p->parent;
@@ -171,8 +117,11 @@ void set_focused_container(swayc_t *c) {
}
// activate current focus
if (p->type == C_VIEW) {
- wlc_view_focus(p->handle);
wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true);
+ // set focus if view_focus is unlocked
+ if (!locked_view_focus) {
+ wlc_view_focus(p->handle);
+ }
}
}
}
diff --git a/sway/handlers.c b/sway/handlers.c
index 534b4e4f..79628fe5 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -13,21 +13,14 @@
#include "workspace.h"
#include "container.h"
#include "focus.h"
-
-uint32_t keys_pressed[32];
+#include "input_state.h"
static struct wlc_origin mouse_origin;
-static bool m1_held = false;
-static bool m2_held = false;
-
static bool pointer_test(swayc_t *view, void *_origin) {
const struct wlc_origin *origin = _origin;
// Determine the output that the view is under
- swayc_t *parent = view;
- while (parent->type != C_OUTPUT) {
- parent = parent->parent;
- }
+ swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
if (origin->x >= view->x && origin->y >= view->y
&& origin->x < view->x + view->width && origin->y < view->y + view->height
&& view->visible && parent == root_container.focused) {
@@ -86,10 +79,12 @@ swayc_t *container_under_pointer(void) {
return lookup;
}
+/* Handles */
+
static bool handle_output_created(wlc_handle 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) {
swayc_t *ws = op->children->items[0];
workspace_switch(ws);
@@ -111,7 +106,7 @@ static void handle_output_destroyed(wlc_handle output) {
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);
}
}
@@ -137,38 +132,64 @@ static void handle_output_focused(wlc_handle output, bool focus) {
}
static bool handle_view_created(wlc_handle handle) {
- swayc_t *focused = get_focused_container(&root_container);
+ // if view is child of another view, the use that as focused container
+ wlc_handle parent = wlc_view_get_parent(handle);
+ swayc_t *focused = NULL;
swayc_t *newview = NULL;
+
+ // Get parent container, to add view in
+ if (parent) {
+ focused = get_swayc_for_handle(parent, &root_container);
+ }
+ if (!focused || focused->type == C_OUTPUT) {
+ focused = get_focused_container(&root_container);
+ }
+ sway_log(L_DEBUG, "handle:%ld type:%x state:%x parent:%ld "
+ "mask:%d (x:%d y:%d w:%d h:%d) title:%s "
+ "class:%s appid:%s",
+ handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent,
+ wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x,
+ wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w,
+ wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle),
+ wlc_view_get_class(handle), wlc_view_get_app_id(handle));
+
+ // TODO properly figure out how each window should be handled.
switch (wlc_view_get_type(handle)) {
// regular view created regularly
case 0:
newview = new_view(focused, handle);
wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true);
break;
- // takes keyboard focus
+
+ // Dmenu keeps viewfocus, but others with this flag dont, for now simulate
+ // dmenu
case WLC_BIT_OVERRIDE_REDIRECT:
- sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT", handle);
- locked_view_focus = true;
+// locked_view_focus = true;
wlc_view_focus(handle);
wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true);
wlc_view_bring_to_front(handle);
break;
- // Takes container focus
+
+ // Firefox popups have this flag set.
case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
- sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT|WLC_BIT_MANAGED", handle);
wlc_view_bring_to_front(handle);
locked_container_focus = true;
break;
- // set modals as floating containers
+
+ // Modals, get focus, popups do not
case WLC_BIT_MODAL:
+ wlc_view_focus(handle);
wlc_view_bring_to_front(handle);
newview = new_floating_view(handle);
case WLC_BIT_POPUP:
+ wlc_view_bring_to_front(handle);
break;
}
+
if (newview) {
set_focused_container(newview);
- arrange_windows(newview->parent, -1, -1);
+ swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT);
+ arrange_windows(output, -1, -1);
}
return true;
}
@@ -181,19 +202,19 @@ static void handle_view_destroyed(wlc_handle handle) {
// regular view created regularly
case 0:
case WLC_BIT_MODAL:
+ case WLC_BIT_POPUP:
if (view) {
swayc_t *parent = destroy_view(view);
arrange_windows(parent, -1, -1);
}
break;
- // takes keyboard focus
+ // DMENU has this flag, and takes view_focus, but other things with this
+ // flag dont
case WLC_BIT_OVERRIDE_REDIRECT:
- locked_view_focus = false;
+// locked_view_focus = false;
break;
- // Takes container focus
case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
locked_container_focus = false;
- case WLC_BIT_POPUP:
break;
}
set_focused_container(get_focused_view(&root_container));
@@ -205,7 +226,7 @@ static void handle_view_focus(wlc_handle view, bool focus) {
static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) {
sway_log(L_DEBUG, "geometry request %d x %d : %d x %d",
- geometry->origin.x, geometry->origin.y, geometry->size.w,geometry->size.h);
+ geometry->origin.x, geometry->origin.y, geometry->size.w, geometry->size.h);
// If the view is floating, then apply the geometry.
// Otherwise save the desired width/height for the view.
// This will not do anything for the time being as WLC improperly sends geometry requests
@@ -225,21 +246,17 @@ 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) {
- swayc_t *c = NULL;
- switch(state) {
+ swayc_t *c = get_swayc_for_handle(view, &root_container);
+ switch (state) {
case WLC_BIT_FULLSCREEN:
// i3 just lets it become fullscreen
wlc_view_set_state(view, state, toggle);
- c = get_swayc_for_handle(view, &root_container);
- sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d",view,c->name,toggle);
if (c) {
+ sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d", view, c->name, toggle);
arrange_windows(c->parent, -1, -1);
// Set it as focused window for that workspace if its going fullscreen
if (toggle) {
- swayc_t *ws = c;
- while (ws->type != C_WORKSPACE) {
- ws = ws->parent;
- }
+ swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE);
// Set ws focus to c
set_focused_container_for(ws, c);
}
@@ -248,7 +265,9 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
case WLC_BIT_MAXIMIZED:
case WLC_BIT_RESIZING:
case WLC_BIT_MOVING:
+ break;
case WLC_BIT_ACTIVATED:
+ sway_log(L_DEBUG, "View %p requested to be activated", c);
break;
}
return;
@@ -257,29 +276,38 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
uint32_t key, uint32_t sym, enum wlc_key_state state) {
- enum { QSIZE = 32 };
+
if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) {
return false;
}
- static uint8_t head = 0;
- bool cmd_success = false;
+
+ // Revert floating container back to original position on keypress
+ if (state == WLC_KEY_STATE_PRESSED &&
+ (pointer_state.floating.drag || pointer_state.floating.resize)) {
+ reset_floating(get_focused_view(&root_container));
+ }
struct sway_mode *mode = config->current_mode;
+
+ if (sym < 70000 /* bullshit made up number */) {
+ if (!isalnum(sym) && sym != ' ' && sym != XKB_KEY_Escape && sym != XKB_KEY_Tab) {
+ // God fucking dammit
+ return false;
+ }
+ }
+
// Lowercase if necessary
sym = tolower(sym);
- // Find key, if it has been pressed
- int mid = 0;
- while (mid < head && keys_pressed[mid] != sym) {
- ++mid;
- }
- if (state == WLC_KEY_STATE_PRESSED && mid == head && head + 1 < QSIZE) {
- keys_pressed[head++] = sym;
- } else if (state == WLC_KEY_STATE_RELEASED && mid < head) {
- memmove(keys_pressed + mid, keys_pressed + mid + 1, sizeof*keys_pressed * (--head - mid));
+ int i;
+
+ if (state == WLC_KEY_STATE_PRESSED) {
+ press_key(sym);
+ } else { // WLC_KEY_STATE_RELEASED
+ release_key(sym);
}
+
// TODO: reminder to check conflicts with mod+q+a versus mod+q
- int i;
for (i = 0; i < mode->bindings->length; ++i) {
struct sway_binding *binding = mode->bindings->items[i];
@@ -287,39 +315,22 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
bool match;
int j;
for (j = 0; j < binding->keys->length; ++j) {
- match = false;
xkb_keysym_t *key = binding->keys->items[j];
- uint8_t k;
- for (k = 0; k < head; ++k) {
- if (keys_pressed[k] == *key) {
- match = true;
- break;
- }
- }
- if (match == false) {
+ if ((match = check_key(*key)) == false) {
break;
}
}
-
if (match) {
- // Remove matched keys from keys_pressed
- int j;
- for (j = 0; j < binding->keys->length; ++j) {
- uint8_t k;
- for (k = 0; k < head; ++k) {
- memmove(keys_pressed + k, keys_pressed + k + 1, sizeof*keys_pressed * (--head - k));
- break;
- }
- }
if (state == WLC_KEY_STATE_PRESSED) {
- cmd_success = handle_command(config, binding->command);
+ handle_command(config, binding->command);
+ return true;
} else if (state == WLC_KEY_STATE_RELEASED) {
// TODO: --released
}
}
}
}
- return cmd_success;
+ return false;
}
static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) {
@@ -327,119 +338,129 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
static wlc_handle prev_handle = 0;
mouse_origin = *origin;
bool changed_floating = false;
- int i = 0;
if (!active_workspace) {
return false;
}
// Do checks to determine if proper keys are being held
- swayc_t *view = active_workspace->focused;
- if (m1_held && view) {
+ swayc_t *view = get_focused_view(active_workspace);
+ uint32_t edge = 0;
+ if (pointer_state.floating.drag && view) {
if (view->is_floating) {
- while (keys_pressed[i++]) {
- if (keys_pressed[i] == config->floating_mod) {
- int dx = mouse_origin.x - prev_pos.x;
- int dy = mouse_origin.y - prev_pos.y;
- sway_log(L_DEBUG, "Moving from px: %d to cx: %d and from py: %d to cy: %d", prev_pos.x, mouse_origin.x, prev_pos.y, mouse_origin.y);
- sway_log(L_DEBUG, "Moving: dx: %d, dy: %d", dx, dy);
-
- view->x += dx;
- view->y += dy;
- changed_floating = true;
- break;
- }
- }
+ int dx = mouse_origin.x - prev_pos.x;
+ int dy = mouse_origin.y - prev_pos.y;
+ view->x += dx;
+ view->y += dy;
+ changed_floating = true;
}
- } else if (m2_held && view) {
+ } else if (pointer_state.floating.resize && view) {
if (view->is_floating) {
- while (keys_pressed[i++]) {
- if (keys_pressed[i] == config->floating_mod) {
- int dx = mouse_origin.x - prev_pos.x;
- int dy = mouse_origin.y - prev_pos.y;
- sway_log(L_DEBUG, "Moving from px: %d to cx: %d and from py: %d to cy: %d", prev_pos.x, mouse_origin.x, prev_pos.y, mouse_origin.y);
- sway_log(L_INFO, "Moving: dx: %d, dy: %d", dx, dy);
-
- // 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) {
+ int dx = mouse_origin.x - prev_pos.x;
+ int dy = mouse_origin.y - prev_pos.y;
+ int min_sane_w = 100;
+ int min_sane_h = 60;
+
+ // 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;
- if (mouse_origin.x > midway_x) {
- sway_log(L_INFO, "Downsizing view to the left");
- view->width += dx;
- } else {
- sway_log(L_INFO, "Upsizing view to the left");
- view->x += dx;
- view->width -= dx;
- }
- } else if (dx > 0){
+ 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;
- if (mouse_origin.x > midway_x) {
- sway_log(L_INFO, "Upsizing to the right");
- view->width += dx;
- } else {
- sway_log(L_INFO, "Downsizing to the right");
- view->x += dx;
- view->width -= dx;
- }
+ view->x += dx;
+ view->width -= dx;
+ edge += WLC_RESIZE_EDGE_LEFT;
}
+ }
+ }
- if (dy < 0) {
+ if (dy < 0) {
+ if (!pointer_state.lock.bottom) {
+ if (view->height > min_sane_h) {
changed_floating = true;
- if (mouse_origin.y > midway_y) {
- sway_log(L_INFO, "Downsizing view to the top");
- view->height += dy;
- } else {
- sway_log(L_INFO, "Upsizing the view to the top");
- view->y += dy;
- view->height -= dy;
- }
- } else if (dy > 0) {
+ 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;
- if (mouse_origin.y > midway_y) {
- sway_log(L_INFO, "Upsizing to the bottom");
- view->height += dy;
- } else {
- sway_log(L_INFO, "Downsizing to the bottom");
- view->y += dy;
- view->height -= dy;
- }
+ view->y += dy;
+ view->height -= dy;
+ edge += WLC_RESIZE_EDGE_TOP;
}
- break;
}
}
}
}
if (config->focus_follows_mouse && prev_handle != handle) {
- //Dont change focus if fullscreen
+ // 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)) {
+ 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) {
- arrange_windows(view, -1, -1);
+ 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 true;
}
return false;
}
+
static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
- uint32_t button, enum wlc_button_state state) {
+ uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) {
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) {
return false;
}
if (state == WLC_BUTTON_STATE_PRESSED) {
sway_log(L_DEBUG, "Mouse button %u pressed", button);
- if (button == 272) {
- m1_held = true;
+ if (button == M_LEFT_CLICK) {
+ pointer_state.l_held = true;
}
- if (button == 273) {
- m2_held = true;
+ if (button == M_RIGHT_CLICK) {
+ pointer_state.r_held = true;
}
swayc_t *pointer = container_under_pointer();
set_focused_container(pointer);
@@ -453,15 +474,32 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
}
}
arrange_windows(pointer->parent, -1, -1);
+ if (modifiers->mods & config->floating_mod) {
+ int midway_x = pointer->x + pointer->width/2;
+ int midway_y = pointer->y + pointer->height/2;
+
+ pointer_state.floating.drag = pointer_state.l_held;
+ pointer_state.floating.resize = pointer_state.r_held;
+ pointer_state.lock.bottom = origin->y < midway_y;
+ pointer_state.lock.top = !pointer_state.lock.bottom;
+ pointer_state.lock.right = origin->x < midway_x;
+ pointer_state.lock.left = !pointer_state.lock.right;
+ start_floating(pointer);
+ }
+ // Dont want pointer sent to window while dragging or resizing
+ return (pointer_state.floating.drag || pointer_state.floating.resize);
}
return (pointer && pointer != focused);
} else {
sway_log(L_DEBUG, "Mouse button %u released", button);
- if (button == 272) {
- m1_held = false;
+ if (button == M_LEFT_CLICK) {
+ pointer_state.l_held = false;
+ pointer_state.floating.drag = false;
}
- if (button == 273) {
- m2_held = false;
+ if (button == M_RIGHT_CLICK) {
+ pointer_state.r_held = false;
+ pointer_state.floating.resize = false;
+ pointer_state.lock = (struct pointer_lock){false ,false ,false ,false};
}
}
return false;
diff --git a/sway/input_state.c b/sway/input_state.c
new file mode 100644
index 00000000..a7f88d4a
--- /dev/null
+++ b/sway/input_state.c
@@ -0,0 +1,68 @@
+#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+#include "input_state.h"
+
+#define KEY_STATE_MAX_LENGTH 64
+
+static keycode key_state_array[KEY_STATE_MAX_LENGTH];
+
+static uint8_t find_key(keycode key) {
+ int i;
+ for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) {
+ if (key_state_array[i] == key) {
+ break;
+ }
+ }
+ return i;
+}
+
+bool check_key(keycode key) {
+ return find_key(key) < KEY_STATE_MAX_LENGTH;
+}
+
+void press_key(keycode key) {
+ // Check if key exists
+ if (!check_key(key)) {
+ // Check that we dont exceed buffer length
+ int insert = find_key(0);
+ if (insert < KEY_STATE_MAX_LENGTH) {
+ key_state_array[insert] = key;
+ }
+ }
+}
+
+void release_key(keycode key) {
+ uint8_t index = find_key(key);
+ if (index < KEY_STATE_MAX_LENGTH) {
+ // shift it over and remove key
+ key_state_array[index] = 0;
+ }
+}
+
+struct pointer_state pointer_state = {0, 0, {0, 0}, {0, 0, 0, 0}};
+
+static struct wlc_geometry saved_floating;
+
+void start_floating(swayc_t *view) {
+ if (view->is_floating) {
+ saved_floating.origin.x = view->x;
+ saved_floating.origin.y = view->y;
+ saved_floating.size.w = view->width;
+ saved_floating.size.h = view->height;
+ }
+}
+
+void reset_floating(swayc_t *view) {
+ if (view->is_floating) {
+ view->x = saved_floating.origin.x;
+ view->y = saved_floating.origin.y;
+ view->width = saved_floating.size.w;
+ view->height = saved_floating.size.h;
+ arrange_windows(view->parent, -1, -1);
+ }
+ pointer_state.floating = (struct pointer_floating){0,0};
+ pointer_state.lock = (struct pointer_lock){0,0,0,0};
+}
+
diff --git a/sway/ipc.c b/sway/ipc.c
new file mode 100644
index 00000000..39e580cd
--- /dev/null
+++ b/sway/ipc.c
@@ -0,0 +1,321 @@
+// See https://i3wm.org/docs/ipc.html for protocol information
+
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdbool.h>
+#include <wlc/wlc.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stropts.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include "ipc.h"
+#include "log.h"
+#include "config.h"
+#include "commands.h"
+#include "list.h"
+#include "stringop.h"
+
+static int ipc_socket = -1;
+static struct wlc_event_source *ipc_event_source = NULL;
+static struct sockaddr_un ipc_sockaddr = {
+ .sun_family = AF_UNIX,
+ .sun_path = "/tmp/sway-ipc.sock"
+};
+
+static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
+
+struct ipc_client {
+ struct wlc_event_source *event_source;
+ int fd;
+ uint32_t payload_length;
+ enum ipc_command_type current_command;
+};
+
+int ipc_handle_connection(int fd, uint32_t mask, void *data);
+int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
+void ipc_client_disconnect(struct ipc_client *client);
+void ipc_client_handle_command(struct ipc_client *client);
+bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
+void ipc_get_workspaces_callback(swayc_t *container, void *data);
+void ipc_get_outputs_callback(swayc_t *container, void *data);
+
+char *json_list(list_t *items);
+
+void ipc_init(void) {
+ ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
+ if (ipc_socket == -1) {
+ sway_abort("Unable to create IPC socket");
+ }
+
+ if (getenv("SWAYSOCK") != NULL) {
+ strncpy(ipc_sockaddr.sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr.sun_path));
+ }
+
+ unlink(ipc_sockaddr.sun_path);
+ if (bind(ipc_socket, (struct sockaddr *)&ipc_sockaddr, sizeof(ipc_sockaddr)) == -1) {
+ sway_abort("Unable to bind IPC socket");
+ }
+
+ if (listen(ipc_socket, 3) == -1) {
+ sway_abort("Unable to listen on IPC socket");
+ }
+
+ // Set i3 IPC socket path so that i3-msg works out of the box
+ setenv("I3SOCK", ipc_sockaddr.sun_path, 1);
+
+ ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL);
+}
+
+void ipc_terminate(void) {
+ if (ipc_event_source) {
+ wlc_event_source_remove(ipc_event_source);
+ }
+ close(ipc_socket);
+ unlink(ipc_sockaddr.sun_path);
+}
+
+int ipc_handle_connection(int fd, uint32_t mask, void *data) {
+ (void) fd; (void) data;
+ sway_log(L_DEBUG, "Event on IPC listening socket");
+ assert(mask == WLC_EVENT_READABLE);
+
+ int client_fd = accept(ipc_socket, NULL, NULL);
+ if (client_fd == -1) {
+ sway_log_errno(L_INFO, "Unable to accept IPC client connection");
+ return 0;
+ }
+
+ int flags;
+ if ((flags=fcntl(client_fd, F_GETFD)) == -1 || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
+ sway_log_errno(L_INFO, "Unable to set CLOEXEC on IPC client socket");
+ return 0;
+ }
+
+ struct ipc_client* client = malloc(sizeof(struct ipc_client));
+ client->payload_length = 0;
+ client->fd = client_fd;
+ client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
+
+ return 0;
+}
+
+static const int ipc_header_size = sizeof(ipc_magic)+8;
+
+int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
+ struct ipc_client *client = data;
+ sway_log(L_DEBUG, "Event on IPC client socket %d", client_fd);
+
+ if (mask & WLC_EVENT_ERROR) {
+ sway_log(L_INFO, "IPC Client socket error, removing client");
+ ipc_client_disconnect(client);
+ return 0;
+ }
+
+ if (mask & WLC_EVENT_HANGUP) {
+ ipc_client_disconnect(client);
+ return 0;
+ }
+
+ int read_available;
+ ioctl(client_fd, FIONREAD, &read_available);
+
+ // Wait for the rest of the command payload in case the header has already been read
+ if (client->payload_length > 0) {
+ if (read_available >= client->payload_length) {
+ ipc_client_handle_command(client);
+ }
+ else {
+ sway_log(L_DEBUG, "Too little data to read payload on IPC Client socket, waiting for more (%d < %d)", read_available, client->payload_length);
+ }
+ return 0;
+ }
+
+ if (read_available < ipc_header_size) {
+ sway_log(L_DEBUG, "Too little data to read header on IPC Client socket, waiting for more (%d < %d)", read_available, ipc_header_size);
+ return 0;
+ }
+
+ char buf[ipc_header_size];
+ ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
+ if (received == -1) {
+ sway_log_errno(L_INFO, "Unable to receive header from IPC client");
+ ipc_client_disconnect(client);
+ return 0;
+ }
+
+ if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
+ sway_log(L_DEBUG, "IPC header check failed");
+ ipc_client_disconnect(client);
+ return 0;
+ }
+
+ client->payload_length = *(uint32_t *)&buf[sizeof(ipc_magic)];
+ client->current_command = (enum ipc_command_type) *(uint32_t *)&buf[sizeof(ipc_magic)+4];
+
+ if (read_available - received >= client->payload_length) {
+ ipc_client_handle_command(client);
+ }
+
+ return 0;
+}
+
+void ipc_client_disconnect(struct ipc_client *client)
+{
+ if (!sway_assert(client != NULL, "client != NULL")) {
+ return;
+ }
+
+ sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
+ wlc_event_source_remove(client->event_source);
+ close(client->fd);
+ free(client);
+}
+
+void ipc_client_handle_command(struct ipc_client *client) {
+ if (!sway_assert(client != NULL, "client != NULL")) {
+ return;
+ }
+
+ char buf[client->payload_length + 1];
+ if (client->payload_length > 0)
+ {
+ ssize_t received = recv(client->fd, buf, client->payload_length, 0);
+ if (received == -1)
+ {
+ sway_log_errno(L_INFO, "Unable to receive payload from IPC client");
+ ipc_client_disconnect(client);
+ return;
+ }
+ }
+
+ switch (client->current_command) {
+ case IPC_COMMAND:
+ {
+ buf[client->payload_length] = '\0';
+ bool success = handle_command(config, buf);
+ char reply[64];
+ int length = snprintf(reply, sizeof(reply), "{\"success\":%s}", success ? "true" : "false");
+ ipc_send_reply(client, reply, (uint32_t) length);
+ break;
+ }
+ case IPC_GET_WORKSPACES:
+ {
+ list_t *workspaces = create_list();
+ container_map(&root_container, ipc_get_workspaces_callback, workspaces);
+ char *json = json_list(workspaces);
+ free_flat_list(workspaces);
+ ipc_send_reply(client, json, strlen(json));
+ free(json);
+ break;
+ }
+ case IPC_GET_OUTPUTS:
+ {
+ list_t *outputs = create_list();
+ container_map(&root_container, ipc_get_outputs_callback, outputs);
+ char *json = json_list(outputs);
+ free_flat_list(outputs);
+ ipc_send_reply(client, json, strlen(json));
+ free(json);
+ break;
+ }
+ default:
+ sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
+ ipc_client_disconnect(client);
+ break;
+ }
+
+ client->payload_length = 0;
+}
+
+bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length) {
+ assert(payload);
+
+ char data[ipc_header_size];
+
+ memcpy(data, ipc_magic, sizeof(ipc_magic));
+ *(uint32_t *)&(data[sizeof(ipc_magic)]) = payload_length;
+ *(uint32_t *)&(data[sizeof(ipc_magic)+4]) = client->current_command;
+
+ if (write(client->fd, data, ipc_header_size) == -1) {
+ sway_log_errno(L_INFO, "Unable to send header to IPC client");
+ ipc_client_disconnect(client);
+ return false;
+ }
+
+ if (write(client->fd, payload, payload_length) == -1) {
+ sway_log_errno(L_INFO, "Unable to send payload to IPC client");
+ ipc_client_disconnect(client);
+ return false;
+ }
+
+ return true;
+}
+
+char *json_list(list_t *items) {
+ char *json_elements = join_list(items, ",");
+ size_t len = strlen(json_elements);
+ char *json = malloc(len + 3);
+ json[0] = '[';
+ memcpy(json + 1, json_elements, len);
+ json[len+1] = ']';
+ json[len+2] = '\0';
+ free(json_elements);
+ return json;
+}
+
+void ipc_get_workspaces_callback(swayc_t *container, void *data) {
+ if (container->type == C_WORKSPACE) {
+ char *json = malloc(512); // Output should usually be around 180 chars
+ int num = isdigit(container->name[0]) ? atoi(container->name) : -1;
+ // TODO: escape the name (quotation marks, unicode)
+ sprintf(json,
+ "{"
+ "\"num\":%d,"
+ "\"name\":\"%s\","
+ "\"visible\":%s,"
+ "\"focused\":%s,"
+ "\"rect\":{"
+ "\"x\":%d,"
+ "\"y\":%d,"
+ "\"width\":%d,"
+ "\"height\":%d"
+ "},"
+ "\"output\":\"%s\","
+ "\"urgent\":%s"
+ "}",
+ num, container->name, container->visible ? "true" : "false", container->is_focused ? "true" : "false",
+ container->x, container->y, container->width, container->height,
+ container->parent->name, "false" // TODO: urgent hint
+ );
+ list_add((list_t *)data, json);
+ }
+}
+
+void ipc_get_outputs_callback(swayc_t *container, void *data) {
+ if (container->type == C_OUTPUT) {
+ char *json = malloc(512); // Output should usually be around 130 chars
+ // TODO: escape the name (quotation marks, unicode)
+ sprintf(json,
+ "{"
+ "\"name\":\"%s\","
+ "\"active\":%s,"
+ "\"primary\":%s,"
+ "\"rect\":{"
+ "\"x\":%d,"
+ "\"y\":%d,"
+ "\"width\":%d,"
+ "\"height\":%d"
+ "},"
+ "\"current_workspace\":\"%s\""
+ "}",
+ container->name, "true", "false", // TODO: active, primary
+ container->x, container->y, container->width, container->height,
+ container->focused ? container->focused->name : ""
+ );
+ list_add((list_t *)data, json);
+ }
+}
diff --git a/sway/layout.c b/sway/layout.c
index 9fdfd62a..a48f15c4 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -4,6 +4,7 @@
#include "layout.h"
#include "log.h"
#include "list.h"
+#include "config.h"
#include "container.h"
#include "workspace.h"
#include "focus.h"
@@ -32,6 +33,21 @@ void add_child(swayc_t *parent, swayc_t *child) {
child->width, child->height, parent, parent->type, parent->width, parent->height);
list_add(parent->children, child);
child->parent = parent;
+ // set focus for this container
+ if (parent->children->length == 1) {
+ set_focused_container_for(parent, child);
+ }
+}
+
+void add_floating(swayc_t *ws, swayc_t *child) {
+ sway_log(L_DEBUG, "Adding %p (%d, %dx%d) to %p (%d, %dx%d)", child, child->type,
+ child->width, child->height, ws, ws->type, ws->width, ws->height);
+ list_add(ws->floating, child);
+ child->parent = ws;
+ child->is_floating = true;
+ if (!ws->focused) {
+ set_focused_container_for(ws, child);
+ }
}
swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) {
@@ -55,7 +71,7 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) {
new_child->parent = child->parent;
if (child->parent->focused == child) {
- child->parent->focused = new_child;
+ set_focused_container_for(child->parent, new_child);
}
child->parent = NULL;
return parent;
@@ -72,6 +88,7 @@ swayc_t *remove_child(swayc_t *child) {
break;
}
}
+ i = 0;
} else {
for (i = 0; i < parent->children->length; ++i) {
if (parent->children->items[i] == child) {
@@ -80,7 +97,7 @@ swayc_t *remove_child(swayc_t *child) {
}
}
}
- //Set focused to new container
+ // Set focused to new container
if (parent->focused == child) {
if (parent->children->length > 0) {
set_focused_container_for(parent, parent->children->items[i?i-1:0]);
@@ -104,7 +121,7 @@ void move_container(swayc_t *container,swayc_t* root,int direction){
//Only one container, meh.
break;
}
-
+ //TODO: Implement horizontal movement.
//TODO: Implement move to a different workspace.
if(direction == MOVE_LEFT && i > 0){
temp = root->children->items[i-1];
@@ -167,11 +184,11 @@ void arrange_windows(swayc_t *container, int width, int height) {
// y -= container->y;
for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i];
- sway_log(L_DEBUG, "Arranging workspace #%d", i);
- child->x = x;
- child->y = y;
- child->width = width;
- child->height = height;
+ child->x = x + container->gaps;
+ child->y = y + container->gaps;
+ child->width = width - container->gaps * 2;
+ child->height = height - container->gaps * 2;
+ sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y);
arrange_windows(child, -1, -1);
}
return;
@@ -179,27 +196,24 @@ void arrange_windows(swayc_t *container, int width, int height) {
{
struct wlc_geometry geometry = {
.origin = {
- .x = container->x,
- .y = container->y
+ .x = container->x + container->gaps / 2,
+ .y = container->y + container->gaps / 2
},
.size = {
- .w = width,
- .h = height
+ .w = width - container->gaps,
+ .h = height - container->gaps
}
};
if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
- swayc_t *parent = container;
- while (parent->type != C_OUTPUT) {
- parent = parent->parent;
- }
+ swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
geometry.origin.x = 0;
geometry.origin.y = 0;
geometry.size.w = parent->width;
geometry.size.h = parent->height;
- wlc_view_set_geometry(container->handle, &geometry);
+ wlc_view_set_geometry(container->handle, 0, &geometry);
wlc_view_bring_to_front(container->handle);
} else {
- wlc_view_set_geometry(container->handle, &geometry);
+ wlc_view_set_geometry(container->handle, 0, &geometry);
container->width = width;
container->height = height;
}
@@ -213,40 +227,62 @@ void arrange_windows(swayc_t *container, int width, int height) {
break;
}
- double total_weight = 0;
- for (i = 0; i < container->children->length; ++i) {
- swayc_t *child = container->children->items[i];
- total_weight += child->weight;
- }
-
+ x = y = 0;
+ double scale = 0;
switch (container->layout) {
case L_HORIZ:
default:
- sway_log(L_DEBUG, "Arranging %p horizontally", container);
+ // Calculate total width
for (i = 0; i < container->children->length; ++i) {
- swayc_t *child = container->children->items[i];
- double percent = child->weight / total_weight;
- sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width);
- child->x = x + container->x;
- child->y = y + container->y;
- int w = width * percent;
- int h = height;
- arrange_windows(child, w, h);
- x += w;
+ int *old_width = &((swayc_t *)container->children->items[i])->width;
+ if (*old_width <= 0) {
+ if (container->children->length > 1) {
+ *old_width = width / (container->children->length - 1);
+ } else {
+ *old_width = width;
+ }
+ }
+ scale += *old_width;
+ }
+ // Resize windows
+ if (scale > 0.1) {
+ scale = width / scale;
+ sway_log(L_DEBUG, "Arranging %p horizontally", container);
+ for (i = 0; i < container->children->length; ++i) {
+ swayc_t *child = container->children->items[i];
+ sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, width, scale);
+ child->x = x + container->x;
+ child->y = y + container->y;
+ arrange_windows(child, child->width * scale, height);
+ x += child->width;
+ }
}
break;
case L_VERT:
- sway_log(L_DEBUG, "Arranging %p vertically", container);
+ // Calculate total height
for (i = 0; i < container->children->length; ++i) {
- swayc_t *child = container->children->items[i];
- double percent = child->weight / total_weight;
- sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width);
- child->x = x + container->x;
- child->y = y + container->y;
- int w = width;
- int h = height * percent;
- arrange_windows(child, w, h);
- y += h;
+ int *old_height = &((swayc_t *)container->children->items[i])->height;
+ if (*old_height <= 0) {
+ if (container->children->length > 1) {
+ *old_height = height / (container->children->length - 1);
+ } else {
+ *old_height = height;
+ }
+ }
+ scale += *old_height;
+ }
+ // Resize
+ if (scale > 0.1) {
+ scale = height / scale;
+ sway_log(L_DEBUG, "Arranging %p vertically", container);
+ for (i = 0; i < container->children->length; ++i) {
+ swayc_t *child = container->children->items[i];
+ sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, height, scale);
+ child->x = x + container->x;
+ child->y = y + container->y;
+ arrange_windows(child, width, child->height * scale);
+ y += child->height;
+ }
}
break;
}
@@ -268,20 +304,15 @@ void arrange_windows(swayc_t *container, int width, int height) {
}
};
if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) {
- swayc_t *parent = view;
- while (parent->type != C_OUTPUT) {
- parent = parent->parent;
- }
+ swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
geometry.origin.x = 0;
geometry.origin.y = 0;
geometry.size.w = parent->width;
geometry.size.h = parent->height;
- wlc_view_set_geometry(view->handle, &geometry);
+ wlc_view_set_geometry(view->handle, 0, &geometry);
wlc_view_bring_to_front(view->handle);
} else {
- wlc_view_set_geometry(view->handle, &geometry);
- view->width = width;
- view->height = height;
+ wlc_view_set_geometry(view->handle, 0, &geometry);
// Bring the views to the front in order of the list, the list
// will be kept up to date so that more recently focused views
// have higher indexes
@@ -326,3 +357,54 @@ swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) {
}
return NULL;
}
+
+swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) {
+ swayc_t *parent = container->parent;
+
+ if (dir == MOVE_PARENT) {
+ if (parent->type == C_OUTPUT) {
+ return NULL;
+ } else {
+ return parent;
+ }
+ }
+ while (true) {
+ // Test if we can even make a difference here
+ bool can_move = false;
+ int diff = 0;
+ if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
+ if (parent->layout == L_HORIZ || parent->type == C_ROOT) {
+ can_move = true;
+ diff = dir == MOVE_LEFT ? -1 : 1;
+ }
+ } else {
+ if (parent->layout == L_VERT) {
+ can_move = true;
+ diff = dir == MOVE_UP ? -1 : 1;
+ }
+ }
+ if (can_move) {
+ int i;
+ for (i = 0; i < parent->children->length; ++i) {
+ swayc_t *child = parent->children->items[i];
+ if (child == container) {
+ break;
+ }
+ }
+ int desired = i + diff;
+ if (desired < 0 || desired >= parent->children->length) {
+ can_move = false;
+ } else {
+ return parent->children->items[desired];
+ }
+ }
+ if (!can_move) {
+ container = parent;
+ parent = parent->parent;
+ if (!parent) {
+ // Nothing we can do
+ return NULL;
+ }
+ }
+ }
+}
diff --git a/sway/log.c b/sway/log.c
index 8e380ffe..6e01421b 100644
--- a/sway/log.c
+++ b/sway/log.c
@@ -1,9 +1,13 @@
#include "log.h"
+#include "sway.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
int colored = 1;
int v = 0;
@@ -18,10 +22,10 @@ static const char *verbosity_colors[] = {
void init_log(int verbosity) {
v = verbosity;
/* set FD_CLOEXEC flag to prevent programs called with exec to write into logs */
- int i, flag;
+ int i;
int fd[] = { STDOUT_FILENO, STDIN_FILENO, STDERR_FILENO };
for (i = 0; i < 3; ++i) {
- flag = fcntl(fd[i], F_GETFD);
+ int flag = fcntl(fd[i], F_GETFD);
if (flag != -1) {
fcntl(fd[i], F_SETFD, flag | FD_CLOEXEC);
}
@@ -32,17 +36,17 @@ void sway_log_colors(int mode) {
colored = (mode == 1) ? 1 : 0;
}
-void sway_abort(char *format, ...) {
+void sway_abort(const char *format, ...) {
fprintf(stderr, "ERROR: ");
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
- exit(1);
+ sway_terminate();
}
-void sway_log(int verbosity, char* format, ...) {
+void sway_log(int verbosity, const char* format, ...) {
if (verbosity <= v) {
int c = verbosity;
if (c > sizeof(verbosity_colors) / sizeof(char *)) {
@@ -64,3 +68,106 @@ void sway_log(int verbosity, char* format, ...) {
fprintf(stderr, "\n");
}
}
+
+void sway_log_errno(int verbosity, char* format, ...) {
+ if (verbosity <= v) {
+ int c = verbosity;
+ if (c > sizeof(verbosity_colors) / sizeof(char *)) {
+ c = sizeof(verbosity_colors) / sizeof(char *) - 1;
+ }
+
+ if (colored) {
+ fprintf(stderr, verbosity_colors[c]);
+ }
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+
+ fprintf(stderr, ": ");
+ char error[256];
+ strerror_r(errno, error, sizeof(error));
+ fprintf(stderr, error);
+
+ if (colored) {
+ fprintf(stderr, "\x1B[0m");
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+bool sway_assert(bool condition, const char* format, ...) {
+ if (condition) {
+ return true;
+ }
+
+#ifndef NDEBUG
+ raise(SIGABRT);
+#endif
+
+ va_list args;
+ va_start(args, format);
+ sway_log(L_ERROR, format, args);
+ va_end(args);
+
+ return false;
+}
+
+#include "workspace.h"
+
+/* XXX:DEBUG:XXX */
+static void container_log(const swayc_t *c) {
+ fprintf(stderr, "focus:%c|",
+ c->is_focused ? 'F' : // Focused
+ c == active_workspace ? 'W' : // active workspace
+ c == &root_container ? 'R' : // root
+ 'X');// not any others
+ fprintf(stderr,"(%p)",c);
+ fprintf(stderr,"(p:%p)",c->parent);
+ fprintf(stderr,"(f:%p)",c->focused);
+ fprintf(stderr,"(h:%ld)",c->handle);
+ fprintf(stderr,"Type:");
+ fprintf(stderr,
+ c->type == C_ROOT ? "Root|" :
+ c->type == C_OUTPUT ? "Output|" :
+ c->type == C_WORKSPACE ? "Workspace|" :
+ c->type == C_CONTAINER ? "Container|" :
+ c->type == C_VIEW ? "View|" : "Unknown|");
+ fprintf(stderr,"layout:");
+ fprintf(stderr,
+ c->layout == L_NONE ? "NONE|" :
+ c->layout == L_HORIZ ? "Horiz|":
+ c->layout == L_VERT ? "Vert|":
+ c->layout == L_STACKED ? "Stacked|":
+ c->layout == L_FLOATING ? "Floating|":
+ "Unknown|");
+ fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
+ fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
+ fprintf(stderr, "vis:%c|", c->visible?'t':'f');
+ fprintf(stderr, "name:%.16s|", c->name);
+ fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
+}
+void layout_log(const swayc_t *c, int depth) {
+ int i, d;
+ int e = c->children ? c->children->length : 0;
+ container_log(c);
+ if (e) {
+ for (i = 0; i < e; ++i) {
+ fputc('|',stderr);
+ for (d = 0; d < depth; ++d) fputc('-', stderr);
+ layout_log(c->children->items[i], depth + 1);
+ }
+ }
+ if (c->type == C_WORKSPACE) {
+ e = c->floating?c->floating->length:0;
+ if (e) {
+ for (i = 0; i < e; ++i) {
+ fputc('|',stderr);
+ for (d = 0; d < depth; ++d) fputc('=', stderr);
+ layout_log(c->floating->items[i], depth + 1);
+ }
+ }
+ }
+}
+/* XXX:DEBUG:XXX */
diff --git a/sway/main.c b/sway/main.c
index 2db4604c..f37f086d 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -4,31 +4,121 @@
#include <wlc/wlc.h>
#include <sys/wait.h>
#include <signal.h>
+#include <getopt.h>
#include "layout.h"
#include "config.h"
#include "log.h"
#include "handlers.h"
+#include "ipc.h"
+#include "sway.h"
+
+static bool terminate_request = false;
+
+void sway_terminate(void) {
+ terminate_request = true;
+ wlc_terminate();
+}
static void sigchld_handle(int signal);
int main(int argc, char **argv) {
+ static int verbose = 0, debug = 0, validate = 0;
+
+ static struct option long_options[] = {
+ {"config", required_argument, NULL, 'c'},
+ {"validate", no_argument, &validate, 1},
+ {"debug", no_argument, &debug, 1},
+ {"version", no_argument, NULL, 'v'},
+ {"verbose", no_argument, &verbose, 1},
+ {"get-socketpath", no_argument, NULL, 'p'},
+ };
+
/* Signal handling */
signal(SIGCHLD, sigchld_handle);
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 */
if (!wlc_init(&interface, argc, argv)) {
return 1;
}
- init_log(L_DEBUG); // TODO: Control this with command line arg
+ char *config_path = NULL;
+
+ int c;
+ while (1) {
+ int option_index = 0;
+ c = getopt_long(argc, argv, "CdvVpc:", long_options, &option_index);
+ if (c == -1) {
+ break;
+ }
+ switch (c) {
+ case 0: // Flag
+ break;
+ case 'c': // config
+ config_path = strdup(optarg);
+ break;
+ case 'C': // validate
+ validate = 1;
+ break;
+ case 'd': // debug
+ debug = 1;
+ break;
+ case 'v': // version
+ // todo
+ exit(0);
+ break;
+ case 'V': // verbose
+ verbose = 1;
+ break;
+ case 'p': // --get-socketpath
+ // TODO
+ break;
+ }
+ }
+
+ if (debug) {
+ init_log(L_DEBUG);
+ wlc_set_log_file(stderr);
+ fclose(devnull);
+ devnull = NULL;
+ } else if (verbose || validate) {
+ init_log(L_INFO);
+ } else {
+ init_log(L_ERROR);
+ }
+
+ if (validate) {
+ bool valid = load_config(config_path);
+ return valid ? 0 : 1;
+ }
+
init_layout();
- if (!load_config()) {
+ if (!load_config(config_path)) {
sway_log(L_ERROR, "Error(s) loading config!");
}
+ if (config_path) {
+ free(config_path);
+ }
+
+ ipc_init();
+
+ if (!terminate_request) {
+ wlc_run();
+ }
+
+ if (devnull) {
+ fclose(devnull);
+ }
- wlc_run();
+ ipc_terminate();
return 0;
}
diff --git a/sway/readline.c b/sway/readline.c
index dfdc3fe8..e75b183f 100644
--- a/sway/readline.c
+++ b/sway/readline.c
@@ -17,18 +17,22 @@ char *read_line(FILE *file) {
continue;
}
if (length == size) {
- string = realloc(string, size *= 2);
- if (!string) {
+ char *new_string = realloc(string, size *= 2);
+ if (!new_string) {
+ free(string);
return NULL;
}
+ string = new_string;
}
string[length++] = c;
}
if (length + 1 == size) {
- string = realloc(string, length + 1);
- if (!string) {
+ char *new_string = realloc(string, length + 1);
+ if (!new_string) {
+ free(string);
return NULL;
}
+ string = new_string;
}
string[length] = '\0';
return string;
diff --git a/sway/stringop.c b/sway/stringop.c
index 1dff97bf..c39e2c34 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -4,6 +4,7 @@
#include "string.h"
#include "list.h"
#include <strings.h>
+#include <log.h>
/* Note: This returns 8 characters for trimmed_start per tab character. */
char *strip_whitespace(char *_str, int *trimmed_start) {
@@ -197,3 +198,41 @@ char *join_args(char **argv, int argc) {
res[len - 1] = '\0';
return res;
}
+
+/*
+ * Join a list of strings, adding separator in between. Separator can be NULL.
+ */
+char *join_list(list_t *list, char *separator) {
+ if (!sway_assert(list != NULL, "list != NULL") || list->length == 0) {
+ return NULL;
+ }
+
+ size_t len = 1; // NULL terminator
+ size_t sep_len = 0;
+ if (separator != NULL) {
+ sep_len = strlen(separator);
+ len += (list->length - 1) * sep_len;
+ }
+
+ for (int i = 0; i < list->length; i++) {
+ len += strlen(list->items[i]);
+ }
+
+ char *res = malloc(len);
+
+ char *p = res + strlen(list->items[0]);
+ strcpy(res, list->items[0]);
+
+ for (int i = 1; i < list->length; i++) {
+ if (sep_len) {
+ memcpy(p, separator, sep_len);
+ p += sep_len;
+ }
+ strcpy(p, list->items[i]);
+ p += strlen(list->items[i]);
+ }
+
+ *p = '\0';
+
+ return res;
+}
diff --git a/sway/workspace.c b/sway/workspace.c
index 05a669fe..d436da8e 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -31,7 +31,7 @@ char *workspace_next_name(void) {
char* target = malloc(strlen(args->items[1]) + 1);
strcpy(target, args->items[1]);
while (*target == ' ' || *target == '\t')
- target++;
+ target++;
// Make sure that the command references an actual workspace
// not a command about workspaces
@@ -42,11 +42,15 @@ char *workspace_next_name(void) {
strcmp(target, "number") == 0 ||
strcmp(target, "back_and_forth") == 0 ||
strcmp(target, "current") == 0)
+ {
+ list_free(args);
continue;
-
- //Make sure that the workspace doesn't already exist
+ }
+
+ // Make sure that the workspace doesn't already exist
if (workspace_find_by_name(target)) {
- continue;
+ list_free(args);
+ continue;
}
list_free(args);
@@ -54,6 +58,7 @@ char *workspace_next_name(void) {
sway_log(L_DEBUG, "Workspace: Found free name %s", target);
return target;
}
+ list_free(args);
}
// As a fall back, get the current number of active workspaces
// and return that + 1 for the next workspace's name
@@ -70,14 +75,12 @@ char *workspace_next_name(void) {
swayc_t *workspace_create(const char* name) {
swayc_t *parent = get_focused_container(&root_container);
- while (parent->type != C_OUTPUT) {
- parent = parent->parent;
- }
+ parent = swayc_parent_by_type(parent, C_OUTPUT);
return new_workspace(parent, name);
}
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);
}
@@ -180,62 +183,4 @@ void workspace_switch(swayc_t *workspace) {
sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
set_focused_container(get_focused_view(workspace));
arrange_windows(workspace, -1, -1);
- active_workspace = workspace;
-}
-
-/* XXX:DEBUG:XXX */
-static void container_log(const swayc_t *c) {
- fprintf(stderr, "focus:%c|",
- c->is_focused ? 'F' : //Focused
- c == active_workspace ? 'W' : //active workspace
- c == &root_container ? 'R' : //root
- 'X');//not any others
- fprintf(stderr,"(%p)",c);
- fprintf(stderr,"(p:%p)",c->parent);
- fprintf(stderr,"(f:%p)",c->focused);
- fprintf(stderr,"(h:%ld)",c->handle);
- fprintf(stderr,"Type:");
- fprintf(stderr,
- c->type == C_ROOT ? "Root|" :
- c->type == C_OUTPUT ? "Output|" :
- c->type == C_WORKSPACE ? "Workspace|" :
- c->type == C_CONTAINER ? "Container|" :
- c->type == C_VIEW ? "View|" : "Unknown|");
- fprintf(stderr,"layout:");
- fprintf(stderr,
- c->layout == L_NONE ? "NONE|" :
- c->layout == L_HORIZ ? "Horiz|":
- c->layout == L_VERT ? "Vert|":
- c->layout == L_STACKED ? "Stacked|":
- c->layout == L_FLOATING ? "Floating|":
- "Unknown|");
- fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
- fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
- fprintf(stderr, "vis:%c|", c->visible?'t':'f');
- fprintf(stderr, "wgt:%d|", c->weight);
- fprintf(stderr, "name:%.16s|", c->name);
- fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
-}
-void layout_log(const swayc_t *c, int depth) {
- int i, d;
- int e = c->children ? c->children->length : 0;
- container_log(c);
- if (e) {
- for (i = 0; i < e; ++i) {
- fputc('|',stderr);
- for (d = 0; d < depth; ++d) fputc('-', stderr);
- layout_log(c->children->items[i], depth + 1);
- }
- }
- if (c->type == C_WORKSPACE) {
- e = c->floating?c->floating->length:0;
- if (e) {
- for (i = 0; i < e; ++i) {
- fputc('|',stderr);
- for (d = 0; d < depth; ++d) fputc('-', stderr);
- layout_log(c->floating->items[i], depth + 1);
- }
- }
- }
}
-/* XXX:DEBUG:XXX */