Merge pull request #1 from SirCmpwn/master

Update
This commit is contained in:
aouelete 2015-08-20 10:31:14 -04:00
commit 9039937c39
22 changed files with 819 additions and 244 deletions

1
.gitignore vendored
View file

@ -9,3 +9,4 @@ bin/
test/ test/
build/ build/
.lvimrc .lvimrc
config-debug

View file

@ -46,7 +46,7 @@ struct sway_config {
int gaps_outer; int gaps_outer;
}; };
bool load_config(void); bool load_config(const char *file);
bool read_config(FILE *file, bool is_active); bool read_config(FILE *file, bool is_active);
char *do_var_replacement(struct sway_config *config, char *str); char *do_var_replacement(struct sway_config *config, char *str);

View file

@ -11,7 +11,7 @@ enum swayc_types{
C_WORKSPACE, C_WORKSPACE,
C_CONTAINER, C_CONTAINER,
C_VIEW, C_VIEW,
//Keep last // Keep last
C_TYPES, C_TYPES,
}; };
@ -22,7 +22,7 @@ enum swayc_layouts{
L_STACKED, L_STACKED,
L_TABBED, L_TABBED,
L_FLOATING, L_FLOATING,
//Keep last // Keep last
L_LAYOUTS, L_LAYOUTS,
}; };
@ -44,8 +44,6 @@ struct sway_container {
bool is_floating; bool is_floating;
bool is_focused; bool is_focused;
int weight;
char *name; char *name;
int gaps; int gaps;

View file

@ -1,7 +1,5 @@
#ifndef _SWAY_FOCUS_H #ifndef _SWAY_FOCUS_H
#define _SWAY_FOCUS_H #define _SWAY_FOCUS_H
#include "container.h"
enum movement_direction { enum movement_direction {
MOVE_LEFT, MOVE_LEFT,
MOVE_RIGHT, MOVE_RIGHT,
@ -10,6 +8,8 @@ enum movement_direction {
MOVE_PARENT MOVE_PARENT
}; };
#include "container.h"
// focused_container - the container found by following the `focused` pointer // focused_container - the container found by following the `focused` pointer
// from a given container to a container with `is_focused` boolean set // from a given container to a container with `is_focused` boolean set
// --- // ---

49
include/input_state.h Normal file
View file

@ -0,0 +1,49 @@
#ifndef _SWAY_KEY_STATE_H
#define _SWAY_KEY_STATE_H
#include <stdbool.h>
#include <stdint.h>
#include "container.h"
/* Keyboard state */
typedef uint32_t keycode;
// returns true if key has been pressed, otherwise false
bool check_key(keycode key);
// sets a key as pressed
void press_key(keycode key);
// unsets a key as pressed
void release_key(keycode key);
/* Pointer state */
enum pointer_values {
M_LEFT_CLICK = 272,
M_RIGHT_CLICK = 273,
M_SCROLL_CLICK = 274,
M_SCROLL_UP = 275,
M_SCROLL_DOWN = 276,
};
extern struct pointer_state {
bool l_held;
bool r_held;
struct pointer_floating {
bool drag;
bool resize;
} floating;
struct pointer_lock {
bool left;
bool right;
bool top;
bool bottom;
} lock;
} pointer_state;
void start_floating(swayc_t *view);
void reset_floating(swayc_t *view);
#endif

18
include/ipc.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef _SWAY_IPC_H
#define _SWAY_IPC_H
enum ipc_command_type {
IPC_COMMAND = 0,
IPC_GET_WORKSPACES = 1,
IPC_SUBSCRIBE = 2,
IPC_GET_OUTPUTS = 3,
IPC_GET_TREE = 4,
IPC_GET_MARKS = 5,
IPC_GET_BAR_CONFIG = 6,
IPC_GET_VERSION = 7,
};
void ipc_init(void);
void ipc_terminate(void);
#endif

View file

@ -4,6 +4,7 @@
#include <wlc/wlc.h> #include <wlc/wlc.h>
#include "list.h" #include "list.h"
#include "container.h" #include "container.h"
#include "focus.h"
extern swayc_t root_container; extern swayc_t root_container;
@ -26,5 +27,6 @@ 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_for_handle(wlc_handle handle, swayc_t *parent);
swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir);
#endif #endif

View file

@ -13,6 +13,7 @@ typedef enum {
void init_log(int verbosity); void init_log(int verbosity);
void sway_log_colors(int mode); void sway_log_colors(int mode);
void sway_log(int verbosity, const char* format, ...) __attribute__((format(printf,2,3))); void sway_log(int verbosity, const char* format, ...) __attribute__((format(printf,2,3)));
void sway_log_errno(int verbosity, char* format, ...) __attribute__((format(printf,2,3)));
void sway_abort(const char* format, ...) __attribute__((format(printf,1,2))); void sway_abort(const char* format, ...) __attribute__((format(printf,1,2)));
bool sway_assert(bool condition, const char* format, ...) __attribute__((format(printf,2,3))); bool sway_assert(bool condition, const char* format, ...) __attribute__((format(printf,2,3)));

6
include/sway.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef _SWAY_SWAY_H
#define _SWAY_SWAY_H
void sway_terminate(void);
#endif

View file

@ -22,11 +22,11 @@ Commands
-------- --------
**bindsym** <key combo> <command>:: **bindsym** <key combo> <command>::
Binds _key combo_ to execute _command_ when pressed. You may use XKB key names Binds _key combo_ to execute _command_ when pressed. You may use XKB key
here (**xev**(1) is a good tool for discovering them). An example bindsym names here (**xev**(1) is a good tool for discovering them). An example
command would be _bindsym Mod1+Shift+f exec firefox_, which would execute bindsym command would be _bindsym Mod1+Shift+f exec firefox_, which would
Firefox if the alt, shift, and F keys are pressed together. Any valid sway execute Firefox if the alt, shift, and F keys are pressed together. Any
command is eligible to be bound to a key combo. valid sway command is eligible to be bound to a key combo.
**exec** <shell command>:: **exec** <shell command>::
Executes _shell command_ with sh. Executes _shell command_ with sh.
@ -48,6 +48,9 @@ Commands
container, which is useful, for example, to open a sibling of the parent container, which is useful, for example, to open a sibling of the parent
container, or to move the entire container around. container, or to move the entire container around.
**focus** mode_toggle::
Toggles focus between floating view and tiled view.
**focus_follows_mouse** <yes|no>:: **focus_follows_mouse** <yes|no>::
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.
@ -83,10 +86,10 @@ Commands
**fullscreen**:: **fullscreen**::
Toggles fullscreen status for the focused view. Toggles fullscreen status for the focused view.
**gaps** <amount>**:: **gaps** <amount>::
Adds _amount_ pixels between each view, and around each output. Adds _amount_ pixels between each view, and around each output.
**gaps** <inner|outer> <amount>**:: **gaps** <inner|outer> <amount>::
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.

View file

@ -15,6 +15,7 @@
#include "commands.h" #include "commands.h"
#include "container.h" #include "container.h"
#include "handlers.h" #include "handlers.h"
#include "sway.h"
struct modifier_key { struct modifier_key {
char *name; char *name;
@ -76,6 +77,18 @@ static bool checkarg(int argc, char *name, enum expected_args type, int val) {
return false; 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) { static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) { if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) {
@ -118,7 +131,10 @@ static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
list_free(split); list_free(split);
// TODO: Check if there are other commands with this key binding // 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); sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command);
return true; return true;
@ -171,7 +187,7 @@ static bool cmd_exit(struct sway_config *config, int argc, char **argv) {
} }
// Close all views // Close all views
container_map(&root_container, kill_views, NULL); container_map(&root_container, kill_views, NULL);
exit(0); sway_terminate();
return true; return true;
} }
@ -188,10 +204,10 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
} }
// Change from nonfloating to floating // Change from nonfloating to floating
if (!view->is_floating) { if (!view->is_floating) {
//Remove view from its current location // Remove view from its current location
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(active_workspace,view);
view->x = (active_workspace->width - view->width)/2; view->x = (active_workspace->width - view->width)/2;
view->y = (active_workspace->height - view->height)/2; view->y = (active_workspace->height - view->height)/2;
@ -218,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); 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) { if (focused->type == C_WORKSPACE) {
add_child(focused, view); add_child(focused, view);
} }
//Regular case, create as sibling of current container // Regular case, create as sibling of current container
else { else {
add_sibling(focused, view); add_sibling(focused, view);
} }
// 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;
arrange_windows(active_workspace, -1, -1); arrange_windows(active_workspace, -1, -1);
return true;
} }
set_focused_container(view); set_focused_container(view);
} }
return true; return true;
} }
@ -244,7 +259,7 @@ static bool cmd_floating_mod(struct sway_config *config, int argc, char **argv)
list_t *split = split_string(argv[0], "+"); list_t *split = split_string(argv[0], "+");
config->floating_mod = 0; config->floating_mod = 0;
//set modifer keys // set modifer keys
for (i = 0; i < split->length; ++i) { for (i = 0; i < split->length; ++i) {
for (j = 0; j < sizeof(modifiers) / sizeof(struct modifier_key); ++j) { for (j = 0; j < sizeof(modifiers) / sizeof(struct modifier_key); ++j) {
if (strcasecmp(modifiers[j].name, split->items[i]) == 0) { if (strcasecmp(modifiers[j].name, split->items[i]) == 0) {
@ -261,6 +276,8 @@ static bool cmd_floating_mod(struct sway_config *config, int argc, char **argv)
} }
static bool cmd_focus(struct sway_config *config, int argc, char **argv) { 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)) { if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
return false; return false;
} }
@ -274,7 +291,44 @@ static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
return move_focus(MOVE_DOWN); return move_focus(MOVE_DOWN);
} else if (strcasecmp(argv[0], "parent") == 0) { } else if (strcasecmp(argv[0], "parent") == 0) {
return move_focus(MOVE_PARENT); 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; return true;
} }
@ -361,7 +415,7 @@ static bool cmd_reload(struct sway_config *config, int argc, char **argv) {
if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) { if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) {
return false; return false;
} }
if (!load_config()) { if (!load_config(NULL)) { // TODO: Use config given from -c
return false; return false;
} }
arrange_windows(&root_container, -1, -1); arrange_windows(&root_container, -1, -1);
@ -455,14 +509,14 @@ 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 = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0;
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
if (current) { if (current) {
while (container->type != C_WORKSPACE) { while (container->type != C_WORKSPACE) {
container = container->parent; container = container->parent;
} }
} }
//Only resize container when going into fullscreen // Only resize container when going into fullscreen
arrange_windows(container, -1, -1); arrange_windows(container, -1, -1);
return true; return true;
@ -626,7 +680,7 @@ bool handle_command(struct sway_config *config, char *exec) {
char **argv = split_directive(exec + strlen(handler->command), &argc); char **argv = split_directive(exec + strlen(handler->command), &argc);
int i; 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) { for (i = 0; i < argc; ++i) {
argv[i] = do_var_replacement(config, argv[i]); argv[i] = do_var_replacement(config, argv[i]);
} }

