summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Half-Shot <half-shot@molrams.com>2015-08-20 21:32:08 +0100
committerLibravatar Half-Shot <half-shot@molrams.com>2015-08-20 21:32:08 +0100
commit5a9ba261bca4ca709ec7a14d2019b55d9ce06994 (patch)
treefe1a924cf8055b2b722566db6ab98295dcf08ce7
parentBasic left right move command implemented. (diff)
parentMerge pull request #104 from minus7/ipc-get-messages (diff)
downloadsway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.tar.gz
sway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.tar.zst
sway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.zip
Merge branch 'master' of https://github.com/SirCmpwn/sway
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/config.h5
-rw-r--r--include/container.h20
-rw-r--r--include/focus.h4
-rw-r--r--include/input_state.h49
-rw-r--r--include/ipc.h18
-rw-r--r--include/layout.h3
-rw-r--r--include/log.h9
-rw-r--r--include/stringop.h1
-rw-r--r--include/sway.h6
-rw-r--r--include/workspace.h1
-rw-r--r--sway.5.txt30
-rw-r--r--sway/commands.c186
-rw-r--r--sway/config.c218
-rw-r--r--sway/container.c166
-rw-r--r--sway/focus.c87
-rw-r--r--sway/handlers.c326
-rw-r--r--sway/input_state.c68
-rw-r--r--sway/ipc.c321
-rw-r--r--sway/layout.c186
-rw-r--r--sway/log.c117
-rw-r--r--sway/main.c96
-rw-r--r--sway/readline.c12
-rw-r--r--sway/stringop.c39
-rw-r--r--sway/workspace.c77
26 files changed, 1485 insertions, 562 deletions
diff --git a/.gitignore b/.gitignore
index b7b3266c..cf23d168 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ bin/
9test/ 9test/
10build/ 10build/
11.lvimrc 11.lvimrc
12config-debug
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ba2f8be3..d190cd8b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,6 @@ project(sway C)
3set(CMAKE_C_FLAGS "-g") 3set(CMAKE_C_FLAGS "-g")
4set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/") 4set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/")
5add_definitions("-Wall") 5add_definitions("-Wall")
6set(CMAKE_BUILD_TYPE Debug)
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake) 6set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake)
8 7
9find_package(XKBCommon REQUIRED) 8find_package(XKBCommon REQUIRED)
diff --git a/include/config.h b/include/config.h
index 9243bf35..c23c3509 100644
--- a/include/config.h
+++ b/include/config.h
@@ -41,9 +41,12 @@ struct sway_config {
41 bool active; 41 bool active;
42 bool failed; 42 bool failed;
43 bool reloading; 43 bool reloading;
44
45 int gaps_inner;
46 int gaps_outer;
44}; 47};
45 48
46bool load_config(void); 49bool load_config(const char *file);
47bool read_config(FILE *file, bool is_active); 50bool read_config(FILE *file, bool is_active);
48char *do_var_replacement(struct sway_config *config, char *str); 51char *do_var_replacement(struct sway_config *config, char *str);
49 52
diff --git a/include/container.h b/include/container.h
index 63529e44..79e023fe 100644
--- a/include/container.h
+++ b/include/container.h
@@ -11,7 +11,7 @@ enum swayc_types{
11 C_WORKSPACE, 11 C_WORKSPACE,
12 C_CONTAINER, 12 C_CONTAINER,
13 C_VIEW, 13 C_VIEW,
14 //Keep last 14 // Keep last
15 C_TYPES, 15 C_TYPES,
16}; 16};
17 17
@@ -23,7 +23,7 @@ enum swayc_layouts{
23 L_STACKED, 23 L_STACKED,
24 L_TABBED, 24 L_TABBED,
25 L_FLOATING, 25 L_FLOATING,
26 //Keep last 26 // Keep last
27 L_LAYOUTS, 27 L_LAYOUTS,
28}; 28};
29 29
@@ -45,10 +45,10 @@ struct sway_container {
45 bool is_floating; 45 bool is_floating;
46 bool is_focused; 46 bool is_focused;
47 47
48 int weight;
49
50 char *name; 48 char *name;
51 49
50 int gaps;
51
52 list_t *children; 52 list_t *children;
53 list_t *floating; 53 list_t *floating;
54 54
@@ -56,6 +56,7 @@ struct sway_container {
56 struct sway_container *focused; 56 struct sway_container *focused;
57}; 57};
58 58
59// Container Creation
59 60
60swayc_t *new_output(wlc_handle handle); 61swayc_t *new_output(wlc_handle handle);
61swayc_t *new_workspace(swayc_t *output, const char *name); 62swayc_t *new_workspace(swayc_t *output, const char *name);
@@ -66,18 +67,29 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle);
66// Creates view as a new floating view which is in the active workspace 67// Creates view as a new floating view which is in the active workspace
67swayc_t *new_floating_view(wlc_handle handle); 68swayc_t *new_floating_view(wlc_handle handle);
68 69
70// Container Destroying
69 71
70swayc_t *destroy_output(swayc_t *output); 72swayc_t *destroy_output(swayc_t *output);
71// Destroys workspace if empty and returns parent pointer, else returns NULL 73// Destroys workspace if empty and returns parent pointer, else returns NULL
72swayc_t *destroy_workspace(swayc_t *workspace); 74swayc_t *destroy_workspace(swayc_t *workspace);
75// Destroyes container and all parent container if they are empty, returns
76// topmost non-empty parent. returns NULL otherwise
73swayc_t *destroy_container(swayc_t *container); 77swayc_t *destroy_container(swayc_t *container);
78// Destroys view and all empty parent containers. return topmost non-empty
79// parent
74swayc_t *destroy_view(swayc_t *view); 80swayc_t *destroy_view(swayc_t *view);
75 81
82// Container Lookup
83
84swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
85swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
86
76swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); 87swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
77void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); 88void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
78 89
79 90
80// Mappings 91// Mappings
81void set_view_visibility(swayc_t *view, void *data); 92void set_view_visibility(swayc_t *view, void *data);
93void reset_gaps(swayc_t *view, void *data);
82 94
83#endif 95#endif
diff --git a/include/focus.h b/include/focus.h
index 410ed134..383993fa 100644
--- a/include/focus.h
+++ b/include/focus.h
@@ -1,7 +1,5 @@
1#ifndef _SWAY_FOCUS_H 1#ifndef _SWAY_FOCUS_H
2#define _SWAY_FOCUS_H 2#define _SWAY_FOCUS_H
3#include "container.h"
4
5enum movement_direction { 3enum movement_direction {
6 MOVE_LEFT, 4 MOVE_LEFT,
7 MOVE_RIGHT, 5 MOVE_RIGHT,
@@ -10,6 +8,8 @@ enum movement_direction {
10 MOVE_PARENT 8 MOVE_PARENT
11}; 9};
12 10
11#include "container.h"
12
13// focused_container - the container found by following the `focused` pointer 13// focused_container - the container found by following the `focused` pointer
14// from a given container to a container with `is_focused` boolean set 14// from a given container to a container with `is_focused` boolean set
15// --- 15// ---
diff --git a/include/input_state.h b/include/input_state.h
new file mode 100644
index 00000000..782b4b19
--- /dev/null
+++ b/include/input_state.h
@@ -0,0 +1,49 @@
1#ifndef _SWAY_KEY_STATE_H
2#define _SWAY_KEY_STATE_H
3#include <stdbool.h>
4#include <stdint.h>
5#include "container.h"
6
7/* Keyboard state */
8
9typedef uint32_t keycode;
10
11// returns true if key has been pressed, otherwise false
12bool check_key(keycode key);
13
14// sets a key as pressed
15void press_key(keycode key);
16
17// unsets a key as pressed
18void release_key(keycode key);
19
20/* Pointer state */
21
22enum pointer_values {
23 M_LEFT_CLICK = 272,
24 M_RIGHT_CLICK = 273,
25 M_SCROLL_CLICK = 274,
26 M_SCROLL_UP = 275,
27 M_SCROLL_DOWN = 276,
28};
29
30extern struct pointer_state {
31 bool l_held;
32 bool r_held;
33 struct pointer_floating {
34 bool drag;
35 bool resize;
36 } floating;
37 struct pointer_lock {
38 bool left;
39 bool right;
40 bool top;
41 bool bottom;
42 } lock;
43} pointer_state;
44
45void start_floating(swayc_t *view);
46void reset_floating(swayc_t *view);
47
48#endif
49
diff --git a/include/ipc.h b/include/ipc.h
new file mode 100644
index 00000000..0b6441f6
--- /dev/null
+++ b/include/ipc.h
@@ -0,0 +1,18 @@
1#ifndef _SWAY_IPC_H
2#define _SWAY_IPC_H
3
4enum ipc_command_type {
5 IPC_COMMAND = 0,
6 IPC_GET_WORKSPACES = 1,
7 IPC_SUBSCRIBE = 2,
8 IPC_GET_OUTPUTS = 3,
9 IPC_GET_TREE = 4,
10 IPC_GET_MARKS = 5,
11 IPC_GET_BAR_CONFIG = 6,
12 IPC_GET_VERSION = 7,
13};
14
15void ipc_init(void);
16void ipc_terminate(void);
17
18#endif
diff --git a/include/layout.h b/include/layout.h
index 79241698..c1d7d8b4 100644
--- a/include/layout.h
+++ b/include/layout.h
@@ -4,12 +4,14 @@
4#include <wlc/wlc.h> 4#include <wlc/wlc.h>
5#include "list.h" 5#include "list.h"
6#include "container.h" 6#include "container.h"
7#include "focus.h"
7 8
8extern swayc_t root_container; 9extern swayc_t root_container;
9 10
10void init_layout(void); 11void init_layout(void);
11 12
12void add_child(swayc_t *parent, swayc_t *child); 13void add_child(swayc_t *parent, swayc_t *child);
14void add_floating(swayc_t *ws, swayc_t *child);
13// Returns parent container which needs to be rearranged. 15// Returns parent container which needs to be rearranged.
14swayc_t *add_sibling(swayc_t *sibling, swayc_t *child); 16swayc_t *add_sibling(swayc_t *sibling, swayc_t *child);
15swayc_t *replace_child(swayc_t *child, swayc_t *new_child); 17swayc_t *replace_child(swayc_t *child, swayc_t *new_child);
@@ -28,5 +30,6 @@ void focus_view_for(swayc_t *ancestor, swayc_t *container);
28 30
29swayc_t *get_focused_container(swayc_t *parent); 31swayc_t *get_focused_container(swayc_t *parent);
30swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent); 32swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent);
33swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir);
31 34
32#endif 35#endif
diff --git a/include/log.h b/include/log.h
index d35b2a54..47a83321 100644
--- a/include/log.h
+++ b/include/log.h
@@ -1,5 +1,7 @@
1#ifndef _SWAY_LOG_H 1#ifndef _SWAY_LOG_H
2#define _SWAY_LOG_H 2#define _SWAY_LOG_H
3#include <stdbool.h>
4#include "container.h"
3 5
4typedef enum { 6typedef enum {
5 L_SILENT = 0, 7 L_SILENT = 0,
@@ -10,7 +12,10 @@ typedef enum {
10 12
11void init_log(int verbosity); 13void init_log(int verbosity);
12void sway_log_colors(int mode); 14void sway_log_colors(int mode);
13void sway_log(int verbosity, char* format, ...) __attribute__((format(printf,2,3))); 15void sway_log(int verbosity, const char* format, ...) __attribute__((format(printf,2,3)));
14void sway_abort(char* format, ...)__attribute__((format(printf,1,2))); 16void sway_log_errno(int verbosity, char* format, ...) __attribute__((format(printf,2,3)));
17void sway_abort(const char* format, ...) __attribute__((format(printf,1,2)));
18bool sway_assert(bool condition, const char* format, ...) __attribute__((format(printf,2,3)));
15 19
20void layout_log(const swayc_t *c, int depth);
16#endif 21#endif
diff --git a/include/stringop.h b/include/stringop.h
index a5346829..4300f9ed 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -10,5 +10,6 @@ char *code_strchr(const char *string, char delimiter);
10char *code_strstr(const char *haystack, const char *needle); 10char *code_strstr(const char *haystack, const char *needle);
11int unescape_string(char *string); 11int unescape_string(char *string);
12char *join_args(char **argv, int argc); 12char *join_args(char **argv, int argc);
13char *join_list(list_t *list, char *separator);
13 14
14#endif 15#endif
diff --git a/include/sway.h b/include/sway.h
new file mode 100644
index 00000000..6499c81d
--- /dev/null
+++ b/include/sway.h
@@ -0,0 +1,6 @@
1#ifndef _SWAY_SWAY_H
2#define _SWAY_SWAY_H
3
4void sway_terminate(void);
5
6#endif
diff --git a/include/workspace.h b/include/workspace.h
index 8ce39bbd..042a15d9 100644
--- a/include/workspace.h
+++ b/include/workspace.h
@@ -15,6 +15,5 @@ void workspace_output_next();
15void workspace_next(); 15void workspace_next();
16void workspace_output_prev(); 16void workspace_output_prev();
17void workspace_prev(); 17void workspace_prev();
18void layout_log(const swayc_t *c, int depth);
19 18
20#endif 19#endif
diff --git a/sway.5.txt b/sway.5.txt
index 9f92dfe8..5bccbd12 100644
--- a/sway.5.txt
+++ b/sway.5.txt
@@ -22,11 +22,11 @@ Commands
22-------- 22--------
23 23
24**bindsym** <key combo> <command>:: 24**bindsym** <key combo> <command>::
25 Binds _key combo_ to execute _command_ when pressed. You may use XKB key names 25 Binds _key combo_ to execute _command_ when pressed. You may use XKB key
26 here (**xev**(1) is a good tool for discovering them). An example bindsym 26 names here (**xev**(1) is a good tool for discovering them). An example
27 command would be _bindsym Mod1+Shift+f exec firefox_, which would execute 27 bindsym command would be _bindsym Mod1+Shift+f exec firefox_, which would
28 Firefox if the alt, shift, and F keys are pressed together. Any valid sway 28 execute Firefox if the alt, shift, and F keys are pressed together. Any
29 command is eligible to be bound to a key combo. 29 valid sway command is eligible to be bound to a key combo.
30 30
31**exec** <shell command>:: 31**exec** <shell command>::
32 Executes _shell command_ with sh. 32 Executes _shell command_ with sh.
@@ -48,6 +48,9 @@ Commands
48 container, which is useful, for example, to open a sibling of the parent 48 container, which is useful, for example, to open a sibling of the parent
49 container, or to move the entire container around. 49 container, or to move the entire container around.
50 50
51**focus** mode_toggle::
52 Toggles focus between floating view and tiled view.
53
51**focus_follows_mouse** <yes|no>:: 54**focus_follows_mouse** <yes|no>::
52 If set to _yes_, the currently focused view will change as you move your 55 If set to _yes_, the currently focused view will change as you move your
53 mouse around the screen to the view that ends up underneath your mouse. 56 mouse around the screen to the view that ends up underneath your mouse.
@@ -76,13 +79,24 @@ Commands
76**splitv**:: 79**splitv**::
77 Equivalent to **split vertical**. 80 Equivalent to **split vertical**.
78 81
79**fullscreen**: 82**floating_modifier** <modifier>::
83 When the _modifier_ key is held down, you may use left click to drag floating
84 windows, and right click to resize them.
85
86**fullscreen**::
80 Toggles fullscreen status for the focused view. 87 Toggles fullscreen status for the focused view.
81 88
82**workspace** <name>: 89**gaps** <amount>::
90 Adds _amount_ pixels between each view, and around each output.
91
92**gaps** <inner|outer> <amount>::
93 Adds _amount_ pixels as an _inner_ or _outer_ gap, where the former affects
94 spacing between views and the latter affects the space around each output.
95
96**workspace** <name>::
83 Switches to the specified workspace. 97 Switches to the specified workspace.
84 98
85**workspace** <prev_on_output|next_on_output>: 99**workspace** <prev_on_output|next_on_output>::
86 Switches to the next workspace on the current output. 100 Switches to the next workspace on the current output.
87 101
88**workspace** <name> output <output>:: 102**workspace** <name> output <output>::
diff --git a/sway/commands.c b/sway/commands.c
index 1ca5c17f..e39b781a 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -3,6 +3,7 @@
3#include <wlc/wlc.h> 3#include <wlc/wlc.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <stdlib.h> 5#include <stdlib.h>
6#include <errno.h>
6#include <string.h> 7#include <string.h>
7#include <unistd.h> 8#include <unistd.h>
8#include <ctype.h> 9#include <ctype.h>
@@ -14,6 +15,7 @@
14#include "commands.h" 15#include "commands.h"
15#include "container.h" 16#include "container.h"
16#include "handlers.h" 17#include "handlers.h"
18#include "sway.h"
17 19
18struct modifier_key { 20struct modifier_key {
19 char *name; 21 char *name;
@@ -75,6 +77,18 @@ static bool checkarg(int argc, char *name, enum expected_args type, int val) {
75 return false; 77 return false;
76} 78}
77 79
80static int bindsym_sort(const void *_lbind, const void *_rbind) {
81 const struct sway_binding *lbind = *(void **)_lbind;
82 const struct sway_binding *rbind = *(void **)_rbind;
83 unsigned int lmod = 0, rmod = 0, i;
84
85 // Count how any modifiers are pressed
86 for (i = 0; i < 8 * sizeof(lbind->modifiers); ++i) {
87 lmod += lbind->modifiers & 1 << i;
88 rmod += rbind->modifiers & 1 << i;
89 }
90 return (rbind->keys->length + rmod) - (lbind->keys->length + lmod);
91}
78 92
79static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) { 93static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
80 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) { 94 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) {
@@ -104,6 +118,10 @@ static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
104 xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], XKB_KEYSYM_CASE_INSENSITIVE); 118 xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], XKB_KEYSYM_CASE_INSENSITIVE);
105 if (!sym) { 119 if (!sym) {
106 sway_log(L_ERROR, "bindsym - unknown key %s", (char *)split->items[i]); 120 sway_log(L_ERROR, "bindsym - unknown key %s", (char *)split->items[i]);
121 list_free(binding->keys);
122 free(binding->command);
123 free(binding);
124 list_free(split);
107 return false; 125 return false;
108 } 126 }
109 xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); 127 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) {
113 list_free(split); 131 list_free(split);
114 132
115 // TODO: Check if there are other commands with this key binding 133 // TODO: Check if there are other commands with this key binding
116 list_add(config->current_mode->bindings, binding); 134 struct sway_mode *mode = config->current_mode;
135 list_add(mode->bindings, binding);
136 qsort(mode->bindings->items, mode->bindings->length,
137 sizeof(mode->bindings->items[0]), bindsym_sort);
117 138
118 sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command); 139 sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command);
119 return true; 140 return true;
@@ -166,7 +187,7 @@ static bool cmd_exit(struct sway_config *config, int argc, char **argv) {
166 } 187 }
167 // Close all views 188 // Close all views
168 container_map(&root_container, kill_views, NULL); 189 container_map(&root_container, kill_views, NULL);
169 exit(0); 190 sway_terminate();
170 return true; 191 return true;
171} 192}
172 193
@@ -181,43 +202,28 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
181 if (view->type != C_VIEW) { 202 if (view->type != C_VIEW) {
182 return true; 203 return true;
183 } 204 }
184 int i;
185 // Change from nonfloating to floating 205 // Change from nonfloating to floating
186 if (!view->is_floating) { 206 if (!view->is_floating) {
187 view->is_floating = true; 207 // Remove view from its current location
188 for (i = 0; i < view->parent->children->length; i++) { 208 destroy_container(remove_child(view));
189 if (view->parent->children->items[i] == view) { 209
190 // Try to use desired geometry to set w/h 210 // and move it into workspace floating
191 if (view->desired_width != -1) { 211 add_floating(active_workspace,view);
192 view->width = view->desired_width; 212 view->x = (active_workspace->width - view->width)/2;
193 } 213 view->y = (active_workspace->height - view->height)/2;
194 if (view->desired_height != -1) { 214 if (view->desired_width != -1) {
195 view->height = view->desired_height; 215 view->width = view->desired_width;
196 } 216 }
197 217 if (view->desired_height != -1) {
198 // Swap from the list of whatever container the view was in 218 view->height = view->desired_height;
199 // to the workspace->floating list
200 list_del(view->parent->children, i);
201 list_add(active_workspace->floating, view);
202 destroy_container(view->parent);
203
204 // Set the new position of the container and arrange windows
205 view->x = (active_workspace->width - view->width)/2;
206 view->y = (active_workspace->height - view->height)/2;
207 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);
208 // Change parent to active_workspace
209 view->parent = active_workspace;
210 arrange_windows(active_workspace, -1, -1);
211 return true;
212 }
213 } 219 }
220 arrange_windows(active_workspace, -1, -1);
214 } else { 221 } else {
215 // Delete the view from the floating list and unset its is_floating flag 222 // Delete the view from the floating list and unset its is_floating flag
216 // Using length-1 as the index is safe because the view must be the currently 223 // Using length-1 as the index is safe because the view must be the currently
217 // focused floating output 224 // focused floating output
218 list_del(active_workspace->floating, active_workspace->floating->length - 1); 225 remove_child(view);
219 view->is_floating = false; 226 view->is_floating = false;
220 active_workspace->focused = NULL;
221 // Get the properly focused container, and add in the view there 227 // Get the properly focused container, and add in the view there
222 swayc_t *focused = container_under_pointer(); 228 swayc_t *focused = container_under_pointer();
223 // If focused is null, it's because the currently focused container is a workspace 229 // 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) {
228 234
229 sway_log(L_DEBUG, "Non-floating focused container is %p", focused); 235 sway_log(L_DEBUG, "Non-floating focused container is %p", focused);
230 236
231 //Case of focused workspace, just create as child of it 237 // Case of focused workspace, just create as child of it
232 if (focused->type == C_WORKSPACE) { 238 if (focused->type == C_WORKSPACE) {
233 add_child(focused, view); 239 add_child(focused, view);
234 } 240 }
235 //Regular case, create as sibling of current container 241 // Regular case, create as sibling of current container
236 else { 242 else {
237 add_sibling(focused, view); 243 add_sibling(focused, view);
238 } 244 }
239 // Refocus on the view once its been put back into the layout 245 // Refocus on the view once its been put back into the layout
240 set_focused_container(view); 246 view->width = view->height = 0;
241 arrange_windows(active_workspace, -1, -1); 247 arrange_windows(active_workspace, -1, -1);
242 return true;
243 } 248 }
249 set_focused_container(view);
244 } 250 }
245
246 return true; 251 return true;
247} 252}
248 253
@@ -250,11 +255,29 @@ static bool cmd_floating_mod(struct sway_config *config, int argc, char **argv)
250 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) { 255 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
251 return false; 256 return false;
252 } 257 }
253 config->floating_mod = xkb_keysym_from_name(argv[0], XKB_KEYSYM_CASE_INSENSITIVE); 258 int i, j;
259 list_t *split = split_string(argv[0], "+");
260 config->floating_mod = 0;
261
262 // set modifer keys
263 for (i = 0; i < split->length; ++i) {
264 for (j = 0; j < sizeof(modifiers) / sizeof(struct modifier_key); ++j) {
265 if (strcasecmp(modifiers[j].name, split->items[i]) == 0) {
266 config->floating_mod |= modifiers[j].mod;
267 }
268 }
269 }
270 list_free(split);
271 if (!config->floating_mod) {
272 sway_log(L_ERROR, "bindsym - unknown keys %s", argv[0]);
273 return false;
274 }
254 return true; 275 return true;
255} 276}
256 277
257static bool cmd_focus(struct sway_config *config, int argc, char **argv) { 278static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
279 static int floating_toggled_index = 0;
280 static int tiled_toggled_index = 0;
258 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) { 281 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
259 return false; 282 return false;
260 } 283 }
@@ -268,7 +291,44 @@ static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
268 return move_focus(MOVE_DOWN); 291 return move_focus(MOVE_DOWN);
269 } else if (strcasecmp(argv[0], "parent") == 0) { 292 } else if (strcasecmp(argv[0], "parent") == 0) {
270 return move_focus(MOVE_PARENT); 293 return move_focus(MOVE_PARENT);
294 } else if (strcasecmp(argv[0], "mode_toggle") == 0) {
295 int i;
296 swayc_t *focused = get_focused_view(active_workspace);
297 if (focused->is_floating) {
298 if (active_workspace->children->length > 0) {
299 for (i = 0;i < active_workspace->floating->length; i++) {
300 if (active_workspace->floating->items[i] == focused) {
301 floating_toggled_index = i;
302 break;
303 }
304 }
305 if (active_workspace->children->length > tiled_toggled_index) {
306 set_focused_container(get_focused_view(active_workspace->children->items[tiled_toggled_index]));
307 } else {
308 set_focused_container(get_focused_view(active_workspace->children->items[0]));
309 tiled_toggled_index = 0;
310 }
311 }
312 } else {
313 if (active_workspace->floating->length > 0) {
314 for (i = 0;i < active_workspace->children->length; i++) {
315 if (active_workspace->children->items[i] == focused) {
316 tiled_toggled_index = i;
317 break;
318 }
319 }
320 if (active_workspace->floating->length > floating_toggled_index) {
321 swayc_t *floating = active_workspace->floating->items[floating_toggled_index];
322 set_focused_container(get_focused_view(floating));
323 } else {
324 swayc_t *floating = active_workspace->floating->items[active_workspace->floating->length - 1];
325 set_focused_container(get_focused_view(floating));
326 tiled_toggled_index = active_workspace->floating->length - 1;
327 }
328 }
329 }
271 } 330 }
331
272 return true; 332 return true;
273} 333}
274 334
@@ -303,6 +363,42 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) {
303 363
304 return true; 364 return true;
305 365
366static bool cmd_gaps(struct sway_config *config, int argc, char **argv) {
367 if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
368 return false;
369 }
370
371 if (argc == 1) {
372 char *end;
373 int amount = (int)strtol(argv[0], &end, 10);
374 if (errno == ERANGE || amount == 0) {
375 errno = 0;
376 return false;
377 }
378 if (config->gaps_inner == 0) {
379 config->gaps_inner = amount;
380 }
381 if (config->gaps_outer == 0) {
382 config->gaps_outer = amount;
383 }
384 } else if (argc == 2) {
385 char *end;
386 int amount = (int)strtol(argv[1], &end, 10);
387 if (errno == ERANGE || amount == 0) {
388 errno = 0;
389 return false;
390 }
391 if (strcasecmp(argv[0], "inner") == 0) {
392 config->gaps_inner = amount;
393 } else if (strcasecmp(argv[0], "outer") == 0) {
394 config->gaps_outer = amount;
395 } else {
396 return false;
397 }
398 } else {
399 return false;
400 }
401 return true;
306} 402}
307 403
308static bool cmd_kill(struct sway_config *config, int argc, char **argv) { 404static 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) {
316 return false; 412 return false;
317 } 413 }
318 swayc_t *parent = get_focused_container(&root_container); 414 swayc_t *parent = get_focused_container(&root_container);
319
320 while (parent->type == C_VIEW) { 415 while (parent->type == C_VIEW) {
321 parent = parent->parent; 416 parent = parent->parent;
322 } 417 }
@@ -341,7 +436,7 @@ static bool cmd_reload(struct sway_config *config, int argc, char **argv) {
341 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) { 436 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) {
342 return false; 437 return false;
343 } 438 }
344 if (!load_config()) { 439 if (!load_config(NULL)) { // TODO: Use config given from -c
345 return false; 440 return false;
346 } 441 }
347 arrange_windows(&root_container, -1, -1); 442 arrange_windows(&root_container, -1, -1);
@@ -435,14 +530,12 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
435 swayc_t *container = get_focused_view(&root_container); 530 swayc_t *container = get_focused_view(&root_container);
436 bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0; 531 bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0;
437 wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); 532 wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current);
438 //Resize workspace if going from fullscreen -> notfullscreen 533 // Resize workspace if going from fullscreen -> notfullscreen
439 //otherwise just resize container 534 // otherwise just resize container
440 if (current) { 535 if (current) {
441 while (container->type != C_WORKSPACE) { 536 container = swayc_parent_by_type(container, C_WORKSPACE);
442 container = container->parent;
443 }
444 } 537 }
445 //Only resize container when going into fullscreen 538 // Only resize container when going into fullscreen
446 arrange_windows(container, -1, -1); 539 arrange_windows(container, -1, -1);
447 540
448 return true; 541 return true;
@@ -508,6 +601,7 @@ static struct cmd_handler handlers[] = {
508 { "focus", cmd_focus }, 601 { "focus", cmd_focus },
509 { "focus_follows_mouse", cmd_focus_follows_mouse }, 602 { "focus_follows_mouse", cmd_focus_follows_mouse },
510 { "fullscreen", cmd_fullscreen }, 603 { "fullscreen", cmd_fullscreen },
604 { "gaps", cmd_gaps },
511 { "kill", cmd_kill }, 605 { "kill", cmd_kill },
512 { "layout", cmd_layout }, 606 { "layout", cmd_layout },
513 { "log_colors", cmd_log_colors }, 607 { "log_colors", cmd_log_colors },
@@ -606,7 +700,7 @@ bool handle_command(struct sway_config *config, char *exec) {
606 char **argv = split_directive(exec + strlen(handler->command), &argc); 700 char **argv = split_directive(exec + strlen(handler->command), &argc);
607 int i; 701 int i;
608 702
609 //Perform var subs on all parts of the command 703 // Perform var subs on all parts of the command
610 for (i = 0; i < argc; ++i) { 704 for (i = 0; i < argc; ++i) {
611 argv[i] = do_var_replacement(config, argv[i]); 705 argv[i] = do_var_replacement(config, argv[i]);
612 } 706 }
diff --git a/sway/config.c b/sway/config.c
index f1de6080..9f65e8a2 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -8,6 +8,7 @@
8#include "log.h" 8#include "log.h"
9#include "commands.h" 9#include "commands.h"
10#include "config.h" 10#include "config.h"
11#include "layout.h"
11 12
12struct sway_config *config; 13struct sway_config *config;
13 14
@@ -15,121 +16,143 @@ static bool exists(const char *path) {
15 return access(path, R_OK) != -1; 16 return access(path, R_OK) != -1;
16} 17}
17 18
18static char *get_config_path() { 19void config_defaults(struct sway_config *config) {
19 char *name = "/.sway/config"; 20 config->symbols = create_list();
20 const char *home = getenv("HOME"); 21 config->modes = create_list();
22 config->cmd_queue = create_list();
23 config->workspace_outputs = create_list();
24 config->current_mode = malloc(sizeof(struct sway_mode));
25 config->current_mode->name = NULL;
26 config->current_mode->bindings = create_list();
27 list_add(config->modes, config->current_mode);
28 // Flags
29 config->focus_follows_mouse = true;
30 config->mouse_warping = true;
31 config->reloading = false;
32 config->active = false;
33 config->failed = false;
34 config->gaps_inner = 0;
35 config->gaps_outer = 0;
36}
21 37
22 // Check home dir 38void free_mode(struct sway_mode *mode) {
23 sway_log(L_DEBUG, "Trying to find config in ~/.sway/config"); 39 free(mode->name);
24 char *temp = malloc(strlen(home) + strlen(name) + 1); 40 free_flat_list(mode->bindings);
25 strcpy(temp, home); 41}
26 strcat(temp, name);
27 if (exists(temp)) {
28 return temp;
29 }
30 42
31 // Check XDG_CONFIG_HOME with fallback to ~/.config/ 43void free_config(struct sway_config *config) {
32 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_HOME/sway/config"); 44 int i;
33 char *xdg_config_home = getenv("XDG_CONFIG_HOME"); 45 for (i = 0; i < config->modes->length; ++i) {
34 if (xdg_config_home == NULL) { 46 free_mode((struct sway_mode *)config->modes->items[i]);
35 sway_log(L_DEBUG, "Falling back to ~/.config/sway/config");
36 name = "/.config/sway/config";
37 temp = malloc(strlen(home) + strlen(name) + 1);
38 strcpy(temp, home);
39 strcat(temp, name);
40 } else {
41 name = "/sway/config";
42 temp = malloc(strlen(xdg_config_home) + strlen(name) + 1);
43 strcpy(xdg_config_home, home);
44 strcat(temp, name);
45 } 47 }
46 if (exists(temp)) { 48 free_flat_list(config->modes);
47 return temp; 49 for (i = 0; i < config->workspace_outputs->length; ++i) {
50 struct workspace_output *wso = config->workspace_outputs->items[i];
51 free(wso->output);
52 free(wso->workspace);
48 } 53 }
49 54 free_flat_list(config->workspace_outputs);
50 // Check /etc/ 55 free_flat_list(config->cmd_queue);
51 sway_log(L_DEBUG, "Trying to find config in /etc/sway/config"); 56 for (i = 0; i < config->symbols->length; ++i) {
52 strcpy(temp, "/etc/sway/config"); 57 struct sway_variable *sym = config->symbols->items[i];
53 if (exists(temp)) { 58 free(sym->name);
54 return temp; 59 free(sym->value);
55 } 60 }
61 free_flat_list(config->symbols);
62}
56 63
57 // Check XDG_CONFIG_DIRS 64static const char *search_paths[] = {
58 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS"); 65 "$home/.sway/config",
59 char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS"); 66 "$config/sway/config",
60 if (xdg_config_dirs != NULL) { 67 "/etc/sway/config",
61 list_t *paths = split_string(xdg_config_dirs, ":"); 68 "$home/.i3/config",
62 name = "/sway/config"; 69 "$config/.i3/config",
63 int i; 70 "/etc/i3/config"
64 for (i = 0; i < paths->length; i++ ) { 71};
65 temp = malloc(strlen(paths->items[i]) + strlen(name) + 1);
66 strcpy(temp, paths->items[i]);
67 strcat(temp, name);
68 if (exists(temp)) {
69 free_flat_list(paths);
70 return temp;
71 }
72 }
73 free_flat_list(paths);
74 }
75 72
76 //Now fall back to i3 paths and try the same thing 73static char *get_config_path() {
77 name = "/.i3/config"; 74 char *home = getenv("HOME");
78 sway_log(L_DEBUG, "Trying to find config in ~/.i3/config"); 75 if (home) {
79 temp = malloc(strlen(home) + strlen(name) + 1); 76 home = strdup(getenv("HOME"));
80 strcpy(temp, home);
81 strcat(temp, name);
82 if (exists(temp)) {
83 return temp;
84 } 77 }
85 78 char *config = getenv("XDG_CONFIG_HOME");
86 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_HOME/i3/config"); 79 if (config) {
87 if (xdg_config_home == NULL) { 80 config = strdup(getenv("XDG_CONFIG_HOME"));
88 sway_log(L_DEBUG, "Falling back to ~/.config/i3/config"); 81 } else if (home) {
89 name = "/.config/i3/config"; 82 const char *def = "/.config";
90 temp = malloc(strlen(home) + strlen(name) + 1); 83 config = malloc(strlen(home) + strlen(def) + 1);
91 strcpy(temp, home); 84 strcpy(config, home);
92 strcat(temp, name); 85 strcat(config, def);
93 } else { 86 } else {
94 name = "/i3/config"; 87 home = strdup("");
95 temp = malloc(strlen(xdg_config_home) + strlen(name) + 1); 88 config = strdup("");
96 strcpy(xdg_config_home, home);
97 strcat(temp, name);
98 }
99 if (exists(temp)) {
100 return temp;
101 } 89 }
102 90
103 sway_log(L_DEBUG, "Trying to find config in /etc/i3/config"); 91 // Set up a temporary config for holding set variables
104 strcpy(temp, "/etc/i3/config"); 92 struct sway_config *temp_config = malloc(sizeof(struct sway_config));
105 if (exists(temp)) { 93 config_defaults(temp_config);
106 return temp; 94 const char *set_home = "set $home ";
95 char *_home = malloc(strlen(home) + strlen(set_home) + 1);
96 strcpy(_home, set_home);
97 strcat(_home, home);
98 handle_command(temp_config, _home);
99 free(_home);
100 const char *set_config = "set $config ";
101 char *_config = malloc(strlen(config) + strlen(set_config) + 1);
102 strcpy(_config, set_config);
103 strcat(_config, config);
104 handle_command(temp_config, _config);
105 free(_config);
106
107 char *test = NULL;
108 int i;
109 for (i = 0; i < sizeof(search_paths) / sizeof(char *); ++i) {
110 test = strdup(search_paths[i]);
111 test = do_var_replacement(temp_config, test);
112 sway_log(L_DEBUG, "Checking for config at %s", test);
113 if (exists(test)) {
114 goto _continue;
115 }
116 free(test);
117 test = NULL;
107 } 118 }
108 119
109 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS"); 120 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
121 char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS");
110 if (xdg_config_dirs != NULL) { 122 if (xdg_config_dirs != NULL) {
111 list_t *paths = split_string(xdg_config_dirs, ":"); 123 list_t *paths = split_string(xdg_config_dirs, ":");
112 name = "/i3/config"; 124 char *name = "/sway/config";
113 int i; 125 int i;
114 for (i = 0; i < paths->length; i++ ) { 126 for (i = 0; i < paths->length; i++ ) {
115 temp = malloc(strlen(paths->items[i]) + strlen(name) + 1); 127 test = malloc(strlen(paths->items[i]) + strlen(name) + 1);
116 strcpy(temp, paths->items[i]); 128 strcpy(test, paths->items[i]);
117 strcat(temp, name); 129 strcat(test, name);
118 if (exists(temp)) { 130 if (exists(test)) {
119 free_flat_list(paths); 131 free_flat_list(paths);
120 return temp; 132 return test;
121 } 133 }
134 free(test);
135 test = NULL;
122 } 136 }
123 free_flat_list(paths); 137 free_flat_list(paths);
124 } 138 }
125 139
126 return NULL; 140_continue:
141 free_config(temp_config);
142 free(home);
143 free(config);
144 return test;
127} 145}
128 146
129bool load_config(void) { 147bool load_config(const char *file) {
130 sway_log(L_INFO, "Loading config"); 148 sway_log(L_INFO, "Loading config");
131 149
132 char *path = get_config_path(); 150 char *path;
151 if (file != NULL) {
152 path = strdup(file);
153 } else {
154 path = get_config_path();
155 }
133 156
134 if (path == NULL) { 157 if (path == NULL) {
135 sway_log(L_ERROR, "Unable to find a config file!"); 158 sway_log(L_ERROR, "Unable to find a config file!");
@@ -155,23 +178,6 @@ bool load_config(void) {
155 return config_load_success; 178 return config_load_success;
156} 179}
157 180
158void config_defaults(struct sway_config *config) {
159 config->symbols = create_list();
160 config->modes = create_list();
161 config->cmd_queue = create_list();
162 config->workspace_outputs = create_list();
163 config->current_mode = malloc(sizeof(struct sway_mode));
164 config->current_mode->name = NULL;
165 config->current_mode->bindings = create_list();
166 list_add(config->modes, config->current_mode);
167 // Flags
168 config->focus_follows_mouse = true;
169 config->mouse_warping = true;
170 config->reloading = false;
171 config->active = false;
172 config->failed = false;
173}
174
175bool read_config(FILE *file, bool is_active) { 181bool read_config(FILE *file, bool is_active) {
176 struct sway_config *temp_config = malloc(sizeof(struct sway_config)); 182 struct sway_config *temp_config = malloc(sizeof(struct sway_config));
177 config_defaults(temp_config); 183 config_defaults(temp_config);
@@ -188,8 +194,8 @@ bool read_config(FILE *file, bool is_active) {
188 while (!feof(file)) { 194 while (!feof(file)) {
189 int _; 195 int _;
190 char *line = read_line(file); 196 char *line = read_line(file);
191 line = strip_comments(line);
192 line = strip_whitespace(line, &_); 197 line = strip_whitespace(line, &_);
198 line = strip_comments(line);
193 if (!line[0]) { 199 if (!line[0]) {
194 goto _continue; 200 goto _continue;
195 } 201 }
@@ -225,6 +231,8 @@ _continue:
225 231
226 if (is_active) { 232 if (is_active) {
227 temp_config->reloading = false; 233 temp_config->reloading = false;
234 container_map(&root_container, reset_gaps, NULL);
235 arrange_windows(&root_container, -1, -1);
228 } 236 }
229 config = temp_config; 237 config = temp_config;
230 238
diff --git a/sway/container.c b/sway/container.c
index 62c5bda0..7ccc2e09 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -8,53 +8,57 @@
8#include "layout.h" 8#include "layout.h"
9#include "log.h" 9#include "log.h"
10 10
11#define ASSERT_NONNULL(PTR) \
12 sway_assert (PTR, "%s: " #PTR "must be non-null", __func__)
11 13
12static swayc_t *new_swayc(enum swayc_types type) { 14static swayc_t *new_swayc(enum swayc_types type) {
13 swayc_t *c = calloc(1, sizeof(swayc_t)); 15 swayc_t *c = calloc(1, sizeof(swayc_t));
14 c->handle = -1; 16 c->handle = -1;
15 c->layout = L_NONE; 17 c->layout = L_NONE;
16 c->type = type; 18 c->type = type;
17 c->weight = 1;
18 if (type != C_VIEW) { 19 if (type != C_VIEW) {
19 c->children = create_list(); 20 c->children = create_list();
20 } 21 }
21 return c; 22 return c;
22} 23}
23 24
24static void free_swayc(swayc_t *c) { 25static void free_swayc(swayc_t *cont) {
26 if (!ASSERT_NONNULL(cont)) {
27 return;
28 }
25 // TODO does not properly handle containers with children, 29 // TODO does not properly handle containers with children,
26 // TODO but functions that call this usually check for that 30 // TODO but functions that call this usually check for that
27 if (c->children) { 31 if (cont->children) {
28 if (c->children->length) { 32 if (cont->children->length) {
29 int i; 33 int i;
30 for (i = 0; i < c->children->length; ++i) { 34 for (i = 0; i < cont->children->length; ++i) {
31 free_swayc(c->children->items[i]); 35 free_swayc(cont->children->items[i]);
32 } 36 }
33 } 37 }
34 list_free(c->children); 38 list_free(cont->children);
35 } 39 }
36 if (c->floating) { 40 if (cont->floating) {
37 if (c->floating->length) { 41 if (cont->floating->length) {
38 int i; 42 int i;
39 for (i = 0; i < c->floating->length; ++i) { 43 for (i = 0; i < cont->floating->length; ++i) {
40 free_swayc(c->floating->items[i]); 44 free_swayc(cont->floating->items[i]);
41 } 45 }
42 } 46 }
43 list_free(c->floating); 47 list_free(cont->floating);
44 } 48 }
45 if (c->parent) { 49 if (cont->parent) {
46 remove_child(c); 50 remove_child(cont);
47 } 51 }
48 if (c->name) { 52 if (cont->name) {
49 free(c->name); 53 free(cont->name);
50 } 54 }
51 free(c); 55 free(cont);
52} 56}
53 57
54/* New containers */ 58// New containers
55 59
56static bool workspace_test(swayc_t *view, void *name) { 60static bool workspace_test(swayc_t *view, void *name) {
57 return strcasecmp(view->name, (char *)name); 61 return strcasecmp(view->name, (char *)name) == 0;
58} 62}
59 63
60swayc_t *new_output(wlc_handle handle) { 64swayc_t *new_output(wlc_handle handle) {
@@ -67,6 +71,7 @@ swayc_t *new_output(wlc_handle handle) {
67 output->height = size->h; 71 output->height = size->h;
68 output->handle = handle; 72 output->handle = handle;
69 output->name = name ? strdup(name) : NULL; 73 output->name = name ? strdup(name) : NULL;
74 output->gaps = config->gaps_outer + config->gaps_inner / 2;
70 75
71 add_child(&root_container, output); 76 add_child(&root_container, output);
72 77
@@ -80,8 +85,10 @@ swayc_t *new_output(wlc_handle handle) {
80 sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); 85 sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output);
81 // Check if any other workspaces are using this name 86 // Check if any other workspaces are using this name
82 if (find_container(&root_container, workspace_test, wso->workspace)) { 87 if (find_container(&root_container, workspace_test, wso->workspace)) {
88 sway_log(L_DEBUG, "But it's already taken");
83 break; 89 break;
84 } 90 }
91 sway_log(L_DEBUG, "So we're going to use it");
85 ws_name = strdup(wso->workspace); 92 ws_name = strdup(wso->workspace);
86 break; 93 break;
87 } 94 }
@@ -101,10 +108,15 @@ swayc_t *new_output(wlc_handle handle) {
101} 108}
102 109
103swayc_t *new_workspace(swayc_t *output, const char *name) { 110swayc_t *new_workspace(swayc_t *output, const char *name) {
111 if (!ASSERT_NONNULL(output)) {
112 return NULL;
113 }
104 sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle); 114 sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
105 swayc_t *workspace = new_swayc(C_WORKSPACE); 115 swayc_t *workspace = new_swayc(C_WORKSPACE);
106 116
107 workspace->layout = L_HORIZ; // TODO: default layout 117 workspace->layout = L_HORIZ; // TODO: default layout
118 workspace->x = output->x;
119 workspace->y = output->y;
108 workspace->width = output->width; 120 workspace->width = output->width;
109 workspace->height = output->height; 121 workspace->height = output->height;
110 workspace->name = strdup(name); 122 workspace->name = strdup(name);
@@ -116,6 +128,9 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
116} 128}
117 129
118swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { 130swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
131 if (!ASSERT_NONNULL(child)) {
132 return NULL;
133 }
119 swayc_t *cont = new_swayc(C_CONTAINER); 134 swayc_t *cont = new_swayc(C_CONTAINER);
120 135
121 sway_log(L_DEBUG, "creating container %p around %p", cont, child); 136 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) {
147 // give them proper layouts 162 // give them proper layouts
148 cont->layout = workspace->layout; 163 cont->layout = workspace->layout;
149 workspace->layout = layout; 164 workspace->layout = layout;
165 set_focused_container_for(workspace, get_focused_view(workspace));
150 } else { // Or is built around container 166 } else { // Or is built around container
151 swayc_t *parent = replace_child(child, cont); 167 swayc_t *parent = replace_child(child, cont);
152 if (parent) { 168 if (parent) {
@@ -157,6 +173,9 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
157} 173}
158 174
159swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { 175swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
176 if (!ASSERT_NONNULL(sibling)) {
177 return NULL;
178 }
160 const char *title = wlc_view_get_title(handle); 179 const char *title = wlc_view_get_title(handle);
161 swayc_t *view = new_swayc(C_VIEW); 180 swayc_t *view = new_swayc(C_VIEW);
162 sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d", 181 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) {
166 view->name = title ? strdup(title) : NULL; 185 view->name = title ? strdup(title) : NULL;
167 view->visible = true; 186 view->visible = true;
168 view->is_focused = true; 187 view->is_focused = true;
188 // Setup geometry
189 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
190 view->width = 0;
191 view->height = 0;
192 view->desired_width = geometry->size.w;
193 view->desired_height = geometry->size.h;
169 194
170 view->desired_width = -1; 195 view->gaps = config->gaps_inner;
171 view->desired_height = -1;
172 196
173 // TODO: properly set this
174 view->is_floating = false; 197 view->is_floating = false;
175 198
176 if (sibling->type == C_WORKSPACE) { 199 if (sibling->type == C_WORKSPACE) {
@@ -196,8 +219,9 @@ swayc_t *new_floating_view(wlc_handle handle) {
196 // Set the geometry of the floating view 219 // Set the geometry of the floating view
197 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); 220 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
198 221
199 view->x = geometry->origin.x; 222 // give it requested geometry, but place in center
200 view->y = geometry->origin.y; 223 view->x = (active_workspace->width - geometry->size.w) / 2;
224 view->y = (active_workspace->height- geometry->size.h) / 2;
201 view->width = geometry->size.w; 225 view->width = geometry->size.w;
202 view->height = geometry->size.h; 226 view->height = geometry->size.h;
203 227
@@ -215,9 +239,12 @@ swayc_t *new_floating_view(wlc_handle handle) {
215 return view; 239 return view;
216} 240}
217 241
218/* Destroy container */ 242// Destroy container
219 243
220swayc_t *destroy_output(swayc_t *output) { 244swayc_t *destroy_output(swayc_t *output) {
245 if (!ASSERT_NONNULL(output)) {
246 return NULL;
247 }
221 if (output->children->length == 0) { 248 if (output->children->length == 0) {
222 // TODO move workspaces to other outputs 249 // TODO move workspaces to other outputs
223 } 250 }
@@ -227,23 +254,21 @@ swayc_t *destroy_output(swayc_t *output) {
227} 254}
228 255
229swayc_t *destroy_workspace(swayc_t *workspace) { 256swayc_t *destroy_workspace(swayc_t *workspace) {
257 if (!ASSERT_NONNULL(workspace)) {
258 return NULL;
259 }
230 // NOTE: This is called from elsewhere without checking children length 260 // NOTE: This is called from elsewhere without checking children length
231 // TODO move containers to other workspaces? 261 // TODO move containers to other workspaces?
232 // for now just dont delete 262 // for now just dont delete
233 263
234 // Do not destroy this if it's the last workspace on this output 264 // Do not destroy this if it's the last workspace on this output
235 swayc_t *output = workspace->parent; 265 swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
236 while (output && output->type != C_OUTPUT) { 266 if (output && output->children->length == 1) {
237 output = output->parent; 267 return NULL;
238 }
239 if (output) {
240 if (output->children->length == 1) {
241 return NULL;
242 }
243 } 268 }
244 269
245 if (workspace->children->length == 0) { 270 if (workspace->children->length == 0) {
246 sway_log(L_DEBUG, "Workspace: Destroying workspace '%s'", workspace->name); 271 sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name);
247 swayc_t *parent = workspace->parent; 272 swayc_t *parent = workspace->parent;
248 free_swayc(workspace); 273 free_swayc(workspace);
249 return parent; 274 return parent;
@@ -252,19 +277,20 @@ swayc_t *destroy_workspace(swayc_t *workspace) {
252} 277}
253 278
254swayc_t *destroy_container(swayc_t *container) { 279swayc_t *destroy_container(swayc_t *container) {
280 if (!ASSERT_NONNULL(container)) {
281 return NULL;
282 }
255 while (container->children->length == 0 && container->type == C_CONTAINER) { 283 while (container->children->length == 0 && container->type == C_CONTAINER) {
256 sway_log(L_DEBUG, "Container: Destroying container '%p'", container); 284 sway_log(L_DEBUG, "Container: Destroying container '%p'", container);
257 swayc_t *parent = container->parent; 285 swayc_t *parent = container->parent;
258 free_swayc(container); 286 free_swayc(container);
259
260 container = parent; 287 container = parent;
261 } 288 }
262 return container; 289 return container;
263} 290}
264 291
265swayc_t *destroy_view(swayc_t *view) { 292swayc_t *destroy_view(swayc_t *view) {
266 if (view == NULL) { 293 if (!ASSERT_NONNULL(view)) {
267 sway_log(L_DEBUG, "Warning: NULL passed into destroy_view");
268 return NULL; 294 return NULL;
269 } 295 }
270 sway_log(L_DEBUG, "Destroying view '%p'", view); 296 sway_log(L_DEBUG, "Destroying view '%p'", view);
@@ -278,6 +304,34 @@ swayc_t *destroy_view(swayc_t *view) {
278 return parent; 304 return parent;
279} 305}
280 306
307// Container lookup
308
309swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
310 if (!ASSERT_NONNULL(container)) {
311 return NULL;
312 }
313 if (!sway_assert(type < C_TYPES && type >= C_ROOT, "%s: invalid type", __func__)) {
314 return NULL;
315 }
316 do {
317 container = container->parent;
318 } while(container && container->type != type);
319 return container;
320}
321
322swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts layout) {
323 if (!ASSERT_NONNULL(container)) {
324 return NULL;
325 }
326 if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "%s: invalid layout", __func__)) {
327 return NULL;
328 }
329 do {
330 container = container->parent;
331 } while (container && container->layout != layout);
332 return container;
333}
334
281swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { 335swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) {
282 if (!container->children) { 336 if (!container->children) {
283 return NULL; 337 return NULL;
@@ -307,25 +361,27 @@ swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *da
307} 361}
308 362
309void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { 363void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
310 if (!container || !container->children || !container->children->length) { 364 if (container && container->children && container->children->length) {
311 return; 365 int i;
312 } 366 for (i = 0; i < container->children->length; ++i) {
313 int i; 367 swayc_t *child = container->children->items[i];
314 for (i = 0; i < container->children->length; ++i) {
315 swayc_t *child = container->children->items[i];
316 f(child, data);
317 container_map(child, f, data);
318 }
319 if (container->type == C_WORKSPACE) {
320 for (i = 0; i < container->floating->length; ++i) {
321 swayc_t *child = container->floating->items[i];
322 f(child, data); 368 f(child, data);
323 container_map(child, f, data); 369 container_map(child, f, data);
324 } 370 }
371 if (container->type == C_WORKSPACE) {
372 for (i = 0; i < container->floating->length; ++i) {
373 swayc_t *child = container->floating->items[i];
374 f(child, data);
375 container_map(child, f, data);
376 }
377 }
325 } 378 }
326} 379}
327 380
328void set_view_visibility(swayc_t *view, void *data) { 381void set_view_visibility(swayc_t *view, void *data) {
382 if (!ASSERT_NONNULL(view)) {
383 return;
384 }
329 uint32_t *p = data; 385 uint32_t *p = data;
330 if (view->type == C_VIEW) { 386 if (view->type == C_VIEW) {
331 wlc_view_set_mask(view->handle, *p); 387 wlc_view_set_mask(view->handle, *p);
@@ -337,3 +393,15 @@ void set_view_visibility(swayc_t *view, void *data) {
337 } 393 }
338 view->visible = (*p == 2); 394 view->visible = (*p == 2);
339} 395}
396
397void reset_gaps(swayc_t *view, void *data) {
398 if (!ASSERT_NONNULL(view)) {
399 return;
400 }
401 if (view->type == C_OUTPUT) {
402 view->gaps = config->gaps_outer;
403 }
404 if (view->type == C_VIEW) {
405 view->gaps = config->gaps_inner;
406 }
407}
diff --git a/sway/focus.c b/sway/focus.c
index 628316dd..5008dbbf 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -3,6 +3,7 @@
3#include "focus.h" 3#include "focus.h"
4#include "log.h" 4#include "log.h"
5#include "workspace.h" 5#include "workspace.h"
6#include "layout.h"
6 7
7bool locked_container_focus = false; 8bool locked_container_focus = false;
8bool locked_view_focus = false; 9bool locked_view_focus = false;
@@ -20,6 +21,8 @@ static void update_focus(swayc_t *c) {
20 // Case where output changes 21 // Case where output changes
21 case C_OUTPUT: 22 case C_OUTPUT:
22 wlc_output_focus(c->handle); 23 wlc_output_focus(c->handle);
24 // Set new workspace to the outputs focused workspace
25 active_workspace = c->focused;
23 break; 26 break;
24 27
25 // Case where workspace changes 28 // Case where workspace changes
@@ -51,74 +54,17 @@ static void update_focus(swayc_t *c) {
51} 54}
52 55
53bool move_focus(enum movement_direction direction) { 56bool move_focus(enum movement_direction direction) {
54 if (locked_container_focus) { 57 swayc_t *view = get_swayc_in_direction(
55 return false; 58 get_focused_container(&root_container), direction);
56 } 59 if (view) {
57 swayc_t *current = get_focused_container(&root_container); 60 if (direction == MOVE_PARENT) {
58 if (current->type == C_VIEW 61 set_focused_container(view);
59 && wlc_view_get_state(current->handle) & WLC_BIT_FULLSCREEN) {
60 return false;
61 }
62 swayc_t *parent = current->parent;
63
64 if (direction == MOVE_PARENT) {
65 if (parent->type == C_OUTPUT) {
66 sway_log(L_DEBUG, "Focus cannot move to parent");
67 return false;
68 } else { 62 } else {
69 sway_log(L_DEBUG, "Moving focus from %p:%ld to %p:%ld", 63 set_focused_container(get_focused_view(view));
70 current, current->handle, parent, parent->handle);
71 set_focused_container(parent);
72 return true;
73 }
74 }
75
76 while (true) {
77 sway_log(L_DEBUG, "Moving focus away from %p", current);
78
79 // Test if we can even make a difference here
80 bool can_move = false;
81 int diff = 0;
82 if (direction == MOVE_LEFT || direction == MOVE_RIGHT) {
83 if (parent->layout == L_HORIZ || parent->type == C_ROOT) {
84 can_move = true;
85 diff = direction == MOVE_LEFT ? -1 : 1;
86 }
87 } else {
88 if (parent->layout == L_VERT) {
89 can_move = true;
90 diff = direction == MOVE_UP ? -1 : 1;
91 }
92 }
93 sway_log(L_DEBUG, "Can move? %s", can_move ? "yes" : "no");
94 if (can_move) {
95 int i;
96 for (i = 0; i < parent->children->length; ++i) {
97 swayc_t *child = parent->children->items[i];
98 if (child == current) {
99 break;
100 }
101 }
102 int desired = i + diff;
103 sway_log(L_DEBUG, "Moving from %d to %d", i, desired);
104 if (desired < 0 || desired >= parent->children->length) {
105 can_move = false;
106 } else {
107 swayc_t *newview = parent->children->items[desired];
108 set_focused_container(get_focused_view(newview));
109 return true;
110 }
111 }
112 if (!can_move) {
113 sway_log(L_DEBUG, "Can't move at current level, moving up tree");
114 current = parent;
115 parent = parent->parent;
116 if (!parent) {
117 // Nothing we can do
118 return false;
119 }
120 } 64 }
65 return true;
121 } 66 }
67 return false;
122} 68}
123 69
124swayc_t *get_focused_container(swayc_t *parent) { 70swayc_t *get_focused_container(swayc_t *parent) {
@@ -142,13 +88,13 @@ void set_focused_container(swayc_t *c) {
142 // Find previous focused view, and the new focused view, if they are the same return 88 // Find previous focused view, and the new focused view, if they are the same return
143 swayc_t *focused = get_focused_view(&root_container); 89 swayc_t *focused = get_focused_view(&root_container);
144 swayc_t *workspace = active_workspace; 90 swayc_t *workspace = active_workspace;
145 if (focused == get_focused_view(c)) {
146 return;
147 }
148 91
149 // update container focus from here to root, making necessary changes along 92 // update container focus from here to root, making necessary changes along
150 // the way 93 // the way
151 swayc_t *p = c; 94 swayc_t *p = c;
95 if (p->type != C_OUTPUT && p->type != C_ROOT) {
96 p->is_focused = true;
97 }
152 while (p != &root_container) { 98 while (p != &root_container) {
153 update_focus(p); 99 update_focus(p);
154 p = p->parent; 100 p = p->parent;
@@ -171,8 +117,11 @@ void set_focused_container(swayc_t *c) {
171 } 117 }
172 // activate current focus 118 // activate current focus
173 if (p->type == C_VIEW) { 119 if (p->type == C_VIEW) {
174 wlc_view_focus(p->handle);
175 wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true); 120 wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true);
121 // set focus if view_focus is unlocked
122 if (!locked_view_focus) {
123 wlc_view_focus(p->handle);
124 }
176 } 125 }
177 } 126 }
178} 127}
diff --git a/sway/handlers.c b/sway/handlers.c
index 534b4e4f..79628fe5 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -13,21 +13,14 @@
13#include "workspace.h" 13#include "workspace.h"
14#include "container.h" 14#include "container.h"
15#include "focus.h" 15#include "focus.h"
16 16#include "input_state.h"
17uint32_t keys_pressed[32];
18 17
19static struct wlc_origin mouse_origin; 18static struct wlc_origin mouse_origin;
20 19
21static bool m1_held = false;
22static bool m2_held = false;
23
24static bool pointer_test(swayc_t *view, void *_origin) { 20static bool pointer_test(swayc_t *view, void *_origin) {
25 const struct wlc_origin *origin = _origin; 21 const struct wlc_origin *origin = _origin;
26 // Determine the output that the view is under 22 // Determine the output that the view is under
27 swayc_t *parent = view; 23 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
28 while (parent->type != C_OUTPUT) {
29 parent = parent->parent;
30 }
31 if (origin->x >= view->x && origin->y >= view->y 24 if (origin->x >= view->x && origin->y >= view->y
32 && origin->x < view->x + view->width && origin->y < view->y + view->height 25 && origin->x < view->x + view->width && origin->y < view->y + view->height
33 && view->visible && parent == root_container.focused) { 26 && view->visible && parent == root_container.focused) {
@@ -86,10 +79,12 @@ swayc_t *container_under_pointer(void) {
86 return lookup; 79 return lookup;
87} 80}
88 81
82/* Handles */
83
89static bool handle_output_created(wlc_handle output) { 84static bool handle_output_created(wlc_handle output) {
90 swayc_t *op = new_output(output); 85 swayc_t *op = new_output(output);
91 86
92 //Switch to workspace if we need to 87 // Switch to workspace if we need to
93 if (active_workspace == NULL) { 88 if (active_workspace == NULL) {
94 swayc_t *ws = op->children->items[0]; 89 swayc_t *ws = op->children->items[0];
95 workspace_switch(ws); 90 workspace_switch(ws);
@@ -111,7 +106,7 @@ static void handle_output_destroyed(wlc_handle output) {
111 if (list->length == 0) { 106 if (list->length == 0) {
112 active_workspace = NULL; 107 active_workspace = NULL;
113 } else { 108 } else {
114 //switch to other outputs active workspace 109 // switch to other outputs active workspace
115 workspace_switch(((swayc_t *)root_container.children->items[0])->focused); 110 workspace_switch(((swayc_t *)root_container.children->items[0])->focused);
116 } 111 }
117} 112}
@@ -137,38 +132,64 @@ static void handle_output_focused(wlc_handle output, bool focus) {
137} 132}
138 133
139static bool handle_view_created(wlc_handle handle) { 134static bool handle_view_created(wlc_handle handle) {
140 swayc_t *focused = get_focused_container(&root_container); 135 // if view is child of another view, the use that as focused container
136 wlc_handle parent = wlc_view_get_parent(handle);
137 swayc_t *focused = NULL;
141 swayc_t *newview = NULL; 138 swayc_t *newview = NULL;
139
140 // Get parent container, to add view in
141 if (parent) {
142 focused = get_swayc_for_handle(parent, &root_container);
143 }
144 if (!focused || focused->type == C_OUTPUT) {
145 focused = get_focused_container(&root_container);
146 }
147 sway_log(L_DEBUG, "handle:%ld type:%x state:%x parent:%ld "
148 "mask:%d (x:%d y:%d w:%d h:%d) title:%s "
149 "class:%s appid:%s",
150 handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent,
151 wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x,
152 wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w,
153 wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle),
154 wlc_view_get_class(handle), wlc_view_get_app_id(handle));
155
156 // TODO properly figure out how each window should be handled.
142 switch (wlc_view_get_type(handle)) { 157 switch (wlc_view_get_type(handle)) {
143 // regular view created regularly 158 // regular view created regularly
144 case 0: 159 case 0:
145 newview = new_view(focused, handle); 160 newview = new_view(focused, handle);
146 wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); 161 wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true);
147 break; 162 break;
148 // takes keyboard focus 163
164 // Dmenu keeps viewfocus, but others with this flag dont, for now simulate
165 // dmenu
149 case WLC_BIT_OVERRIDE_REDIRECT: 166 case WLC_BIT_OVERRIDE_REDIRECT:
150 sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT", handle); 167// locked_view_focus = true;
151 locked_view_focus = true;
152 wlc_view_focus(handle); 168 wlc_view_focus(handle);
153 wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); 169 wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true);
154 wlc_view_bring_to_front(handle); 170 wlc_view_bring_to_front(handle);
155 break; 171 break;
156 // Takes container focus 172
173 // Firefox popups have this flag set.
157 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: 174 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
158 sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT|WLC_BIT_MANAGED", handle);
159 wlc_view_bring_to_front(handle); 175 wlc_view_bring_to_front(handle);
160 locked_container_focus = true; 176 locked_container_focus = true;
161 break; 177 break;
162 // set modals as floating containers 178
179 // Modals, get focus, popups do not
163 case WLC_BIT_MODAL: 180 case WLC_BIT_MODAL:
181 wlc_view_focus(handle);
164 wlc_view_bring_to_front(handle); 182 wlc_view_bring_to_front(handle);
165 newview = new_floating_view(handle); 183 newview = new_floating_view(handle);
166 case WLC_BIT_POPUP: 184 case WLC_BIT_POPUP:
185 wlc_view_bring_to_front(handle);
167 break; 186 break;
168 } 187 }
188
169 if (newview) { 189 if (newview) {
170 set_focused_container(newview); 190 set_focused_container(newview);
171 arrange_windows(newview->parent, -1, -1); 191 swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT);
192 arrange_windows(output, -1, -1);
172 } 193 }
173 return true; 194 return true;
174} 195}
@@ -181,19 +202,19 @@ static void handle_view_destroyed(wlc_handle handle) {
181 // regular view created regularly 202 // regular view created regularly
182 case 0: 203 case 0:
183 case WLC_BIT_MODAL: 204 case WLC_BIT_MODAL:
205 case WLC_BIT_POPUP:
184 if (view) { 206 if (view) {
185 swayc_t *parent = destroy_view(view); 207 swayc_t *parent = destroy_view(view);
186 arrange_windows(parent, -1, -1); 208 arrange_windows(parent, -1, -1);
187 } 209 }
188 break; 210 break;
189 // takes keyboard focus 211 // DMENU has this flag, and takes view_focus, but other things with this
212 // flag dont
190 case WLC_BIT_OVERRIDE_REDIRECT: 213 case WLC_BIT_OVERRIDE_REDIRECT:
191 locked_view_focus = false; 214// locked_view_focus = false;
192 break; 215 break;
193 // Takes container focus
194 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: 216 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
195 locked_container_focus = false; 217 locked_container_focus = false;
196 case WLC_BIT_POPUP:
197 break; 218 break;
198 } 219 }
199 set_focused_container(get_focused_view(&root_container)); 220 set_focused_container(get_focused_view(&root_container));
@@ -205,7 +226,7 @@ static void handle_view_focus(wlc_handle view, bool focus) {
205 226
206static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { 227static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) {
207 sway_log(L_DEBUG, "geometry request %d x %d : %d x %d", 228 sway_log(L_DEBUG, "geometry request %d x %d : %d x %d",
208 geometry->origin.x, geometry->origin.y, geometry->size.w,geometry->size.h); 229 geometry->origin.x, geometry->origin.y, geometry->size.w, geometry->size.h);
209 // If the view is floating, then apply the geometry. 230 // If the view is floating, then apply the geometry.
210 // Otherwise save the desired width/height for the view. 231 // Otherwise save the desired width/height for the view.
211 // This will not do anything for the time being as WLC improperly sends geometry requests 232 // 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
225} 246}
226 247
227static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { 248static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) {
228 swayc_t *c = NULL; 249 swayc_t *c = get_swayc_for_handle(view, &root_container);
229 switch(state) { 250 switch (state) {
230 case WLC_BIT_FULLSCREEN: 251 case WLC_BIT_FULLSCREEN:
231 // i3 just lets it become fullscreen 252 // i3 just lets it become fullscreen
232 wlc_view_set_state(view, state, toggle); 253 wlc_view_set_state(view, state, toggle);
233 c = get_swayc_for_handle(view, &root_container);
234 sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d",view,c->name,toggle);
235 if (c) { 254 if (c) {
255 sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d", view, c->name, toggle);
236 arrange_windows(c->parent, -1, -1); 256 arrange_windows(c->parent, -1, -1);
237 // Set it as focused window for that workspace if its going fullscreen 257 // Set it as focused window for that workspace if its going fullscreen
238 if (toggle) { 258 if (toggle) {
239 swayc_t *ws = c; 259 swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE);
240 while (ws->type != C_WORKSPACE) {
241 ws = ws->parent;
242 }
243 // Set ws focus to c 260 // Set ws focus to c
244 set_focused_container_for(ws, c); 261 set_focused_container_for(ws, c);
245 } 262 }
@@ -248,7 +265,9 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
248 case WLC_BIT_MAXIMIZED: 265 case WLC_BIT_MAXIMIZED:
249 case WLC_BIT_RESIZING: 266 case WLC_BIT_RESIZING:
250 case WLC_BIT_MOVING: 267 case WLC_BIT_MOVING:
268 break;
251 case WLC_BIT_ACTIVATED: 269 case WLC_BIT_ACTIVATED:
270 sway_log(L_DEBUG, "View %p requested to be activated", c);
252 break; 271 break;
253 } 272 }
254 return; 273 return;
@@ -257,29 +276,38 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
257 276
258static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, 277static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
259 uint32_t key, uint32_t sym, enum wlc_key_state state) { 278 uint32_t key, uint32_t sym, enum wlc_key_state state) {
260 enum { QSIZE = 32 }; 279
261 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) { 280 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) {
262 return false; 281 return false;
263 } 282 }
264 static uint8_t head = 0; 283
265 bool cmd_success = false; 284 // Revert floating container back to original position on keypress
285 if (state == WLC_KEY_STATE_PRESSED &&
286 (pointer_state.floating.drag || pointer_state.floating.resize)) {
287 reset_floating(get_focused_view(&root_container));
288 }
266 289
267 struct sway_mode *mode = config->current_mode; 290 struct sway_mode *mode = config->current_mode;
291
292 if (sym < 70000 /* bullshit made up number */) {
293 if (!isalnum(sym) && sym != ' ' && sym != XKB_KEY_Escape && sym != XKB_KEY_Tab) {
294 // God fucking dammit
295 return false;
296 }
297 }
298
268 // Lowercase if necessary 299 // Lowercase if necessary
269 sym = tolower(sym); 300 sym = tolower(sym);
270 301
271 // Find key, if it has been pressed 302 int i;
272 int mid = 0; 303
273 while (mid < head && keys_pressed[mid] != sym) { 304 if (state == WLC_KEY_STATE_PRESSED) {
274 ++mid; 305 press_key(sym);
275 } 306 } else { // WLC_KEY_STATE_RELEASED
276 if (state == WLC_KEY_STATE_PRESSED && mid == head && head + 1 < QSIZE) { 307 release_key(sym);
277 keys_pressed[head++] = sym;
278 } else if (state == WLC_KEY_STATE_RELEASED && mid < head) {
279 memmove(keys_pressed + mid, keys_pressed + mid + 1, sizeof*keys_pressed * (--head - mid));
280 } 308 }
309
281 // TODO: reminder to check conflicts with mod+q+a versus mod+q 310 // TODO: reminder to check conflicts with mod+q+a versus mod+q
282 int i;
283 for (i = 0; i < mode->bindings->length; ++i) { 311 for (i = 0; i < mode->bindings->length; ++i) {
284 struct sway_binding *binding = mode->bindings->items[i]; 312 struct sway_binding *binding = mode->bindings->items[i];
285 313
@@ -287,39 +315,22 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
287 bool match; 315 bool match;
288 int j; 316 int j;
289 for (j = 0; j < binding->keys->length; ++j) { 317 for (j = 0; j < binding->keys->length; ++j) {
290 match = false;
291 xkb_keysym_t *key = binding->keys->items[j]; 318 xkb_keysym_t *key = binding->keys->items[j];
292 uint8_t k; 319 if ((match = check_key(*key)) == false) {
293 for (k = 0; k < head; ++k) {
294 if (keys_pressed[k] == *key) {
295 match = true;
296 break;
297 }
298 }
299 if (match == false) {
300 break; 320 break;
301 } 321 }
302 } 322 }
303
304 if (match) { 323 if (match) {
305 // Remove matched keys from keys_pressed
306 int j;
307 for (j = 0; j < binding->keys->length; ++j) {
308 uint8_t k;
309 for (k = 0; k < head; ++k) {
310 memmove(keys_pressed + k, keys_pressed + k + 1, sizeof*keys_pressed * (--head - k));
311 break;
312 }
313 }
314 if (state == WLC_KEY_STATE_PRESSED) { 324 if (state == WLC_KEY_STATE_PRESSED) {
315 cmd_success = handle_command(config, binding->command); 325 handle_command(config, binding->command);
326 return true;
316 } else if (state == WLC_KEY_STATE_RELEASED) { 327 } else if (state == WLC_KEY_STATE_RELEASED) {
317 // TODO: --released 328 // TODO: --released
318 } 329 }
319 } 330 }
320 } 331 }
321 } 332 }
322 return cmd_success; 333 return false;
323} 334}
324 335
325static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) { 336static 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
327 static wlc_handle prev_handle = 0; 338 static wlc_handle prev_handle = 0;
328 mouse_origin = *origin; 339 mouse_origin = *origin;
329 bool changed_floating = false; 340 bool changed_floating = false;
330 int i = 0;
331 if (!active_workspace) { 341 if (!active_workspace) {
332 return false; 342 return false;
333 } 343 }
334 // Do checks to determine if proper keys are being held 344 // Do checks to determine if proper keys are being held
335 swayc_t *view = active_workspace->focused; 345 swayc_t *view = get_focused_view(active_workspace);
336 if (m1_held && view) { 346 uint32_t edge = 0;
347 if (pointer_state.floating.drag && view) {
337 if (view->is_floating) { 348 if (view->is_floating) {
338 while (keys_pressed[i++]) { 349 int dx = mouse_origin.x - prev_pos.x;
339 if (keys_pressed[i] == config->floating_mod) { 350 int dy = mouse_origin.y - prev_pos.y;
340 int dx = mouse_origin.x - prev_pos.x; 351 view->x += dx;
341 int dy = mouse_origin.y - prev_pos.y; 352 view->y += dy;
342 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); 353 changed_floating = true;
343 sway_log(L_DEBUG, "Moving: dx: %d, dy: %d", dx, dy);
344
345 view->x += dx;
346 view->y += dy;
347 changed_floating = true;
348 break;
349 }
350 }
351 } 354 }
352 } else if (m2_held && view) { 355 } else if (pointer_state.floating.resize && view) {
353 if (view->is_floating) { 356 if (view->is_floating) {
354 while (keys_pressed[i++]) { 357 int dx = mouse_origin.x - prev_pos.x;
355 if (keys_pressed[i] == config->floating_mod) { 358 int dy = mouse_origin.y - prev_pos.y;
356 int dx = mouse_origin.x - prev_pos.x; 359 int min_sane_w = 100;
357 int dy = mouse_origin.y - prev_pos.y; 360 int min_sane_h = 60;
358 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); 361
359 sway_log(L_INFO, "Moving: dx: %d, dy: %d", dx, dy); 362 // Move and resize the view based on the dx/dy and mouse position
360 363 int midway_x = view->x + view->width/2;
361 // Move and resize the view based on the dx/dy and mouse position 364 int midway_y = view->y + view->height/2;
362 int midway_x = view->x + view->width/2; 365 if (dx < 0) {
363 int midway_y = view->y + view->height/2; 366 if (!pointer_state.lock.right) {
364 367 if (view->width > min_sane_w) {
365 if (dx < 0) {
366 changed_floating = true; 368 changed_floating = true;
367 if (mouse_origin.x > midway_x) { 369 view->width += dx;
368 sway_log(L_INFO, "Downsizing view to the left"); 370 edge += WLC_RESIZE_EDGE_RIGHT;
369 view->width += dx; 371 }
370 } else { 372 } else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
371 sway_log(L_INFO, "Upsizing view to the left"); 373 changed_floating = true;
372 view->x += dx; 374 view->x += dx;
373 view->width -= dx; 375 view->width -= dx;
374 } 376 edge += WLC_RESIZE_EDGE_LEFT;
375 } else if (dx > 0){ 377 }
378 } else if (dx > 0) {
379 if (mouse_origin.x > midway_x && !pointer_state.lock.right) {
380 changed_floating = true;
381 view->width += dx;
382 edge += WLC_RESIZE_EDGE_RIGHT;
383 } else if (!pointer_state.lock.left) {
384 if (view->width > min_sane_w) {
376 changed_floating = true; 385 changed_floating = true;
377 if (mouse_origin.x > midway_x) { 386 view->x += dx;
378 sway_log(L_INFO, "Upsizing to the right"); 387 view->width -= dx;
379 view->width += dx; 388 edge += WLC_RESIZE_EDGE_LEFT;
380 } else {
381 sway_log(L_INFO, "Downsizing to the right");
382 view->x += dx;
383 view->width -= dx;
384 }
385 } 389 }
390 }
391 }
386 392
387 if (dy < 0) { 393 if (dy < 0) {
394 if (!pointer_state.lock.bottom) {
395 if (view->height > min_sane_h) {
388 changed_floating = true; 396 changed_floating = true;
389 if (mouse_origin.y > midway_y) { 397 view->height += dy;
390 sway_log(L_INFO, "Downsizing view to the top"); 398 edge += WLC_RESIZE_EDGE_BOTTOM;
391 view->height += dy; 399 }
392 } else { 400 } else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
393 sway_log(L_INFO, "Upsizing the view to the top"); 401 changed_floating = true;
394 view->y += dy; 402 view->y += dy;
395 view->height -= dy; 403 view->height -= dy;
396 } 404 edge += WLC_RESIZE_EDGE_TOP;
397 } else if (dy > 0) { 405 }
406 } else if (dy > 0) {
407 if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) {
408 changed_floating = true;
409 view->height += dy;
410 edge += WLC_RESIZE_EDGE_BOTTOM;
411 } else if (!pointer_state.lock.top) {
412 if (view->height > min_sane_h) {
398 changed_floating = true; 413 changed_floating = true;
399 if (mouse_origin.y > midway_y) { 414 view->y += dy;
400 sway_log(L_INFO, "Upsizing to the bottom"); 415 view->height -= dy;
401 view->height += dy; 416 edge += WLC_RESIZE_EDGE_TOP;
402 } else {
403 sway_log(L_INFO, "Downsizing to the bottom");
404 view->y += dy;
405 view->height -= dy;
406 }
407 } 417 }
408 break;
409 } 418 }
410 } 419 }
411 } 420 }
412 } 421 }
413 if (config->focus_follows_mouse && prev_handle != handle) { 422 if (config->focus_follows_mouse && prev_handle != handle) {
414 //Dont change focus if fullscreen 423 // Dont change focus if fullscreen
415 swayc_t *focused = get_focused_view(view); 424 swayc_t *focused = get_focused_view(view);
416 if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)) { 425 if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)
426 && !(pointer_state.l_held || pointer_state.r_held)) {
417 set_focused_container(container_under_pointer()); 427 set_focused_container(container_under_pointer());
418 } 428 }
419 } 429 }
420 prev_handle = handle; 430 prev_handle = handle;
421 prev_pos = mouse_origin; 431 prev_pos = mouse_origin;
422 if (changed_floating) { 432 if (changed_floating) {
423 arrange_windows(view, -1, -1); 433 struct wlc_geometry geometry = {
434 .origin = {
435 .x = view->x,
436 .y = view->y
437 },
438 .size = {
439 .w = view->width,
440 .h = view->height
441 }
442 };
443 wlc_view_set_geometry(view->handle, edge, &geometry);
424 return true; 444 return true;
425 } 445 }
426 return false; 446 return false;
427} 447}
428 448
449
429static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, 450static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
430 uint32_t button, enum wlc_button_state state) { 451 uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) {
431 swayc_t *focused = get_focused_container(&root_container); 452 swayc_t *focused = get_focused_container(&root_container);
432 //dont change focus if fullscreen 453 // dont change focus if fullscreen
433 if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { 454 if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) {
434 return false; 455 return false;
435 } 456 }
436 if (state == WLC_BUTTON_STATE_PRESSED) { 457 if (state == WLC_BUTTON_STATE_PRESSED) {
437 sway_log(L_DEBUG, "Mouse button %u pressed", button); 458 sway_log(L_DEBUG, "Mouse button %u pressed", button);
438 if (button == 272) { 459 if (button == M_LEFT_CLICK) {
439 m1_held = true; 460 pointer_state.l_held = true;
440 } 461 }
441 if (button == 273) { 462 if (button == M_RIGHT_CLICK) {
442 m2_held = true; 463 pointer_state.r_held = true;
443 } 464 }
444 swayc_t *pointer = container_under_pointer(); 465 swayc_t *pointer = container_under_pointer();
445 set_focused_container(pointer); 466 set_focused_container(pointer);
@@ -453,15 +474,32 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
453 } 474 }
454 } 475 }
455 arrange_windows(pointer->parent, -1, -1); 476 arrange_windows(pointer->parent, -1, -1);
477 if (modifiers->mods & config->floating_mod) {
478 int midway_x = pointer->x + pointer->width/2;
479 int midway_y = pointer->y + pointer->height/2;
480
481 pointer_state.floating.drag = pointer_state.l_held;
482 pointer_state.floating.resize = pointer_state.r_held;
483 pointer_state.lock.bottom = origin->y < midway_y;
484 pointer_state.lock.top = !pointer_state.lock.bottom;
485 pointer_state.lock.right = origin->x < midway_x;
486 pointer_state.lock.left = !pointer_state.lock.right;
487 start_floating(pointer);
488 }
489 // Dont want pointer sent to window while dragging or resizing
490 return (pointer_state.floating.drag || pointer_state.floating.resize);
456 } 491 }
457 return (pointer && pointer != focused); 492 return (pointer && pointer != focused);
458 } else { 493 } else {
459 sway_log(L_DEBUG, "Mouse button %u released", button); 494 sway_log(L_DEBUG, "Mouse button %u released", button);
460 if (button == 272) { 495 if (button == M_LEFT_CLICK) {
461 m1_held = false; 496 pointer_state.l_held = false;
497 pointer_state.floating.drag = false;
462 } 498 }
463 if (button == 273) { 499 if (button == M_RIGHT_CLICK) {
464 m2_held = false; 500 pointer_state.r_held = false;
501 pointer_state.floating.resize = false;
502 pointer_state.lock = (struct pointer_lock){false ,false ,false ,false};
465 } 503 }
466 } 504 }
467 return false; 505 return false;
diff --git a/sway/input_state.c b/sway/input_state.c
new file mode 100644
index 00000000..a7f88d4a
--- /dev/null
+++ b/sway/input_state.c
@@ -0,0 +1,68 @@
1#include <string.h>
2#include <stdbool.h>
3#include <ctype.h>
4
5#include "input_state.h"
6
7#define KEY_STATE_MAX_LENGTH 64
8
9static keycode key_state_array[KEY_STATE_MAX_LENGTH];
10
11static uint8_t find_key(keycode key) {
12 int i;
13 for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) {
14 if (key_state_array[i] == key) {
15 break;
16 }
17 }
18 return i;
19}
20
21bool check_key(keycode key) {
22 return find_key(key) < KEY_STATE_MAX_LENGTH;
23}
24
25void press_key(keycode key) {
26 // Check if key exists
27 if (!check_key(key)) {
28 // Check that we dont exceed buffer length
29 int insert = find_key(0);
30 if (insert < KEY_STATE_MAX_LENGTH) {
31 key_state_array[insert] = key;
32 }
33 }
34}
35
36void release_key(keycode key) {
37 uint8_t index = find_key(key);
38 if (index < KEY_STATE_MAX_LENGTH) {
39 // shift it over and remove key
40 key_state_array[index] = 0;
41 }
42}
43
44struct pointer_state pointer_state = {0, 0, {0, 0}, {0, 0, 0, 0}};
45
46static struct wlc_geometry saved_floating;
47
48void start_floating(swayc_t *view) {
49 if (view->is_floating) {
50 saved_floating.origin.x = view->x;
51 saved_floating.origin.y = view->y;
52 saved_floating.size.w = view->width;
53 saved_floating.size.h = view->height;
54 }
55}
56
57void reset_floating(swayc_t *view) {
58 if (view->is_floating) {
59 view->x = saved_floating.origin.x;
60 view->y = saved_floating.origin.y;
61 view->width = saved_floating.size.w;
62 view->height = saved_floating.size.h;
63 arrange_windows(view->parent, -1, -1);
64 }
65 pointer_state.floating = (struct pointer_floating){0,0};
66 pointer_state.lock = (struct pointer_lock){0,0,0,0};
67}
68
diff --git a/sway/ipc.c b/sway/ipc.c
new file mode 100644
index 00000000..39e580cd
--- /dev/null
+++ b/sway/ipc.c
@@ -0,0 +1,321 @@
1// See https://i3wm.org/docs/ipc.html for protocol information
2
3#include <errno.h>
4#include <string.h>
5#include <sys/socket.h>
6#include <sys/un.h>
7#include <stdbool.h>
8#include <wlc/wlc.h>
9#include <unistd.h>
10#include <stdlib.h>
11#include <stropts.h>
12#include <sys/ioctl.h>
13#include <fcntl.h>
14#include <ctype.h>
15#include "ipc.h"
16#include "log.h"
17#include "config.h"
18#include "commands.h"
19#include "list.h"
20#include "stringop.h"
21
22static int ipc_socket = -1;
23static struct wlc_event_source *ipc_event_source = NULL;
24static struct sockaddr_un ipc_sockaddr = {
25 .sun_family = AF_UNIX,
26 .sun_path = "/tmp/sway-ipc.sock"
27};
28
29static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
30
31struct ipc_client {
32 struct wlc_event_source *event_source;
33 int fd;
34 uint32_t payload_length;
35 enum ipc_command_type current_command;
36};
37
38int ipc_handle_connection(int fd, uint32_t mask, void *data);
39int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
40void ipc_client_disconnect(struct ipc_client *client);
41void ipc_client_handle_command(struct ipc_client *client);
42bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
43void ipc_get_workspaces_callback(swayc_t *container, void *data);
44void ipc_get_outputs_callback(swayc_t *container, void *data);
45
46char *json_list(list_t *items);
47
48void ipc_init(void) {
49 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
50 if (ipc_socket == -1) {
51 sway_abort("Unable to create IPC socket");
52 }
53
54 if (getenv("SWAYSOCK") != NULL) {
55 strncpy(ipc_sockaddr.sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr.sun_path));
56 }
57
58 unlink(ipc_sockaddr.sun_path);
59 if (bind(ipc_socket, (struct sockaddr *)&ipc_sockaddr, sizeof(ipc_sockaddr)) == -1) {
60 sway_abort("Unable to bind IPC socket");
61 }
62
63 if (listen(ipc_socket, 3) == -1) {
64 sway_abort("Unable to listen on IPC socket");
65 }
66
67 // Set i3 IPC socket path so that i3-msg works out of the box
68 setenv("I3SOCK", ipc_sockaddr.sun_path, 1);
69
70 ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL);
71}
72
73void ipc_terminate(void) {
74 if (ipc_event_source) {
75 wlc_event_source_remove(ipc_event_source);
76 }
77 close(ipc_socket);
78 unlink(ipc_sockaddr.sun_path);
79}
80
81int ipc_handle_connection(int fd, uint32_t mask, void *data) {
82 (void) fd; (void) data;
83 sway_log(L_DEBUG, "Event on IPC listening socket");
84 assert(mask == WLC_EVENT_READABLE);
85
86 int client_fd = accept(ipc_socket, NULL, NULL);
87 if (client_fd == -1) {
88 sway_log_errno(L_INFO, "Unable to accept IPC client connection");
89 return 0;
90 }
91
92 int flags;
93 if ((flags=fcntl(client_fd, F_GETFD)) == -1 || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
94 sway_log_errno(L_INFO, "Unable to set CLOEXEC on IPC client socket");
95 return 0;
96 }
97
98 struct ipc_client* client = malloc(sizeof(struct ipc_client));
99 client->payload_length = 0;
100 client->fd = client_fd;
101 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
102
103 return 0;
104}
105
106static const int ipc_header_size = sizeof(ipc_magic)+8;
107
108int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
109 struct ipc_client *client = data;
110 sway_log(L_DEBUG, "Event on IPC client socket %d", client_fd);
111
112 if (mask & WLC_EVENT_ERROR) {
113 sway_log(L_INFO, "IPC Client socket error, removing client");
114 ipc_client_disconnect(client);
115 return 0;
116 }
117
118 if (mask & WLC_EVENT_HANGUP) {
119 ipc_client_disconnect(client);
120 return 0;
121 }
122
123 int read_available;
124 ioctl(client_fd, FIONREAD, &read_available);
125
126 // Wait for the rest of the command payload in case the header has already been read
127 if (client->payload_length > 0) {
128 if (read_available >= client->payload_length) {
129 ipc_client_handle_command(client);
130 }
131 else {
132 sway_log(L_DEBUG, "Too little data to read payload on IPC Client socket, waiting for more (%d < %d)", read_available, client->payload_length);
133 }
134 return 0;
135 }
136
137 if (read_available < ipc_header_size) {
138 sway_log(L_DEBUG, "Too little data to read header on IPC Client socket, waiting for more (%d < %d)", read_available, ipc_header_size);
139 return 0;
140 }
141
142 char buf[ipc_header_size];
143 ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
144 if (received == -1) {
145 sway_log_errno(L_INFO, "Unable to receive header from IPC client");
146 ipc_client_disconnect(client);
147 return 0;
148 }
149
150 if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
151 sway_log(L_DEBUG, "IPC header check failed");
152 ipc_client_disconnect(client);
153 return 0;
154 }
155
156 client->payload_length = *(uint32_t *)&buf[sizeof(ipc_magic)];
157 client->current_command = (enum ipc_command_type) *(uint32_t *)&buf[sizeof(ipc_magic)+4];
158
159 if (read_available - received >= client->payload_length) {
160 ipc_client_handle_command(client);
161 }
162
163 return 0;
164}
165
166void ipc_client_disconnect(struct ipc_client *client)
167{
168 if (!sway_assert(client != NULL, "client != NULL")) {
169 return;
170 }
171
172 sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
173 wlc_event_source_remove(client->event_source);
174 close(client->fd);
175 free(client);
176}
177
178void ipc_client_handle_command(struct ipc_client *client) {
179 if (!sway_assert(client != NULL, "client != NULL")) {
180 return;
181 }
182
183 char buf[client->payload_length + 1];
184 if (client->payload_length > 0)
185 {
186 ssize_t received = recv(client->fd, buf, client->payload_length, 0);
187 if (received == -1)
188 {
189 sway_log_errno(L_INFO, "Unable to receive payload from IPC client");
190 ipc_client_disconnect(client);
191 return;
192 }
193 }
194
195 switch (client->current_command) {
196 case IPC_COMMAND:
197 {
198 buf[client->payload_length] = '\0';
199 bool success = handle_command(config, buf);
200 char reply[64];
201 int length = snprintf(reply, sizeof(reply), "{\"success\":%s}", success ? "true" : "false");
202 ipc_send_reply(client, reply, (uint32_t) length);
203 break;
204 }
205 case IPC_GET_WORKSPACES:
206 {
207 list_t *workspaces = create_list();
208 container_map(&root_container, ipc_get_workspaces_callback, workspaces);
209 char *json = json_list(workspaces);
210 free_flat_list(workspaces);
211 ipc_send_reply(client, json, strlen(json));
212 free(json);
213 break;
214 }
215 case IPC_GET_OUTPUTS:
216 {
217 list_t *outputs = create_list();
218 container_map(&root_container, ipc_get_outputs_callback, outputs);
219 char *json = json_list(outputs);
220 free_flat_list(outputs);
221 ipc_send_reply(client, json, strlen(json));
222 free(json);
223 break;
224 }
225 default:
226 sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
227 ipc_client_disconnect(client);
228 break;
229 }
230
231 client->payload_length = 0;
232}
233
234bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length) {
235 assert(payload);
236
237 char data[ipc_header_size];
238
239 memcpy(data, ipc_magic, sizeof(ipc_magic));
240 *(uint32_t *)&(data[sizeof(ipc_magic)]) = payload_length;
241 *(uint32_t *)&(data[sizeof(ipc_magic)+4]) = client->current_command;
242
243 if (write(client->fd, data, ipc_header_size) == -1) {
244 sway_log_errno(L_INFO, "Unable to send header to IPC client");
245 ipc_client_disconnect(client);
246 return false;
247 }
248
249 if (write(client->fd, payload, payload_length) == -1) {
250 sway_log_errno(L_INFO, "Unable to send payload to IPC client");
251 ipc_client_disconnect(client);
252 return false;
253 }
254
255 return true;
256}
257
258char *json_list(list_t *items) {
259 char *json_elements = join_list(items, ",");
260 size_t len = strlen(json_elements);
261 char *json = malloc(len + 3);
262 json[0] = '[';
263 memcpy(json + 1, json_elements, len);
264 json[len+1] = ']';
265 json[len+2] = '\0';
266 free(json_elements);
267 return json;
268}
269
270void ipc_get_workspaces_callback(swayc_t *container, void *data) {
271 if (container->type == C_WORKSPACE) {
272 char *json = malloc(512); // Output should usually be around 180 chars
273 int num = isdigit(container->name[0]) ? atoi(container->name) : -1;
274 // TODO: escape the name (quotation marks, unicode)
275 sprintf(json,
276 "{"
277 "\"num\":%d,"
278 "\"name\":\"%s\","
279 "\"visible\":%s,"
280 "\"focused\":%s,"
281 "\"rect\":{"
282 "\"x\":%d,"
283 "\"y\":%d,"
284 "\"width\":%d,"
285 "\"height\":%d"
286 "},"
287 "\"output\":\"%s\","
288 "\"urgent\":%s"
289 "}",
290 num, container->name, container->visible ? "true" : "false", container->is_focused ? "true" : "false",
291 container->x, container->y, container->width, container->height,
292 container->parent->name, "false" // TODO: urgent hint
293 );
294 list_add((list_t *)data, json);
295 }
296}
297
298void ipc_get_outputs_callback(swayc_t *container, void *data) {
299 if (container->type == C_OUTPUT) {
300 char *json = malloc(512); // Output should usually be around 130 chars
301 // TODO: escape the name (quotation marks, unicode)
302 sprintf(json,
303 "{"
304 "\"name\":\"%s\","
305 "\"active\":%s,"
306 "\"primary\":%s,"
307 "\"rect\":{"
308 "\"x\":%d,"
309 "\"y\":%d,"
310 "\"width\":%d,"
311 "\"height\":%d"
312 "},"
313 "\"current_workspace\":\"%s\""
314 "}",
315 container->name, "true", "false", // TODO: active, primary
316 container->x, container->y, container->width, container->height,
317 container->focused ? container->focused->name : ""
318 );
319 list_add((list_t *)data, json);
320 }
321}
diff --git a/sway/layout.c b/sway/layout.c
index 9fdfd62a..a48f15c4 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -4,6 +4,7 @@
4#include "layout.h" 4#include "layout.h"
5#include "log.h" 5#include "log.h"
6#include "list.h" 6#include "list.h"
7#include "config.h"
7#include "container.h" 8#include "container.h"
8#include "workspace.h" 9#include "workspace.h"
9#include "focus.h" 10#include "focus.h"
@@ -32,6 +33,21 @@ void add_child(swayc_t *parent, swayc_t *child) {
32 child->width, child->height, parent, parent->type, parent->width, parent->height); 33 child->width, child->height, parent, parent->type, parent->width, parent->height);
33 list_add(parent->children, child); 34 list_add(parent->children, child);
34 child->parent = parent; 35 child->parent = parent;
36 // set focus for this container
37 if (parent->children->length == 1) {
38 set_focused_container_for(parent, child);
39 }
40}
41
42void add_floating(swayc_t *ws, swayc_t *child) {
43 sway_log(L_DEBUG, "Adding %p (%d, %dx%d) to %p (%d, %dx%d)", child, child->type,
44 child->width, child->height, ws, ws->type, ws->width, ws->height);
45 list_add(ws->floating, child);
46 child->parent = ws;
47 child->is_floating = true;
48 if (!ws->focused) {
49 set_focused_container_for(ws, child);
50 }
35} 51}
36 52
37swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { 53swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) {
@@ -55,7 +71,7 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) {
55 new_child->parent = child->parent; 71 new_child->parent = child->parent;
56 72
57 if (child->parent->focused == child) { 73 if (child->parent->focused == child) {
58 child->parent->focused = new_child; 74 set_focused_container_for(child->parent, new_child);
59 } 75 }
60 child->parent = NULL; 76 child->parent = NULL;
61 return parent; 77 return parent;
@@ -72,6 +88,7 @@ swayc_t *remove_child(swayc_t *child) {
72 break; 88 break;
73 } 89 }
74 } 90 }
91 i = 0;
75 } else { 92 } else {
76 for (i = 0; i < parent->children->length; ++i) { 93 for (i = 0; i < parent->children->length; ++i) {
77 if (parent->children->items[i] == child) { 94 if (parent->children->items[i] == child) {
@@ -80,7 +97,7 @@ swayc_t *remove_child(swayc_t *child) {
80 } 97 }
81 } 98 }
82 } 99 }
83 //Set focused to new container 100 // Set focused to new container
84 if (parent->focused == child) { 101 if (parent->focused == child) {
85 if (parent->children->length > 0) { 102 if (parent->children->length > 0) {
86 set_focused_container_for(parent, parent->children->items[i?i-1:0]); 103 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){
104 //Only one container, meh. 121 //Only one container, meh.
105 break; 122 break;
106 } 123 }
107 124 //TODO: Implement horizontal movement.
108 //TODO: Implement move to a different workspace. 125 //TODO: Implement move to a different workspace.
109 if(direction == MOVE_LEFT && i > 0){ 126 if(direction == MOVE_LEFT && i > 0){
110 temp = root->children->items[i-1]; 127 temp = root->children->items[i-1];
@@ -167,11 +184,11 @@ void arrange_windows(swayc_t *container, int width, int height) {
167 // y -= container->y; 184 // y -= container->y;
168 for (i = 0; i < container->children->length; ++i) { 185 for (i = 0; i < container->children->length; ++i) {
169 swayc_t *child = container->children->items[i]; 186 swayc_t *child = container->children->items[i];
170 sway_log(L_DEBUG, "Arranging workspace #%d", i); 187 child->x = x + container->gaps;
171 child->x = x; 188 child->y = y + container->gaps;
172 child->y = y; 189 child->width = width - container->gaps * 2;
173 child->width = width; 190 child->height = height - container->gaps * 2;
174 child->height = height; 191 sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y);
175 arrange_windows(child, -1, -1); 192 arrange_windows(child, -1, -1);
176 } 193 }
177 return; 194 return;
@@ -179,27 +196,24 @@ void arrange_windows(swayc_t *container, int width, int height) {
179 { 196 {
180 struct wlc_geometry geometry = { 197 struct wlc_geometry geometry = {
181 .origin = { 198 .origin = {
182 .x = container->x, 199 .x = container->x + container->gaps / 2,
183 .y = container->y 200 .y = container->y + container->gaps / 2
184 }, 201 },
185 .size = { 202 .size = {
186 .w = width, 203 .w = width - container->gaps,
187 .h = height 204 .h = height - container->gaps
188 } 205 }
189 }; 206 };
190 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { 207 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
191 swayc_t *parent = container; 208 swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
192 while (parent->type != C_OUTPUT) {
193 parent = parent->parent;
194 }
195 geometry.origin.x = 0; 209 geometry.origin.x = 0;
196 geometry.origin.y = 0; 210 geometry.origin.y = 0;
197 geometry.size.w = parent->width; 211 geometry.size.w = parent->width;
198 geometry.size.h = parent->height; 212 geometry.size.h = parent->height;
199 wlc_view_set_geometry(container->handle, &geometry); 213 wlc_view_set_geometry(container->handle, 0, &geometry);
200 wlc_view_bring_to_front(container->handle); 214 wlc_view_bring_to_front(container->handle);
201 } else { 215 } else {
202 wlc_view_set_geometry(container->handle, &geometry); 216 wlc_view_set_geometry(container->handle, 0, &geometry);
203 container->width = width; 217 container->width = width;
204 container->height = height; 218 container->height = height;
205 } 219 }
@@ -213,40 +227,62 @@ void arrange_windows(swayc_t *container, int width, int height) {
213 break; 227 break;
214 } 228 }
215 229
216 double total_weight = 0; 230 x = y = 0;
217 for (i = 0; i < container->children->length; ++i) { 231 double scale = 0;
218 swayc_t *child = container->children->items[i];
219 total_weight += child->weight;
220 }
221
222 switch (container->layout) { 232 switch (container->layout) {
223 case L_HORIZ: 233 case L_HORIZ:
224 default: 234 default:
225 sway_log(L_DEBUG, "Arranging %p horizontally", container); 235 // Calculate total width
226 for (i = 0; i < container->children->length; ++i) { 236 for (i = 0; i < container->children->length; ++i) {
227 swayc_t *child = container->children->items[i]; 237 int *old_width = &((swayc_t *)container->children->items[i])->width;
228 double percent = child->weight / total_weight; 238 if (*old_width <= 0) {
229 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); 239 if (container->children->length > 1) {
230 child->x = x + container->x; 240 *old_width = width / (container->children->length - 1);
231 child->y = y + container->y; 241 } else {
232 int w = width * percent; 242 *old_width = width;
233 int h = height; 243 }
234 arrange_windows(child, w, h); 244 }
235 x += w; 245 scale += *old_width;
246 }
247 // Resize windows
248 if (scale > 0.1) {
249 scale = width / scale;
250 sway_log(L_DEBUG, "Arranging %p horizontally", container);
251 for (i = 0; i < container->children->length; ++i) {
252 swayc_t *child = container->children->items[i];
253 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, width, scale);
254 child->x = x + container->x;
255 child->y = y + container->y;
256 arrange_windows(child, child->width * scale, height);
257 x += child->width;
258 }
236 } 259 }
237 break; 260 break;
238 case L_VERT: 261 case L_VERT:
239 sway_log(L_DEBUG, "Arranging %p vertically", container); 262 // Calculate total height
240 for (i = 0; i < container->children->length; ++i) { 263 for (i = 0; i < container->children->length; ++i) {
241 swayc_t *child = container->children->items[i]; 264 int *old_height = &((swayc_t *)container->children->items[i])->height;
242 double percent = child->weight / total_weight; 265 if (*old_height <= 0) {
243 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); 266 if (container->children->length > 1) {
244 child->x = x + container->x; 267 *old_height = height / (container->children->length - 1);
245 child->y = y + container->y; 268 } else {
246 int w = width; 269 *old_height = height;
247 int h = height * percent; 270 }
248 arrange_windows(child, w, h); 271 }
249 y += h; 272 scale += *old_height;
273 }
274 // Resize
275 if (scale > 0.1) {
276 scale = height / scale;
277 sway_log(L_DEBUG, "Arranging %p vertically", container);
278 for (i = 0; i < container->children->length; ++i) {
279 swayc_t *child = container->children->items[i];
280 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, height, scale);
281 child->x = x + container->x;
282 child->y = y + container->y;
283 arrange_windows(child, width, child->height * scale);
284 y += child->height;
285 }
250 } 286 }
251 break; 287 break;
252 } 288 }
@@ -268,20 +304,15 @@ void arrange_windows(swayc_t *container, int width, int height) {
268 } 304 }
269 }; 305 };
270 if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { 306 if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) {
271 swayc_t *parent = view; 307 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
272 while (parent->type != C_OUTPUT) {
273 parent = parent->parent;
274 }
275 geometry.origin.x = 0; 308 geometry.origin.x = 0;
276 geometry.origin.y = 0; 309 geometry.origin.y = 0;
277 geometry.size.w = parent->width; 310 geometry.size.w = parent->width;
278 geometry.size.h = parent->height; 311 geometry.size.h = parent->height;
279 wlc_view_set_geometry(view->handle, &geometry); 312 wlc_view_set_geometry(view->handle, 0, &geometry);
280 wlc_view_bring_to_front(view->handle); 313 wlc_view_bring_to_front(view->handle);
281 } else { 314 } else {
282 wlc_view_set_geometry(view->handle, &geometry); 315 wlc_view_set_geometry(view->handle, 0, &geometry);
283 view->width = width;
284 view->height = height;
285 // Bring the views to the front in order of the list, the list 316 // Bring the views to the front in order of the list, the list
286 // will be kept up to date so that more recently focused views 317 // will be kept up to date so that more recently focused views
287 // have higher indexes 318 // have higher indexes
@@ -326,3 +357,54 @@ swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) {
326 } 357 }
327 return NULL; 358 return NULL;
328} 359}
360
361swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) {
362 swayc_t *parent = container->parent;
363
364 if (dir == MOVE_PARENT) {
365 if (parent->type == C_OUTPUT) {
366 return NULL;
367 } else {
368 return parent;
369 }
370 }
371 while (true) {
372 // Test if we can even make a difference here
373 bool can_move = false;
374 int diff = 0;
375 if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
376 if (parent->layout == L_HORIZ || parent->type == C_ROOT) {
377 can_move = true;
378 diff = dir == MOVE_LEFT ? -1 : 1;
379 }
380 } else {
381 if (parent->layout == L_VERT) {
382 can_move = true;
383 diff = dir == MOVE_UP ? -1 : 1;
384 }
385 }
386 if (can_move) {
387 int i;
388 for (i = 0; i < parent->children->length; ++i) {
389 swayc_t *child = parent->children->items[i];
390 if (child == container) {
391 break;
392 }
393 }
394 int desired = i + diff;
395 if (desired < 0 || desired >= parent->children->length) {
396 can_move = false;
397 } else {
398 return parent->children->items[desired];
399 }
400 }
401 if (!can_move) {
402 container = parent;
403 parent = parent->parent;
404 if (!parent) {
405 // Nothing we can do
406 return NULL;
407 }
408 }
409 }
410}
diff --git a/sway/log.c b/sway/log.c
index 8e380ffe..6e01421b 100644
--- a/sway/log.c
+++ b/sway/log.c
@@ -1,9 +1,13 @@
1#include "log.h" 1#include "log.h"
2#include "sway.h"
2#include <stdarg.h> 3#include <stdarg.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <fcntl.h> 6#include <fcntl.h>
6#include <unistd.h> 7#include <unistd.h>
8#include <signal.h>
9#include <errno.h>
10#include <string.h>
7 11
8int colored = 1; 12int colored = 1;
9int v = 0; 13int v = 0;
@@ -18,10 +22,10 @@ static const char *verbosity_colors[] = {
18void init_log(int verbosity) { 22void init_log(int verbosity) {
19 v = verbosity; 23 v = verbosity;
20 /* set FD_CLOEXEC flag to prevent programs called with exec to write into logs */ 24 /* set FD_CLOEXEC flag to prevent programs called with exec to write into logs */
21 int i, flag; 25 int i;
22 int fd[] = { STDOUT_FILENO, STDIN_FILENO, STDERR_FILENO }; 26 int fd[] = { STDOUT_FILENO, STDIN_FILENO, STDERR_FILENO };
23 for (i = 0; i < 3; ++i) { 27 for (i = 0; i < 3; ++i) {
24 flag = fcntl(fd[i], F_GETFD); 28 int flag = fcntl(fd[i], F_GETFD);
25 if (flag != -1) { 29 if (flag != -1) {
26 fcntl(fd[i], F_SETFD, flag | FD_CLOEXEC); 30 fcntl(fd[i], F_SETFD, flag | FD_CLOEXEC);
27 } 31 }
@@ -32,17 +36,17 @@ void sway_log_colors(int mode) {
32 colored = (mode == 1) ? 1 : 0; 36 colored = (mode == 1) ? 1 : 0;
33} 37}
34 38
35void sway_abort(char *format, ...) { 39void sway_abort(const char *format, ...) {
36 fprintf(stderr, "ERROR: "); 40 fprintf(stderr, "ERROR: ");
37 va_list args; 41 va_list args;
38 va_start(args, format); 42 va_start(args, format);
39 vfprintf(stderr, format, args); 43 vfprintf(stderr, format, args);
40 va_end(args); 44 va_end(args);
41 fprintf(stderr, "\n"); 45 fprintf(stderr, "\n");
42 exit(1); 46 sway_terminate();
43} 47}
44 48
45void sway_log(int verbosity, char* format, ...) { 49void sway_log(int verbosity, const char* format, ...) {
46 if (verbosity <= v) { 50 if (verbosity <= v) {
47 int c = verbosity; 51 int c = verbosity;
48 if (c > sizeof(verbosity_colors) / sizeof(char *)) { 52 if (c > sizeof(verbosity_colors) / sizeof(char *)) {
@@ -64,3 +68,106 @@ void sway_log(int verbosity, char* format, ...) {
64 fprintf(stderr, "\n"); 68 fprintf(stderr, "\n");
65 } 69 }
66} 70}
71
72void sway_log_errno(int verbosity, char* format, ...) {
73 if (verbosity <= v) {
74 int c = verbosity;
75 if (c > sizeof(verbosity_colors) / sizeof(char *)) {
76 c = sizeof(verbosity_colors) / sizeof(char *) - 1;
77 }
78
79 if (colored) {
80 fprintf(stderr, verbosity_colors[c]);
81 }
82
83 va_list args;
84 va_start(args, format);
85 vfprintf(stderr, format, args);
86 va_end(args);
87
88 fprintf(stderr, ": ");
89 char error[256];
90 strerror_r(errno, error, sizeof(error));
91 fprintf(stderr, error);
92
93 if (colored) {
94 fprintf(stderr, "\x1B[0m");
95 }
96 fprintf(stderr, "\n");
97 }
98}
99
100bool sway_assert(bool condition, const char* format, ...) {
101 if (condition) {
102 return true;
103 }
104
105#ifndef NDEBUG
106 raise(SIGABRT);
107#endif
108
109 va_list args;
110 va_start(args, format);
111 sway_log(L_ERROR, format, args);
112 va_end(args);
113
114 return false;
115}
116
117#include "workspace.h"
118
119/* XXX:DEBUG:XXX */
120static void container_log(const swayc_t *c) {
121 fprintf(stderr, "focus:%c|",
122 c->is_focused ? 'F' : // Focused
123 c == active_workspace ? 'W' : // active workspace
124 c == &root_container ? 'R' : // root
125 'X');// not any others
126 fprintf(stderr,"(%p)",c);
127 fprintf(stderr,"(p:%p)",c->parent);
128 fprintf(stderr,"(f:%p)",c->focused);
129 fprintf(stderr,"(h:%ld)",c->handle);
130 fprintf(stderr,"Type:");
131 fprintf(stderr,
132 c->type == C_ROOT ? "Root|" :
133 c->type == C_OUTPUT ? "Output|" :
134 c->type == C_WORKSPACE ? "Workspace|" :
135 c->type == C_CONTAINER ? "Container|" :
136 c->type == C_VIEW ? "View|" : "Unknown|");
137 fprintf(stderr,"layout:");
138 fprintf(stderr,
139 c->layout == L_NONE ? "NONE|" :
140 c->layout == L_HORIZ ? "Horiz|":
141 c->layout == L_VERT ? "Vert|":
142 c->layout == L_STACKED ? "Stacked|":
143 c->layout == L_FLOATING ? "Floating|":
144 "Unknown|");
145 fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
146 fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
147 fprintf(stderr, "vis:%c|", c->visible?'t':'f');
148 fprintf(stderr, "name:%.16s|", c->name);
149 fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
150}
151void layout_log(const swayc_t *c, int depth) {
152 int i, d;
153 int e = c->children ? c->children->length : 0;
154 container_log(c);
155 if (e) {
156 for (i = 0; i < e; ++i) {
157 fputc('|',stderr);
158 for (d = 0; d < depth; ++d) fputc('-', stderr);
159 layout_log(c->children->items[i], depth + 1);
160 }
161 }
162 if (c->type == C_WORKSPACE) {
163 e = c->floating?c->floating->length:0;
164 if (e) {
165 for (i = 0; i < e; ++i) {
166 fputc('|',stderr);
167 for (d = 0; d < depth; ++d) fputc('=', stderr);
168 layout_log(c->floating->items[i], depth + 1);
169 }
170 }
171 }
172}
173/* XXX:DEBUG:XXX */
diff --git a/sway/main.c b/sway/main.c
index 2db4604c..f37f086d 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -4,31 +4,121 @@
4#include <wlc/wlc.h> 4#include <wlc/wlc.h>
5#include <sys/wait.h> 5#include <sys/wait.h>
6#include <signal.h> 6#include <signal.h>
7#include <getopt.h>
7#include "layout.h" 8#include "layout.h"
8#include "config.h" 9#include "config.h"
9#include "log.h" 10#include "log.h"
10#include "handlers.h" 11#include "handlers.h"
12#include "ipc.h"
13#include "sway.h"
14
15static bool terminate_request = false;
16
17void sway_terminate(void) {
18 terminate_request = true;
19 wlc_terminate();
20}
11 21
12static void sigchld_handle(int signal); 22static void sigchld_handle(int signal);
13 23
14int main(int argc, char **argv) { 24int main(int argc, char **argv) {
25 static int verbose = 0, debug = 0, validate = 0;
26
27 static struct option long_options[] = {
28 {"config", required_argument, NULL, 'c'},
29 {"validate", no_argument, &validate, 1},
30 {"debug", no_argument, &debug, 1},
31 {"version", no_argument, NULL, 'v'},
32 {"verbose", no_argument, &verbose, 1},
33 {"get-socketpath", no_argument, NULL, 'p'},
34 };
35
15 /* Signal handling */ 36 /* Signal handling */
16 signal(SIGCHLD, sigchld_handle); 37 signal(SIGCHLD, sigchld_handle);
17 38
18 setenv("WLC_DIM", "0", 0); 39 setenv("WLC_DIM", "0", 0);
40
41 FILE *devnull = fopen("/dev/null", "w");
42 if (devnull) {
43 // NOTE: Does not work, see wlc issue #54
44 wlc_set_log_file(devnull);
45 }
46
19 /* Changing code earlier than this point requires detailed review */ 47 /* Changing code earlier than this point requires detailed review */
20 if (!wlc_init(&interface, argc, argv)) { 48 if (!wlc_init(&interface, argc, argv)) {
21 return 1; 49 return 1;
22 } 50 }
23 51
24 init_log(L_DEBUG); // TODO: Control this with command line arg 52 char *config_path = NULL;
53
54 int c;
55 while (1) {
56 int option_index = 0;
57 c = getopt_long(argc, argv, "CdvVpc:", long_options, &option_index);
58 if (c == -1) {
59 break;
60 }
61 switch (c) {
62 case 0: // Flag
63 break;
64 case 'c': // config
65 config_path = strdup(optarg);
66 break;
67 case 'C': // validate
68 validate = 1;
69 break;
70 case 'd': // debug
71 debug = 1;
72 break;
73 case 'v': // version
74 // todo
75 exit(0);
76 break;
77 case 'V': // verbose
78 verbose = 1;
79 break;
80 case 'p': // --get-socketpath
81 // TODO
82 break;
83 }
84 }
85
86 if (debug) {
87 init_log(L_DEBUG);
88 wlc_set_log_file(stderr);
89 fclose(devnull);
90 devnull = NULL;
91 } else if (verbose || validate) {
92 init_log(L_INFO);
93 } else {
94 init_log(L_ERROR);
95 }
96
97 if (validate) {
98 bool valid = load_config(config_path);
99 return valid ? 0 : 1;
100 }
101
25 init_layout(); 102 init_layout();
26 103
27 if (!load_config()) { 104 if (!load_config(config_path)) {
28 sway_log(L_ERROR, "Error(s) loading config!"); 105 sway_log(L_ERROR, "Error(s) loading config!");
29 } 106 }
107 if (config_path) {
108 free(config_path);
109 }
110
111 ipc_init();
112
113 if (!terminate_request) {
114 wlc_run();
115 }
116
117 if (devnull) {
118 fclose(devnull);
119 }
30 120
31 wlc_run(); 121 ipc_terminate();
32 122
33 return 0; 123 return 0;
34} 124}
diff --git a/sway/readline.c b/sway/readline.c
index dfdc3fe8..e75b183f 100644
--- a/sway/readline.c
+++ b/sway/readline.c
@@ -17,18 +17,22 @@ char *read_line(FILE *file) {
17 continue; 17 continue;
18 } 18 }
19 if (length == size) { 19 if (length == size) {
20 string = realloc(string, size *= 2); 20 char *new_string = realloc(string, size *= 2);
21 if (!string) { 21 if (!new_string) {
22 free(string);
22 return NULL; 23 return NULL;
23 } 24 }
25 string = new_string;
24 } 26 }
25 string[length++] = c; 27 string[length++] = c;
26 } 28 }
27 if (length + 1 == size) { 29 if (length + 1 == size) {
28 string = realloc(string, length + 1); 30 char *new_string = realloc(string, length + 1);
29 if (!string) { 31 if (!new_string) {
32 free(string);
30 return NULL; 33 return NULL;
31 } 34 }
35 string = new_string;
32 } 36 }
33 string[length] = '\0'; 37 string[length] = '\0';
34 return string; 38 return string;
diff --git a/sway/stringop.c b/sway/stringop.c
index 1dff97bf..c39e2c34 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -4,6 +4,7 @@
4#include "string.h" 4#include "string.h"
5#include "list.h" 5#include "list.h"
6#include <strings.h> 6#include <strings.h>
7#include <log.h>
7 8
8/* Note: This returns 8 characters for trimmed_start per tab character. */ 9/* Note: This returns 8 characters for trimmed_start per tab character. */
9char *strip_whitespace(char *_str, int *trimmed_start) { 10char *strip_whitespace(char *_str, int *trimmed_start) {
@@ -197,3 +198,41 @@ char *join_args(char **argv, int argc) {
197 res[len - 1] = '\0'; 198 res[len - 1] = '\0';
198 return res; 199 return res;
199} 200}
201
202/*
203 * Join a list of strings, adding separator in between. Separator can be NULL.
204 */
205char *join_list(list_t *list, char *separator) {
206 if (!sway_assert(list != NULL, "list != NULL") || list->length == 0) {
207 return NULL;
208 }
209
210 size_t len = 1; // NULL terminator
211 size_t sep_len = 0;
212 if (separator != NULL) {
213 sep_len = strlen(separator);
214 len += (list->length - 1) * sep_len;
215 }
216
217 for (int i = 0; i < list->length; i++) {
218 len += strlen(list->items[i]);
219 }
220
221 char *res = malloc(len);
222
223 char *p = res + strlen(list->items[0]);
224 strcpy(res, list->items[0]);
225
226 for (int i = 1; i < list->length; i++) {
227 if (sep_len) {
228 memcpy(p, separator, sep_len);
229 p += sep_len;
230 }
231 strcpy(p, list->items[i]);
232 p += strlen(list->items[i]);
233 }
234
235 *p = '\0';
236
237 return res;
238}
diff --git a/sway/workspace.c b/sway/workspace.c
index 05a669fe..d436da8e 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -31,7 +31,7 @@ char *workspace_next_name(void) {
31 char* target = malloc(strlen(args->items[1]) + 1); 31 char* target = malloc(strlen(args->items[1]) + 1);
32 strcpy(target, args->items[1]); 32 strcpy(target, args->items[1]);
33 while (*target == ' ' || *target == '\t') 33 while (*target == ' ' || *target == '\t')
34 target++; 34 target++;
35 35
36 // Make sure that the command references an actual workspace 36 // Make sure that the command references an actual workspace
37 // not a command about workspaces 37 // not a command about workspaces
@@ -42,11 +42,15 @@ char *workspace_next_name(void) {
42 strcmp(target, "number") == 0 || 42 strcmp(target, "number") == 0 ||
43 strcmp(target, "back_and_forth") == 0 || 43 strcmp(target, "back_and_forth") == 0 ||
44 strcmp(target, "current") == 0) 44 strcmp(target, "current") == 0)
45 {
46 list_free(args);
45 continue; 47 continue;
46 48 }
47 //Make sure that the workspace doesn't already exist 49
50 // Make sure that the workspace doesn't already exist
48 if (workspace_find_by_name(target)) { 51 if (workspace_find_by_name(target)) {
49 continue; 52 list_free(args);
53 continue;
50 } 54 }
51 55
52 list_free(args); 56 list_free(args);
@@ -54,6 +58,7 @@ char *workspace_next_name(void) {
54 sway_log(L_DEBUG, "Workspace: Found free name %s", target); 58 sway_log(L_DEBUG, "Workspace: Found free name %s", target);
55 return target; 59 return target;
56 } 60 }
61 list_free(args);
57 } 62 }
58 // As a fall back, get the current number of active workspaces 63 // As a fall back, get the current number of active workspaces
59 // and return that + 1 for the next workspace's name 64 // and return that + 1 for the next workspace's name
@@ -70,14 +75,12 @@ char *workspace_next_name(void) {
70 75
71swayc_t *workspace_create(const char* name) { 76swayc_t *workspace_create(const char* name) {
72 swayc_t *parent = get_focused_container(&root_container); 77 swayc_t *parent = get_focused_container(&root_container);
73 while (parent->type != C_OUTPUT) { 78 parent = swayc_parent_by_type(parent, C_OUTPUT);
74 parent = parent->parent;
75 }
76 return new_workspace(parent, name); 79 return new_workspace(parent, name);
77} 80}
78 81
79bool workspace_by_name(swayc_t *view, void *data) { 82bool workspace_by_name(swayc_t *view, void *data) {
80 return (view->type == C_WORKSPACE) && 83 return (view->type == C_WORKSPACE) &&
81 (strcasecmp(view->name, (char *) data) == 0); 84 (strcasecmp(view->name, (char *) data) == 0);
82} 85}
83 86
@@ -180,62 +183,4 @@ void workspace_switch(swayc_t *workspace) {
180 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); 183 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
181 set_focused_container(get_focused_view(workspace)); 184 set_focused_container(get_focused_view(workspace));
182 arrange_windows(workspace, -1, -1); 185 arrange_windows(workspace, -1, -1);
183 active_workspace = workspace;
184}
185
186/* XXX:DEBUG:XXX */
187static void container_log(const swayc_t *c) {
188 fprintf(stderr, "focus:%c|",
189 c->is_focused ? 'F' : //Focused
190 c == active_workspace ? 'W' : //active workspace
191 c == &root_container ? 'R' : //root
192 'X');//not any others
193 fprintf(stderr,"(%p)",c);
194 fprintf(stderr,"(p:%p)",c->parent);
195 fprintf(stderr,"(f:%p)",c->focused);
196 fprintf(stderr,"(h:%ld)",c->handle);
197 fprintf(stderr,"Type:");
198 fprintf(stderr,
199 c->type == C_ROOT ? "Root|" :
200 c->type == C_OUTPUT ? "Output|" :
201 c->type == C_WORKSPACE ? "Workspace|" :
202 c->type == C_CONTAINER ? "Container|" :
203 c->type == C_VIEW ? "View|" : "Unknown|");
204 fprintf(stderr,"layout:");
205 fprintf(stderr,
206 c->layout == L_NONE ? "NONE|" :
207 c->layout == L_HORIZ ? "Horiz|":
208 c->layout == L_VERT ? "Vert|":
209 c->layout == L_STACKED ? "Stacked|":
210 c->layout == L_FLOATING ? "Floating|":
211 "Unknown|");
212 fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
213 fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
214 fprintf(stderr, "vis:%c|", c->visible?'t':'f');
215 fprintf(stderr, "wgt:%d|", c->weight);
216 fprintf(stderr, "name:%.16s|", c->name);
217 fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
218}
219void layout_log(const swayc_t *c, int depth) {
220 int i, d;
221 int e = c->children ? c->children->length : 0;
222 container_log(c);
223 if (e) {
224 for (i = 0; i < e; ++i) {
225 fputc('|',stderr);
226 for (d = 0; d < depth; ++d) fputc('-', stderr);
227 layout_log(c->children->items[i], depth + 1);
228 }
229 }
230 if (c->type == C_WORKSPACE) {
231 e = c->floating?c->floating->length:0;
232 if (e) {
233 for (i = 0; i < e; ++i) {
234 fputc('|',stderr);
235 for (d = 0; d < depth; ++d) fputc('-', stderr);
236 layout_log(c->floating->items[i], depth + 1);
237 }
238 }
239 }
240} 186}
241/* XXX:DEBUG:XXX */