This commit is contained in:
Half-Shot 2015-08-20 21:32:08 +01:00
commit 5a9ba261bc
26 changed files with 1493 additions and 570 deletions

1
.gitignore vendored
View file

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

View file

@ -3,7 +3,6 @@ project(sway C)
set(CMAKE_C_FLAGS "-g") set(CMAKE_C_FLAGS "-g")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/")
add_definitions("-Wall") add_definitions("-Wall")
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake)
find_package(XKBCommon REQUIRED) find_package(XKBCommon REQUIRED)

View file

@ -41,9 +41,12 @@ struct sway_config {
bool active; bool active;
bool failed; bool failed;
bool reloading; bool reloading;
int gaps_inner;
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,
}; };
@ -23,7 +23,7 @@ enum swayc_layouts{
L_STACKED, L_STACKED,
L_TABBED, L_TABBED,
L_FLOATING, L_FLOATING,
//Keep last // Keep last
L_LAYOUTS, L_LAYOUTS,
}; };
@ -45,10 +45,10 @@ struct sway_container {
bool is_floating; bool is_floating;
bool is_focused; bool is_focused;
int weight;
char *name; char *name;
int gaps;
list_t *children; list_t *children;
list_t *floating; list_t *floating;
@ -56,6 +56,7 @@ struct sway_container {
struct sway_container *focused; struct sway_container *focused;
}; };
// Container Creation
swayc_t *new_output(wlc_handle handle); swayc_t *new_output(wlc_handle handle);
swayc_t *new_workspace(swayc_t *output, const char *name); swayc_t *new_workspace(swayc_t *output, const char *name);
@ -66,18 +67,29 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle);
// Creates view as a new floating view which is in the active workspace // Creates view as a new floating view which is in the active workspace
swayc_t *new_floating_view(wlc_handle handle); swayc_t *new_floating_view(wlc_handle handle);
// Container Destroying
swayc_t *destroy_output(swayc_t *output); swayc_t *destroy_output(swayc_t *output);
// Destroys workspace if empty and returns parent pointer, else returns NULL // Destroys workspace if empty and returns parent pointer, else returns NULL
swayc_t *destroy_workspace(swayc_t *workspace); swayc_t *destroy_workspace(swayc_t *workspace);
// Destroyes container and all parent container if they are empty, returns
// topmost non-empty parent. returns NULL otherwise
swayc_t *destroy_container(swayc_t *container); swayc_t *destroy_container(swayc_t *container);
// Destroys view and all empty parent containers. return topmost non-empty
// parent
swayc_t *destroy_view(swayc_t *view); swayc_t *destroy_view(swayc_t *view);
// Container Lookup
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
// Mappings // Mappings
void set_view_visibility(swayc_t *view, void *data); void set_view_visibility(swayc_t *view, void *data);
void reset_gaps(swayc_t *view, void *data);
#endif #endif

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,12 +4,14 @@
#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;
void init_layout(void); void init_layout(void);
void add_child(swayc_t *parent, swayc_t *child); void add_child(swayc_t *parent, swayc_t *child);
void add_floating(swayc_t *ws, swayc_t *child);
// Returns parent container which needs to be rearranged. // Returns parent container which needs to be rearranged.
swayc_t *add_sibling(swayc_t *sibling, swayc_t *child); swayc_t *add_sibling(swayc_t *sibling, swayc_t *child);
swayc_t *replace_child(swayc_t *child, swayc_t *new_child); swayc_t *replace_child(swayc_t *child, swayc_t *new_child);
@ -28,5 +30,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