View file

@ -144,10 +144,15 @@ _continue:
return test; return test;
} }
bool load_config(void) { bool load_config(const char *file) {
sway_log(L_INFO, "Loading config"); 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) { if (path == NULL) {
sway_log(L_ERROR, "Unable to find a config file!"); sway_log(L_ERROR, "Unable to find a config file!");

View file

@ -14,7 +14,6 @@ static swayc_t *new_swayc(enum swayc_types type) {
c->handle = -1; c->handle = -1;
c->layout = L_NONE; c->layout = L_NONE;
c->type = type; c->type = type;
c->weight = 1;
if (type != C_VIEW) { if (type != C_VIEW) {
c->children = create_list(); c->children = create_list();
} }
@ -54,7 +53,7 @@ static void free_swayc(swayc_t *c) {
/* New containers */ /* New containers */
static bool workspace_test(swayc_t *view, void *name) { 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) { swayc_t *new_output(wlc_handle handle) {
@ -67,7 +66,7 @@ swayc_t *new_output(wlc_handle handle) {
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; output->gaps = config->gaps_outer + config->gaps_inner / 2;
add_child(&root_container, output); add_child(&root_container, output);
@ -81,8 +80,10 @@ swayc_t *new_output(wlc_handle handle) {
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 (find_container(&root_container, workspace_test, wso->workspace)) {
sway_log(L_DEBUG, "But it's already taken");
break; break;
} }
sway_log(L_DEBUG, "So we're going to use it");
ws_name = strdup(wso->workspace); ws_name = strdup(wso->workspace);
break; break;
} }
@ -150,6 +151,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
// give them proper layouts // give them proper layouts
cont->layout = workspace->layout; cont->layout = workspace->layout;
workspace->layout = layout; workspace->layout = layout;
set_focused_container_for(workspace, get_focused_view(workspace));
} else { // Or is built around container } else { // Or is built around container
swayc_t *parent = replace_child(child, cont); swayc_t *parent = replace_child(child, cont);
if (parent) { if (parent) {
@ -169,6 +171,9 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
view->name = title ? strdup(title) : NULL; view->name = title ? strdup(title) : NULL;
view->visible = true; view->visible = true;
view->is_focused = true; view->is_focused = true;
// Setup geometry
view->width = 0;
view->height = 0;
view->gaps = config->gaps_inner; view->gaps = config->gaps_inner;
@ -200,7 +205,7 @@ swayc_t *new_floating_view(wlc_handle handle) {
// Set the geometry of the floating view // Set the geometry of the floating view
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 = (active_workspace->width - geometry->size.w) / 2;
view->y = (active_workspace->height- geometry->size.h) / 2; view->y = (active_workspace->height- geometry->size.h) / 2;
view->width = geometry->size.w; view->width = geometry->size.w;

View file

@ -3,6 +3,7 @@
#include "focus.h" #include "focus.h"
#include "log.h" #include "log.h"
#include "workspace.h" #include "workspace.h"
#include "layout.h"
bool locked_container_focus = false; bool locked_container_focus = false;
bool locked_view_focus = false; bool locked_view_focus = false;
@ -20,6 +21,8 @@ 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
@ -51,74 +54,17 @@ static void update_focus(swayc_t *c) {
} }
bool move_focus(enum movement_direction direction) { bool move_focus(enum movement_direction direction) {
if (locked_container_focus) { swayc_t *view = get_swayc_in_direction(
return false; get_focused_container(&root_container), direction);
} if (view) {
swayc_t *current = get_focused_container(&root_container); if (direction == MOVE_PARENT) {
if (current->type == C_VIEW set_focused_container(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;
} else { } else {
sway_log(L_DEBUG, "Moving focus from %p:%ld to %p:%ld", set_focused_container(get_focused_view(view));
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;
}
} }
return true;
} }
return false;
} }
swayc_t *get_focused_container(swayc_t *parent) { swayc_t *get_focused_container(swayc_t *parent) {
@ -172,7 +118,7 @@ void set_focused_container(swayc_t *c) {
// activate current focus // activate current focus
if (p->type == C_VIEW) { if (p->type == C_VIEW) {
wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true); wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true);
//set focus if view_focus is unlocked // set focus if view_focus is unlocked
if (!locked_view_focus) { if (!locked_view_focus) {
wlc_view_focus(p->handle); wlc_view_focus(p->handle);
} }

View file

@ -13,19 +13,10 @@
#include "workspace.h" #include "workspace.h"
#include "container.h" #include "container.h"
#include "focus.h" #include "focus.h"
#include "input_state.h"
uint32_t keys_pressed[32];
int keys_pressed_length = 0;
static struct wlc_origin mouse_origin; static struct wlc_origin mouse_origin;
static bool m1_held = false;
static bool dragging = false;
static bool m2_held = false;
static bool resizing = false;
static bool lock_left, lock_right, lock_top, lock_bottom = false;
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;
// Determine the output that the view is under // Determine the output that the view is under
@ -91,10 +82,12 @@ swayc_t *container_under_pointer(void) {
return lookup; return lookup;
} }
/* Handles */
static bool handle_output_created(wlc_handle output) { 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 (active_workspace == NULL) {
swayc_t *ws = op->children->items[0]; swayc_t *ws = op->children->items[0];
workspace_switch(ws); workspace_switch(ws);
@ -116,7 +109,7 @@ static void handle_output_destroyed(wlc_handle output) {
if (list->length == 0) { if (list->length == 0) {
active_workspace = NULL; active_workspace = NULL;
} else { } 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);
} }
} }
@ -154,8 +147,14 @@ static bool handle_view_created(wlc_handle handle) {
if (!focused || focused->type == C_OUTPUT) { if (!focused || focused->type == C_OUTPUT) {
focused = get_focused_container(&root_container); focused = get_focused_container(&root_container);
} }
sway_log(L_DEBUG, "creating view %ld with type %x, state %x, with parent %ld", sway_log(L_DEBUG, "handle:%ld type:%x state:%x parent:%ld "
handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent); "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. // TODO properly figure out how each window should be handled.
switch (wlc_view_get_type(handle)) { switch (wlc_view_get_type(handle)) {
@ -168,7 +167,7 @@ static bool handle_view_created(wlc_handle handle) {
// Dmenu keeps viewfocus, but others with this flag dont, for now simulate // Dmenu keeps viewfocus, but others with this flag dont, for now simulate
// dmenu // dmenu
case WLC_BIT_OVERRIDE_REDIRECT: case WLC_BIT_OVERRIDE_REDIRECT:
// locked_view_focus = true; // locked_view_focus = true;
wlc_view_focus(handle); wlc_view_focus(handle);
wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true);
wlc_view_bring_to_front(handle); wlc_view_bring_to_front(handle);
@ -218,7 +217,7 @@ static void handle_view_destroyed(wlc_handle handle) {
// DMENU has this flag, and takes view_focus, but other things with this // DMENU has this flag, and takes view_focus, but other things with this
// flag dont // flag dont
case WLC_BIT_OVERRIDE_REDIRECT: case WLC_BIT_OVERRIDE_REDIRECT:
// locked_view_focus = false; // locked_view_focus = false;
break; break;
case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
locked_container_focus = false; locked_container_focus = false;
@ -233,7 +232,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) { 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", 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. // 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
@ -253,14 +252,13 @@ 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 = NULL; swayc_t *c = get_swayc_for_handle(view, &root_container);
switch(state) { switch (state) {
case WLC_BIT_FULLSCREEN: case WLC_BIT_FULLSCREEN:
// i3 just lets it become fullscreen // i3 just lets it become fullscreen
wlc_view_set_state(view, state, toggle); 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) { if (c) {
sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d", view, c->name, toggle);
arrange_windows(c->parent, -1, -1); arrange_windows(c->parent, -1, -1);
// Set it as focused window for that workspace if its going fullscreen // Set it as focused window for that workspace if its going fullscreen
if (toggle) { if (toggle) {
@ -276,7 +274,9 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
case WLC_BIT_MAXIMIZED: case WLC_BIT_MAXIMIZED:
case WLC_BIT_RESIZING: case WLC_BIT_RESIZING:
case WLC_BIT_MOVING: case WLC_BIT_MOVING:
break;
case WLC_BIT_ACTIVATED: case WLC_BIT_ACTIVATED:
sway_log(L_DEBUG, "View %p requested to be activated", c);
break; break;
} }
return; return;
@ -285,30 +285,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, 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) { uint32_t key, uint32_t sym, enum wlc_key_state state) {
enum { QSIZE = 32 };
if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) { if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) {
return false; return false;
} }
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; 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 // Lowercase if necessary
sym = tolower(sym); sym = tolower(sym);
// Find key, if it has been pressed
int mid = 0;
while (mid < keys_pressed_length && keys_pressed[mid] != sym) {
++mid;
}
//Add or remove key depending on state
if (state == WLC_KEY_STATE_PRESSED && mid == keys_pressed_length && keys_pressed_length + 1 < QSIZE) {
keys_pressed[keys_pressed_length++] = sym;
} else if (state == WLC_KEY_STATE_RELEASED && mid < keys_pressed_length) {
memmove(keys_pressed + mid, keys_pressed + mid + 1, sizeof*keys_pressed * (--keys_pressed_length - mid));
keys_pressed[keys_pressed_length] = 0;
}
// TODO: reminder to check conflicts with mod+q+a versus mod+q
int i; 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
for (i = 0; i < mode->bindings->length; ++i) { for (i = 0; i < mode->bindings->length; ++i) {
struct sway_binding *binding = mode->bindings->items[i]; struct sway_binding *binding = mode->bindings->items[i];
@ -316,40 +324,22 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
bool match; bool match;
int j; int j;
for (j = 0; j < binding->keys->length; ++j) { for (j = 0; j < binding->keys->length; ++j) {
match = false;
xkb_keysym_t *key = binding->keys->items[j]; xkb_keysym_t *key = binding->keys->items[j];
uint8_t k; if ((match = check_key(*key)) == false) {
for (k = 0; k < keys_pressed_length; ++k) {
if (keys_pressed[k] == *key) {
match = true;
break;
}
}
if (match == false) {
break; break;
} }
} }
if (match) { 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 < keys_pressed_length; ++k) {
memmove(keys_pressed + k, keys_pressed + k + 1, sizeof*keys_pressed * (--keys_pressed_length - k));
keys_pressed[keys_pressed_length] = 0;
break;
}
}
if (state == WLC_KEY_STATE_PRESSED) { 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) { } else if (state == WLC_KEY_STATE_RELEASED) {
// TODO: --released // TODO: --released
} }
} }
} }
} }
return cmd_success; return false;
} }
static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) { static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) {
@ -363,7 +353,7 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
// Do checks to determine if proper keys are being held // Do checks to determine if proper keys are being held
swayc_t *view = get_focused_view(active_workspace); swayc_t *view = get_focused_view(active_workspace);
uint32_t edge = 0; uint32_t edge = 0;
if (dragging && 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;
@ -371,7 +361,7 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
view->y += dy; view->y += dy;
changed_floating = true; changed_floating = true;
} }
} else if (resizing && view) { } else if (pointer_state.floating.resize && 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;
@ -382,24 +372,24 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
int midway_x = view->x + view->width/2; int midway_x = view->x + view->width/2;
int midway_y = view->y + view->height/2; int midway_y = view->y + view->height/2;
if (dx < 0) { if (dx < 0) {
if (!lock_right) { if (!pointer_state.lock.right) {
if (view->width > min_sane_w) { if (view->width > min_sane_w) {
changed_floating = true; changed_floating = true;
view->width += dx; view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT; edge += WLC_RESIZE_EDGE_RIGHT;
} }
} else if (mouse_origin.x < midway_x && !lock_left) { } else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
changed_floating = true; changed_floating = true;
view->x += dx; view->x += dx;
view->width -= dx; view->width -= dx;
edge += WLC_RESIZE_EDGE_LEFT; edge += WLC_RESIZE_EDGE_LEFT;
} }
} else if (dx > 0){ } else if (dx > 0) {
if (mouse_origin.x > midway_x && !lock_right) { if (mouse_origin.x > midway_x && !pointer_state.lock.right) {
changed_floating = true; changed_floating = true;
view->width += dx; view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT; edge += WLC_RESIZE_EDGE_RIGHT;
} else if (!lock_left) { } else if (!pointer_state.lock.left) {
if (view->width > min_sane_w) { if (view->width > min_sane_w) {
changed_floating = true; changed_floating = true;
view->x += dx; view->x += dx;
@ -410,24 +400,24 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
} }
if (dy < 0) { if (dy < 0) {
if (!lock_bottom) { if (!pointer_state.lock.bottom) {
if (view->height > min_sane_h) { if (view->height > min_sane_h) {
changed_floating = true; changed_floating = true;
view->height += dy; view->height += dy;
edge += WLC_RESIZE_EDGE_BOTTOM; edge += WLC_RESIZE_EDGE_BOTTOM;
} }
} else if (mouse_origin.y < midway_y && !lock_top) { } else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
changed_floating = true; changed_floating = true;
view->y += dy; view->y += dy;
view->height -= dy; view->height -= dy;
edge += WLC_RESIZE_EDGE_TOP; edge += WLC_RESIZE_EDGE_TOP;
} }
} else if (dy > 0) { } else if (dy > 0) {
if (mouse_origin.y > midway_y && !lock_bottom) { if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) {
changed_floating = true; changed_floating = true;
view->height += dy; view->height += dy;
edge += WLC_RESIZE_EDGE_BOTTOM; edge += WLC_RESIZE_EDGE_BOTTOM;
} else if (!lock_top) { } else if (!pointer_state.lock.top) {
if (view->height > min_sane_h) { if (view->height > min_sane_h) {
changed_floating = true; changed_floating = true;
view->y += dy; view->y += dy;
@ -439,9 +429,10 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
} }
} }
if (config->focus_follows_mouse && prev_handle != handle) { 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); swayc_t *focused = get_focused_view(view);
if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) && !(m1_held || m2_held)) { 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()); set_focused_container(container_under_pointer());
} }
} }
@ -464,20 +455,21 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
return false; return false;
} }
static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
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 (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) {
return false; return false;
} }
if (state == WLC_BUTTON_STATE_PRESSED) { if (state == WLC_BUTTON_STATE_PRESSED) {
sway_log(L_DEBUG, "Mouse button %u pressed", button); sway_log(L_DEBUG, "Mouse button %u pressed", button);
if (button == 272) { if (button == M_LEFT_CLICK) {
m1_held = true; pointer_state.l_held = true;
} }
if (button == 273) { if (button == M_RIGHT_CLICK) {
m2_held = true; pointer_state.r_held = true;
} }
swayc_t *pointer = container_under_pointer(); swayc_t *pointer = container_under_pointer();
set_focused_container(pointer); set_focused_container(pointer);
@ -492,29 +484,31 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
} }
arrange_windows(pointer->parent, -1, -1); arrange_windows(pointer->parent, -1, -1);
if (modifiers->mods & config->floating_mod) { if (modifiers->mods & config->floating_mod) {
dragging = m1_held;
resizing = m2_held;
int midway_x = pointer->x + pointer->width/2; int midway_x = pointer->x + pointer->width/2;
int midway_y = pointer->y + pointer->height/2; int midway_y = pointer->y + pointer->height/2;
lock_bottom = origin->y < midway_y;
lock_top = !lock_bottom; pointer_state.floating.drag = pointer_state.l_held;
lock_right = origin->x < midway_x; pointer_state.floating.resize = pointer_state.r_held;
lock_left = !lock_right; 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 // Dont want pointer sent to window while dragging or resizing
return (dragging || resizing); return (pointer_state.floating.drag || pointer_state.floating.resize);
} }
return (pointer && pointer != focused); return (pointer && pointer != focused);
} else { } else {
sway_log(L_DEBUG, "Mouse button %u released", button); sway_log(L_DEBUG, "Mouse button %u released", button);
if (button == 272) { if (button == M_LEFT_CLICK) {
m1_held = false; pointer_state.l_held = false;
dragging = false; pointer_state.floating.drag = false;
} }
if (button == 273) { if (button == M_RIGHT_CLICK) {
m2_held = false; pointer_state.r_held = false;
resizing = false; pointer_state.floating.resize = false;
lock_top = lock_bottom = lock_left = lock_right = false; pointer_state.lock = (struct pointer_lock){false ,false ,false ,false};
} }
} }
return false; return false;

