summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt1
-rw-r--r--README.md46
-rw-r--r--include/config.h5
-rw-r--r--include/container.h22
-rw-r--r--include/focus.h4
-rw-r--r--include/input_state.h49
-rw-r--r--include/ipc.h18
-rw-r--r--include/layout.h6
-rw-r--r--include/log.h9
-rw-r--r--include/stringop.h5
-rw-r--r--include/sway.h6
-rw-r--r--include/workspace.h1
-rw-r--r--sway.5.txt30
-rw-r--r--sway/commands.c216
-rw-r--r--sway/config.c221
-rw-r--r--sway/container.c173
-rw-r--r--sway/focus.c154
-rw-r--r--sway/handlers.c356
-rw-r--r--sway/input_state.c68
-rw-r--r--sway/ipc.c321
-rw-r--r--sway/layout.c271
-rw-r--r--sway/log.c117
-rw-r--r--sway/main.c96
-rw-r--r--sway/readline.c12
-rw-r--r--sway/stringop.c91
-rw-r--r--sway/workspace.c88
27 files changed, 1749 insertions, 638 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/README.md b/README.md
index 8c312984..a51a0a86 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,11 @@
1# sway 1# sway
2 2
3"**S**irCmpwn's **Way**land window manager" 3"**S**irCmpwn's **Way**land window manager" is a **work in progress**
4 4i3-compatible window manager for [Wayland](http://wayland.freedesktop.org/).
5sway is a **work in progress** i3-compatible window manager for 5Read the [FAQ](https://github.com/SirCmpwn/sway/wiki).
6[Wayland](http://wayland.freedesktop.org/).
7 6
8![](https://sr.ht/qxGE.png) 7![](https://sr.ht/qxGE.png)
9 8
10Chat on #sway on irc.freenode.net
11
12## Rationale 9## Rationale
13 10
14I use i3 on xorg. Wayland is coming, and [i3way](http://i3way.org/) still has 11I use i3 on xorg. Wayland is coming, and [i3way](http://i3way.org/) still has
@@ -20,44 +17,39 @@ zero lines of source code after two years.
20 17
21## Installation 18## Installation
22 19
23### Arch Linux 20### From Packages
21
22sway is not supported by many distributions yet. Here's a list of packages
23available for you to install:
24 24
25Install [aur/sway-git](https://aur.archlinux.org/packages/sway-git/). 25* [Arch Linux](https://aur.archlinux.org/packages/sway-git/).
26 26
27### Manual 27### Compiling from Source
28 28
29Dependencies: 29Install dependencies:
30 30
31* cmake 31* cmake
32* [wlc](https://github.com/Cloudef/wlc) 32* [wlc](https://github.com/Cloudef/wlc)
33* xwayland 33* xwayland
34* asciidoc 34* asciidoc
35 35
36Compiling: 36Run these commands:
37 37
38 cmake . 38 cmake .
39 make 39 make
40 # sudo make install 40 sudo make install
41
42Binary shows up in `./bin` (or `/usr/local/bin` if you `make install`).
43 41
44## Configuration 42## Configuration
45 43
46 mkdir ~/.config/sway 44If you already use i3, then copy your i3 config to `~/.config/sway/config` and
47 cp ~/.config/i3/config ~/.config/sway/ 45it'll work out of the box. Otherwise, copy `/etc/sway/config` to
48 46`~/.config/sway/config`. Run `man 5 sway` for information on the configuration.
49Or if you don't already use i3:
50
51 mkdir ~/.config/sway
52 cp /etc/sway/config ~/.config/sway/
53
54Edit to your liking.
55
56[See also](http://i3wm.org/docs/)
57 47
58## Running 48## Running
59 49
50Run this from a tty (instead of starting x):
51
60 sway 52 sway
61 53
62If you run this while xorg is running, it'll run inside of an x window (useful 54If you run it from within x, it will spawn x windows instead of using your
63for testing). Otherwise, it'll run wayland properly. 55hardware directly (useful for development).
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 186ee8b6..79e023fe 100644
--- a/include/container.h
+++ b/include/container.h
@@ -11,10 +11,11 @@ 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
18
18enum swayc_layouts{ 19enum swayc_layouts{
19 L_NONE, 20 L_NONE,
20 L_HORIZ, 21 L_HORIZ,
@@ -22,7 +23,7 @@ enum swayc_layouts{
22 L_STACKED, 23 L_STACKED,
23 L_TABBED, 24 L_TABBED,
24 L_FLOATING, 25 L_FLOATING,
25 //Keep last 26 // Keep last
26 L_LAYOUTS, 27 L_LAYOUTS,
27}; 28};
28 29
@@ -44,10 +45,10 @@ struct sway_container {
44 bool is_floating; 45 bool is_floating;
45 bool is_focused; 46 bool is_focused;
46 47
47 int weight;
48
49 char *name; 48 char *name;
50 49
50 int gaps;
51
51 list_t *children; 52 list_t *children;
52 list_t *floating; 53 list_t *floating;
53 54
@@ -55,6 +56,7 @@ struct sway_container {
55 struct sway_container *focused; 56 struct sway_container *focused;
56}; 57};
57 58
59// Container Creation
58 60
59swayc_t *new_output(wlc_handle handle); 61swayc_t *new_output(wlc_handle handle);
60swayc_t *new_workspace(swayc_t *output, const char *name); 62swayc_t *new_workspace(swayc_t *output, const char *name);
@@ -65,17 +67,29 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle);
65// 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
66swayc_t *new_floating_view(wlc_handle handle); 68swayc_t *new_floating_view(wlc_handle handle);
67 69
70// Container Destroying
68 71
69swayc_t *destroy_output(swayc_t *output); 72swayc_t *destroy_output(swayc_t *output);
70// Destroys workspace if empty and returns parent pointer, else returns NULL 73// Destroys workspace if empty and returns parent pointer, else returns NULL
71swayc_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
72swayc_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
73swayc_t *destroy_view(swayc_t *view); 80swayc_t *destroy_view(swayc_t *view);
74 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
75swayc_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);
76void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); 88void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
77 89
90
78// Mappings 91// Mappings
79void 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);
80 94
81#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 282f92ee..c1d7d8b4 100644
--- a/include/layout.h
+++ b/include/layout.h
@@ -4,17 +4,22 @@
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);
16swayc_t *remove_child(swayc_t *child); 18swayc_t *remove_child(swayc_t *child);
17 19
20void move_container(swayc_t* container,swayc_t* root,int direction);
21
22
18// Layout 23// Layout
19void arrange_windows(swayc_t *container, int width, int height); 24void arrange_windows(swayc_t *container, int width, int height);
20 25
@@ -25,5 +30,6 @@ void focus_view_for(swayc_t *ancestor, swayc_t *container);
25 30
26swayc_t *get_focused_container(swayc_t *parent); 31swayc_t *get_focused_container(swayc_t *parent);
27swayc_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);
28 34
29#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 03387345..4300f9ed 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -2,13 +2,14 @@
2#define _SWAY_STRINGOP_H 2#define _SWAY_STRINGOP_H
3#include "list.h" 3#include "list.h"
4 4
5void strip_whitespace(char *str); 5char *strip_whitespace(char *str, int *trimmed_start);
6void strip_comments(char *str); 6char *strip_comments(char *str);
7list_t *split_string(const char *str, const char *delims); 7list_t *split_string(const char *str, const char *delims);
8void free_flat_list(list_t *list); 8void free_flat_list(list_t *list);
9char *code_strchr(const char *string, char delimiter); 9char *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 2ecfeb98..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
@@ -282,7 +342,62 @@ static bool cmd_focus_follows_mouse(struct sway_config *config, int argc, char *
282} 342}
283 343
284static bool cmd_move(struct sway_config *config, int argc, char **argv) { 344static bool cmd_move(struct sway_config *config, int argc, char **argv) {
285 sway_log(L_DEBUG, "move cmd stub called");//Stubbed method until I get back. 345 if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 1)) {
346 return false;
347 }
348
349 swayc_t *view = get_focused_container(&root_container);
350
351 if (strcasecmp(argv[0], "left") == 0) {
352 move_container(view,&root_container,MOVE_LEFT);
353 } else if (strcasecmp(argv[0], "right") == 0) {
354 move_container(view,&root_container,MOVE_RIGHT);
355 } else if (strcasecmp(argv[0], "up") == 0) {
356 move_container(view,&root_container,MOVE_UP);
357 } else if (strcasecmp(argv[0], "down") == 0) {
358 move_container(view,&root_container,MOVE_DOWN);
359 } else
360 {
361 return false;
362 }
363
364 return true;
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 }
286 return true; 401 return true;
287} 402}
288 403
@@ -297,7 +412,6 @@ static bool cmd_layout(struct sway_config *config, int argc, char **argv) {
297 return false; 412 return false;
298 } 413 }
299 swayc_t *parent = get_focused_container(&root_container); 414 swayc_t *parent = get_focused_container(&root_container);
300
301 while (parent->type == C_VIEW) { 415 while (parent->type == C_VIEW) {
302 parent = parent->parent; 416 parent = parent->parent;
303 } 417 }
@@ -322,7 +436,7 @@ static bool cmd_reload(struct sway_config *config, int argc, char **argv) {
322 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) { 436 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) {
323 return false; 437 return false;
324 } 438 }
325 if (!load_config()) { 439 if (!load_config(NULL)) { // TODO: Use config given from -c
326 return false; 440 return false;
327 } 441 }
328 arrange_windows(&root_container, -1, -1); 442 arrange_windows(&root_container, -1, -1);
@@ -413,17 +527,15 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
413 return false; 527 return false;
414 } 528 }
415 529
416 swayc_t *container = get_focused_container(&root_container); 530 swayc_t *container = get_focused_view(&root_container);
417 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;
418 wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); 532 wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current);
419 //Resize workspace if going from fullscreen -> notfullscreen 533 // Resize workspace if going from fullscreen -> notfullscreen
420 //otherwise just resize container 534 // otherwise just resize container
421 if (current) { 535 if (current) {
422 while (container->type != C_WORKSPACE) { 536 container = swayc_parent_by_type(container, C_WORKSPACE);
423 container = container->parent;
424 }
425 } 537 }
426 //Only resize container when going into fullscreen 538 // Only resize container when going into fullscreen
427 arrange_windows(container, -1, -1); 539 arrange_windows(container, -1, -1);
428 540
429 return true; 541 return true;
@@ -489,9 +601,11 @@ static struct cmd_handler handlers[] = {
489 { "focus", cmd_focus }, 601 { "focus", cmd_focus },
490 { "focus_follows_mouse", cmd_focus_follows_mouse }, 602 { "focus_follows_mouse", cmd_focus_follows_mouse },
491 { "fullscreen", cmd_fullscreen }, 603 { "fullscreen", cmd_fullscreen },
604 { "gaps", cmd_gaps },
492 { "kill", cmd_kill }, 605 { "kill", cmd_kill },
493 { "layout", cmd_layout }, 606 { "layout", cmd_layout },
494 { "log_colors", cmd_log_colors }, 607 { "log_colors", cmd_log_colors },
608 { "move",cmd_move},
495 { "reload", cmd_reload }, 609 { "reload", cmd_reload },
496 { "set", cmd_set }, 610 { "set", cmd_set },
497 { "split", cmd_split }, 611 { "split", cmd_split },
@@ -511,7 +625,7 @@ static char **split_directive(char *line, int *argc) {
511 if (!*line) return parts; 625 if (!*line) return parts;
512 626
513 int in_string = 0, in_character = 0; 627 int in_string = 0, in_character = 0;
514 int i, j; 628 int i, j, _;
515 for (i = 0, j = 0; line[i]; ++i) { 629 for (i = 0, j = 0; line[i]; ++i) {
516 if (line[i] == '\\') { 630 if (line[i] == '\\') {
517 ++i; 631 ++i;
@@ -524,7 +638,7 @@ static char **split_directive(char *line, int *argc) {
524 char *item = malloc(i - j + 1); 638 char *item = malloc(i - j + 1);
525 strncpy(item, line + j, i - j); 639 strncpy(item, line + j, i - j);
526 item[i - j] = '\0'; 640 item[i - j] = '\0';
527 strip_whitespace(item); 641 item = strip_whitespace(item, &_);
528 if (item[0] == '\0') { 642 if (item[0] == '\0') {
529 free(item); 643 free(item);
530 } else { 644 } else {
@@ -542,7 +656,7 @@ static char **split_directive(char *line, int *argc) {
542 char *item = malloc(i - j + 1); 656 char *item = malloc(i - j + 1);
543 strncpy(item, line + j, i - j); 657 strncpy(item, line + j, i - j);
544 item[i - j] = '\0'; 658 item[i - j] = '\0';
545 strip_whitespace(item); 659 item = strip_whitespace(item, &_);
546 if (*argc == capacity) { 660 if (*argc == capacity) {
547 capacity++; 661 capacity++;
548 parts = realloc(parts, sizeof(char *) * capacity); 662 parts = realloc(parts, sizeof(char *) * capacity);
@@ -586,7 +700,7 @@ bool handle_command(struct sway_config *config, char *exec) {
586 char **argv = split_directive(exec + strlen(handler->command), &argc); 700 char **argv = split_directive(exec + strlen(handler->command), &argc);
587 int i; 701 int i;
588 702
589 //Perform var subs on all parts of the command 703 // Perform var subs on all parts of the command
590 for (i = 0; i < argc; ++i) { 704 for (i = 0; i < argc; ++i) {
591 argv[i] = do_var_replacement(config, argv[i]); 705 argv[i] = do_var_replacement(config, argv[i]);
592 } 706 }
diff --git a/sway/config.c b/sway/config.c
index 6d39839d..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);
@@ -186,9 +192,10 @@ bool read_config(FILE *file, bool is_active) {
186 int temp_depth = 0; // Temporary: skip all config sections with depth 192 int temp_depth = 0; // Temporary: skip all config sections with depth
187 193
188 while (!feof(file)) { 194 while (!feof(file)) {
195 int _;
189 char *line = read_line(file); 196 char *line = read_line(file);
190 strip_comments(line); 197 line = strip_whitespace(line, &_);
191 strip_whitespace(line); 198 line = strip_comments(line);
192 if (!line[0]) { 199 if (!line[0]) {
193 goto _continue; 200 goto _continue;
194 } 201 }
@@ -224,6 +231,8 @@ _continue:
224 231
225 if (is_active) { 232 if (is_active) {
226 temp_config->reloading = false; 233 temp_config->reloading = false;
234 container_map(&root_container, reset_gaps, NULL);
235 arrange_windows(&root_container, -1, -1);
227 } 236 }
228 config = temp_config; 237 config = temp_config;
229 238
diff --git a/sway/container.c b/sway/container.c
index e679e823..7ccc2e09 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -4,38 +4,62 @@
4#include "config.h" 4#include "config.h"
5#include "container.h" 5#include "container.h"
6#include "workspace.h" 6#include "workspace.h"
7#include "focus.h"
7#include "layout.h" 8#include "layout.h"
8#include "log.h" 9#include "log.h"
9 10
11#define ASSERT_NONNULL(PTR) \
12 sway_assert (PTR, "%s: " #PTR "must be non-null", __func__)
10 13
11static swayc_t *new_swayc(enum swayc_types type) { 14static swayc_t *new_swayc(enum swayc_types type) {
12 swayc_t *c = calloc(1, sizeof(swayc_t)); 15 swayc_t *c = calloc(1, sizeof(swayc_t));
13 c->handle = -1; 16 c->handle = -1;
14 c->layout = L_NONE; 17 c->layout = L_NONE;
15 c->type = type; 18 c->type = type;
16 c->weight = 1;
17 if (type != C_VIEW) { 19 if (type != C_VIEW) {
18 c->children = create_list(); 20 c->children = create_list();
19 } 21 }
20 return c; 22 return c;
21} 23}
22 24
23static void free_swayc(swayc_t *c) { 25static void free_swayc(swayc_t *cont) {
24 //TODO does not properly handle containers with children, 26 if (!ASSERT_NONNULL(cont)) {
25 //TODO but functions that call this usually check for that 27 return;
26 if (c->children) { 28 }
27 list_free(c->children); 29 // TODO does not properly handle containers with children,
30 // TODO but functions that call this usually check for that
31 if (cont->children) {
32 if (cont->children->length) {
33 int i;
34 for (i = 0; i < cont->children->length; ++i) {
35 free_swayc(cont->children->items[i]);
36 }
37 }
38 list_free(cont->children);
28 } 39 }
29 if (c->parent) { 40 if (cont->floating) {
30 remove_child(c); 41 if (cont->floating->length) {
42 int i;
43 for (i = 0; i < cont->floating->length; ++i) {
44 free_swayc(cont->floating->items[i]);
45 }
46 }
47 list_free(cont->floating);
31 } 48 }
32 if (c->name) { 49 if (cont->parent) {
33 free(c->name); 50 remove_child(cont);
34 } 51 }
35 free(c); 52 if (cont->name) {
53 free(cont->name);
54 }
55 free(cont);
36} 56}
37 57
38/* New containers */ 58// New containers
59
60static bool workspace_test(swayc_t *view, void *name) {
61 return strcasecmp(view->name, (char *)name) == 0;
62}
39 63
40swayc_t *new_output(wlc_handle handle) { 64swayc_t *new_output(wlc_handle handle) {
41 const struct wlc_size* size = wlc_output_get_resolution(handle); 65 const struct wlc_size* size = wlc_output_get_resolution(handle);
@@ -47,6 +71,7 @@ swayc_t *new_output(wlc_handle handle) {
47 output->height = size->h; 71 output->height = size->h;
48 output->handle = handle; 72 output->handle = handle;
49 output->name = name ? strdup(name) : NULL; 73 output->name = name ? strdup(name) : NULL;
74 output->gaps = config->gaps_outer + config->gaps_inner / 2;
50 75
51 add_child(&root_container, output); 76 add_child(&root_container, output);
52 77
@@ -58,6 +83,12 @@ swayc_t *new_output(wlc_handle handle) {
58 struct workspace_output *wso = config->workspace_outputs->items[i]; 83 struct workspace_output *wso = config->workspace_outputs->items[i];
59 if (strcasecmp(wso->output, name) == 0) { 84 if (strcasecmp(wso->output, name) == 0) {
60 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);
86 // Check if any other workspaces are using this name
87 if (find_container(&root_container, workspace_test, wso->workspace)) {
88 sway_log(L_DEBUG, "But it's already taken");
89 break;
90 }
91 sway_log(L_DEBUG, "So we're going to use it");
61 ws_name = strdup(wso->workspace); 92 ws_name = strdup(wso->workspace);
62 break; 93 break;
63 } 94 }
@@ -77,10 +108,15 @@ swayc_t *new_output(wlc_handle handle) {
77} 108}
78 109
79swayc_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 }
80 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);
81 swayc_t *workspace = new_swayc(C_WORKSPACE); 115 swayc_t *workspace = new_swayc(C_WORKSPACE);
82 116
83 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;
84 workspace->width = output->width; 120 workspace->width = output->width;
85 workspace->height = output->height; 121 workspace->height = output->height;
86 workspace->name = strdup(name); 122 workspace->name = strdup(name);
@@ -92,6 +128,9 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
92} 128}
93 129
94swayc_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 }
95 swayc_t *cont = new_swayc(C_CONTAINER); 134 swayc_t *cont = new_swayc(C_CONTAINER);
96 135
97 sway_log(L_DEBUG, "creating container %p around %p", cont, child); 136 sway_log(L_DEBUG, "creating container %p around %p", cont, child);
@@ -123,6 +162,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
123 // give them proper layouts 162 // give them proper layouts
124 cont->layout = workspace->layout; 163 cont->layout = workspace->layout;
125 workspace->layout = layout; 164 workspace->layout = layout;
165 set_focused_container_for(workspace, get_focused_view(workspace));
126 } else { // Or is built around container 166 } else { // Or is built around container
127 swayc_t *parent = replace_child(child, cont); 167 swayc_t *parent = replace_child(child, cont);
128 if (parent) { 168 if (parent) {
@@ -133,6 +173,9 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
133} 173}
134 174
135swayc_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 }
136 const char *title = wlc_view_get_title(handle); 179 const char *title = wlc_view_get_title(handle);
137 swayc_t *view = new_swayc(C_VIEW); 180 swayc_t *view = new_swayc(C_VIEW);
138 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",
@@ -142,11 +185,15 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
142 view->name = title ? strdup(title) : NULL; 185 view->name = title ? strdup(title) : NULL;
143 view->visible = true; 186 view->visible = true;
144 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;
145 194
146 view->desired_width = -1; 195 view->gaps = config->gaps_inner;
147 view->desired_height = -1;
148 196
149 // TODO: properly set this
150 view->is_floating = false; 197 view->is_floating = false;
151 198
152 if (sibling->type == C_WORKSPACE) { 199 if (sibling->type == C_WORKSPACE) {
@@ -172,8 +219,9 @@ swayc_t *new_floating_view(wlc_handle handle) {
172 // Set the geometry of the floating view 219 // Set the geometry of the floating view
173 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); 220 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
174 221
175 view->x = geometry->origin.x; 222 // give it requested geometry, but place in center
176 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;
177 view->width = geometry->size.w; 225 view->width = geometry->size.w;
178 view->height = geometry->size.h; 226 view->height = geometry->size.h;
179 227
@@ -186,14 +234,17 @@ swayc_t *new_floating_view(wlc_handle handle) {
186 list_add(active_workspace->floating, view); 234 list_add(active_workspace->floating, view);
187 view->parent = active_workspace; 235 view->parent = active_workspace;
188 if (active_workspace->focused == NULL) { 236 if (active_workspace->focused == NULL) {
189 active_workspace->focused = view; 237 set_focused_container_for(active_workspace, view);
190 } 238 }
191 return view; 239 return view;
192} 240}
193 241
194/* Destroy container */ 242// Destroy container
195 243
196swayc_t *destroy_output(swayc_t *output) { 244swayc_t *destroy_output(swayc_t *output) {
245 if (!ASSERT_NONNULL(output)) {
246 return NULL;
247 }
197 if (output->children->length == 0) { 248 if (output->children->length == 0) {
198 // TODO move workspaces to other outputs 249 // TODO move workspaces to other outputs
199 } 250 }
@@ -203,11 +254,21 @@ swayc_t *destroy_output(swayc_t *output) {
203} 254}
204 255
205swayc_t *destroy_workspace(swayc_t *workspace) { 256swayc_t *destroy_workspace(swayc_t *workspace) {
257 if (!ASSERT_NONNULL(workspace)) {
258 return NULL;
259 }
206 // NOTE: This is called from elsewhere without checking children length 260 // NOTE: This is called from elsewhere without checking children length
207 // TODO move containers to other workspaces? 261 // TODO move containers to other workspaces?
208 // for now just dont delete 262 // for now just dont delete
263
264 // Do not destroy this if it's the last workspace on this output
265 swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
266 if (output && output->children->length == 1) {
267 return NULL;
268 }
269
209 if (workspace->children->length == 0) { 270 if (workspace->children->length == 0) {
210 sway_log(L_DEBUG, "Workspace: Destroying workspace '%s'", workspace->name); 271 sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name);
211 swayc_t *parent = workspace->parent; 272 swayc_t *parent = workspace->parent;
212 free_swayc(workspace); 273 free_swayc(workspace);
213 return parent; 274 return parent;
@@ -216,19 +277,20 @@ swayc_t *destroy_workspace(swayc_t *workspace) {
216} 277}
217 278
218swayc_t *destroy_container(swayc_t *container) { 279swayc_t *destroy_container(swayc_t *container) {
280 if (!ASSERT_NONNULL(container)) {
281 return NULL;
282 }
219 while (container->children->length == 0 && container->type == C_CONTAINER) { 283 while (container->children->length == 0 && container->type == C_CONTAINER) {
220 sway_log(L_DEBUG, "Container: Destroying container '%p'", container); 284 sway_log(L_DEBUG, "Container: Destroying container '%p'", container);
221 swayc_t *parent = container->parent; 285 swayc_t *parent = container->parent;
222 free_swayc(container); 286 free_swayc(container);
223
224 container = parent; 287 container = parent;
225 } 288 }
226 return container; 289 return container;
227} 290}
228 291
229swayc_t *destroy_view(swayc_t *view) { 292swayc_t *destroy_view(swayc_t *view) {
230 if (view == NULL) { 293 if (!ASSERT_NONNULL(view)) {
231 sway_log(L_DEBUG, "Warning: NULL passed into destroy_view");
232 return NULL; 294 return NULL;
233 } 295 }
234 sway_log(L_DEBUG, "Destroying view '%p'", view); 296 sway_log(L_DEBUG, "Destroying view '%p'", view);
@@ -242,6 +304,34 @@ swayc_t *destroy_view(swayc_t *view) {
242 return parent; 304 return parent;
243} 305}
244 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
245swayc_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) {
246 if (!container->children) { 336 if (!container->children) {
247 return NULL; 337 return NULL;
@@ -271,18 +361,27 @@ swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *da
271} 361}
272 362
273void 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) {
274 if (!container->children || !container->children->length) { 364 if (container && container->children && container->children->length) {
275 return; 365 int i;
276 } 366 for (i = 0; i < container->children->length; ++i) {
277 int i; 367 swayc_t *child = container->children->items[i];
278 for (i = 0; i < container->children->length; ++i) { 368 f(child, data);
279 swayc_t *child = container->children->items[i]; 369 container_map(child, f, data);
280 f(child, data); 370 }
281 container_map(child, f, data); 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 }
282 } 378 }
283} 379}
284 380
285void 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 }
286 uint32_t *p = data; 385 uint32_t *p = data;
287 if (view->type == C_VIEW) { 386 if (view->type == C_VIEW) {
288 wlc_view_set_mask(view->handle, *p); 387 wlc_view_set_mask(view->handle, *p);
@@ -294,3 +393,15 @@ void set_view_visibility(swayc_t *view, void *data) {
294 } 393 }
295 view->visible = (*p == 2); 394 view->visible = (*p == 2);
296} 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 99cb2570..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;
@@ -14,11 +15,17 @@ static void update_focus(swayc_t *c) {
14 swayc_t *parent = c->parent; 15 swayc_t *parent = c->parent;
15 if (parent->focused != c) { 16 if (parent->focused != c) {
16 switch (c->type) { 17 switch (c->type) {
18 // Shouldnt happen
17 case C_ROOT: return; 19 case C_ROOT: return;
20
21 // Case where output changes
18 case C_OUTPUT: 22 case C_OUTPUT:
19 wlc_output_focus(c->parent->handle); 23 wlc_output_focus(c->handle);
24 // Set new workspace to the outputs focused workspace
25 active_workspace = c->focused;
20 break; 26 break;
21 // switching workspaces 27
28 // Case where workspace changes
22 case C_WORKSPACE: 29 case C_WORKSPACE:
23 if (parent->focused) { 30 if (parent->focused) {
24 swayc_t *ws = parent->focused; 31 swayc_t *ws = parent->focused;
@@ -29,10 +36,12 @@ static void update_focus(swayc_t *c) {
29 mask = 2; 36 mask = 2;
30 container_map(c, set_view_visibility, &mask); 37 container_map(c, set_view_visibility, &mask);
31 wlc_output_set_mask(parent->handle, 2); 38 wlc_output_set_mask(parent->handle, 2);
39 c->parent->focused = c;
32 destroy_workspace(ws); 40 destroy_workspace(ws);
33 } 41 }
34 active_workspace = c; 42 active_workspace = c;
35 break; 43 break;
44
36 default: 45 default:
37 case C_VIEW: 46 case C_VIEW:
38 case C_CONTAINER: 47 case C_CONTAINER:
@@ -45,70 +54,17 @@ static void update_focus(swayc_t *c) {
45} 54}
46 55
47bool move_focus(enum movement_direction direction) { 56bool move_focus(enum movement_direction direction) {
48 if (locked_container_focus) { 57 swayc_t *view = get_swayc_in_direction(
49 return false; 58 get_focused_container(&root_container), direction);
50 } 59 if (view) {
51 swayc_t *current = get_focused_container(&root_container); 60 if (direction == MOVE_PARENT) {
52 swayc_t *parent = current->parent; 61 set_focused_container(view);
53
54 if (direction == MOVE_PARENT) {
55 if (parent->type == C_OUTPUT) {
56 sway_log(L_DEBUG, "Focus cannot move to parent");
57 return false;
58 } else {
59 sway_log(L_DEBUG, "Moving focus from %p:%ld to %p:%ld",
60 current, current->handle, parent, parent->handle);
61 set_focused_container(parent);
62 return true;
63 }
64 }
65
66 while (true) {
67 sway_log(L_DEBUG, "Moving focus away from %p", current);
68
69 // Test if we can even make a difference here
70 bool can_move = false;
71 int diff = 0;
72 if (direction == MOVE_LEFT || direction == MOVE_RIGHT) {
73 if (parent->layout == L_HORIZ || parent->type == C_ROOT) {
74 can_move = true;
75 diff = direction == MOVE_LEFT ? -1 : 1;
76 }
77 } else { 62 } else {
78 if (parent->layout == L_VERT) { 63 set_focused_container(get_focused_view(view));
79 can_move = true;
80 diff = direction == MOVE_UP ? -1 : 1;
81 }
82 }
83 sway_log(L_DEBUG, "Can move? %s", can_move ? "yes" : "no");
84 if (can_move) {
85 int i;
86 for (i = 0; i < parent->children->length; ++i) {
87 swayc_t *child = parent->children->items[i];
88 if (child == current) {
89 break;
90 }
91 }
92 int desired = i + diff;
93 sway_log(L_DEBUG, "Moving from %d to %d", i, desired);
94 if (desired < 0 || desired >= parent->children->length) {
95 can_move = false;
96 } else {
97 swayc_t *newview = parent->children->items[desired];
98 set_focused_container(get_focused_view(newview));
99 return true;
100 }
101 }
102 if (!can_move) {
103 sway_log(L_DEBUG, "Can't move at current level, moving up tree");
104 current = parent;
105 parent = parent->parent;
106 if (!parent) {
107 // Nothing we can do
108 return false;
109 }
110 } 64 }
65 return true;
111 } 66 }
67 return false;
112} 68}
113 69
114swayc_t *get_focused_container(swayc_t *parent) { 70swayc_t *get_focused_container(swayc_t *parent) {
@@ -128,25 +84,44 @@ void set_focused_container(swayc_t *c) {
128 return; 84 return;
129 } 85 }
130 sway_log(L_DEBUG, "Setting focus to %p:%ld", c, c->handle); 86 sway_log(L_DEBUG, "Setting focus to %p:%ld", c, c->handle);
131 if (c->type != C_ROOT && c->type != C_OUTPUT) { 87
132 c->is_focused = true; 88 // Find previous focused view, and the new focused view, if they are the same return
133 } 89 swayc_t *focused = get_focused_view(&root_container);
134 swayc_t *prev_view = get_focused_view(&root_container); 90 swayc_t *workspace = active_workspace;
91
92 // update container focus from here to root, making necessary changes along
93 // the way
135 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 }
136 while (p != &root_container) { 98 while (p != &root_container) {
137 update_focus(p); 99 update_focus(p);
138 p = p->parent; 100 p = p->parent;
139 p->is_focused = false; 101 p->is_focused = false;
140 } 102 }
141 if (!locked_view_focus) { 103
142 p = get_focused_view(c); 104 // if the workspace is the same, and previous focus is fullscreen, dont
143 // Set focus to p 105 // change focus
144 if (p && !(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) { 106 if (workspace == active_workspace
145 if (prev_view) { 107 && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) {
146 wlc_view_set_state(prev_view->handle, WLC_BIT_ACTIVATED, false); 108 return;
147 } 109 }
148 wlc_view_focus(p->handle); 110
111 // get new focused view and set focus to it.
112 p = get_focused_view(c);
113 if (p->type == C_VIEW && !(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) {
114 // unactivate previous focus
115 if (focused->type == C_VIEW) {
116 wlc_view_set_state(focused->handle, WLC_BIT_ACTIVATED, false);
117 }
118 // activate current focus
119 if (p->type == C_VIEW) {
149 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 }
150 } 125 }
151 } 126 }
152} 127}
@@ -156,12 +131,25 @@ void set_focused_container_for(swayc_t *a, swayc_t *c) {
156 return; 131 return;
157 } 132 }
158 swayc_t *find = c; 133 swayc_t *find = c;
159 //Ensure that a is an ancestor of c 134 // Ensure that a is an ancestor of c
160 while (find != a && (find = find->parent)) { 135 while (find != a && (find = find->parent)) {
161 if (find == &root_container) { 136 if (find == &root_container) {
162 return; 137 return;
163 } 138 }
164 } 139 }
140 // Check if we changing a parent container that will see chnage
141 bool effective = true;
142 while (find != &root_container) {
143 if (find->parent->focused != find) {
144 effective = false;
145 }
146 find = find->parent;
147 }
148 if (effective) {
149 // Go to set_focused_container
150 set_focused_container(c);
151 return;
152 }
165 153
166 sway_log(L_DEBUG, "Setting focus for %p:%ld to %p:%ld", 154 sway_log(L_DEBUG, "Setting focus for %p:%ld to %p:%ld",
167 a, a->handle, c, c->handle); 155 a, a->handle, c, c->handle);
@@ -173,19 +161,17 @@ void set_focused_container_for(swayc_t *a, swayc_t *c) {
173 p = p->parent; 161 p = p->parent;
174 p->is_focused = false; 162 p->is_focused = false;
175 } 163 }
176 if (!locked_view_focus) {
177 p = get_focused_view(c);
178 // Set focus to p
179 if (p) {
180 wlc_view_focus(p->handle);
181 wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true);
182 }
183 }
184} 164}
185 165
186swayc_t *get_focused_view(swayc_t *parent) { 166swayc_t *get_focused_view(swayc_t *parent) {
187 while (parent && parent->type != C_VIEW) { 167 while (parent && parent->type != C_VIEW) {
168 if (parent->type == C_WORKSPACE && parent->focused == NULL) {
169 return parent;
170 }
188 parent = parent->focused; 171 parent = parent->focused;
189 } 172 }
173 if (parent == NULL) {
174 return active_workspace;
175 }
190 return parent; 176 return parent;
191} 177}
diff --git a/sway/handlers.c b/sway/handlers.c
index cd97ab43..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) {
@@ -57,14 +50,16 @@ swayc_t *container_under_pointer(void) {
57 } 50 }
58 // if workspace, search floating 51 // if workspace, search floating
59 if (lookup->type == C_WORKSPACE) { 52 if (lookup->type == C_WORKSPACE) {
60 len = lookup->floating->length; 53 i = len = lookup->floating->length;
61 for (i = 0; i < len; ++i) { 54 bool got_floating = false;
55 while (--i > -1) {
62 if (pointer_test(lookup->floating->items[i], &mouse_origin)) { 56 if (pointer_test(lookup->floating->items[i], &mouse_origin)) {
63 lookup = lookup->floating->items[i]; 57 lookup = lookup->floating->items[i];
58 got_floating = true;
64 break; 59 break;
65 } 60 }
66 } 61 }
67 if (i < len) { 62 if (got_floating) {
68 continue; 63 continue;
69 } 64 }
70 } 65 }
@@ -84,10 +79,12 @@ swayc_t *container_under_pointer(void) {
84 return lookup; 79 return lookup;
85} 80}
86 81
82/* Handles */
83
87static bool handle_output_created(wlc_handle output) { 84static bool handle_output_created(wlc_handle output) {
88 swayc_t *op = new_output(output); 85 swayc_t *op = new_output(output);
89 86
90 //Switch to workspace if we need to 87 // Switch to workspace if we need to
91 if (active_workspace == NULL) { 88 if (active_workspace == NULL) {
92 swayc_t *ws = op->children->items[0]; 89 swayc_t *ws = op->children->items[0];
93 workspace_switch(ws); 90 workspace_switch(ws);
@@ -106,6 +103,12 @@ static void handle_output_destroyed(wlc_handle output) {
106 if (i < list->length) { 103 if (i < list->length) {
107 destroy_output(list->items[i]); 104 destroy_output(list->items[i]);
108 } 105 }
106 if (list->length == 0) {
107 active_workspace = NULL;
108 } else {
109 // switch to other outputs active workspace
110 workspace_switch(((swayc_t *)root_container.children->items[0])->focused);
111 }
109} 112}
110 113
111static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { 114static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) {
@@ -129,38 +132,64 @@ static void handle_output_focused(wlc_handle output, bool focus) {
129} 132}
130 133
131static bool handle_view_created(wlc_handle handle) { 134static bool handle_view_created(wlc_handle handle) {
132 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;
133 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.
134 switch (wlc_view_get_type(handle)) { 157 switch (wlc_view_get_type(handle)) {
135 // regular view created regularly 158 // regular view created regularly
136 case 0: 159 case 0:
137 newview = new_view(focused, handle); 160 newview = new_view(focused, handle);
138 wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); 161 wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true);
139 break; 162 break;
140 // takes keyboard focus 163
164 // Dmenu keeps viewfocus, but others with this flag dont, for now simulate
165 // dmenu
141 case WLC_BIT_OVERRIDE_REDIRECT: 166 case WLC_BIT_OVERRIDE_REDIRECT:
142 sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT", handle); 167// locked_view_focus = true;
143 locked_view_focus = true;
144 wlc_view_focus(handle); 168 wlc_view_focus(handle);
145 wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); 169 wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true);
146 wlc_view_bring_to_front(handle); 170 wlc_view_bring_to_front(handle);
147 break; 171 break;
148 // Takes container focus 172
173 // Firefox popups have this flag set.
149 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: 174 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
150 sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT|WLC_BIT_MANAGED", handle);
151 wlc_view_bring_to_front(handle); 175 wlc_view_bring_to_front(handle);
152 locked_container_focus = true; 176 locked_container_focus = true;
153 break; 177 break;
154 // set modals as floating containers 178
179 // Modals, get focus, popups do not
155 case WLC_BIT_MODAL: 180 case WLC_BIT_MODAL:
181 wlc_view_focus(handle);
156 wlc_view_bring_to_front(handle); 182 wlc_view_bring_to_front(handle);
157 newview = new_floating_view(handle); 183 newview = new_floating_view(handle);
158 case WLC_BIT_POPUP: 184 case WLC_BIT_POPUP:
185 wlc_view_bring_to_front(handle);
159 break; 186 break;
160 } 187 }
188
161 if (newview) { 189 if (newview) {
162 set_focused_container(newview); 190 set_focused_container(newview);
163 arrange_windows(newview->parent, -1, -1); 191 swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT);
192 arrange_windows(output, -1, -1);
164 } 193 }
165 return true; 194 return true;
166} 195}
@@ -173,19 +202,19 @@ static void handle_view_destroyed(wlc_handle handle) {
173 // regular view created regularly 202 // regular view created regularly
174 case 0: 203 case 0:
175 case WLC_BIT_MODAL: 204 case WLC_BIT_MODAL:
205 case WLC_BIT_POPUP:
176 if (view) { 206 if (view) {
177 swayc_t *parent = destroy_view(view); 207 swayc_t *parent = destroy_view(view);
178 arrange_windows(parent, -1, -1); 208 arrange_windows(parent, -1, -1);
179 } 209 }
180 break; 210 break;
181 // takes keyboard focus 211 // DMENU has this flag, and takes view_focus, but other things with this
212 // flag dont
182 case WLC_BIT_OVERRIDE_REDIRECT: 213 case WLC_BIT_OVERRIDE_REDIRECT:
183 locked_view_focus = false; 214// locked_view_focus = false;
184 break; 215 break;
185 // Takes container focus
186 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: 216 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
187 locked_container_focus = false; 217 locked_container_focus = false;
188 case WLC_BIT_POPUP:
189 break; 218 break;
190 } 219 }
191 set_focused_container(get_focused_view(&root_container)); 220 set_focused_container(get_focused_view(&root_container));
@@ -197,7 +226,7 @@ static void handle_view_focus(wlc_handle view, bool focus) {
197 226
198static 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) {
199 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",
200 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);
201 // If the view is floating, then apply the geometry. 230 // If the view is floating, then apply the geometry.
202 // Otherwise save the desired width/height for the view. 231 // Otherwise save the desired width/height for the view.
203 // 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
@@ -217,21 +246,17 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
217} 246}
218 247
219static 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) {
220 swayc_t *c = NULL; 249 swayc_t *c = get_swayc_for_handle(view, &root_container);
221 switch(state) { 250 switch (state) {
222 case WLC_BIT_FULLSCREEN: 251 case WLC_BIT_FULLSCREEN:
223 // i3 just lets it become fullscreen 252 // i3 just lets it become fullscreen
224 wlc_view_set_state(view, state, toggle); 253 wlc_view_set_state(view, state, toggle);
225 c = get_swayc_for_handle(view, &root_container);
226 sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d",view,c->name,toggle);
227 if (c) { 254 if (c) {
255 sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d", view, c->name, toggle);
228 arrange_windows(c->parent, -1, -1); 256 arrange_windows(c->parent, -1, -1);
229 // 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
230 if (toggle) { 258 if (toggle) {
231 swayc_t *ws = c; 259 swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE);
232 while (ws->type != C_WORKSPACE) {
233 ws = ws->parent;
234 }
235 // Set ws focus to c 260 // Set ws focus to c
236 set_focused_container_for(ws, c); 261 set_focused_container_for(ws, c);
237 } 262 }
@@ -240,7 +265,9 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
240 case WLC_BIT_MAXIMIZED: 265 case WLC_BIT_MAXIMIZED:
241 case WLC_BIT_RESIZING: 266 case WLC_BIT_RESIZING:
242 case WLC_BIT_MOVING: 267 case WLC_BIT_MOVING:
268 break;
243 case WLC_BIT_ACTIVATED: 269 case WLC_BIT_ACTIVATED:
270 sway_log(L_DEBUG, "View %p requested to be activated", c);
244 break; 271 break;
245 } 272 }
246 return; 273 return;
@@ -249,29 +276,38 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
249 276
250static 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,
251 uint32_t key, uint32_t sym, enum wlc_key_state state) { 278 uint32_t key, uint32_t sym, enum wlc_key_state state) {
252 enum { QSIZE = 32 }; 279
253 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) { 280 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) {
254 return false; 281 return false;
255 } 282 }
256 static uint8_t head = 0; 283
257 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 }
258 289
259 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
260 // Lowercase if necessary 299 // Lowercase if necessary
261 sym = tolower(sym); 300 sym = tolower(sym);
262 301
263 // Find key, if it has been pressed 302 int i;
264 int mid = 0; 303
265 while (mid < head && keys_pressed[mid] != sym) { 304 if (state == WLC_KEY_STATE_PRESSED) {
266 ++mid; 305 press_key(sym);
267 } 306 } else { // WLC_KEY_STATE_RELEASED
268 if (state == WLC_KEY_STATE_PRESSED && mid == head && head + 1 < QSIZE) { 307 release_key(sym);
269 keys_pressed[head++] = sym;
270 } else if (state == WLC_KEY_STATE_RELEASED && mid < head) {
271 memmove(keys_pressed + mid, keys_pressed + mid + 1, sizeof*keys_pressed * (--head - mid));
272 } 308 }
309
273 // 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
274 int i;
275 for (i = 0; i < mode->bindings->length; ++i) { 311 for (i = 0; i < mode->bindings->length; ++i) {
276 struct sway_binding *binding = mode->bindings->items[i]; 312 struct sway_binding *binding = mode->bindings->items[i];
277 313
@@ -279,39 +315,22 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
279 bool match; 315 bool match;
280 int j; 316 int j;
281 for (j = 0; j < binding->keys->length; ++j) { 317 for (j = 0; j < binding->keys->length; ++j) {
282 match = false;
283 xkb_keysym_t *key = binding->keys->items[j]; 318 xkb_keysym_t *key = binding->keys->items[j];
284 uint8_t k; 319 if ((match = check_key(*key)) == false) {
285 for (k = 0; k < head; ++k) {
286 if (keys_pressed[k] == *key) {
287 match = true;
288 break;
289 }
290 }
291 if (match == false) {
292 break; 320 break;
293 } 321 }
294 } 322 }
295
296 if (match) { 323 if (match) {
297 // Remove matched keys from keys_pressed
298 int j;
299 for (j = 0; j < binding->keys->length; ++j) {
300 uint8_t k;
301 for (k = 0; k < head; ++k) {
302 memmove(keys_pressed + k, keys_pressed + k + 1, sizeof*keys_pressed * (--head - k));
303 break;
304 }
305 }
306 if (state == WLC_KEY_STATE_PRESSED) { 324 if (state == WLC_KEY_STATE_PRESSED) {
307 cmd_success = handle_command(config, binding->command); 325 handle_command(config, binding->command);
326 return true;
308 } else if (state == WLC_KEY_STATE_RELEASED) { 327 } else if (state == WLC_KEY_STATE_RELEASED) {
309 // TODO: --released 328 // TODO: --released
310 } 329 }
311 } 330 }
312 } 331 }
313 } 332 }
314 return cmd_success; 333 return false;
315} 334}
316 335
317static 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) {
@@ -319,119 +338,168 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
319 static wlc_handle prev_handle = 0; 338 static wlc_handle prev_handle = 0;
320 mouse_origin = *origin; 339 mouse_origin = *origin;
321 bool changed_floating = false; 340 bool changed_floating = false;
322 int i = 0; 341 if (!active_workspace) {
342 return false;
343 }
323 // Do checks to determine if proper keys are being held 344 // Do checks to determine if proper keys are being held
324 swayc_t *view = active_workspace->focused; 345 swayc_t *view = get_focused_view(active_workspace);
325 if (m1_held) { 346 uint32_t edge = 0;
347 if (pointer_state.floating.drag && view) {
326 if (view->is_floating) { 348 if (view->is_floating) {
327 while (keys_pressed[i++]) { 349 int dx = mouse_origin.x - prev_pos.x;
328 if (keys_pressed[i] == config->floating_mod) { 350 int dy = mouse_origin.y - prev_pos.y;
329 int dx = mouse_origin.x - prev_pos.x; 351 view->x += dx;
330 int dy = mouse_origin.y - prev_pos.y; 352 view->y += dy;
331 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;
332 sway_log(L_DEBUG, "Moving: dx: %d, dy: %d", dx, dy);
333
334 view->x += dx;
335 view->y += dy;
336 changed_floating = true;
337 break;
338 }
339 }
340 } 354 }
341 } else if (m2_held) { 355 } else if (pointer_state.floating.resize && view) {
342 if (view->is_floating) { 356 if (view->is_floating) {
343 while (keys_pressed[i++]) { 357 int dx = mouse_origin.x - prev_pos.x;
344 if (keys_pressed[i] == config->floating_mod) { 358 int dy = mouse_origin.y - prev_pos.y;
345 int dx = mouse_origin.x - prev_pos.x; 359 int min_sane_w = 100;
346 int dy = mouse_origin.y - prev_pos.y; 360 int min_sane_h = 60;
347 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
348 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
349 363 int midway_x = view->x + view->width/2;
350 // Move and resize the view based on the dx/dy and mouse position 364 int midway_y = view->y + view->height/2;
351 int midway_x = view->x + view->width/2; 365 if (dx < 0) {
352 int midway_y = view->y + view->height/2; 366 if (!pointer_state.lock.right) {
353 367 if (view->width > min_sane_w) {
354 if (dx < 0) {
355 changed_floating = true; 368 changed_floating = true;
356 if (mouse_origin.x > midway_x) { 369 view->width += dx;
357 sway_log(L_INFO, "Downsizing view to the left"); 370 edge += WLC_RESIZE_EDGE_RIGHT;
358 view->width += dx; 371 }
359 } else { 372 } else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
360 sway_log(L_INFO, "Upsizing view to the left"); 373 changed_floating = true;
361 view->x += dx; 374 view->x += dx;
362 view->width -= dx; 375 view->width -= dx;
363 } 376 edge += WLC_RESIZE_EDGE_LEFT;
364 } 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) {
365 changed_floating = true; 385 changed_floating = true;
366 if (mouse_origin.x > midway_x) { 386 view->x += dx;
367 sway_log(L_INFO, "Upsizing to the right"); 387 view->width -= dx;
368 view->width += dx; 388 edge += WLC_RESIZE_EDGE_LEFT;
369 } else {
370 sway_log(L_INFO, "Downsizing to the right");
371 view->x += dx;
372 view->width -= dx;
373 }
374 } 389 }
390 }
391 }
375 392
376 if (dy < 0) { 393 if (dy < 0) {
394 if (!pointer_state.lock.bottom) {
395 if (view->height > min_sane_h) {
377 changed_floating = true; 396 changed_floating = true;
378 if (mouse_origin.y > midway_y) { 397 view->height += dy;
379 sway_log(L_INFO, "Downsizing view to the top"); 398 edge += WLC_RESIZE_EDGE_BOTTOM;
380 view->height += dy; 399 }
381 } else { 400 } else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
382 sway_log(L_INFO, "Upsizing the view to the top"); 401 changed_floating = true;
383 view->y += dy; 402 view->y += dy;
384 view->height -= dy; 403 view->height -= dy;
385 } 404 edge += WLC_RESIZE_EDGE_TOP;
386 } 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) {
387 changed_floating = true; 413 changed_floating = true;
388 if (mouse_origin.y > midway_y) { 414 view->y += dy;
389 sway_log(L_INFO, "Upsizing to the bottom"); 415 view->height -= dy;
390 view->height += dy; 416 edge += WLC_RESIZE_EDGE_TOP;
391 } else {
392 sway_log(L_INFO, "Downsizing to the bottom");
393 view->y += dy;
394 view->height -= dy;
395 }
396 } 417 }
397 break;
398 } 418 }
399 } 419 }
400 } 420 }
401 } 421 }
402 if (config->focus_follows_mouse && prev_handle != handle) { 422 if (config->focus_follows_mouse && prev_handle != handle) {
403 set_focused_container(container_under_pointer()); 423 // Dont change focus if fullscreen
424 swayc_t *focused = get_focused_view(view);
425 if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)
426 && !(pointer_state.l_held || pointer_state.r_held)) {
427 set_focused_container(container_under_pointer());
428 }
404 } 429 }
405 prev_handle = handle; 430 prev_handle = handle;
406 prev_pos = mouse_origin; 431 prev_pos = mouse_origin;
407 if (changed_floating) { 432 if (changed_floating) {
408 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);
409 return true; 444 return true;
410 } 445 }
411 return false; 446 return false;
412} 447}
413 448
449
414static 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,
415 uint32_t button, enum wlc_button_state state) { 451 uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) {
416 swayc_t *focused = get_focused_container(&root_container); 452 swayc_t *focused = get_focused_container(&root_container);
453 // dont change focus if fullscreen
454 if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) {
455 return false;
456 }
417 if (state == WLC_BUTTON_STATE_PRESSED) { 457 if (state == WLC_BUTTON_STATE_PRESSED) {
418 sway_log(L_DEBUG, "Mouse button %u pressed", button); 458 sway_log(L_DEBUG, "Mouse button %u pressed", button);
419 if (button == 272) { 459 if (button == M_LEFT_CLICK) {
420 m1_held = true; 460 pointer_state.l_held = true;
421 } 461 }
422 if (button == 273) { 462 if (button == M_RIGHT_CLICK) {
423 m2_held = true; 463 pointer_state.r_held = true;
424 } 464 }
425 swayc_t *pointer = container_under_pointer(); 465 swayc_t *pointer = container_under_pointer();
426 set_focused_container(pointer); 466 set_focused_container(pointer);
467 if (pointer->is_floating) {
468 int i;
469 for (i = 0; i < pointer->parent->floating->length; i++) {
470 if (pointer->parent->floating->items[i] == pointer) {
471 list_del(pointer->parent->floating, i);
472 list_add(pointer->parent->floating, pointer);
473 break;
474 }
475 }
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);
491 }
427 return (pointer && pointer != focused); 492 return (pointer && pointer != focused);
428 } else { 493 } else {
429 sway_log(L_DEBUG, "Mouse button %u released", button); 494 sway_log(L_DEBUG, "Mouse button %u released", button);
430 if (button == 272) { 495 if (button == M_LEFT_CLICK) {
431 m1_held = false; 496 pointer_state.l_held = false;
497 pointer_state.floating.drag = false;
432 } 498 }
433 if (button == 273) { 499 if (button == M_RIGHT_CLICK) {
434 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};
435 } 503 }
436 } 504 }
437 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 e2ea46a7..a48f15c4 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -1,11 +1,13 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include <stdbool.h> 2#include <stdbool.h>
3#include <wlc/wlc.h> 3#include <wlc/wlc.h>
4#include "list.h"
5#include "log.h"
6#include "layout.h" 4#include "layout.h"
5#include "log.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"
10#include "focus.h"
9 11
10swayc_t root_container; 12swayc_t root_container;
11 13
@@ -31,6 +33,21 @@ void add_child(swayc_t *parent, swayc_t *child) {
31 child->width, child->height, parent, parent->type, parent->width, parent->height); 33 child->width, child->height, parent, parent->type, parent->width, parent->height);
32 list_add(parent->children, child); 34 list_add(parent->children, child);
33 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 }
34} 51}
35 52
36swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { 53swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) {
@@ -54,7 +71,7 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) {
54 new_child->parent = child->parent; 71 new_child->parent = child->parent;
55 72
56 if (child->parent->focused == child) { 73 if (child->parent->focused == child) {
57 child->parent->focused = new_child; 74 set_focused_container_for(child->parent, new_child);
58 } 75 }
59 child->parent = NULL; 76 child->parent = NULL;
60 return parent; 77 return parent;
@@ -71,6 +88,7 @@ swayc_t *remove_child(swayc_t *child) {
71 break; 88 break;
72 } 89 }
73 } 90 }
91 i = 0;
74 } else { 92 } else {
75 for (i = 0; i < parent->children->length; ++i) { 93 for (i = 0; i < parent->children->length; ++i) {
76 if (parent->children->items[i] == child) { 94 if (parent->children->items[i] == child) {
@@ -79,9 +97,10 @@ swayc_t *remove_child(swayc_t *child) {
79 } 97 }
80 } 98 }
81 } 99 }
100 // Set focused to new container
82 if (parent->focused == child) { 101 if (parent->focused == child) {
83 if (parent->children->length > 0) { 102 if (parent->children->length > 0) {
84 parent->focused = parent->children->items[i?i-1:0]; 103 set_focused_container_for(parent, parent->children->items[i?i-1:0]);
85 } else { 104 } else {
86 parent->focused = NULL; 105 parent->focused = NULL;
87 } 106 }
@@ -89,6 +108,50 @@ swayc_t *remove_child(swayc_t *child) {
89 return parent; 108 return parent;
90} 109}
91 110
111void move_container(swayc_t *container,swayc_t* root,int direction){
112 sway_log(L_DEBUG, "Moved window");
113 swayc_t *temp;
114 int i;
115 uint clength = root->children->length;
116 //Rearrange
117 for (i = 0; i < clength; ++i) {
118 swayc_t *child = root->children->items[i];
119 if(child->handle == container->handle){
120 if(clength == 1){
121 //Only one container, meh.
122 break;
123 }
124 //TODO: Implement horizontal movement.
125 //TODO: Implement move to a different workspace.
126 if(direction == MOVE_LEFT && i > 0){
127 temp = root->children->items[i-1];
128 root->children->items[i] = temp;
129 root->children->items[i-1] = container;
130 arrange_windows(&root_container,-1,-1);
131 }
132 else if(direction == MOVE_RIGHT && i < clength-1){
133 temp = root->children->items[i+1];
134 root->children->items[i] = temp;
135 root->children->items[i+1] = container;
136 arrange_windows(&root_container,-1,-1);
137
138 }
139 else if(direction == MOVE_UP){
140 sway_log(L_INFO, "Moving up not implemented");
141 }
142 else if(direction == MOVE_DOWN){
143 sway_log(L_INFO, "Moving down not implemented");
144 }
145
146 break;
147 }
148 else if(child->children != NULL){
149 move_container(container,child,direction);
150 }
151 }
152
153}
154
92 155
93void arrange_windows(swayc_t *container, int width, int height) { 156void arrange_windows(swayc_t *container, int width, int height) {
94 int i; 157 int i;
@@ -121,11 +184,11 @@ void arrange_windows(swayc_t *container, int width, int height) {
121 // y -= container->y; 184 // y -= container->y;
122 for (i = 0; i < container->children->length; ++i) { 185 for (i = 0; i < container->children->length; ++i) {
123 swayc_t *child = container->children->items[i]; 186 swayc_t *child = container->children->items[i];
124 sway_log(L_DEBUG, "Arranging workspace #%d", i); 187 child->x = x + container->gaps;
125 child->x = x; 188 child->y = y + container->gaps;
126 child->y = y; 189 child->width = width - container->gaps * 2;
127 child->width = width; 190 child->height = height - container->gaps * 2;
128 child->height = height; 191 sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y);
129 arrange_windows(child, -1, -1); 192 arrange_windows(child, -1, -1);
130 } 193 }
131 return; 194 return;
@@ -133,27 +196,24 @@ void arrange_windows(swayc_t *container, int width, int height) {
133 { 196 {
134 struct wlc_geometry geometry = { 197 struct wlc_geometry geometry = {
135 .origin = { 198 .origin = {
136 .x = container->x, 199 .x = container->x + container->gaps / 2,
137 .y = container->y 200 .y = container->y + container->gaps / 2
138 }, 201 },
139 .size = { 202 .size = {
140 .w = width, 203 .w = width - container->gaps,
141 .h = height 204 .h = height - container->gaps
142 } 205 }
143 }; 206 };
144 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { 207 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
145 swayc_t *parent = container; 208 swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
146 while (parent->type != C_OUTPUT) {
147 parent = parent->parent;
148 }
149 geometry.origin.x = 0; 209 geometry.origin.x = 0;
150 geometry.origin.y = 0; 210 geometry.origin.y = 0;
151 geometry.size.w = parent->width; 211 geometry.size.w = parent->width;
152 geometry.size.h = parent->height; 212 geometry.size.h = parent->height;
153 wlc_view_set_geometry(container->handle, &geometry); 213 wlc_view_set_geometry(container->handle, 0, &geometry);
154 wlc_view_bring_to_front(container->handle); 214 wlc_view_bring_to_front(container->handle);
155 } else { 215 } else {
156 wlc_view_set_geometry(container->handle, &geometry); 216 wlc_view_set_geometry(container->handle, 0, &geometry);
157 container->width = width; 217 container->width = width;
158 container->height = height; 218 container->height = height;
159 } 219 }
@@ -167,40 +227,62 @@ void arrange_windows(swayc_t *container, int width, int height) {
167 break; 227 break;
168 } 228 }
169 229
170 double total_weight = 0; 230 x = y = 0;
171 for (i = 0; i < container->children->length; ++i) { 231 double scale = 0;
172 swayc_t *child = container->children->items[i];
173 total_weight += child->weight;
174 }
175
176 switch (container->layout) { 232 switch (container->layout) {
177 case L_HORIZ: 233 case L_HORIZ:
178 default: 234 default:
179 sway_log(L_DEBUG, "Arranging %p horizontally", container); 235 // Calculate total width
180 for (i = 0; i < container->children->length; ++i) { 236 for (i = 0; i < container->children->length; ++i) {
181 swayc_t *child = container->children->items[i]; 237 int *old_width = &((swayc_t *)container->children->items[i])->width;
182 double percent = child->weight / total_weight; 238 if (*old_width <= 0) {
183 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) {
184 child->x = x + container->x; 240 *old_width = width / (container->children->length - 1);
185 child->y = y + container->y; 241 } else {
186 int w = width * percent; 242 *old_width = width;
187 int h = height; 243 }
188 arrange_windows(child, w, h); 244 }
189 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 }
190 } 259 }
191 break; 260 break;
192 case L_VERT: 261 case L_VERT:
193 sway_log(L_DEBUG, "Arranging %p vertically", container); 262 // Calculate total height
194 for (i = 0; i < container->children->length; ++i) { 263 for (i = 0; i < container->children->length; ++i) {
195 swayc_t *child = container->children->items[i]; 264 int *old_height = &((swayc_t *)container->children->items[i])->height;
196 double percent = child->weight / total_weight; 265 if (*old_height <= 0) {
197 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) {
198 child->x = x + container->x; 267 *old_height = height / (container->children->length - 1);
199 child->y = y + container->y; 268 } else {
200 int w = width; 269 *old_height = height;
201 int h = height * percent; 270 }
202 arrange_windows(child, w, h); 271 }
203 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 }
204 } 286 }
205 break; 287 break;
206 } 288 }
@@ -209,26 +291,37 @@ void arrange_windows(swayc_t *container, int width, int height) {
209 if (container->type == C_WORKSPACE) { 291 if (container->type == C_WORKSPACE) {
210 for (i = 0; i < container->floating->length; ++i) { 292 for (i = 0; i < container->floating->length; ++i) {
211 swayc_t *view = container->floating->items[i]; 293 swayc_t *view = container->floating->items[i];
212 // Set the geometry 294 if (view->type == C_VIEW) {
213 struct wlc_geometry geometry = { 295 // Set the geometry
214 .origin = { 296 struct wlc_geometry geometry = {
215 .x = view->x, 297 .origin = {
216 .y = view->y 298 .x = view->x,
217 }, 299 .y = view->y
218 .size = { 300 },
219 .w = view->width, 301 .size = {
220 .h = view->height 302 .w = view->width,
303 .h = view->height
304 }
305 };
306 if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) {
307 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
308 geometry.origin.x = 0;
309 geometry.origin.y = 0;
310 geometry.size.w = parent->width;
311 geometry.size.h = parent->height;
312 wlc_view_set_geometry(view->handle, 0, &geometry);
313 wlc_view_bring_to_front(view->handle);
314 } else {
315 wlc_view_set_geometry(view->handle, 0, &geometry);
316 // Bring the views to the front in order of the list, the list
317 // will be kept up to date so that more recently focused views
318 // have higher indexes
319 // This is conditional on there not being a fullscreen view in the workspace
320 if (!container->focused
321 || !(wlc_view_get_state(container->focused->handle) & WLC_BIT_FULLSCREEN)) {
322 wlc_view_bring_to_front(view->handle);
323 }
221 } 324 }
222 };
223 wlc_view_set_geometry(view->handle, &geometry);
224
225 // Bring the views to the front in order of the list, the list
226 // will be kept up to date so that more recently focused views
227 // have higher indexes
228 // This is conditional on there not being a fullscreen view in the workspace
229 if (!container->focused
230 || !(wlc_view_get_state(container->focused->handle) & WLC_BIT_FULLSCREEN)) {
231 wlc_view_bring_to_front(view->handle);
232 } 325 }
233 } 326 }
234 } 327 }
@@ -265,3 +358,53 @@ swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) {
265 return NULL; 358 return NULL;
266} 359}
267 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 00cc32b8..c39e2c34 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -1,38 +1,38 @@
1#include "stringop.h"
1#include <stdlib.h> 2#include <stdlib.h>
2#include <stdio.h> 3#include <stdio.h>
3#include <strings.h>
4#include <ctype.h>
5#include "stringop.h"
6#include "string.h" 4#include "string.h"
7#include "list.h" 5#include "list.h"
6#include <strings.h>
7#include <log.h>
8 8
9/* Note: This returns 8 characters for trimmed_start per tab character. */ 9/* Note: This returns 8 characters for trimmed_start per tab character. */
10void strip_whitespace(char *str) { 10char *strip_whitespace(char *_str, int *trimmed_start) {
11 int shift = 0; 11 *trimmed_start = 0;
12 int bpair = 1; 12 if (*_str == '\0')
13 int in_str = 0, in_ch = 0; 13 return _str;
14 while (*str) { 14 char *strold = _str;
15 str[-shift] = str[0]; 15 while (*_str == ' ' || *_str == '\t') {
16 if (*str == '"' && !in_ch) { 16 if (*_str == '\t') {
17 in_str = !in_str; 17 *trimmed_start += 8;
18 } else if (*str == '\'' && !in_str) { 18 } else {
19 in_ch = !in_ch; 19 *trimmed_start += 1;
20 } else if (!in_ch && !in_str) {
21 if (isblank(*str)) {
22 if (bpair) {
23 ++shift;
24 }
25 bpair=1;
26 } else {
27 bpair = 0;
28 }
29 } 20 }
30 ++str; 21 _str++;
31 } 22 }
32 str[-shift-bpair] = 0; 23 char *str = malloc(strlen(_str) + 1);
24 strcpy(str, _str);
25 free(strold);
26 int i;
27 for (i = 0; str[i] != '\0'; ++i);
28 do {
29 i--;
30 } while (i >= 0 && (str[i] == ' ' || str[i] == '\t'));
31 str[i + 1] = '\0';
32 return str;
33} 33}
34 34
35void strip_comments(char *str) { 35char *strip_comments(char *str) {
36 int in_string = 0, in_character = 0; 36 int in_string = 0, in_character = 0;
37 int i = 0; 37 int i = 0;
38 while (str[i] != '\0') { 38 while (str[i] != '\0') {
@@ -41,13 +41,14 @@ void strip_comments(char *str) {
41 } else if (str[i] == '\'' && !in_string) { 41 } else if (str[i] == '\'' && !in_string) {
42 in_character = !in_character; 42 in_character = !in_character;
43 } else if (!in_character && !in_string) { 43 } else if (!in_character && !in_string) {
44 if (str[i] == '#') { 44 if (str[i] == '#' && i == 0) {
45 str[i] = '\0'; 45 str[i] = '\0';
46 break; 46 break;
47 } 47 }
48 } 48 }
49 ++i; 49 ++i;
50 } 50 }
51 return str;
51} 52}
52 53
53list_t *split_string(const char *str, const char *delims) { 54list_t *split_string(const char *str, const char *delims) {
@@ -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 bc0fa2c8..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
@@ -174,69 +177,10 @@ void workspace_prev() {
174} 177}
175 178
176void workspace_switch(swayc_t *workspace) { 179void workspace_switch(swayc_t *workspace) {
177 set_focused_container(workspace); 180 if (!workspace) {
178 active_workspace = workspace; 181 return;
179}
180
181/* XXX:DEBUG:XXX */
182static void container_log(const swayc_t *c) {
183 fprintf(stderr, "focus:%c|",
184 c->is_focused ? 'F' : //Focused
185 c == active_workspace ? 'W' : //active workspace
186 c == &root_container ? 'R' : //root
187 'X');//not any others
188 fprintf(stderr,"(%p)",c);
189 fprintf(stderr,"(p:%p)",c->parent);
190 fprintf(stderr,"(f:%p)",c->focused);
191 fprintf(stderr,"(h:%ld)",c->handle);
192 fprintf(stderr,"Type:");
193 fprintf(stderr,
194 c->type == C_ROOT ? "Root|" :
195 c->type == C_OUTPUT ? "Output|" :
196 c->type == C_WORKSPACE ? "Workspace|" :
197 c->type == C_CONTAINER ? "Container|" :
198 c->type == C_VIEW ? "View|" : "Unknown|");
199 fprintf(stderr,"layout:");
200 fprintf(stderr,
201 c->layout == L_NONE ? "NONE|" :
202 c->layout == L_HORIZ ? "Horiz|":
203 c->layout == L_VERT ? "Vert|":
204 c->layout == L_STACKED ? "Stacked|":
205 c->layout == L_FLOATING ? "Floating|":
206 "Unknown|");
207 fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
208 fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
209 fprintf(stderr, "vis:%c|", c->visible?'t':'f');
210 fprintf(stderr, "wgt:%d|", c->weight);
211 fprintf(stderr, "name:%.16s|", c->name);
212 fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
213}
214void layout_log(const swayc_t *c, int depth) {
215 int i;
216 int e = c->children?c->children->length:0;
217 for (i = 0; i < depth; ++i) fputc(' ', stderr);
218 container_log(c);
219 if (e) {
220 for (i = 0; i < depth; ++i) fputc(' ', stderr);
221 fprintf(stderr,"(\n");
222 for (i = 0; i < e; ++i) {
223 layout_log(c->children->items[i], depth + 1);
224 }
225 for (i = 0; i < depth; ++i) fputc(' ', stderr);
226 fprintf(stderr,")\n");
227 }
228 if (c->type == C_WORKSPACE) {
229 e = c->floating?c->floating->length:0;
230 for (i = 0; i < depth; ++i) fputc(' ', stderr);
231 if (e) {
232 for (i = 0; i < depth; ++i) fputc(' ', stderr);
233 fprintf(stderr,"(\n");
234 for (i = 0; i < e; ++i) {
235 layout_log(c->floating->items[i], depth + 1);
236 }
237 for (i = 0; i < depth; ++i) fputc(' ', stderr);
238 fprintf(stderr,")\n");
239 }
240 } 182 }
183 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
184 set_focused_container(get_focused_view(workspace));
185 arrange_windows(workspace, -1, -1);
241} 186}
242/* XXX:DEBUG:XXX */