@ -1,5 +1,7 @@
#ifndef _SWAY_LOG_H #ifndef _SWAY_LOG_H
#define _SWAY_LOG_H #define _SWAY_LOG_H
#include <stdbool.h>
#include "container.h"
typedef enum { typedef enum {
L_SILENT = 0, L_SILENT = 0,
@ -10,7 +12,10 @@ 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, char* format, ...) __attribute__((format(printf,2,3))); void sway_log(int verbosity, const char* format, ...) __attribute__((format(printf,2,3)));
void sway_abort(char* format, ...)__attribute__((format(printf,1,2))); void sway_log_errno(int verbosity, char* format, ...) __attribute__((format(printf,2,3)));
void sway_abort(const char* format, ...) __attribute__((format(printf,1,2)));
bool sway_assert(bool condition, const char* format, ...) __attribute__((format(printf,2,3)));
void layout_log(const swayc_t *c, int depth);
#endif #endif

View file

@ -10,5 +10,6 @@ char *code_strchr(const char *string, char delimiter);
char *code_strstr(const char *haystack, const char *needle); char *code_strstr(const char *haystack, const char *needle);
int unescape_string(char *string); int unescape_string(char *string);
char *join_args(char **argv, int argc); char *join_args(char **argv, int argc);
char *join_list(list_t *list, char *separator);
#endif #endif

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

@ -15,6 +15,5 @@ void workspace_output_next();
void workspace_next(); void workspace_next();
void workspace_output_prev(); void workspace_output_prev();
void workspace_prev(); void workspace_prev();
void layout_log(const swayc_t *c, int depth);
#endif #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.
@ -76,13 +79,24 @@ Commands
**splitv**:: **splitv**::
Equivalent to **split vertical**. Equivalent to **split vertical**.
**fullscreen**: **floating_modifier** <modifier>::
When the _modifier_ key is held down, you may use left click to drag floating
windows, and right click to resize them.
**fullscreen**::
Toggles fullscreen status for the focused view. Toggles fullscreen status for the focused view.
**workspace** <name>: **gaps** <amount>::
Adds _amount_ pixels between each view, and around each output.
**gaps** <inner|outer> <amount>::
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.
**workspace** <name>::
Switches to the specified workspace. Switches to the specified workspace.
**workspace** <prev_on_output|next_on_output>: **workspace** <prev_on_output|next_on_output>::
Switches to the next workspace on the current output. Switches to the next workspace on the current output.
**workspace** <name> output <output>:: **workspace** <name> output <output>::

View file

@ -3,6 +3,7 @@
#include <wlc/wlc.h> #include <wlc/wlc.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <ctype.h> #include <ctype.h>
@ -14,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;
@ -75,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)) {
@ -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); xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], XKB_KEYSYM_CASE_INSENSITIVE);
if (!sym) { if (!sym) {
sway_log(L_ERROR, "bindsym - unknown key %s", (char *)split->items[i]); 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; return false;
} }
xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); 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); 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;
@ -166,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;
} }
@ -181,43 +202,28 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
if (view->type != C_VIEW) { if (view->type != C_VIEW) {
return true; return true;
} }
int i;
// Change from nonfloating to floating // Change from nonfloating to floating
if (!view->is_floating) { if (!view->is_floating) {
view->is_floating = true; // Remove view from its current location
for (i = 0; i < view->parent->children->length; i++) { destroy_container(remove_child(view));
if (view->parent->children->items[i] == view) {
// Try to use desired geometry to set w/h // and move it into workspace floating
if (view->desired_width != -1) { add_floating(active_workspace,view);
view->width = view->desired_width; view->x = (active_workspace->width - view->width)/2;
} view->y = (active_workspace->height - view->height)/2;
if (view->desired_height != -1) { if (view->desired_width != -1) {
view->height = view->desired_height; view->width = view->desired_width;
}
// 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;
}
} }
if (view->desired_height != -1) {
view->height = view->desired_height;
}
arrange_windows(active_workspace, -1, -1);
} else { } else {
// Delete the view from the floating list and unset its is_floating flag // Delete the view from the floating list and unset its is_floating flag
// Using length-1 as the index is safe because the view must be the currently // Using length-1 as the index is safe because the view must be the currently
// focused floating output // focused floating output
list_del(active_workspace->floating, active_workspace->floating->length - 1); remove_child(view);
view->is_floating = false; view->is_floating = false;
active_workspace->focused = NULL;
// Get the properly focused container, and add in the view there // Get the properly focused container, and add in the view there
swayc_t *focused = container_under_pointer(); swayc_t *focused = container_under_pointer();
// If focused is null, it's because the currently focused container is a workspace // If focused is null, it's because the currently focused container is a workspace
@ -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); 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
set_focused_container(view); view->width = view->height = 0;
arrange_windows(active_workspace, -1, -1); arrange_windows(active_workspace, -1, -1);
return true;
} }
set_focused_container(view);
} }
return true; 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)) { if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
return false; 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; return true;
} }
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;
} }
@ -268,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;
} }
@ -303,6 +363,42 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) {
return true; 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) { 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; return false;
} }
swayc_t *parent = get_focused_container(&root_container); swayc_t *parent = get_focused_container(&root_container);
while (parent->type == C_VIEW) { while (parent->type == C_VIEW) {
parent = parent->parent; 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)) { 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);
@ -435,14 +530,12 @@ 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) { container = swayc_parent_by_type(container, C_WORKSPACE);
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;
@ -508,6 +601,7 @@ static struct cmd_handler handlers[] = {
{ "focus", cmd_focus }, { "focus", cmd_focus },
{ "focus_follows_mouse", cmd_focus_follows_mouse }, { "focus_follows_mouse", cmd_focus_follows_mouse },
{ "fullscreen", cmd_fullscreen }, { "fullscreen", cmd_fullscreen },
{ "gaps", cmd_gaps },
{ "kill", cmd_kill }, { "kill", cmd_kill },
{ "layout", cmd_layout }, { "layout", cmd_layout },
{ "log_colors", cmd_log_colors }, { "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); 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

@ -8,6 +8,7 @@
#include "log.h" #include "log.h"
#include "commands.h" #include "commands.h"
#include "config.h" #include "config.h"
#include "layout.h"
struct sway_config *config; struct sway_config *config;
@ -15,121 +16,143 @@ static bool exists(const char *path) {
return access(path, R_OK) != -1; return access(path, R_OK) != -1;
} }
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;
}
void free_mode(struct sway_mode *mode) {
free(mode->name);
free_flat_list(mode->bindings);
}
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]);
}
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);
}
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);
}
static const char *search_paths[] = {
"$home/.sway/config",
"$config/sway/config",
"/etc/sway/config",
"$home/.i3/config",
"$config/.i3/config",
"/etc/i3/config"
};
static char *get_config_path() { static char *get_config_path() {
char *name = "/.sway/config"; char *home = getenv("HOME");
const char *home = getenv("HOME"); if (home) {
home = strdup(getenv("HOME"));
// 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;
} }
char *config = getenv("XDG_CONFIG_HOME");
// Check XDG_CONFIG_HOME with fallback to ~/.config/ if (config) {
sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_HOME/sway/config"); config = strdup(getenv("XDG_CONFIG_HOME"));
char *xdg_config_home = getenv("XDG_CONFIG_HOME"); } else if (home) {
if (xdg_config_home == NULL) { const char *def = "/.config";
sway_log(L_DEBUG, "Falling back to ~/.config/sway/config"); config = malloc(strlen(home) + strlen(def) + 1);
name = "/.config/sway/config"; strcpy(config, home);
temp = malloc(strlen(home) + strlen(name) + 1); strcat(config, def);
strcpy(temp, home);
strcat(temp, name);
} else { } else {
name = "/sway/config"; home = strdup("");
temp = malloc(strlen(xdg_config_home) + strlen(name) + 1); config = strdup("");
strcpy(xdg_config_home, home);
strcat(temp, name);
}
if (exists(temp)) {
return temp;
} }
// Check /etc/ // Set up a temporary config for holding set variables
sway_log(L_DEBUG, "Trying to find config in /etc/sway/config"); struct sway_config *temp_config = malloc(sizeof(struct sway_config));
strcpy(temp, "/etc/sway/config"); config_defaults(temp_config);
if (exists(temp)) { const char *set_home = "set $home ";
return temp; 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;
} }
// Check XDG_CONFIG_DIRS
sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS"); sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS"); char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS");
if (xdg_config_dirs != NULL) { if (xdg_config_dirs != NULL) {
list_t *paths = split_string(xdg_config_dirs, ":"); list_t *paths = split_string(xdg_config_dirs, ":");
name = "/sway/config"; char *name = "/sway/config";
int i; int i;
for (i = 0; i < paths->length; i++ ) { for (i = 0; i < paths->length; i++ ) {
temp = malloc(strlen(paths->items[i]) + strlen(name) + 1); test = malloc(strlen(paths->items[i]) + strlen(name) + 1);
strcpy(temp, paths->items[i]); strcpy(test, paths->items[i]);
strcat(temp, name); strcat(test, name);
if (exists(temp)) { if (exists(test)) {
free_flat_list(paths); free_flat_list(paths);
return temp; return test;
} }
free(test);
test = NULL;
} }
free_flat_list(paths); free_flat_list(paths);
} }
//Now fall back to i3 paths and try the same thing _continue:
name = "/.i3/config"; free_config(temp_config);
sway_log(L_DEBUG, "Trying to find config in ~/.i3/config"); free(home);
temp = malloc(strlen(home) + strlen(name) + 1); free(config);
strcpy(temp, home); return test;
strcat(temp, name);
if (exists(temp)) {
return temp;
}
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);
} 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;
}
sway_log(L_DEBUG, "Trying to find config in /etc/i3/config");
strcpy(temp, "/etc/i3/config");
if (exists(temp)) {
return temp;
}
sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
if (xdg_config_dirs != NULL) {
list_t *paths = split_string(xdg_config_dirs, ":");
name = "/i3/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);
}
return NULL;
} }
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!");
@ -155,23 +178,6 @@ bool load_config(void) {
return config_load_success; 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) { bool read_config(FILE *file, bool is_active) {
struct sway_config *temp_config = malloc(sizeof(struct sway_config)); struct sway_config *temp_config = malloc(sizeof(struct sway_config));
config_defaults(temp_config); config_defaults(temp_config);
@ -188,8 +194,8 @@ bool read_config(FILE *file, bool is_active) {
while (!feof(file)) { while (!feof(file)) {
int _; int _;
char *line = read_line(file); char *line = read_line(file);
line = strip_comments(line);
line = strip_whitespace(line, &_); line = strip_whitespace(line, &_);
line = strip_comments(line);
if (!line[0]) { if (!line[0]) {
goto _continue; goto _continue;
} }
@ -225,6 +231,8 @@ _continue:
if (is_active) { if (is_active) {
temp_config->reloading = false; temp_config->reloading = false;
container_map(&root_container, reset_gaps, NULL);
arrange_windows(&root_container, -1, -1);
} }
config = temp_config; config = temp_config;

View file

@ -8,53 +8,57 @@
#include "layout.h" #include "layout.h"
#include "log.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) { static swayc_t *new_swayc(enum swayc_types type) {
swayc_t *c = calloc(1, sizeof(swayc_t)); swayc_t *c = calloc(1, sizeof(swayc_t));
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();
} }
return c; 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 does not properly handle containers with children,
// TODO but functions that call this usually check for that // TODO but functions that call this usually check for that
if (c->children) { if (cont->children) {
if (c->children->length) { if (cont->children->length) {
int i; int i;
for (i = 0; i < c->children->length; ++i) { for (i = 0; i < cont->children->length; ++i) {
free_swayc(c->children->items[i]); free_swayc(cont->children->items[i]);
} }
} }
list_free(c->children); list_free(cont->children);
} }
if (c->floating) { if (cont->floating) {
if (c->floating->length) { if (cont->floating->length) {
int i; int i;
for (i = 0; i < c->floating->length; ++i) { for (i = 0; i < cont->floating->length; ++i) {
free_swayc(c->floating->items[i]); free_swayc(cont->floating->items[i]);
} }
} }
list_free(c->floating); list_free(cont->floating);
} }
if (c->parent) { if (cont->parent) {
remove_child(c); remove_child(cont);
} }
if (c->name) { if (cont->name) {
free(c->name); free(cont->name);
} }
free(c); free(cont);
} }
/* 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,6 +71,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 + config->gaps_inner / 2;
add_child(&root_container, output); 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); 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;
} }
@ -101,10 +108,15 @@ swayc_t *new_output(wlc_handle handle) {
} }
swayc_t *new_workspace(swayc_t *output, const char *name) { 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); sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
swayc_t *workspace = new_swayc(C_WORKSPACE); swayc_t *workspace = new_swayc(C_WORKSPACE);
workspace->layout = L_HORIZ; // TODO: default layout workspace->layout = L_HORIZ; // TODO: default layout
workspace->x = output->x;
workspace->y = output->y;
workspace->width = output->width; workspace->width = output->width;
workspace->height = output->height; workspace->height = output->height;
workspace->name = strdup(name); 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) { swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
if (!ASSERT_NONNULL(child)) {
return NULL;
}
swayc_t *cont = new_swayc(C_CONTAINER); swayc_t *cont = new_swayc(C_CONTAINER);
sway_log(L_DEBUG, "creating container %p around %p", cont, child); 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 // 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) {
@ -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) { swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
if (!ASSERT_NONNULL(sibling)) {
return NULL;
}
const char *title = wlc_view_get_title(handle); const char *title = wlc_view_get_title(handle);
swayc_t *view = new_swayc(C_VIEW); swayc_t *view = new_swayc(C_VIEW);
sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d", 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->name = title ? strdup(title) : NULL;
view->visible = true; view->visible = true;
view->is_focused = 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->gaps = config->gaps_inner;
view->desired_height = -1;
// TODO: properly set this
view->is_floating = false; view->is_floating = false;
if (sibling->type == C_WORKSPACE) { if (sibling->type == C_WORKSPACE) {
@ -196,8 +219,9 @@ 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);
view->x = geometry->origin.x; // give it requested geometry, but place in center
view->y = geometry->origin.y; view->x = (active_workspace->width - geometry->size.w) / 2;
view->y = (active_workspace->height- geometry->size.h) / 2;
view->width = geometry->size.w; view->width = geometry->size.w;
view->height = geometry->size.h; view->height = geometry->size.h;
@ -215,9 +239,12 @@ swayc_t *new_floating_view(wlc_handle handle) {
return view; return view;
} }
/* Destroy container */ // Destroy container
swayc_t *destroy_output(swayc_t *output) { swayc_t *destroy_output(swayc_t *output) {
if (!ASSERT_NONNULL(output)) {
return NULL;
}
if (output->children->length == 0) { if (output->children->length == 0) {
// TODO move workspaces to other outputs // TODO move workspaces to other outputs
} }
@ -227,23 +254,21 @@ swayc_t *destroy_output(swayc_t *output) {
} }
swayc_t *destroy_workspace(swayc_t *workspace) { swayc_t *destroy_workspace(swayc_t *workspace) {
if (!ASSERT_NONNULL(workspace)) {
return NULL;
}
// NOTE: This is called from elsewhere without checking children length // NOTE: This is called from elsewhere without checking children length
// TODO move containers to other workspaces? // TODO move containers to other workspaces?
// for now just dont delete // for now just dont delete
// Do not destroy this if it's the last workspace on this output // Do not destroy this if it's the last workspace on this output
swayc_t *output = workspace->parent; swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
while (output && output->type != C_OUTPUT) { if (output && output->children->length == 1) {
output = output->parent; return NULL;
}
if (output) {
if (output->children->length == 1) {
return NULL;
}
} }
if (workspace->children->length == 0) { 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; swayc_t *parent = workspace->parent;
free_swayc(workspace); free_swayc(workspace);
return parent; return parent;
@ -252,19 +277,20 @@ swayc_t *destroy_workspace(swayc_t *workspace) {
} }
swayc_t *destroy_container(swayc_t *container) { swayc_t *destroy_container(swayc_t *container) {
if (!ASSERT_NONNULL(container)) {
return NULL;
}
while (container->children->length == 0 && container->type == C_CONTAINER) { while (container->children->length == 0 && container->type == C_CONTAINER) {
sway_log(L_DEBUG, "Container: Destroying container '%p'", container); sway_log(L_DEBUG, "Container: Destroying container '%p'", container);
swayc_t *parent = container->parent; swayc_t *parent = container->parent;
free_swayc(container); free_swayc(container);
container = parent; container = parent;
} }
return container; return container;
} }
swayc_t *destroy_view(swayc_t *view) { swayc_t *destroy_view(swayc_t *view) {
if (view == NULL) { if (!ASSERT_NONNULL(view)) {
sway_log(L_DEBUG, "Warning: NULL passed into destroy_view");
return NULL; return NULL;
} }
sway_log(L_DEBUG, "Destroying view '%p'", view); sway_log(L_DEBUG, "Destroying view '%p'", view);
@ -278,6 +304,34 @@ swayc_t *destroy_view(swayc_t *view) {
return parent; 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) { swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) {
if (!container->children) { if (!container->children) {
return NULL; 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) { void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
if (!container || !container->children || !container->children->length) { if (container && container->children && container->children->length) {
return; int i;
} for (i = 0; i < container->children->length; ++i) {
int i; swayc_t *child = container->children->items[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); f(child, data);
container_map(child, f, 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) { void set_view_visibility(swayc_t *view, void *data) {
if (!ASSERT_NONNULL(view)) {
return;
}
uint32_t *p = data; uint32_t *p = data;
if (view->type == C_VIEW) { if (view->type == C_VIEW) {
wlc_view_set_mask(view->handle, *p); wlc_view_set_mask(view->handle, *p);
@ -337,3 +393,15 @@ void set_view_visibility(swayc_t *view, void *data) {
} }
view->visible = (*p == 2); 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;
}
}

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) {
@ -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 // 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 *focused = get_focused_view(&root_container);
swayc_t *workspace = active_workspace; swayc_t *workspace = active_workspace;
if (focused == get_focused_view(c)) {
return;
}
// update container focus from here to root, making necessary changes along // update container focus from here to root, making necessary changes along
// the way // the way
swayc_t *p = c; swayc_t *p = c;
if (p->type != C_OUTPUT && p->type != C_ROOT) {
p->is_focused = true;
}
while (p != &root_container) { while (p != &root_container) {
update_focus(p); update_focus(p);
p = p->parent; p = p->parent;
@ -171,8 +117,11 @@ 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_focus(p->handle);
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
if (!locked_view_focus) {
wlc_view_focus(p->handle);
}
} }
} }
} }

View file

@ -13,21 +13,14 @@
#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];
static struct wlc_origin mouse_origin; 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) { 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
swayc_t *parent = view; swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
while (parent->type != C_OUTPUT) {
parent = parent->parent;
}
if (origin->x >= view->x && origin->y >= view->y if (origin->x >= view->x && origin->y >= view->y
&& origin->x < view->x + view->width && origin->y < view->y + view->height && origin->x < view->x + view->width && origin->y < view->y + view->height
&& view->visible && parent == root_container.focused) { && view->visible && parent == root_container.focused) {
@ -86,10 +79,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);
@ -111,7 +106,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);
} }
} }
@ -137,38 +132,64 @@ static void handle_output_focused(wlc_handle output, bool focus) {
} }
static bool handle_view_created(wlc_handle handle) { 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; 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)) { switch (wlc_view_get_type(handle)) {
// regular view created regularly // regular view created regularly
case 0: case 0:
newview = new_view(focused, handle); newview = new_view(focused, handle);
wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true);
break; break;
// takes keyboard focus
// Dmenu keeps viewfocus, but others with this flag dont, for now simulate
// dmenu
case WLC_BIT_OVERRIDE_REDIRECT: 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_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);
break; break;
// Takes container focus
// Firefox popups have this flag set.
case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: 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); wlc_view_bring_to_front(handle);
locked_container_focus = true; locked_container_focus = true;
break; break;
// set modals as floating containers
// Modals, get focus, popups do not
case WLC_BIT_MODAL: case WLC_BIT_MODAL:
wlc_view_focus(handle);
wlc_view_bring_to_front(handle); wlc_view_bring_to_front(handle);
newview = new_floating_view(handle); newview = new_floating_view(handle);
case WLC_BIT_POPUP: case WLC_BIT_POPUP:
wlc_view_bring_to_front(handle);
break; break;
} }
if (newview) { if (newview) {
set_focused_container(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; return true;
} }
@ -181,19 +202,19 @@ static void handle_view_destroyed(wlc_handle handle) {
// regular view created regularly // regular view created regularly
case 0: case 0:
case WLC_BIT_MODAL: case WLC_BIT_MODAL:
case WLC_BIT_POPUP:
if (view) { if (view) {
swayc_t *parent = destroy_view(view); swayc_t *parent = destroy_view(view);
arrange_windows(parent, -1, -1); arrange_windows(parent, -1, -1);
} }
break; break;
// takes keyboard focus // DMENU has this flag, and takes view_focus, but other things with this
// flag dont
case WLC_BIT_OVERRIDE_REDIRECT: case WLC_BIT_OVERRIDE_REDIRECT:
locked_view_focus = false; // locked_view_focus = false;
break; break;
// Takes container focus
case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
locked_container_focus = false; locked_container_focus = false;
case WLC_BIT_POPUP:
break; break;
} }
set_focused_container(get_focused_view(&root_container)); 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) { 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
@ -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) { 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) {
swayc_t *ws = c; swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE);
while (ws->type != C_WORKSPACE) {
ws = ws->parent;
}
// Set ws focus to c // Set ws focus to c
set_focused_container_for(ws, 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_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;
@ -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, 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;
} }
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; 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 < 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));
}
// 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];
@ -287,39 +315,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 < head; ++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 < head; ++k) {
memmove(keys_pressed + k, keys_pressed + k + 1, sizeof*keys_pressed * (--head - k));
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) {
@ -327,119 +338,129 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
static wlc_handle prev_handle = 0; static wlc_handle prev_handle = 0;
mouse_origin = *origin; mouse_origin = *origin;
bool changed_floating = false; bool changed_floating = false;
int i = 0;
if (!active_workspace) { if (!active_workspace) {
return false; return false;
} }
// Do checks to determine if proper keys are being held // Do checks to determine if proper keys are being held
swayc_t *view = active_workspace->focused; swayc_t *view = get_focused_view(active_workspace);
if (m1_held && view) { uint32_t edge = 0;
if (pointer_state.floating.drag && view) {
if (view->is_floating) { if (view->is_floating) {
while (keys_pressed[i++]) { int dx = mouse_origin.x - prev_pos.x;
if (keys_pressed[i] == config->floating_mod) { int dy = mouse_origin.y - prev_pos.y;
int dx = mouse_origin.x - prev_pos.x; view->x += dx;
int dy = mouse_origin.y - prev_pos.y; view->y += dy;
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); changed_floating = true;
sway_log(L_DEBUG, "Moving: dx: %d, dy: %d", dx, dy); }
} else if (pointer_state.floating.resize && view) {
if (view->is_floating) {
int dx = mouse_origin.x - prev_pos.x;
int dy = mouse_origin.y - prev_pos.y;
int min_sane_w = 100;
int min_sane_h = 60;
view->x += dx; // Move and resize the view based on the dx/dy and mouse position
view->y += dy; int midway_x = view->x + view->width/2;
int midway_y = view->y + view->height/2;
if (dx < 0) {
if (!pointer_state.lock.right) {
if (view->width > min_sane_w) {
changed_floating = true;
view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT;
}
} else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
changed_floating = true; changed_floating = true;
break; view->x += dx;
view->width -= dx;
edge += WLC_RESIZE_EDGE_LEFT;
}
} else if (dx > 0) {
if (mouse_origin.x > midway_x && !pointer_state.lock.right) {
changed_floating = true;
view->width += dx;
edge += WLC_RESIZE_EDGE_RIGHT;
} else if (!pointer_state.lock.left) {
if (view->width > min_sane_w) {
changed_floating = true;
view->x += dx;
view->width -= dx;
edge += WLC_RESIZE_EDGE_LEFT;
}
} }
} }
}
} else if (m2_held && 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 if (dy < 0) {
int midway_x = view->x + view->width/2; if (!pointer_state.lock.bottom) {
int midway_y = view->y + view->height/2; if (view->height > min_sane_h) {
if (dx < 0) {
changed_floating = true; changed_floating = true;
if (mouse_origin.x > midway_x) { view->height += dy;
sway_log(L_INFO, "Downsizing view to the left"); edge += WLC_RESIZE_EDGE_BOTTOM;
view->width += dx;
} else {
sway_log(L_INFO, "Upsizing view to the left");
view->x += dx;
view->width -= dx;
}
} else if (dx > 0){
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;
}
} }
} else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
if (dy < 0) { 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; changed_floating = true;
if (mouse_origin.y > midway_y) { view->y += dy;
sway_log(L_INFO, "Downsizing view to the top"); view->height -= dy;
view->height += dy; edge += WLC_RESIZE_EDGE_TOP;
} else {
sway_log(L_INFO, "Upsizing the view to the top");
view->y += dy;
view->height -= dy;
}
} else if (dy > 0) {
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;
}
} }
break;
} }
} }
} }
} }
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)) { 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());
} }
} }
prev_handle = handle; prev_handle = handle;
prev_pos = mouse_origin; prev_pos = mouse_origin;
if (changed_floating) { 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 true;
} }
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) { 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);
@ -453,15 +474,32 @@ 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) {
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); 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;
pointer_state.floating.drag = false;
} }
if (button == 273) { if (button == M_RIGHT_CLICK) {
m2_held = false; pointer_state.r_held = false;
pointer_state.floating.resize = 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};
}