68
sway/input_state.c Normal file
View file

@ -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};
}

229
sway/ipc.c Normal file
View file

@ -0,0 +1,229 @@
// 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 "ipc.h"
#include "log.h"
#include "config.h"
#include "commands.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_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;
}
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;
}

View file

@ -33,8 +33,9 @@ void add_child(swayc_t *parent, swayc_t *child) {
child->width, child->height, parent, parent->type, parent->width, parent->height); child->width, child->height, parent, parent->type, parent->width, parent->height);
list_add(parent->children, child); list_add(parent->children, child);
child->parent = parent; child->parent = parent;
// set focus for this container
if (parent->children->length == 1) { if (parent->children->length == 1) {
parent->focused = child; set_focused_container_for(parent, child);
} }
} }
@ -45,7 +46,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) {
ws->focused = child; set_focused_container_for(ws, child);
} }
} }
@ -70,7 +71,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) {
child->parent->focused = new_child; set_focused_container_for(child->parent, new_child);
} }
child->parent = NULL; child->parent = NULL;
return parent; return parent;
@ -96,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->focused == child) {
if (parent->children->length > 0) { if (parent->children->length > 0) {
set_focused_container_for(parent, parent->children->items[i?i-1:0]); set_focused_container_for(parent, parent->children->items[i?i-1:0]);
@ -151,12 +152,12 @@ void arrange_windows(swayc_t *container, int width, int height) {
{ {
struct wlc_geometry geometry = { struct wlc_geometry geometry = {
.origin = { .origin = {
.x = container->x + container->gaps, .x = container->x + container->gaps / 2,
.y = container->y + container->gaps .y = container->y + container->gaps / 2
}, },
.size = { .size = {
.w = width - container->gaps * 2, .w = width - container->gaps,
.h = height - container->gaps * 2 .h = height - container->gaps
} }
}; };
if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
@ -185,40 +186,62 @@ void arrange_windows(swayc_t *container, int width, int height) {
break; break;
} }
double total_weight = 0; x = y = 0;
for (i = 0; i < container->children->length; ++i) { double scale = 0;
swayc_t *child = container->children->items[i];
total_weight += child->weight;
}
switch (container->layout) { switch (container->layout) {
case L_HORIZ: case L_HORIZ:
default: default:
sway_log(L_DEBUG, "Arranging %p horizontally", container); // Calculate total width
for (i = 0; i < container->children->length; ++i) { for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i]; int *old_width = &((swayc_t *)container->children->items[i])->width;
double percent = child->weight / total_weight; if (*old_width <= 0) {
sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); if (container->children->length > 1) {
child->x = x + container->x; *old_width = width / (container->children->length - 1);
child->y = y + container->y; } else {
int w = width * percent; *old_width = width;
int h = height; }
arrange_windows(child, w, h); }
x += w; 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; break;
case L_VERT: case L_VERT:
sway_log(L_DEBUG, "Arranging %p vertically", container); // Calculate total height
for (i = 0; i < container->children->length; ++i) { for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i]; int *old_height = &((swayc_t *)container->children->items[i])->height;
double percent = child->weight / total_weight; if (*old_height <= 0) {
sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); if (container->children->length > 1) {
child->x = x + container->x; *old_height = height / (container->children->length - 1);
child->y = y + container->y; } else {
int w = width; *old_height = height;
int h = height * percent; }
arrange_windows(child, w, h); }
y += h; 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; break;
} }
@ -297,3 +320,53 @@ swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) {
return NULL; 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;
}
}
}
}

