diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | README.md | 46 | ||||
-rw-r--r-- | include/config.h | 5 | ||||
-rw-r--r-- | include/container.h | 22 | ||||
-rw-r--r-- | include/focus.h | 4 | ||||
-rw-r--r-- | include/input_state.h | 49 | ||||
-rw-r--r-- | include/ipc.h | 18 | ||||
-rw-r--r-- | include/layout.h | 6 | ||||
-rw-r--r-- | include/log.h | 9 | ||||
-rw-r--r-- | include/stringop.h | 5 | ||||
-rw-r--r-- | include/sway.h | 6 | ||||
-rw-r--r-- | include/workspace.h | 1 | ||||
-rw-r--r-- | sway.5.txt | 30 | ||||
-rw-r--r-- | sway/commands.c | 216 | ||||
-rw-r--r-- | sway/config.c | 221 | ||||
-rw-r--r-- | sway/container.c | 173 | ||||
-rw-r--r-- | sway/focus.c | 154 | ||||
-rw-r--r-- | sway/handlers.c | 356 | ||||
-rw-r--r-- | sway/input_state.c | 68 | ||||
-rw-r--r-- | sway/ipc.c | 321 | ||||
-rw-r--r-- | sway/layout.c | 271 | ||||
-rw-r--r-- | sway/log.c | 117 | ||||
-rw-r--r-- | sway/main.c | 96 | ||||
-rw-r--r-- | sway/readline.c | 12 | ||||
-rw-r--r-- | sway/stringop.c | 91 | ||||
-rw-r--r-- | sway/workspace.c | 88 |
27 files changed, 1749 insertions, 638 deletions
@@ -9,3 +9,4 @@ bin/ | |||
9 | test/ | 9 | test/ |
10 | build/ | 10 | build/ |
11 | .lvimrc | 11 | .lvimrc |
12 | config-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) | |||
3 | set(CMAKE_C_FLAGS "-g") | 3 | set(CMAKE_C_FLAGS "-g") |
4 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/") | 4 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/") |
5 | add_definitions("-Wall") | 5 | add_definitions("-Wall") |
6 | set(CMAKE_BUILD_TYPE Debug) | ||
7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake) | 6 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake) |
8 | 7 | ||
9 | find_package(XKBCommon REQUIRED) | 8 | find_package(XKBCommon REQUIRED) |
@@ -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 | 4 | i3-compatible window manager for [Wayland](http://wayland.freedesktop.org/). | |
5 | sway is a **work in progress** i3-compatible window manager for | 5 | Read 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 | ||
10 | Chat on #sway on irc.freenode.net | ||
11 | |||
12 | ## Rationale | 9 | ## Rationale |
13 | 10 | ||
14 | I use i3 on xorg. Wayland is coming, and [i3way](http://i3way.org/) still has | 11 | I 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 | |||
22 | sway is not supported by many distributions yet. Here's a list of packages | ||
23 | available for you to install: | ||
24 | 24 | ||
25 | Install [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 | ||
29 | Dependencies: | 29 | Install 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 | ||
36 | Compiling: | 36 | Run these commands: |
37 | 37 | ||
38 | cmake . | 38 | cmake . |
39 | make | 39 | make |
40 | # sudo make install | 40 | sudo make install |
41 | |||
42 | Binary shows up in `./bin` (or `/usr/local/bin` if you `make install`). | ||
43 | 41 | ||
44 | ## Configuration | 42 | ## Configuration |
45 | 43 | ||
46 | mkdir ~/.config/sway | 44 | If you already use i3, then copy your i3 config to `~/.config/sway/config` and |
47 | cp ~/.config/i3/config ~/.config/sway/ | 45 | it'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. | |
49 | Or if you don't already use i3: | ||
50 | |||
51 | mkdir ~/.config/sway | ||
52 | cp /etc/sway/config ~/.config/sway/ | ||
53 | |||
54 | Edit to your liking. | ||
55 | |||
56 | [See also](http://i3wm.org/docs/) | ||
57 | 47 | ||
58 | ## Running | 48 | ## Running |
59 | 49 | ||
50 | Run this from a tty (instead of starting x): | ||
51 | |||
60 | sway | 52 | sway |
61 | 53 | ||
62 | If you run this while xorg is running, it'll run inside of an x window (useful | 54 | If you run it from within x, it will spawn x windows instead of using your |
63 | for testing). Otherwise, it'll run wayland properly. | 55 | hardware 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 | ||
46 | bool load_config(void); | 49 | bool load_config(const char *file); |
47 | bool read_config(FILE *file, bool is_active); | 50 | bool read_config(FILE *file, bool is_active); |
48 | char *do_var_replacement(struct sway_config *config, char *str); | 51 | char *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 | |||
18 | enum swayc_layouts{ | 19 | enum 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 | ||
59 | swayc_t *new_output(wlc_handle handle); | 61 | swayc_t *new_output(wlc_handle handle); |
60 | swayc_t *new_workspace(swayc_t *output, const char *name); | 62 | swayc_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 |
66 | swayc_t *new_floating_view(wlc_handle handle); | 68 | swayc_t *new_floating_view(wlc_handle handle); |
67 | 69 | ||
70 | // Container Destroying | ||
68 | 71 | ||
69 | swayc_t *destroy_output(swayc_t *output); | 72 | swayc_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 |
71 | swayc_t *destroy_workspace(swayc_t *workspace); | 74 | swayc_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 | ||
72 | swayc_t *destroy_container(swayc_t *container); | 77 | swayc_t *destroy_container(swayc_t *container); |
78 | // Destroys view and all empty parent containers. return topmost non-empty | ||
79 | // parent | ||
73 | swayc_t *destroy_view(swayc_t *view); | 80 | swayc_t *destroy_view(swayc_t *view); |
74 | 81 | ||
82 | // Container Lookup | ||
83 | |||
84 | swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); | ||
85 | swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); | ||
86 | |||
75 | swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); | 87 | swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); |
76 | void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); | 88 | void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); |
77 | 89 | ||
90 | |||
78 | // Mappings | 91 | // Mappings |
79 | void set_view_visibility(swayc_t *view, void *data); | 92 | void set_view_visibility(swayc_t *view, void *data); |
93 | void 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 | |||
5 | enum movement_direction { | 3 | enum 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 | |||
9 | typedef uint32_t keycode; | ||
10 | |||
11 | // returns true if key has been pressed, otherwise false | ||
12 | bool check_key(keycode key); | ||
13 | |||
14 | // sets a key as pressed | ||
15 | void press_key(keycode key); | ||
16 | |||
17 | // unsets a key as pressed | ||
18 | void release_key(keycode key); | ||
19 | |||
20 | /* Pointer state */ | ||
21 | |||
22 | enum 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 | |||
30 | extern 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 | |||
45 | void start_floating(swayc_t *view); | ||
46 | void 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 | |||
4 | enum 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 | |||
15 | void ipc_init(void); | ||
16 | void 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 | ||
8 | extern swayc_t root_container; | 9 | extern swayc_t root_container; |
9 | 10 | ||
10 | void init_layout(void); | 11 | void init_layout(void); |
11 | 12 | ||
12 | void add_child(swayc_t *parent, swayc_t *child); | 13 | void add_child(swayc_t *parent, swayc_t *child); |
14 | void 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. |
14 | swayc_t *add_sibling(swayc_t *sibling, swayc_t *child); | 16 | swayc_t *add_sibling(swayc_t *sibling, swayc_t *child); |
15 | swayc_t *replace_child(swayc_t *child, swayc_t *new_child); | 17 | swayc_t *replace_child(swayc_t *child, swayc_t *new_child); |
16 | swayc_t *remove_child(swayc_t *child); | 18 | swayc_t *remove_child(swayc_t *child); |
17 | 19 | ||
20 | void move_container(swayc_t* container,swayc_t* root,int direction); | ||
21 | |||
22 | |||
18 | // Layout | 23 | // Layout |
19 | void arrange_windows(swayc_t *container, int width, int height); | 24 | void 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 | ||
26 | swayc_t *get_focused_container(swayc_t *parent); | 31 | swayc_t *get_focused_container(swayc_t *parent); |
27 | swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent); | 32 | swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent); |
33 | swayc_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 | ||
4 | typedef enum { | 6 | typedef enum { |
5 | L_SILENT = 0, | 7 | L_SILENT = 0, |
@@ -10,7 +12,10 @@ typedef enum { | |||
10 | 12 | ||
11 | void init_log(int verbosity); | 13 | void init_log(int verbosity); |
12 | void sway_log_colors(int mode); | 14 | void sway_log_colors(int mode); |
13 | void sway_log(int verbosity, char* format, ...) __attribute__((format(printf,2,3))); | 15 | void sway_log(int verbosity, const char* format, ...) __attribute__((format(printf,2,3))); |
14 | void sway_abort(char* format, ...)__attribute__((format(printf,1,2))); | 16 | void sway_log_errno(int verbosity, char* format, ...) __attribute__((format(printf,2,3))); |
17 | void sway_abort(const char* format, ...) __attribute__((format(printf,1,2))); | ||
18 | bool sway_assert(bool condition, const char* format, ...) __attribute__((format(printf,2,3))); | ||
15 | 19 | ||
20 | void 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 | ||
5 | void strip_whitespace(char *str); | 5 | char *strip_whitespace(char *str, int *trimmed_start); |
6 | void strip_comments(char *str); | 6 | char *strip_comments(char *str); |
7 | list_t *split_string(const char *str, const char *delims); | 7 | list_t *split_string(const char *str, const char *delims); |
8 | void free_flat_list(list_t *list); | 8 | void free_flat_list(list_t *list); |
9 | char *code_strchr(const char *string, char delimiter); | 9 | char *code_strchr(const char *string, char delimiter); |
10 | char *code_strstr(const char *haystack, const char *needle); | 10 | char *code_strstr(const char *haystack, const char *needle); |
11 | int unescape_string(char *string); | 11 | int unescape_string(char *string); |
12 | char *join_args(char **argv, int argc); | 12 | char *join_args(char **argv, int argc); |
13 | char *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 | |||
4 | void 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(); | |||
15 | void workspace_next(); | 15 | void workspace_next(); |
16 | void workspace_output_prev(); | 16 | void workspace_output_prev(); |
17 | void workspace_prev(); | 17 | void workspace_prev(); |
18 | void layout_log(const swayc_t *c, int depth); | ||
19 | 18 | ||
20 | #endif | 19 | #endif |
@@ -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 | ||
18 | struct modifier_key { | 20 | struct 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 | ||
80 | static 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 | ||
79 | static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) { | 93 | static 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 | ||
257 | static bool cmd_focus(struct sway_config *config, int argc, char **argv) { | 278 | static 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 | ||
284 | static bool cmd_move(struct sway_config *config, int argc, char **argv) { | 344 | static 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 | |||
366 | static 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 | ||
12 | struct sway_config *config; | 13 | struct 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 | ||
18 | static char *get_config_path() { | 19 | void 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 | 38 | void 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/ | 43 | void 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 | 64 | static 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 | 73 | static 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 | ||
129 | bool load_config(void) { | 147 | bool 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 | ||
158 | void 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 | |||
175 | bool read_config(FILE *file, bool is_active) { | 181 | bool 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 | ||
11 | static swayc_t *new_swayc(enum swayc_types type) { | 14 | static 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 | ||
23 | static void free_swayc(swayc_t *c) { | 25 | static 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 | |||
60 | static bool workspace_test(swayc_t *view, void *name) { | ||
61 | return strcasecmp(view->name, (char *)name) == 0; | ||
62 | } | ||
39 | 63 | ||
40 | swayc_t *new_output(wlc_handle handle) { | 64 | swayc_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 | ||
79 | swayc_t *new_workspace(swayc_t *output, const char *name) { | 110 | swayc_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 | ||
94 | swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { | 130 | swayc_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 | ||
135 | swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { | 175 | swayc_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 | ||
196 | swayc_t *destroy_output(swayc_t *output) { | 244 | swayc_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 | ||
205 | swayc_t *destroy_workspace(swayc_t *workspace) { | 256 | swayc_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 | ||
218 | swayc_t *destroy_container(swayc_t *container) { | 279 | swayc_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 | ||
229 | swayc_t *destroy_view(swayc_t *view) { | 292 | swayc_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 | |||
309 | swayc_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 | |||
322 | swayc_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 | |||
245 | swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { | 335 | swayc_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 | ||
273 | void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { | 363 | void 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 | ||
285 | void set_view_visibility(swayc_t *view, void *data) { | 381 | void 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 | |||
397 | void 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 | ||
7 | bool locked_container_focus = false; | 8 | bool locked_container_focus = false; |
8 | bool locked_view_focus = false; | 9 | bool 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 | ||
47 | bool move_focus(enum movement_direction direction) { | 56 | bool 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 | ||
114 | swayc_t *get_focused_container(swayc_t *parent) { | 70 | swayc_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 | ||
186 | swayc_t *get_focused_view(swayc_t *parent) { | 166 | swayc_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" | |
17 | uint32_t keys_pressed[32]; | ||
18 | 17 | ||
19 | static struct wlc_origin mouse_origin; | 18 | static struct wlc_origin mouse_origin; |
20 | 19 | ||
21 | static bool m1_held = false; | ||
22 | static bool m2_held = false; | ||
23 | |||
24 | static bool pointer_test(swayc_t *view, void *_origin) { | 20 | static 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 | |||
87 | static bool handle_output_created(wlc_handle output) { | 84 | static 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 | ||
111 | static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { | 114 | static 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 | ||
131 | static bool handle_view_created(wlc_handle handle) { | 134 | static 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 | ||
198 | static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { | 227 | static 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 | ||
219 | static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { | 248 | static 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 | ||
250 | static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, | 277 | static 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 | ||
317 | static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) { | 336 | static 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 | |||
414 | static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, | 450 | static 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 | |||
9 | static keycode key_state_array[KEY_STATE_MAX_LENGTH]; | ||
10 | |||
11 | static 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 | |||
21 | bool check_key(keycode key) { | ||
22 | return find_key(key) < KEY_STATE_MAX_LENGTH; | ||
23 | } | ||
24 | |||
25 | void 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 | |||
36 | void 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 | |||
44 | struct pointer_state pointer_state = {0, 0, {0, 0}, {0, 0, 0, 0}}; | ||
45 | |||
46 | static struct wlc_geometry saved_floating; | ||
47 | |||
48 | void 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 | |||
57 | void 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 | |||
22 | static int ipc_socket = -1; | ||
23 | static struct wlc_event_source *ipc_event_source = NULL; | ||
24 | static struct sockaddr_un ipc_sockaddr = { | ||
25 | .sun_family = AF_UNIX, | ||
26 | .sun_path = "/tmp/sway-ipc.sock" | ||
27 | }; | ||
28 | |||
29 | static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; | ||
30 | |||
31 | struct 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 | |||
38 | int ipc_handle_connection(int fd, uint32_t mask, void *data); | ||
39 | int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); | ||
40 | void ipc_client_disconnect(struct ipc_client *client); | ||
41 | void ipc_client_handle_command(struct ipc_client *client); | ||
42 | bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); | ||
43 | void ipc_get_workspaces_callback(swayc_t *container, void *data); | ||
44 | void ipc_get_outputs_callback(swayc_t *container, void *data); | ||
45 | |||
46 | char *json_list(list_t *items); | ||
47 | |||
48 | void 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 | |||
73 | void 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 | |||
81 | int 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 | |||
106 | static const int ipc_header_size = sizeof(ipc_magic)+8; | ||
107 | |||
108 | int 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 | |||
166 | void 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 | |||
178 | void 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 | |||
234 | bool 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 | |||
258 | char *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 | |||
270 | void 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 | |||
298 | void 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 | ||
10 | swayc_t root_container; | 12 | swayc_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 | |||
42 | void 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 | ||
36 | swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { | 53 | swayc_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 | ||
111 | void 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 | ||
93 | void arrange_windows(swayc_t *container, int width, int height) { | 156 | void 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 | ||
361 | swayc_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 | } | ||
@@ -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 | ||
8 | int colored = 1; | 12 | int colored = 1; |
9 | int v = 0; | 13 | int v = 0; |
@@ -18,10 +22,10 @@ static const char *verbosity_colors[] = { | |||
18 | void init_log(int verbosity) { | 22 | void 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 | ||
35 | void sway_abort(char *format, ...) { | 39 | void 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 | ||
45 | void sway_log(int verbosity, char* format, ...) { | 49 | void 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 | |||
72 | void 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 | |||
100 | bool 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 */ | ||
120 | static 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 | } | ||
151 | void 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 | |||
15 | static bool terminate_request = false; | ||
16 | |||
17 | void sway_terminate(void) { | ||
18 | terminate_request = true; | ||
19 | wlc_terminate(); | ||
20 | } | ||
11 | 21 | ||
12 | static void sigchld_handle(int signal); | 22 | static void sigchld_handle(int signal); |
13 | 23 | ||
14 | int main(int argc, char **argv) { | 24 | int 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. */ |
10 | void strip_whitespace(char *str) { | 10 | char *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 | ||
35 | void strip_comments(char *str) { | 35 | char *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 | ||
53 | list_t *split_string(const char *str, const char *delims) { | 54 | list_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 | */ | ||
205 | char *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 | ||
71 | swayc_t *workspace_create(const char* name) { | 76 | swayc_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 | ||
79 | bool workspace_by_name(swayc_t *view, void *data) { | 82 | bool 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 | ||
176 | void workspace_switch(swayc_t *workspace) { | 179 | void 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 */ | ||
182 | static 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 | } | ||
214 | void 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 */ | ||