321
sway/ipc.c Normal file
View file

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

View file

@ -4,6 +4,7 @@
#include "layout.h" #include "layout.h"
#include "log.h" #include "log.h"
#include "list.h" #include "list.h"
#include "config.h"
#include "container.h" #include "container.h"
#include "workspace.h" #include "workspace.h"
#include "focus.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); 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) {
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) { 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; 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;
@ -72,6 +88,7 @@ swayc_t *remove_child(swayc_t *child) {
break; break;
} }
} }
i = 0;
} else { } else {
for (i = 0; i < parent->children->length; ++i) { for (i = 0; i < parent->children->length; ++i) {
if (parent->children->items[i] == child) { 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->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]);
@ -104,7 +121,7 @@ void move_container(swayc_t *container,swayc_t* root,int direction){
//Only one container, meh. //Only one container, meh.
break; break;
} }
//TODO: Implement horizontal movement.
//TODO: Implement move to a different workspace. //TODO: Implement move to a different workspace.
if(direction == MOVE_LEFT && i > 0){ if(direction == MOVE_LEFT && i > 0){
temp = root->children->items[i-1]; temp = root->children->items[i-1];
@ -167,11 +184,11 @@ void arrange_windows(swayc_t *container, int width, int height) {
// y -= container->y; // y -= container->y;
for (i = 0; i < container->children->length; ++i) { for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i]; swayc_t *child = container->children->items[i];
sway_log(L_DEBUG, "Arranging workspace #%d", i); child->x = x + container->gaps;
child->x = x; child->y = y + container->gaps;
child->y = y; child->width = width - container->gaps * 2;
child->width = width; child->height = height - container->gaps * 2;
child->height = height; sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y);
arrange_windows(child, -1, -1); arrange_windows(child, -1, -1);
} }
return; return;
@ -179,27 +196,24 @@ void arrange_windows(swayc_t *container, int width, int height) {
{ {
struct wlc_geometry geometry = { struct wlc_geometry geometry = {
.origin = { .origin = {
.x = container->x, .x = container->x + container->gaps / 2,
.y = container->y .y = container->y + container->gaps / 2
}, },
.size = { .size = {
.w = width, .w = width - container->gaps,
.h = height .h = height - container->gaps
} }
}; };
if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
swayc_t *parent = container; swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
while (parent->type != C_OUTPUT) {
parent = parent->parent;
}
geometry.origin.x = 0; geometry.origin.x = 0;
geometry.origin.y = 0; geometry.origin.y = 0;
geometry.size.w = parent->width; geometry.size.w = parent->width;
geometry.size.h = parent->height; 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); wlc_view_bring_to_front(container->handle);
} else { } else {
wlc_view_set_geometry(container->handle, &geometry); wlc_view_set_geometry(container->handle, 0, &geometry);
container->width = width; container->width = width;
container->height = height; container->height = height;
} }
@ -213,40 +227,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;
} }
@ -268,20 +304,15 @@ void arrange_windows(swayc_t *container, int width, int height) {
} }
}; };
if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) {
swayc_t *parent = view; swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
while (parent->type != C_OUTPUT) {
parent = parent->parent;
}
geometry.origin.x = 0; geometry.origin.x = 0;
geometry.origin.y = 0; geometry.origin.y = 0;
geometry.size.w = parent->width; geometry.size.w = parent->width;
geometry.size.h = parent->height; 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); wlc_view_bring_to_front(view->handle);
} else { } else {
wlc_view_set_geometry(view->handle, &geometry); wlc_view_set_geometry(view->handle, 0, &geometry);
view->width = width;
view->height = height;
// Bring the views to the front in order of the list, the list // 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 // will be kept up to date so that more recently focused views
// have higher indexes // have higher indexes
@ -326,3 +357,54 @@ 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,9 +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 <errno.h>
#include <string.h>
int colored = 1; int colored = 1;
int v = 0; int v = 0;
@ -18,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);
} }
@ -32,17 +36,17 @@ void sway_log_colors(int mode) {
colored = (mode == 1) ? 1 : 0; colored = (mode == 1) ? 1 : 0;
} }
void sway_abort(char *format, ...) { void sway_abort(const char *format, ...) {
fprintf(stderr, "ERROR: "); fprintf(stderr, "ERROR: ");
va_list args; va_list args;
va_start(args, format); va_start(args, 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, char* format, ...) { void sway_log(int verbosity, const char* format, ...) {
if (verbosity <= v) { if (verbosity <= v) {
int c = verbosity; int c = verbosity;
if (c > sizeof(verbosity_colors) / sizeof(char *)) { if (c > sizeof(verbosity_colors) / sizeof(char *)) {
@ -64,3 +68,106 @@ void sway_log(int verbosity, char* format, ...) {
fprintf(stderr, "\n"); 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 */

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

@ -4,6 +4,7 @@
#include "string.h" #include "string.h"
#include "list.h" #include "list.h"
#include <strings.h> #include <strings.h>
#include <log.h>
/* Note: This returns 8 characters for trimmed_start per tab character. */ /* Note: This returns 8 characters for trimmed_start per tab character. */
char *strip_whitespace(char *_str, int *trimmed_start) { char *strip_whitespace(char *_str, int *trimmed_start) {
@ -197,3 +198,41 @@ char *join_args(char **argv, int argc) {
res[len - 1] = '\0'; res[len - 1] = '\0';
return res; 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;
}

View file

@ -31,7 +31,7 @@ char *workspace_next_name(void) {
char* target = malloc(strlen(args->items[1]) + 1); char* target = malloc(strlen(args->items[1]) + 1);
strcpy(target, args->items[1]); strcpy(target, args->items[1]);
while (*target == ' ' || *target == '\t') while (*target == ' ' || *target == '\t')
target++; target++;
// Make sure that the command references an actual workspace // Make sure that the command references an actual workspace
// not a command about workspaces // not a command about workspaces
@ -42,11 +42,15 @@ char *workspace_next_name(void) {
strcmp(target, "number") == 0 || strcmp(target, "number") == 0 ||
strcmp(target, "back_and_forth") == 0 || strcmp(target, "back_and_forth") == 0 ||
strcmp(target, "current") == 0) strcmp(target, "current") == 0)
{
list_free(args);
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)) {
continue; list_free(args);
continue;
} }
list_free(args); list_free(args);
@ -54,6 +58,7 @@ char *workspace_next_name(void) {
sway_log(L_DEBUG, "Workspace: Found free name %s", target); sway_log(L_DEBUG, "Workspace: Found free name %s", target);
return target; return target;
} }
list_free(args);
} }
// As a fall back, get the current number of active workspaces // As a fall back, get the current number of active workspaces
// and return that + 1 for the next workspace's name // 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 *workspace_create(const char* name) {
swayc_t *parent = get_focused_container(&root_container); swayc_t *parent = get_focused_container(&root_container);
while (parent->type != C_OUTPUT) { parent = swayc_parent_by_type(parent, C_OUTPUT);
parent = parent->parent;
}
return new_workspace(parent, name); return new_workspace(parent, name);
} }
bool workspace_by_name(swayc_t *view, void *data) { bool workspace_by_name(swayc_t *view, void *data) {
return (view->type == C_WORKSPACE) && return (view->type == C_WORKSPACE) &&
(strcasecmp(view->name, (char *) data) == 0); (strcasecmp(view->name, (char *) data) == 0);
} }
@ -180,62 +183,4 @@ void workspace_switch(swayc_t *workspace) {
sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
set_focused_container(get_focused_view(workspace)); set_focused_container(get_focused_view(workspace));
arrange_windows(workspace, -1, -1); 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 */