View file

@ -1,10 +1,13 @@
#include "log.h" #include "log.h"
#include "sway.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <errno.h>
#include <string.h>
int colored = 1; int colored = 1;
int v = 0; int v = 0;
@ -19,10 +22,10 @@ static const char *verbosity_colors[] = {
void init_log(int verbosity) { void init_log(int verbosity) {
v = verbosity; v = verbosity;
/* set FD_CLOEXEC flag to prevent programs called with exec to write into logs */ /* 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 }; int fd[] = { STDOUT_FILENO, STDIN_FILENO, STDERR_FILENO };
for (i = 0; i < 3; ++i) { for (i = 0; i < 3; ++i) {
flag = fcntl(fd[i], F_GETFD); int flag = fcntl(fd[i], F_GETFD);
if (flag != -1) { if (flag != -1) {
fcntl(fd[i], F_SETFD, flag | FD_CLOEXEC); fcntl(fd[i], F_SETFD, flag | FD_CLOEXEC);
} }
@ -40,7 +43,7 @@ void sway_abort(const char *format, ...) {
vfprintf(stderr, format, args); vfprintf(stderr, format, args);
va_end(args); va_end(args);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
exit(1); sway_terminate();
} }
void sway_log(int verbosity, const char* format, ...) { void sway_log(int verbosity, const char* format, ...) {
@ -66,6 +69,34 @@ void sway_log(int verbosity, const char* format, ...) {
} }
} }
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, ...) { bool sway_assert(bool condition, const char* format, ...) {
if (condition) { if (condition) {
return true; return true;
@ -88,10 +119,10 @@ 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->is_focused ? 'F' : // Focused
c == active_workspace ? 'W' : //active workspace c == 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);
fprintf(stderr,"(p:%p)",c->parent); fprintf(stderr,"(p:%p)",c->parent);
fprintf(stderr,"(f:%p)",c->focused); fprintf(stderr,"(f:%p)",c->focused);
@ -114,7 +145,6 @@ static void container_log(const swayc_t *c) {
fprintf(stderr, "w:%d|h:%d|", c->width, c->height); fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
fprintf(stderr, "x:%d|y:%d|", c->x, c->y); fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
fprintf(stderr, "vis:%c|", c->visible?'t':'f'); fprintf(stderr, "vis:%c|", c->visible?'t':'f');
fprintf(stderr, "wgt:%d|", c->weight);
fprintf(stderr, "name:%.16s|", c->name); fprintf(stderr, "name:%.16s|", c->name);
fprintf(stderr, "children:%d\n",c->children?c->children->length:0); fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
} }

View file

@ -4,31 +4,121 @@
#include <wlc/wlc.h> #include <wlc/wlc.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <signal.h> #include <signal.h>
#include <getopt.h>
#include "layout.h" #include "layout.h"
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
#include "handlers.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); static void sigchld_handle(int signal);
int main(int argc, char **argv) { 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 handling */
signal(SIGCHLD, sigchld_handle); signal(SIGCHLD, sigchld_handle);
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;
} }
init_log(L_DEBUG); // TODO: Control this with command line arg char *config_path = NULL;
init_layout();
if (!load_config()) { int c;
sway_log(L_ERROR, "Error(s) loading config!"); 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;
}
} }
wlc_run(); 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(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);
}
ipc_terminate();
return 0; return 0;
} }

View file

@ -17,18 +17,22 @@ char *read_line(FILE *file) {
continue; continue;
} }
if (length == size) { if (length == size) {
string = realloc(string, size *= 2); char *new_string = realloc(string, size *= 2);
if (!string) { if (!new_string) {
free(string);
return NULL; return NULL;
} }
string = new_string;
} }
string[length++] = c; string[length++] = c;
} }
if (length + 1 == size) { if (length + 1 == size) {
string = realloc(string, length + 1); char *new_string = realloc(string, length + 1);
if (!string) { if (!new_string) {
free(string);
return NULL; return NULL;
} }
string = new_string;
} }
string[length] = '\0'; string[length] = '\0';
return string; return string;

View file

@ -47,7 +47,7 @@ char *workspace_next_name(void) {
continue; 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)) { if (workspace_find_by_name(target)) {
list_free(args); list_free(args);
continue; continue;
@ -183,7 +183,6 @@ void workspace_switch(swayc_t *workspace) {
return; return;
} }
sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
active_workspace = workspace;
set_focused_container(get_focused_view(workspace)); set_focused_container(get_focused_view(workspace));
arrange_windows(workspace, -1, -1); arrange_windows(workspace, -1, -1);
} }