diff options
author | Half-Shot <half-shot@molrams.com> | 2015-08-20 21:32:08 +0100 |
---|---|---|
committer | Half-Shot <half-shot@molrams.com> | 2015-08-20 21:32:08 +0100 |
commit | 5a9ba261bca4ca709ec7a14d2019b55d9ce06994 (patch) | |
tree | fe1a924cf8055b2b722566db6ab98295dcf08ce7 | |
parent | Basic left right move command implemented. (diff) | |
parent | Merge pull request #104 from minus7/ipc-get-messages (diff) | |
download | sway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.tar.gz sway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.tar.zst sway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.zip |
Merge branch 'master' of https://github.com/SirCmpwn/sway
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | include/config.h | 5 | ||||
-rw-r--r-- | include/container.h | 20 | ||||
-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 | 3 | ||||
-rw-r--r-- | include/log.h | 9 | ||||
-rw-r--r-- | include/stringop.h | 1 | ||||
-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 | 186 | ||||
-rw-r--r-- | sway/config.c | 218 | ||||
-rw-r--r-- | sway/container.c | 166 | ||||
-rw-r--r-- | sway/focus.c | 87 | ||||
-rw-r--r-- | sway/handlers.c | 326 | ||||
-rw-r--r-- | sway/input_state.c | 68 | ||||
-rw-r--r-- | sway/ipc.c | 321 | ||||
-rw-r--r-- | sway/layout.c | 186 | ||||
-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 | 39 | ||||
-rw-r--r-- | sway/workspace.c | 77 |
26 files changed, 1485 insertions, 562 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) |
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 63529e44..79e023fe 100644 --- a/include/container.h +++ b/include/container.h | |||
@@ -11,7 +11,7 @@ enum swayc_types{ | |||
11 | C_WORKSPACE, | 11 | C_WORKSPACE, |
12 | C_CONTAINER, | 12 | C_CONTAINER, |
13 | C_VIEW, | 13 | C_VIEW, |
14 | //Keep last | 14 | // Keep last |
15 | C_TYPES, | 15 | C_TYPES, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -23,7 +23,7 @@ enum swayc_layouts{ | |||
23 | L_STACKED, | 23 | L_STACKED, |
24 | L_TABBED, | 24 | L_TABBED, |
25 | L_FLOATING, | 25 | L_FLOATING, |
26 | //Keep last | 26 | // Keep last |
27 | L_LAYOUTS, | 27 | L_LAYOUTS, |
28 | }; | 28 | }; |
29 | 29 | ||
@@ -45,10 +45,10 @@ struct sway_container { | |||
45 | bool is_floating; | 45 | bool is_floating; |
46 | bool is_focused; | 46 | bool is_focused; |
47 | 47 | ||
48 | int weight; | ||
49 | |||
50 | char *name; | 48 | char *name; |
51 | 49 | ||
50 | int gaps; | ||
51 | |||
52 | list_t *children; | 52 | list_t *children; |
53 | list_t *floating; | 53 | list_t *floating; |
54 | 54 | ||
@@ -56,6 +56,7 @@ struct sway_container { | |||
56 | struct sway_container *focused; | 56 | struct sway_container *focused; |
57 | }; | 57 | }; |
58 | 58 | ||
59 | // Container Creation | ||
59 | 60 | ||
60 | swayc_t *new_output(wlc_handle handle); | 61 | swayc_t *new_output(wlc_handle handle); |
61 | swayc_t *new_workspace(swayc_t *output, const char *name); | 62 | swayc_t *new_workspace(swayc_t *output, const char *name); |
@@ -66,18 +67,29 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle); | |||
66 | // Creates view as a new floating view which is in the active workspace | 67 | // Creates view as a new floating view which is in the active workspace |
67 | swayc_t *new_floating_view(wlc_handle handle); | 68 | swayc_t *new_floating_view(wlc_handle handle); |
68 | 69 | ||
70 | // Container Destroying | ||
69 | 71 | ||
70 | swayc_t *destroy_output(swayc_t *output); | 72 | swayc_t *destroy_output(swayc_t *output); |
71 | // Destroys workspace if empty and returns parent pointer, else returns NULL | 73 | // Destroys workspace if empty and returns parent pointer, else returns NULL |
72 | 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 | ||
73 | 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 | ||
74 | swayc_t *destroy_view(swayc_t *view); | 80 | swayc_t *destroy_view(swayc_t *view); |
75 | 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 | |||
76 | 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); |
77 | void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); | 88 | void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); |
78 | 89 | ||
79 | 90 | ||
80 | // Mappings | 91 | // Mappings |
81 | 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); | ||
82 | 94 | ||
83 | #endif | 95 | #endif |
diff --git a/include/focus.h b/include/focus.h index 410ed134..383993fa 100644 --- a/include/focus.h +++ b/include/focus.h | |||
@@ -1,7 +1,5 @@ | |||
1 | #ifndef _SWAY_FOCUS_H | 1 | #ifndef _SWAY_FOCUS_H |
2 | #define _SWAY_FOCUS_H | 2 | #define _SWAY_FOCUS_H |
3 | #include "container.h" | ||
4 | |||
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 79241698..c1d7d8b4 100644 --- a/include/layout.h +++ b/include/layout.h | |||
@@ -4,12 +4,14 @@ | |||
4 | #include <wlc/wlc.h> | 4 | #include <wlc/wlc.h> |
5 | #include "list.h" | 5 | #include "list.h" |
6 | #include "container.h" | 6 | #include "container.h" |
7 | #include "focus.h" | ||
7 | 8 | ||
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); |
@@ -28,5 +30,6 @@ void focus_view_for(swayc_t *ancestor, swayc_t *container); | |||
28 | 30 | ||
29 | swayc_t *get_focused_container(swayc_t *parent); | 31 | swayc_t *get_focused_container(swayc_t *parent); |
30 | 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); | ||
31 | 34 | ||
32 | #endif | 35 | #endif |
diff --git a/include/log.h b/include/log.h index d35b2a54..47a83321 100644 --- a/include/log.h +++ b/include/log.h | |||
@@ -1,5 +1,7 @@ | |||
1 | #ifndef _SWAY_LOG_H | 1 | #ifndef _SWAY_LOG_H |
2 | #define _SWAY_LOG_H | 2 | #define _SWAY_LOG_H |
3 | #include <stdbool.h> | ||
4 | #include "container.h" | ||
3 | 5 | ||
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 a5346829..4300f9ed 100644 --- a/include/stringop.h +++ b/include/stringop.h | |||
@@ -10,5 +10,6 @@ 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 1ca5c17f..e39b781a 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <wlc/wlc.h> | 3 | #include <wlc/wlc.h> |
4 | #include <stdio.h> | 4 | #include <stdio.h> |
5 | #include <stdlib.h> | 5 | #include <stdlib.h> |
6 | #include <errno.h> | ||
6 | #include <string.h> | 7 | #include <string.h> |
7 | #include <unistd.h> | 8 | #include <unistd.h> |
8 | #include <ctype.h> | 9 | #include <ctype.h> |
@@ -14,6 +15,7 @@ | |||
14 | #include "commands.h" | 15 | #include "commands.h" |
15 | #include "container.h" | 16 | #include "container.h" |
16 | #include "handlers.h" | 17 | #include "handlers.h" |
18 | #include "sway.h" | ||
17 | 19 | ||
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 | ||
@@ -303,6 +363,42 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) { | |||
303 | 363 | ||
304 | return true; | 364 | return true; |
305 | 365 | ||
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 | } | ||
401 | return true; | ||
306 | } | 402 | } |
307 | 403 | ||
308 | static bool cmd_kill(struct sway_config *config, int argc, char **argv) { | 404 | static bool cmd_kill(struct sway_config *config, int argc, char **argv) { |
@@ -316,7 +412,6 @@ static bool cmd_layout(struct sway_config *config, int argc, char **argv) { | |||
316 | return false; | 412 | return false; |
317 | } | 413 | } |
318 | swayc_t *parent = get_focused_container(&root_container); | 414 | swayc_t *parent = get_focused_container(&root_container); |
319 | |||
320 | while (parent->type == C_VIEW) { | 415 | while (parent->type == C_VIEW) { |
321 | parent = parent->parent; | 416 | parent = parent->parent; |
322 | } | 417 | } |
@@ -341,7 +436,7 @@ static bool cmd_reload(struct sway_config *config, int argc, char **argv) { | |||
341 | if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) { | 436 | if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) { |
342 | return false; | 437 | return false; |
343 | } | 438 | } |
344 | if (!load_config()) { | 439 | if (!load_config(NULL)) { // TODO: Use config given from -c |
345 | return false; | 440 | return false; |
346 | } | 441 | } |
347 | arrange_windows(&root_container, -1, -1); | 442 | arrange_windows(&root_container, -1, -1); |
@@ -435,14 +530,12 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) { | |||
435 | swayc_t *container = get_focused_view(&root_container); | 530 | swayc_t *container = get_focused_view(&root_container); |
436 | bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0; | 531 | bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0; |
437 | wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); | 532 | wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); |
438 | //Resize workspace if going from fullscreen -> notfullscreen | 533 | // Resize workspace if going from fullscreen -> notfullscreen |
439 | //otherwise just resize container | 534 | // otherwise just resize container |
440 | if (current) { | 535 | if (current) { |
441 | while (container->type != C_WORKSPACE) { | 536 | container = swayc_parent_by_type(container, C_WORKSPACE); |
442 | container = container->parent; | ||
443 | } | ||
444 | } | 537 | } |
445 | //Only resize container when going into fullscreen | 538 | // Only resize container when going into fullscreen |
446 | arrange_windows(container, -1, -1); | 539 | arrange_windows(container, -1, -1); |
447 | 540 | ||
448 | return true; | 541 | return true; |
@@ -508,6 +601,7 @@ static struct cmd_handler handlers[] = { | |||
508 | { "focus", cmd_focus }, | 601 | { "focus", cmd_focus }, |
509 | { "focus_follows_mouse", cmd_focus_follows_mouse }, | 602 | { "focus_follows_mouse", cmd_focus_follows_mouse }, |
510 | { "fullscreen", cmd_fullscreen }, | 603 | { "fullscreen", cmd_fullscreen }, |
604 | { "gaps", cmd_gaps }, | ||
511 | { "kill", cmd_kill }, | 605 | { "kill", cmd_kill }, |
512 | { "layout", cmd_layout }, | 606 | { "layout", cmd_layout }, |
513 | { "log_colors", cmd_log_colors }, | 607 | { "log_colors", cmd_log_colors }, |
@@ -606,7 +700,7 @@ bool handle_command(struct sway_config *config, char *exec) { | |||
606 | char **argv = split_directive(exec + strlen(handler->command), &argc); | 700 | char **argv = split_directive(exec + strlen(handler->command), &argc); |
607 | int i; | 701 | int i; |
608 | 702 | ||
609 | //Perform var subs on all parts of the command | 703 | // Perform var subs on all parts of the command |
610 | for (i = 0; i < argc; ++i) { | 704 | for (i = 0; i < argc; ++i) { |
611 | argv[i] = do_var_replacement(config, argv[i]); | 705 | argv[i] = do_var_replacement(config, argv[i]); |
612 | } | 706 | } |
diff --git a/sway/config.c b/sway/config.c index f1de6080..9f65e8a2 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "log.h" | 8 | #include "log.h" |
9 | #include "commands.h" | 9 | #include "commands.h" |
10 | #include "config.h" | 10 | #include "config.h" |
11 | #include "layout.h" | ||
11 | 12 | ||
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); |
@@ -188,8 +194,8 @@ bool read_config(FILE *file, bool is_active) { | |||
188 | while (!feof(file)) { | 194 | while (!feof(file)) { |
189 | int _; | 195 | int _; |
190 | char *line = read_line(file); | 196 | char *line = read_line(file); |
191 | line = strip_comments(line); | ||
192 | line = strip_whitespace(line, &_); | 197 | line = strip_whitespace(line, &_); |
198 | line = strip_comments(line); | ||
193 | if (!line[0]) { | 199 | if (!line[0]) { |
194 | goto _continue; | 200 | goto _continue; |
195 | } | 201 | } |
@@ -225,6 +231,8 @@ _continue: | |||
225 | 231 | ||
226 | if (is_active) { | 232 | if (is_active) { |
227 | temp_config->reloading = false; | 233 | temp_config->reloading = false; |
234 | container_map(&root_container, reset_gaps, NULL); | ||
235 | arrange_windows(&root_container, -1, -1); | ||
228 | } | 236 | } |
229 | config = temp_config; | 237 | config = temp_config; |
230 | 238 | ||
diff --git a/sway/container.c b/sway/container.c index 62c5bda0..7ccc2e09 100644 --- a/sway/container.c +++ b/sway/container.c | |||
@@ -8,53 +8,57 @@ | |||
8 | #include "layout.h" | 8 | #include "layout.h" |
9 | #include "log.h" | 9 | #include "log.h" |
10 | 10 | ||
11 | #define ASSERT_NONNULL(PTR) \ | ||
12 | sway_assert (PTR, "%s: " #PTR "must be non-null", __func__) | ||
11 | 13 | ||
12 | static swayc_t *new_swayc(enum swayc_types type) { | 14 | static swayc_t *new_swayc(enum swayc_types type) { |
13 | swayc_t *c = calloc(1, sizeof(swayc_t)); | 15 | swayc_t *c = calloc(1, sizeof(swayc_t)); |
14 | c->handle = -1; | 16 | c->handle = -1; |
15 | c->layout = L_NONE; | 17 | c->layout = L_NONE; |
16 | c->type = type; | 18 | c->type = type; |
17 | c->weight = 1; | ||
18 | if (type != C_VIEW) { | 19 | if (type != C_VIEW) { |
19 | c->children = create_list(); | 20 | c->children = create_list(); |
20 | } | 21 | } |
21 | return c; | 22 | return c; |
22 | } | 23 | } |
23 | 24 | ||
24 | static void free_swayc(swayc_t *c) { | 25 | static void free_swayc(swayc_t *cont) { |
26 | if (!ASSERT_NONNULL(cont)) { | ||
27 | return; | ||
28 | } | ||
25 | // TODO does not properly handle containers with children, | 29 | // TODO does not properly handle containers with children, |
26 | // TODO but functions that call this usually check for that | 30 | // TODO but functions that call this usually check for that |
27 | if (c->children) { | 31 | if (cont->children) { |
28 | if (c->children->length) { | 32 | if (cont->children->length) { |
29 | int i; | 33 | int i; |
30 | for (i = 0; i < c->children->length; ++i) { | 34 | for (i = 0; i < cont->children->length; ++i) { |
31 | free_swayc(c->children->items[i]); | 35 | free_swayc(cont->children->items[i]); |
32 | } | 36 | } |
33 | } | 37 | } |
34 | list_free(c->children); | 38 | list_free(cont->children); |
35 | } | 39 | } |
36 | if (c->floating) { | 40 | if (cont->floating) { |
37 | if (c->floating->length) { | 41 | if (cont->floating->length) { |
38 | int i; | 42 | int i; |
39 | for (i = 0; i < c->floating->length; ++i) { | 43 | for (i = 0; i < cont->floating->length; ++i) { |
40 | free_swayc(c->floating->items[i]); | 44 | free_swayc(cont->floating->items[i]); |
41 | } | 45 | } |
42 | } | 46 | } |
43 | list_free(c->floating); | 47 | list_free(cont->floating); |
44 | } | 48 | } |
45 | if (c->parent) { | 49 | if (cont->parent) { |
46 | remove_child(c); | 50 | remove_child(cont); |
47 | } | 51 | } |
48 | if (c->name) { | 52 | if (cont->name) { |
49 | free(c->name); | 53 | free(cont->name); |
50 | } | 54 | } |
51 | free(c); | 55 | free(cont); |
52 | } | 56 | } |
53 | 57 | ||
54 | /* New containers */ | 58 | // New containers |
55 | 59 | ||
56 | static bool workspace_test(swayc_t *view, void *name) { | 60 | static bool workspace_test(swayc_t *view, void *name) { |
57 | return strcasecmp(view->name, (char *)name); | 61 | return strcasecmp(view->name, (char *)name) == 0; |
58 | } | 62 | } |
59 | 63 | ||
60 | swayc_t *new_output(wlc_handle handle) { | 64 | swayc_t *new_output(wlc_handle handle) { |
@@ -67,6 +71,7 @@ swayc_t *new_output(wlc_handle handle) { | |||
67 | output->height = size->h; | 71 | output->height = size->h; |
68 | output->handle = handle; | 72 | output->handle = handle; |
69 | output->name = name ? strdup(name) : NULL; | 73 | output->name = name ? strdup(name) : NULL; |
74 | output->gaps = config->gaps_outer + config->gaps_inner / 2; | ||
70 | 75 | ||
71 | add_child(&root_container, output); | 76 | add_child(&root_container, output); |
72 | 77 | ||
@@ -80,8 +85,10 @@ swayc_t *new_output(wlc_handle handle) { | |||
80 | sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); | 85 | sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); |
81 | // Check if any other workspaces are using this name | 86 | // Check if any other workspaces are using this name |
82 | if (find_container(&root_container, workspace_test, wso->workspace)) { | 87 | if (find_container(&root_container, workspace_test, wso->workspace)) { |
88 | sway_log(L_DEBUG, "But it's already taken"); | ||
83 | break; | 89 | break; |
84 | } | 90 | } |
91 | sway_log(L_DEBUG, "So we're going to use it"); | ||
85 | ws_name = strdup(wso->workspace); | 92 | ws_name = strdup(wso->workspace); |
86 | break; | 93 | break; |
87 | } | 94 | } |
@@ -101,10 +108,15 @@ swayc_t *new_output(wlc_handle handle) { | |||
101 | } | 108 | } |
102 | 109 | ||
103 | 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 | } | ||
104 | sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle); | 114 | sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle); |
105 | swayc_t *workspace = new_swayc(C_WORKSPACE); | 115 | swayc_t *workspace = new_swayc(C_WORKSPACE); |
106 | 116 | ||
107 | workspace->layout = L_HORIZ; // TODO: default layout | 117 | workspace->layout = L_HORIZ; // TODO: default layout |
118 | workspace->x = output->x; | ||
119 | workspace->y = output->y; | ||
108 | workspace->width = output->width; | 120 | workspace->width = output->width; |
109 | workspace->height = output->height; | 121 | workspace->height = output->height; |
110 | workspace->name = strdup(name); | 122 | workspace->name = strdup(name); |
@@ -116,6 +128,9 @@ swayc_t *new_workspace(swayc_t *output, const char *name) { | |||
116 | } | 128 | } |
117 | 129 | ||
118 | 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 | } | ||
119 | swayc_t *cont = new_swayc(C_CONTAINER); | 134 | swayc_t *cont = new_swayc(C_CONTAINER); |
120 | 135 | ||
121 | sway_log(L_DEBUG, "creating container %p around %p", cont, child); | 136 | sway_log(L_DEBUG, "creating container %p around %p", cont, child); |
@@ -147,6 +162,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { | |||
147 | // give them proper layouts | 162 | // give them proper layouts |
148 | cont->layout = workspace->layout; | 163 | cont->layout = workspace->layout; |
149 | workspace->layout = layout; | 164 | workspace->layout = layout; |
165 | set_focused_container_for(workspace, get_focused_view(workspace)); | ||
150 | } else { // Or is built around container | 166 | } else { // Or is built around container |
151 | swayc_t *parent = replace_child(child, cont); | 167 | swayc_t *parent = replace_child(child, cont); |
152 | if (parent) { | 168 | if (parent) { |
@@ -157,6 +173,9 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { | |||
157 | } | 173 | } |
158 | 174 | ||
159 | 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 | } | ||
160 | const char *title = wlc_view_get_title(handle); | 179 | const char *title = wlc_view_get_title(handle); |
161 | swayc_t *view = new_swayc(C_VIEW); | 180 | swayc_t *view = new_swayc(C_VIEW); |
162 | sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d", | 181 | sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d", |
@@ -166,11 +185,15 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { | |||
166 | view->name = title ? strdup(title) : NULL; | 185 | view->name = title ? strdup(title) : NULL; |
167 | view->visible = true; | 186 | view->visible = true; |
168 | view->is_focused = true; | 187 | view->is_focused = true; |
188 | // Setup geometry | ||
189 | const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); | ||
190 | view->width = 0; | ||
191 | view->height = 0; | ||
192 | view->desired_width = geometry->size.w; | ||
193 | view->desired_height = geometry->size.h; | ||
169 | 194 | ||
170 | view->desired_width = -1; | 195 | view->gaps = config->gaps_inner; |
171 | view->desired_height = -1; | ||
172 | 196 | ||
173 | // TODO: properly set this | ||
174 | view->is_floating = false; | 197 | view->is_floating = false; |
175 | 198 | ||
176 | if (sibling->type == C_WORKSPACE) { | 199 | if (sibling->type == C_WORKSPACE) { |
@@ -196,8 +219,9 @@ swayc_t *new_floating_view(wlc_handle handle) { | |||
196 | // Set the geometry of the floating view | 219 | // Set the geometry of the floating view |
197 | const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); | 220 | const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); |
198 | 221 | ||
199 | view->x = geometry->origin.x; | 222 | // give it requested geometry, but place in center |
200 | view->y = geometry->origin.y; | 223 | view->x = (active_workspace->width - geometry->size.w) / 2; |
224 | view->y = (active_workspace->height- geometry->size.h) / 2; | ||
201 | view->width = geometry->size.w; | 225 | view->width = geometry->size.w; |
202 | view->height = geometry->size.h; | 226 | view->height = geometry->size.h; |
203 | 227 | ||
@@ -215,9 +239,12 @@ swayc_t *new_floating_view(wlc_handle handle) { | |||
215 | return view; | 239 | return view; |
216 | } | 240 | } |
217 | 241 | ||
218 | /* Destroy container */ | 242 | // Destroy container |
219 | 243 | ||
220 | swayc_t *destroy_output(swayc_t *output) { | 244 | swayc_t *destroy_output(swayc_t *output) { |
245 | if (!ASSERT_NONNULL(output)) { | ||
246 | return NULL; | ||
247 | } | ||
221 | if (output->children->length == 0) { | 248 | if (output->children->length == 0) { |
222 | // TODO move workspaces to other outputs | 249 | // TODO move workspaces to other outputs |
223 | } | 250 | } |
@@ -227,23 +254,21 @@ swayc_t *destroy_output(swayc_t *output) { | |||
227 | } | 254 | } |
228 | 255 | ||
229 | swayc_t *destroy_workspace(swayc_t *workspace) { | 256 | swayc_t *destroy_workspace(swayc_t *workspace) { |
257 | if (!ASSERT_NONNULL(workspace)) { | ||
258 | return NULL; | ||
259 | } | ||
230 | // NOTE: This is called from elsewhere without checking children length | 260 | // NOTE: This is called from elsewhere without checking children length |
231 | // TODO move containers to other workspaces? | 261 | // TODO move containers to other workspaces? |
232 | // for now just dont delete | 262 | // for now just dont delete |
233 | 263 | ||
234 | // Do not destroy this if it's the last workspace on this output | 264 | // Do not destroy this if it's the last workspace on this output |
235 | swayc_t *output = workspace->parent; | 265 | swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); |
236 | while (output && output->type != C_OUTPUT) { | 266 | if (output && output->children->length == 1) { |
237 | output = output->parent; | 267 | return NULL; |
238 | } | ||
239 | if (output) { | ||
240 | if (output->children->length == 1) { | ||
241 | return NULL; | ||
242 | } | ||
243 | } | 268 | } |
244 | 269 | ||
245 | if (workspace->children->length == 0) { | 270 | if (workspace->children->length == 0) { |
246 | sway_log(L_DEBUG, "Workspace: Destroying workspace '%s'", workspace->name); | 271 | sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name); |
247 | swayc_t *parent = workspace->parent; | 272 | swayc_t *parent = workspace->parent; |
248 | free_swayc(workspace); | 273 | free_swayc(workspace); |
249 | return parent; | 274 | return parent; |
@@ -252,19 +277,20 @@ swayc_t *destroy_workspace(swayc_t *workspace) { | |||
252 | } | 277 | } |
253 | 278 | ||
254 | swayc_t *destroy_container(swayc_t *container) { | 279 | swayc_t *destroy_container(swayc_t *container) { |
280 | if (!ASSERT_NONNULL(container)) { | ||
281 | return NULL; | ||
282 | } | ||
255 | while (container->children->length == 0 && container->type == C_CONTAINER) { | 283 | while (container->children->length == 0 && container->type == C_CONTAINER) { |
256 | sway_log(L_DEBUG, "Container: Destroying container '%p'", container); | 284 | sway_log(L_DEBUG, "Container: Destroying container '%p'", container); |
257 | swayc_t *parent = container->parent; | 285 | swayc_t *parent = container->parent; |
258 | free_swayc(container); | 286 | free_swayc(container); |
259 | |||
260 | container = parent; | 287 | container = parent; |
261 | } | 288 | } |
262 | return container; | 289 | return container; |
263 | } | 290 | } |
264 | 291 | ||
265 | swayc_t *destroy_view(swayc_t *view) { | 292 | swayc_t *destroy_view(swayc_t *view) { |
266 | if (view == NULL) { | 293 | if (!ASSERT_NONNULL(view)) { |
267 | sway_log(L_DEBUG, "Warning: NULL passed into destroy_view"); | ||
268 | return NULL; | 294 | return NULL; |
269 | } | 295 | } |
270 | sway_log(L_DEBUG, "Destroying view '%p'", view); | 296 | sway_log(L_DEBUG, "Destroying view '%p'", view); |
@@ -278,6 +304,34 @@ swayc_t *destroy_view(swayc_t *view) { | |||
278 | return parent; | 304 | return parent; |
279 | } | 305 | } |
280 | 306 | ||
307 | // Container lookup | ||
308 | |||
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 | |||
281 | 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) { |
282 | if (!container->children) { | 336 | if (!container->children) { |
283 | return NULL; | 337 | return NULL; |
@@ -307,25 +361,27 @@ swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *da | |||
307 | } | 361 | } |
308 | 362 | ||
309 | 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) { |
310 | if (!container || !container->children || !container->children->length) { | 364 | if (container && container->children && container->children->length) { |
311 | return; | 365 | int i; |
312 | } | 366 | for (i = 0; i < container->children->length; ++i) { |
313 | int i; | 367 | swayc_t *child = container->children->items[i]; |
314 | for (i = 0; i < container->children->length; ++i) { | ||
315 | swayc_t *child = container->children->items[i]; | ||
316 | f(child, data); | ||
317 | container_map(child, f, data); | ||
318 | } | ||
319 | if (container->type == C_WORKSPACE) { | ||
320 | for (i = 0; i < container->floating->length; ++i) { | ||
321 | swayc_t *child = container->floating->items[i]; | ||
322 | f(child, data); | 368 | f(child, data); |
323 | container_map(child, f, data); | 369 | container_map(child, f, data); |
324 | } | 370 | } |
371 | if (container->type == C_WORKSPACE) { | ||
372 | for (i = 0; i < container->floating->length; ++i) { | ||
373 | swayc_t *child = container->floating->items[i]; | ||
374 | f(child, data); | ||
375 | container_map(child, f, data); | ||
376 | } | ||
377 | } | ||
325 | } | 378 | } |
326 | } | 379 | } |
327 | 380 | ||
328 | 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 | } | ||
329 | uint32_t *p = data; | 385 | uint32_t *p = data; |
330 | if (view->type == C_VIEW) { | 386 | if (view->type == C_VIEW) { |
331 | wlc_view_set_mask(view->handle, *p); | 387 | wlc_view_set_mask(view->handle, *p); |
@@ -337,3 +393,15 @@ void set_view_visibility(swayc_t *view, void *data) { | |||
337 | } | 393 | } |
338 | view->visible = (*p == 2); | 394 | view->visible = (*p == 2); |
339 | } | 395 | } |
396 | |||
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 628316dd..5008dbbf 100644 --- a/sway/focus.c +++ b/sway/focus.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "focus.h" | 3 | #include "focus.h" |
4 | #include "log.h" | 4 | #include "log.h" |
5 | #include "workspace.h" | 5 | #include "workspace.h" |
6 | #include "layout.h" | ||
6 | 7 | ||
7 | bool locked_container_focus = false; | 8 | bool locked_container_focus = false; |
8 | bool locked_view_focus = false; | 9 | bool locked_view_focus = false; |
@@ -20,6 +21,8 @@ static void update_focus(swayc_t *c) { | |||
20 | // Case where output changes | 21 | // Case where output changes |
21 | case C_OUTPUT: | 22 | case C_OUTPUT: |
22 | wlc_output_focus(c->handle); | 23 | wlc_output_focus(c->handle); |
24 | // Set new workspace to the outputs focused workspace | ||
25 | active_workspace = c->focused; | ||
23 | break; | 26 | break; |
24 | 27 | ||
25 | // Case where workspace changes | 28 | // Case where workspace changes |
@@ -51,74 +54,17 @@ static void update_focus(swayc_t *c) { | |||
51 | } | 54 | } |
52 | 55 | ||
53 | bool move_focus(enum movement_direction direction) { | 56 | bool move_focus(enum movement_direction direction) { |
54 | if (locked_container_focus) { | 57 | swayc_t *view = get_swayc_in_direction( |
55 | return false; | 58 | get_focused_container(&root_container), direction); |
56 | } | 59 | if (view) { |
57 | swayc_t *current = get_focused_container(&root_container); | 60 | if (direction == MOVE_PARENT) { |
58 | if (current->type == C_VIEW | 61 | set_focused_container(view); |
59 | && wlc_view_get_state(current->handle) & WLC_BIT_FULLSCREEN) { | ||
60 | return false; | ||
61 | } | ||
62 | swayc_t *parent = current->parent; | ||
63 | |||
64 | if (direction == MOVE_PARENT) { | ||
65 | if (parent->type == C_OUTPUT) { | ||
66 | sway_log(L_DEBUG, "Focus cannot move to parent"); | ||
67 | return false; | ||
68 | } else { | 62 | } else { |
69 | sway_log(L_DEBUG, "Moving focus from %p:%ld to %p:%ld", | 63 | set_focused_container(get_focused_view(view)); |
70 | current, current->handle, parent, parent->handle); | ||
71 | set_focused_container(parent); | ||
72 | return true; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | while (true) { | ||
77 | sway_log(L_DEBUG, "Moving focus away from %p", current); | ||
78 | |||
79 | // Test if we can even make a difference here | ||
80 | bool can_move = false; | ||
81 | int diff = 0; | ||
82 | if (direction == MOVE_LEFT || direction == MOVE_RIGHT) { | ||
83 | if (parent->layout == L_HORIZ || parent->type == C_ROOT) { | ||
84 | can_move = true; | ||
85 | diff = direction == MOVE_LEFT ? -1 : 1; | ||
86 | } | ||
87 | } else { | ||
88 | if (parent->layout == L_VERT) { | ||
89 | can_move = true; | ||
90 | diff = direction == MOVE_UP ? -1 : 1; | ||
91 | } | ||
92 | } | ||
93 | sway_log(L_DEBUG, "Can move? %s", can_move ? "yes" : "no"); | ||
94 | if (can_move) { | ||
95 | int i; | ||
96 | for (i = 0; i < parent->children->length; ++i) { | ||
97 | swayc_t *child = parent->children->items[i]; | ||
98 | if (child == current) { | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | int desired = i + diff; | ||
103 | sway_log(L_DEBUG, "Moving from %d to %d", i, desired); | ||
104 | if (desired < 0 || desired >= parent->children->length) { | ||
105 | can_move = false; | ||
106 | } else { | ||
107 | swayc_t *newview = parent->children->items[desired]; | ||
108 | set_focused_container(get_focused_view(newview)); | ||
109 | return true; | ||
110 | } | ||
111 | } | ||
112 | if (!can_move) { | ||
113 | sway_log(L_DEBUG, "Can't move at current level, moving up tree"); | ||
114 | current = parent; | ||
115 | parent = parent->parent; | ||
116 | if (!parent) { | ||
117 | // Nothing we can do | ||
118 | return false; | ||
119 | } | ||
120 | } | 64 | } |
65 | return true; | ||
121 | } | 66 | } |
67 | return false; | ||
122 | } | 68 | } |
123 | 69 | ||
124 | swayc_t *get_focused_container(swayc_t *parent) { | 70 | swayc_t *get_focused_container(swayc_t *parent) { |
@@ -142,13 +88,13 @@ void set_focused_container(swayc_t *c) { | |||
142 | // Find previous focused view, and the new focused view, if they are the same return | 88 | // Find previous focused view, and the new focused view, if they are the same return |
143 | swayc_t *focused = get_focused_view(&root_container); | 89 | swayc_t *focused = get_focused_view(&root_container); |
144 | swayc_t *workspace = active_workspace; | 90 | swayc_t *workspace = active_workspace; |
145 | if (focused == get_focused_view(c)) { | ||
146 | return; | ||
147 | } | ||
148 | 91 | ||
149 | // update container focus from here to root, making necessary changes along | 92 | // update container focus from here to root, making necessary changes along |
150 | // the way | 93 | // the way |
151 | swayc_t *p = c; | 94 | swayc_t *p = c; |
95 | if (p->type != C_OUTPUT && p->type != C_ROOT) { | ||
96 | p->is_focused = true; | ||
97 | } | ||
152 | while (p != &root_container) { | 98 | while (p != &root_container) { |
153 | update_focus(p); | 99 | update_focus(p); |
154 | p = p->parent; | 100 | p = p->parent; |
@@ -171,8 +117,11 @@ void set_focused_container(swayc_t *c) { | |||
171 | } | 117 | } |
172 | // activate current focus | 118 | // activate current focus |
173 | if (p->type == C_VIEW) { | 119 | if (p->type == C_VIEW) { |
174 | wlc_view_focus(p->handle); | ||
175 | wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true); | 120 | wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true); |
121 | // set focus if view_focus is unlocked | ||
122 | if (!locked_view_focus) { | ||
123 | wlc_view_focus(p->handle); | ||
124 | } | ||
176 | } | 125 | } |
177 | } | 126 | } |
178 | } | 127 | } |
diff --git a/sway/handlers.c b/sway/handlers.c index 534b4e4f..79628fe5 100644 --- a/sway/handlers.c +++ b/sway/handlers.c | |||
@@ -13,21 +13,14 @@ | |||
13 | #include "workspace.h" | 13 | #include "workspace.h" |
14 | #include "container.h" | 14 | #include "container.h" |
15 | #include "focus.h" | 15 | #include "focus.h" |
16 | 16 | #include "input_state.h" | |
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) { |
@@ -86,10 +79,12 @@ swayc_t *container_under_pointer(void) { | |||
86 | return lookup; | 79 | return lookup; |
87 | } | 80 | } |
88 | 81 | ||
82 | /* Handles */ | ||
83 | |||
89 | static bool handle_output_created(wlc_handle output) { | 84 | static bool handle_output_created(wlc_handle output) { |
90 | swayc_t *op = new_output(output); | 85 | swayc_t *op = new_output(output); |
91 | 86 | ||
92 | //Switch to workspace if we need to | 87 | // Switch to workspace if we need to |
93 | if (active_workspace == NULL) { | 88 | if (active_workspace == NULL) { |
94 | swayc_t *ws = op->children->items[0]; | 89 | swayc_t *ws = op->children->items[0]; |
95 | workspace_switch(ws); | 90 | workspace_switch(ws); |
@@ -111,7 +106,7 @@ static void handle_output_destroyed(wlc_handle output) { | |||
111 | if (list->length == 0) { | 106 | if (list->length == 0) { |
112 | active_workspace = NULL; | 107 | active_workspace = NULL; |
113 | } else { | 108 | } else { |
114 | //switch to other outputs active workspace | 109 | // switch to other outputs active workspace |
115 | workspace_switch(((swayc_t *)root_container.children->items[0])->focused); | 110 | workspace_switch(((swayc_t *)root_container.children->items[0])->focused); |
116 | } | 111 | } |
117 | } | 112 | } |
@@ -137,38 +132,64 @@ static void handle_output_focused(wlc_handle output, bool focus) { | |||
137 | } | 132 | } |
138 | 133 | ||
139 | static bool handle_view_created(wlc_handle handle) { | 134 | static bool handle_view_created(wlc_handle handle) { |
140 | swayc_t *focused = get_focused_container(&root_container); | 135 | // if view is child of another view, the use that as focused container |
136 | wlc_handle parent = wlc_view_get_parent(handle); | ||
137 | swayc_t *focused = NULL; | ||
141 | swayc_t *newview = NULL; | 138 | swayc_t *newview = NULL; |
139 | |||
140 | // Get parent container, to add view in | ||
141 | if (parent) { | ||
142 | focused = get_swayc_for_handle(parent, &root_container); | ||
143 | } | ||
144 | if (!focused || focused->type == C_OUTPUT) { | ||
145 | focused = get_focused_container(&root_container); | ||
146 | } | ||
147 | sway_log(L_DEBUG, "handle:%ld type:%x state:%x parent:%ld " | ||
148 | "mask:%d (x:%d y:%d w:%d h:%d) title:%s " | ||
149 | "class:%s appid:%s", | ||
150 | handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent, | ||
151 | wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x, | ||
152 | wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w, | ||
153 | wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle), | ||
154 | wlc_view_get_class(handle), wlc_view_get_app_id(handle)); | ||
155 | |||
156 | // TODO properly figure out how each window should be handled. | ||
142 | switch (wlc_view_get_type(handle)) { | 157 | switch (wlc_view_get_type(handle)) { |
143 | // regular view created regularly | 158 | // regular view created regularly |
144 | case 0: | 159 | case 0: |
145 | newview = new_view(focused, handle); | 160 | newview = new_view(focused, handle); |
146 | wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); | 161 | wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); |
147 | break; | 162 | break; |
148 | // takes keyboard focus | 163 | |
164 | // Dmenu keeps viewfocus, but others with this flag dont, for now simulate | ||
165 | // dmenu | ||
149 | case WLC_BIT_OVERRIDE_REDIRECT: | 166 | case WLC_BIT_OVERRIDE_REDIRECT: |
150 | sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT", handle); | 167 | // locked_view_focus = true; |
151 | locked_view_focus = true; | ||
152 | wlc_view_focus(handle); | 168 | wlc_view_focus(handle); |
153 | wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); | 169 | wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); |
154 | wlc_view_bring_to_front(handle); | 170 | wlc_view_bring_to_front(handle); |
155 | break; | 171 | break; |
156 | // Takes container focus | 172 | |
173 | // Firefox popups have this flag set. | ||
157 | case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: | 174 | case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: |
158 | sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT|WLC_BIT_MANAGED", handle); | ||
159 | wlc_view_bring_to_front(handle); | 175 | wlc_view_bring_to_front(handle); |
160 | locked_container_focus = true; | 176 | locked_container_focus = true; |
161 | break; | 177 | break; |
162 | // set modals as floating containers | 178 | |
179 | // Modals, get focus, popups do not | ||
163 | case WLC_BIT_MODAL: | 180 | case WLC_BIT_MODAL: |
181 | wlc_view_focus(handle); | ||
164 | wlc_view_bring_to_front(handle); | 182 | wlc_view_bring_to_front(handle); |
165 | newview = new_floating_view(handle); | 183 | newview = new_floating_view(handle); |
166 | case WLC_BIT_POPUP: | 184 | case WLC_BIT_POPUP: |
185 | wlc_view_bring_to_front(handle); | ||
167 | break; | 186 | break; |
168 | } | 187 | } |
188 | |||
169 | if (newview) { | 189 | if (newview) { |
170 | set_focused_container(newview); | 190 | set_focused_container(newview); |
171 | arrange_windows(newview->parent, -1, -1); | 191 | swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT); |
192 | arrange_windows(output, -1, -1); | ||
172 | } | 193 | } |
173 | return true; | 194 | return true; |
174 | } | 195 | } |
@@ -181,19 +202,19 @@ static void handle_view_destroyed(wlc_handle handle) { | |||
181 | // regular view created regularly | 202 | // regular view created regularly |
182 | case 0: | 203 | case 0: |
183 | case WLC_BIT_MODAL: | 204 | case WLC_BIT_MODAL: |
205 | case WLC_BIT_POPUP: | ||
184 | if (view) { | 206 | if (view) { |
185 | swayc_t *parent = destroy_view(view); | 207 | swayc_t *parent = destroy_view(view); |
186 | arrange_windows(parent, -1, -1); | 208 | arrange_windows(parent, -1, -1); |
187 | } | 209 | } |
188 | break; | 210 | break; |
189 | // takes keyboard focus | 211 | // DMENU has this flag, and takes view_focus, but other things with this |
212 | // flag dont | ||
190 | case WLC_BIT_OVERRIDE_REDIRECT: | 213 | case WLC_BIT_OVERRIDE_REDIRECT: |
191 | locked_view_focus = false; | 214 | // locked_view_focus = false; |
192 | break; | 215 | break; |
193 | // Takes container focus | ||
194 | case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: | 216 | case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: |
195 | locked_container_focus = false; | 217 | locked_container_focus = false; |
196 | case WLC_BIT_POPUP: | ||
197 | break; | 218 | break; |
198 | } | 219 | } |
199 | set_focused_container(get_focused_view(&root_container)); | 220 | set_focused_container(get_focused_view(&root_container)); |
@@ -205,7 +226,7 @@ static void handle_view_focus(wlc_handle view, bool focus) { | |||
205 | 226 | ||
206 | 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) { |
207 | sway_log(L_DEBUG, "geometry request %d x %d : %d x %d", | 228 | sway_log(L_DEBUG, "geometry request %d x %d : %d x %d", |
208 | geometry->origin.x, geometry->origin.y, geometry->size.w,geometry->size.h); | 229 | geometry->origin.x, geometry->origin.y, geometry->size.w, geometry->size.h); |
209 | // If the view is floating, then apply the geometry. | 230 | // If the view is floating, then apply the geometry. |
210 | // Otherwise save the desired width/height for the view. | 231 | // Otherwise save the desired width/height for the view. |
211 | // This will not do anything for the time being as WLC improperly sends geometry requests | 232 | // This will not do anything for the time being as WLC improperly sends geometry requests |
@@ -225,21 +246,17 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo | |||
225 | } | 246 | } |
226 | 247 | ||
227 | 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) { |
228 | swayc_t *c = NULL; | 249 | swayc_t *c = get_swayc_for_handle(view, &root_container); |
229 | switch(state) { | 250 | switch (state) { |
230 | case WLC_BIT_FULLSCREEN: | 251 | case WLC_BIT_FULLSCREEN: |
231 | // i3 just lets it become fullscreen | 252 | // i3 just lets it become fullscreen |
232 | wlc_view_set_state(view, state, toggle); | 253 | wlc_view_set_state(view, state, toggle); |
233 | c = get_swayc_for_handle(view, &root_container); | ||
234 | sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d",view,c->name,toggle); | ||
235 | if (c) { | 254 | if (c) { |
255 | sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d", view, c->name, toggle); | ||
236 | arrange_windows(c->parent, -1, -1); | 256 | arrange_windows(c->parent, -1, -1); |
237 | // Set it as focused window for that workspace if its going fullscreen | 257 | // Set it as focused window for that workspace if its going fullscreen |
238 | if (toggle) { | 258 | if (toggle) { |
239 | swayc_t *ws = c; | 259 | swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE); |
240 | while (ws->type != C_WORKSPACE) { | ||
241 | ws = ws->parent; | ||
242 | } | ||
243 | // Set ws focus to c | 260 | // Set ws focus to c |
244 | set_focused_container_for(ws, c); | 261 | set_focused_container_for(ws, c); |
245 | } | 262 | } |
@@ -248,7 +265,9 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s | |||
248 | case WLC_BIT_MAXIMIZED: | 265 | case WLC_BIT_MAXIMIZED: |
249 | case WLC_BIT_RESIZING: | 266 | case WLC_BIT_RESIZING: |
250 | case WLC_BIT_MOVING: | 267 | case WLC_BIT_MOVING: |
268 | break; | ||
251 | case WLC_BIT_ACTIVATED: | 269 | case WLC_BIT_ACTIVATED: |
270 | sway_log(L_DEBUG, "View %p requested to be activated", c); | ||
252 | break; | 271 | break; |
253 | } | 272 | } |
254 | return; | 273 | return; |
@@ -257,29 +276,38 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s | |||
257 | 276 | ||
258 | 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, |
259 | uint32_t key, uint32_t sym, enum wlc_key_state state) { | 278 | uint32_t key, uint32_t sym, enum wlc_key_state state) { |
260 | enum { QSIZE = 32 }; | 279 | |
261 | if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) { | 280 | if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) { |
262 | return false; | 281 | return false; |
263 | } | 282 | } |
264 | static uint8_t head = 0; | 283 | |
265 | bool cmd_success = false; | 284 | // Revert floating container back to original position on keypress |
285 | if (state == WLC_KEY_STATE_PRESSED && | ||
286 | (pointer_state.floating.drag || pointer_state.floating.resize)) { | ||
287 | reset_floating(get_focused_view(&root_container)); | ||
288 | } | ||
266 | 289 | ||
267 | struct sway_mode *mode = config->current_mode; | 290 | struct sway_mode *mode = config->current_mode; |
291 | |||
292 | if (sym < 70000 /* bullshit made up number */) { | ||
293 | if (!isalnum(sym) && sym != ' ' && sym != XKB_KEY_Escape && sym != XKB_KEY_Tab) { | ||
294 | // God fucking dammit | ||
295 | return false; | ||
296 | } | ||
297 | } | ||
298 | |||
268 | // Lowercase if necessary | 299 | // Lowercase if necessary |
269 | sym = tolower(sym); | 300 | sym = tolower(sym); |
270 | 301 | ||
271 | // Find key, if it has been pressed | 302 | int i; |
272 | int mid = 0; | 303 | |
273 | while (mid < head && keys_pressed[mid] != sym) { | 304 | if (state == WLC_KEY_STATE_PRESSED) { |
274 | ++mid; | 305 | press_key(sym); |
275 | } | 306 | } else { // WLC_KEY_STATE_RELEASED |
276 | if (state == WLC_KEY_STATE_PRESSED && mid == head && head + 1 < QSIZE) { | 307 | release_key(sym); |
277 | keys_pressed[head++] = sym; | ||
278 | } else if (state == WLC_KEY_STATE_RELEASED && mid < head) { | ||
279 | memmove(keys_pressed + mid, keys_pressed + mid + 1, sizeof*keys_pressed * (--head - mid)); | ||
280 | } | 308 | } |
309 | |||
281 | // TODO: reminder to check conflicts with mod+q+a versus mod+q | 310 | // TODO: reminder to check conflicts with mod+q+a versus mod+q |
282 | int i; | ||
283 | for (i = 0; i < mode->bindings->length; ++i) { | 311 | for (i = 0; i < mode->bindings->length; ++i) { |
284 | struct sway_binding *binding = mode->bindings->items[i]; | 312 | struct sway_binding *binding = mode->bindings->items[i]; |
285 | 313 | ||
@@ -287,39 +315,22 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier | |||
287 | bool match; | 315 | bool match; |
288 | int j; | 316 | int j; |
289 | for (j = 0; j < binding->keys->length; ++j) { | 317 | for (j = 0; j < binding->keys->length; ++j) { |
290 | match = false; | ||
291 | xkb_keysym_t *key = binding->keys->items[j]; | 318 | xkb_keysym_t *key = binding->keys->items[j]; |
292 | uint8_t k; | 319 | if ((match = check_key(*key)) == false) { |
293 | for (k = 0; k < head; ++k) { | ||
294 | if (keys_pressed[k] == *key) { | ||
295 | match = true; | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | if (match == false) { | ||
300 | break; | 320 | break; |
301 | } | 321 | } |
302 | } | 322 | } |
303 | |||
304 | if (match) { | 323 | if (match) { |
305 | // Remove matched keys from keys_pressed | ||
306 | int j; | ||
307 | for (j = 0; j < binding->keys->length; ++j) { | ||
308 | uint8_t k; | ||
309 | for (k = 0; k < head; ++k) { | ||
310 | memmove(keys_pressed + k, keys_pressed + k + 1, sizeof*keys_pressed * (--head - k)); | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | if (state == WLC_KEY_STATE_PRESSED) { | 324 | if (state == WLC_KEY_STATE_PRESSED) { |
315 | cmd_success = handle_command(config, binding->command); | 325 | handle_command(config, binding->command); |
326 | return true; | ||
316 | } else if (state == WLC_KEY_STATE_RELEASED) { | 327 | } else if (state == WLC_KEY_STATE_RELEASED) { |
317 | // TODO: --released | 328 | // TODO: --released |
318 | } | 329 | } |
319 | } | 330 | } |
320 | } | 331 | } |
321 | } | 332 | } |
322 | return cmd_success; | 333 | return false; |
323 | } | 334 | } |
324 | 335 | ||
325 | 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) { |
@@ -327,119 +338,129 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct | |||
327 | static wlc_handle prev_handle = 0; | 338 | static wlc_handle prev_handle = 0; |
328 | mouse_origin = *origin; | 339 | mouse_origin = *origin; |
329 | bool changed_floating = false; | 340 | bool changed_floating = false; |
330 | int i = 0; | ||
331 | if (!active_workspace) { | 341 | if (!active_workspace) { |
332 | return false; | 342 | return false; |
333 | } | 343 | } |
334 | // Do checks to determine if proper keys are being held | 344 | // Do checks to determine if proper keys are being held |
335 | swayc_t *view = active_workspace->focused; | 345 | swayc_t *view = get_focused_view(active_workspace); |
336 | if (m1_held && view) { | 346 | uint32_t edge = 0; |
347 | if (pointer_state.floating.drag && view) { | ||
337 | if (view->is_floating) { | 348 | if (view->is_floating) { |
338 | while (keys_pressed[i++]) { | 349 | int dx = mouse_origin.x - prev_pos.x; |
339 | if (keys_pressed[i] == config->floating_mod) { | 350 | int dy = mouse_origin.y - prev_pos.y; |
340 | int dx = mouse_origin.x - prev_pos.x; | 351 | view->x += dx; |
341 | int dy = mouse_origin.y - prev_pos.y; | 352 | view->y += dy; |
342 | sway_log(L_DEBUG, "Moving from px: %d to cx: %d and from py: %d to cy: %d", prev_pos.x, mouse_origin.x, prev_pos.y, mouse_origin.y); | 353 | changed_floating = true; |
343 | sway_log(L_DEBUG, "Moving: dx: %d, dy: %d", dx, dy); | ||
344 | |||
345 | view->x += dx; | ||
346 | view->y += dy; | ||
347 | changed_floating = true; | ||
348 | break; | ||
349 | } | ||
350 | } | ||
351 | } | 354 | } |
352 | } else if (m2_held && view) { | 355 | } else if (pointer_state.floating.resize && view) { |
353 | if (view->is_floating) { | 356 | if (view->is_floating) { |
354 | while (keys_pressed[i++]) { | 357 | int dx = mouse_origin.x - prev_pos.x; |
355 | if (keys_pressed[i] == config->floating_mod) { | 358 | int dy = mouse_origin.y - prev_pos.y; |
356 | int dx = mouse_origin.x - prev_pos.x; | 359 | int min_sane_w = 100; |
357 | int dy = mouse_origin.y - prev_pos.y; | 360 | int min_sane_h = 60; |
358 | sway_log(L_DEBUG, "Moving from px: %d to cx: %d and from py: %d to cy: %d", prev_pos.x, mouse_origin.x, prev_pos.y, mouse_origin.y); | 361 | |
359 | sway_log(L_INFO, "Moving: dx: %d, dy: %d", dx, dy); | 362 | // Move and resize the view based on the dx/dy and mouse position |
360 | 363 | int midway_x = view->x + view->width/2; | |
361 | // Move and resize the view based on the dx/dy and mouse position | 364 | int midway_y = view->y + view->height/2; |
362 | int midway_x = view->x + view->width/2; | 365 | if (dx < 0) { |
363 | int midway_y = view->y + view->height/2; | 366 | if (!pointer_state.lock.right) { |
364 | 367 | if (view->width > min_sane_w) { | |
365 | if (dx < 0) { | ||
366 | changed_floating = true; | 368 | changed_floating = true; |
367 | if (mouse_origin.x > midway_x) { | 369 | view->width += dx; |
368 | sway_log(L_INFO, "Downsizing view to the left"); | 370 | edge += WLC_RESIZE_EDGE_RIGHT; |
369 | view->width += dx; | 371 | } |
370 | } else { | 372 | } else if (mouse_origin.x < midway_x && !pointer_state.lock.left) { |
371 | sway_log(L_INFO, "Upsizing view to the left"); | 373 | changed_floating = true; |
372 | view->x += dx; | 374 | view->x += dx; |
373 | view->width -= dx; | 375 | view->width -= dx; |
374 | } | 376 | edge += WLC_RESIZE_EDGE_LEFT; |
375 | } else if (dx > 0){ | 377 | } |
378 | } else if (dx > 0) { | ||
379 | if (mouse_origin.x > midway_x && !pointer_state.lock.right) { | ||
380 | changed_floating = true; | ||
381 | view->width += dx; | ||
382 | edge += WLC_RESIZE_EDGE_RIGHT; | ||
383 | } else if (!pointer_state.lock.left) { | ||
384 | if (view->width > min_sane_w) { | ||
376 | changed_floating = true; | 385 | changed_floating = true; |
377 | if (mouse_origin.x > midway_x) { | 386 | view->x += dx; |
378 | sway_log(L_INFO, "Upsizing to the right"); | 387 | view->width -= dx; |
379 | view->width += dx; | 388 | edge += WLC_RESIZE_EDGE_LEFT; |
380 | } else { | ||
381 | sway_log(L_INFO, "Downsizing to the right"); | ||
382 | view->x += dx; | ||
383 | view->width -= dx; | ||
384 | } | ||
385 | } | 389 | } |
390 | } | ||
391 | } | ||
386 | 392 | ||
387 | if (dy < 0) { | 393 | if (dy < 0) { |
394 | if (!pointer_state.lock.bottom) { | ||
395 | if (view->height > min_sane_h) { | ||
388 | changed_floating = true; | 396 | changed_floating = true; |
389 | if (mouse_origin.y > midway_y) { | 397 | view->height += dy; |
390 | sway_log(L_INFO, "Downsizing view to the top"); | 398 | edge += WLC_RESIZE_EDGE_BOTTOM; |
391 | view->height += dy; | 399 | } |
392 | } else { | 400 | } else if (mouse_origin.y < midway_y && !pointer_state.lock.top) { |
393 | sway_log(L_INFO, "Upsizing the view to the top"); | 401 | changed_floating = true; |
394 | view->y += dy; | 402 | view->y += dy; |
395 | view->height -= dy; | 403 | view->height -= dy; |
396 | } | 404 | edge += WLC_RESIZE_EDGE_TOP; |
397 | } else if (dy > 0) { | 405 | } |
406 | } else if (dy > 0) { | ||
407 | if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) { | ||
408 | changed_floating = true; | ||
409 | view->height += dy; | ||
410 | edge += WLC_RESIZE_EDGE_BOTTOM; | ||
411 | } else if (!pointer_state.lock.top) { | ||
412 | if (view->height > min_sane_h) { | ||
398 | changed_floating = true; | 413 | changed_floating = true; |
399 | if (mouse_origin.y > midway_y) { | 414 | view->y += dy; |
400 | sway_log(L_INFO, "Upsizing to the bottom"); | 415 | view->height -= dy; |
401 | view->height += dy; | 416 | edge += WLC_RESIZE_EDGE_TOP; |
402 | } else { | ||
403 | sway_log(L_INFO, "Downsizing to the bottom"); | ||
404 | view->y += dy; | ||
405 | view->height -= dy; | ||
406 | } | ||
407 | } | 417 | } |
408 | break; | ||
409 | } | 418 | } |
410 | } | 419 | } |
411 | } | 420 | } |
412 | } | 421 | } |
413 | if (config->focus_follows_mouse && prev_handle != handle) { | 422 | if (config->focus_follows_mouse && prev_handle != handle) { |
414 | //Dont change focus if fullscreen | 423 | // Dont change focus if fullscreen |
415 | swayc_t *focused = get_focused_view(view); | 424 | swayc_t *focused = get_focused_view(view); |
416 | if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)) { | 425 | if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) |
426 | && !(pointer_state.l_held || pointer_state.r_held)) { | ||
417 | set_focused_container(container_under_pointer()); | 427 | set_focused_container(container_under_pointer()); |
418 | } | 428 | } |
419 | } | 429 | } |
420 | prev_handle = handle; | 430 | prev_handle = handle; |
421 | prev_pos = mouse_origin; | 431 | prev_pos = mouse_origin; |
422 | if (changed_floating) { | 432 | if (changed_floating) { |
423 | arrange_windows(view, -1, -1); | 433 | struct wlc_geometry geometry = { |
434 | .origin = { | ||
435 | .x = view->x, | ||
436 | .y = view->y | ||
437 | }, | ||
438 | .size = { | ||
439 | .w = view->width, | ||
440 | .h = view->height | ||
441 | } | ||
442 | }; | ||
443 | wlc_view_set_geometry(view->handle, edge, &geometry); | ||
424 | return true; | 444 | return true; |
425 | } | 445 | } |
426 | return false; | 446 | return false; |
427 | } | 447 | } |
428 | 448 | ||
449 | |||
429 | 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, |
430 | uint32_t button, enum wlc_button_state state) { | 451 | uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) { |
431 | swayc_t *focused = get_focused_container(&root_container); | 452 | swayc_t *focused = get_focused_container(&root_container); |
432 | //dont change focus if fullscreen | 453 | // dont change focus if fullscreen |
433 | if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { | 454 | if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { |
434 | return false; | 455 | return false; |
435 | } | 456 | } |
436 | if (state == WLC_BUTTON_STATE_PRESSED) { | 457 | if (state == WLC_BUTTON_STATE_PRESSED) { |
437 | sway_log(L_DEBUG, "Mouse button %u pressed", button); | 458 | sway_log(L_DEBUG, "Mouse button %u pressed", button); |
438 | if (button == 272) { | 459 | if (button == M_LEFT_CLICK) { |
439 | m1_held = true; | 460 | pointer_state.l_held = true; |
440 | } | 461 | } |
441 | if (button == 273) { | 462 | if (button == M_RIGHT_CLICK) { |
442 | m2_held = true; | 463 | pointer_state.r_held = true; |
443 | } | 464 | } |
444 | swayc_t *pointer = container_under_pointer(); | 465 | swayc_t *pointer = container_under_pointer(); |
445 | set_focused_container(pointer); | 466 | set_focused_container(pointer); |
@@ -453,15 +474,32 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w | |||
453 | } | 474 | } |
454 | } | 475 | } |
455 | arrange_windows(pointer->parent, -1, -1); | 476 | arrange_windows(pointer->parent, -1, -1); |
477 | if (modifiers->mods & config->floating_mod) { | ||
478 | int midway_x = pointer->x + pointer->width/2; | ||
479 | int midway_y = pointer->y + pointer->height/2; | ||
480 | |||
481 | pointer_state.floating.drag = pointer_state.l_held; | ||
482 | pointer_state.floating.resize = pointer_state.r_held; | ||
483 | pointer_state.lock.bottom = origin->y < midway_y; | ||
484 | pointer_state.lock.top = !pointer_state.lock.bottom; | ||
485 | pointer_state.lock.right = origin->x < midway_x; | ||
486 | pointer_state.lock.left = !pointer_state.lock.right; | ||
487 | start_floating(pointer); | ||
488 | } | ||
489 | // Dont want pointer sent to window while dragging or resizing | ||
490 | return (pointer_state.floating.drag || pointer_state.floating.resize); | ||
456 | } | 491 | } |
457 | return (pointer && pointer != focused); | 492 | return (pointer && pointer != focused); |
458 | } else { | 493 | } else { |
459 | sway_log(L_DEBUG, "Mouse button %u released", button); | 494 | sway_log(L_DEBUG, "Mouse button %u released", button); |
460 | if (button == 272) { | 495 | if (button == M_LEFT_CLICK) { |
461 | m1_held = false; | 496 | pointer_state.l_held = false; |
497 | pointer_state.floating.drag = false; | ||
462 | } | 498 | } |
463 | if (button == 273) { | 499 | if (button == M_RIGHT_CLICK) { |
464 | m2_held = false; | 500 | pointer_state.r_held = false; |
501 | pointer_state.floating.resize = false; | ||
502 | pointer_state.lock = (struct pointer_lock){false ,false ,false ,false}; | ||
465 | } | 503 | } |
466 | } | 504 | } |
467 | return false; | 505 | return false; |
diff --git a/sway/input_state.c b/sway/input_state.c new file mode 100644 index 00000000..a7f88d4a --- /dev/null +++ b/sway/input_state.c | |||
@@ -0,0 +1,68 @@ | |||
1 | #include <string.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <ctype.h> | ||
4 | |||
5 | #include "input_state.h" | ||
6 | |||
7 | #define KEY_STATE_MAX_LENGTH 64 | ||
8 | |||
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 9fdfd62a..a48f15c4 100644 --- a/sway/layout.c +++ b/sway/layout.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "layout.h" | 4 | #include "layout.h" |
5 | #include "log.h" | 5 | #include "log.h" |
6 | #include "list.h" | 6 | #include "list.h" |
7 | #include "config.h" | ||
7 | #include "container.h" | 8 | #include "container.h" |
8 | #include "workspace.h" | 9 | #include "workspace.h" |
9 | #include "focus.h" | 10 | #include "focus.h" |
@@ -32,6 +33,21 @@ void add_child(swayc_t *parent, swayc_t *child) { | |||
32 | child->width, child->height, parent, parent->type, parent->width, parent->height); | 33 | child->width, child->height, parent, parent->type, parent->width, parent->height); |
33 | list_add(parent->children, child); | 34 | list_add(parent->children, child); |
34 | child->parent = parent; | 35 | child->parent = parent; |
36 | // set focus for this container | ||
37 | if (parent->children->length == 1) { | ||
38 | set_focused_container_for(parent, child); | ||
39 | } | ||
40 | } | ||
41 | |||
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 | } | ||
35 | } | 51 | } |
36 | 52 | ||
37 | swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { | 53 | swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { |
@@ -55,7 +71,7 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) { | |||
55 | new_child->parent = child->parent; | 71 | new_child->parent = child->parent; |
56 | 72 | ||
57 | if (child->parent->focused == child) { | 73 | if (child->parent->focused == child) { |
58 | child->parent->focused = new_child; | 74 | set_focused_container_for(child->parent, new_child); |
59 | } | 75 | } |
60 | child->parent = NULL; | 76 | child->parent = NULL; |
61 | return parent; | 77 | return parent; |
@@ -72,6 +88,7 @@ swayc_t *remove_child(swayc_t *child) { | |||
72 | break; | 88 | break; |
73 | } | 89 | } |
74 | } | 90 | } |
91 | i = 0; | ||
75 | } else { | 92 | } else { |
76 | for (i = 0; i < parent->children->length; ++i) { | 93 | for (i = 0; i < parent->children->length; ++i) { |
77 | if (parent->children->items[i] == child) { | 94 | if (parent->children->items[i] == child) { |
@@ -80,7 +97,7 @@ swayc_t *remove_child(swayc_t *child) { | |||
80 | } | 97 | } |
81 | } | 98 | } |
82 | } | 99 | } |
83 | //Set focused to new container | 100 | // Set focused to new container |
84 | if (parent->focused == child) { | 101 | if (parent->focused == child) { |
85 | if (parent->children->length > 0) { | 102 | if (parent->children->length > 0) { |
86 | set_focused_container_for(parent, parent->children->items[i?i-1:0]); | 103 | set_focused_container_for(parent, parent->children->items[i?i-1:0]); |
@@ -104,7 +121,7 @@ void move_container(swayc_t *container,swayc_t* root,int direction){ | |||
104 | //Only one container, meh. | 121 | //Only one container, meh. |
105 | break; | 122 | break; |
106 | } | 123 | } |
107 | 124 | //TODO: Implement horizontal movement. | |
108 | //TODO: Implement move to a different workspace. | 125 | //TODO: Implement move to a different workspace. |
109 | if(direction == MOVE_LEFT && i > 0){ | 126 | if(direction == MOVE_LEFT && i > 0){ |
110 | temp = root->children->items[i-1]; | 127 | temp = root->children->items[i-1]; |
@@ -167,11 +184,11 @@ void arrange_windows(swayc_t *container, int width, int height) { | |||
167 | // y -= container->y; | 184 | // y -= container->y; |
168 | for (i = 0; i < container->children->length; ++i) { | 185 | for (i = 0; i < container->children->length; ++i) { |
169 | swayc_t *child = container->children->items[i]; | 186 | swayc_t *child = container->children->items[i]; |
170 | sway_log(L_DEBUG, "Arranging workspace #%d", i); | 187 | child->x = x + container->gaps; |
171 | child->x = x; | 188 | child->y = y + container->gaps; |
172 | child->y = y; | 189 | child->width = width - container->gaps * 2; |
173 | child->width = width; | 190 | child->height = height - container->gaps * 2; |
174 | child->height = height; | 191 | sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y); |
175 | arrange_windows(child, -1, -1); | 192 | arrange_windows(child, -1, -1); |
176 | } | 193 | } |
177 | return; | 194 | return; |
@@ -179,27 +196,24 @@ void arrange_windows(swayc_t *container, int width, int height) { | |||
179 | { | 196 | { |
180 | struct wlc_geometry geometry = { | 197 | struct wlc_geometry geometry = { |
181 | .origin = { | 198 | .origin = { |
182 | .x = container->x, | 199 | .x = container->x + container->gaps / 2, |
183 | .y = container->y | 200 | .y = container->y + container->gaps / 2 |
184 | }, | 201 | }, |
185 | .size = { | 202 | .size = { |
186 | .w = width, | 203 | .w = width - container->gaps, |
187 | .h = height | 204 | .h = height - container->gaps |
188 | } | 205 | } |
189 | }; | 206 | }; |
190 | if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { | 207 | if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { |
191 | swayc_t *parent = container; | 208 | swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT); |
192 | while (parent->type != C_OUTPUT) { | ||
193 | parent = parent->parent; | ||
194 | } | ||
195 | geometry.origin.x = 0; | 209 | geometry.origin.x = 0; |
196 | geometry.origin.y = 0; | 210 | geometry.origin.y = 0; |
197 | geometry.size.w = parent->width; | 211 | geometry.size.w = parent->width; |
198 | geometry.size.h = parent->height; | 212 | geometry.size.h = parent->height; |
199 | wlc_view_set_geometry(container->handle, &geometry); | 213 | wlc_view_set_geometry(container->handle, 0, &geometry); |
200 | wlc_view_bring_to_front(container->handle); | 214 | wlc_view_bring_to_front(container->handle); |
201 | } else { | 215 | } else { |
202 | wlc_view_set_geometry(container->handle, &geometry); | 216 | wlc_view_set_geometry(container->handle, 0, &geometry); |
203 | container->width = width; | 217 | container->width = width; |
204 | container->height = height; | 218 | container->height = height; |
205 | } | 219 | } |
@@ -213,40 +227,62 @@ void arrange_windows(swayc_t *container, int width, int height) { | |||
213 | break; | 227 | break; |
214 | } | 228 | } |
215 | 229 | ||
216 | double total_weight = 0; | 230 | x = y = 0; |
217 | for (i = 0; i < container->children->length; ++i) { | 231 | double scale = 0; |
218 | swayc_t *child = container->children->items[i]; | ||
219 | total_weight += child->weight; | ||
220 | } | ||
221 | |||
222 | switch (container->layout) { | 232 | switch (container->layout) { |
223 | case L_HORIZ: | 233 | case L_HORIZ: |
224 | default: | 234 | default: |
225 | sway_log(L_DEBUG, "Arranging %p horizontally", container); | 235 | // Calculate total width |
226 | for (i = 0; i < container->children->length; ++i) { | 236 | for (i = 0; i < container->children->length; ++i) { |
227 | swayc_t *child = container->children->items[i]; | 237 | int *old_width = &((swayc_t *)container->children->items[i])->width; |
228 | double percent = child->weight / total_weight; | 238 | if (*old_width <= 0) { |
229 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); | 239 | if (container->children->length > 1) { |
230 | child->x = x + container->x; | 240 | *old_width = width / (container->children->length - 1); |
231 | child->y = y + container->y; | 241 | } else { |
232 | int w = width * percent; | 242 | *old_width = width; |
233 | int h = height; | 243 | } |
234 | arrange_windows(child, w, h); | 244 | } |
235 | x += w; | 245 | scale += *old_width; |
246 | } | ||
247 | // Resize windows | ||
248 | if (scale > 0.1) { | ||
249 | scale = width / scale; | ||
250 | sway_log(L_DEBUG, "Arranging %p horizontally", container); | ||
251 | for (i = 0; i < container->children->length; ++i) { | ||
252 | swayc_t *child = container->children->items[i]; | ||
253 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, width, scale); | ||
254 | child->x = x + container->x; | ||
255 | child->y = y + container->y; | ||
256 | arrange_windows(child, child->width * scale, height); | ||
257 | x += child->width; | ||
258 | } | ||
236 | } | 259 | } |
237 | break; | 260 | break; |
238 | case L_VERT: | 261 | case L_VERT: |
239 | sway_log(L_DEBUG, "Arranging %p vertically", container); | 262 | // Calculate total height |
240 | for (i = 0; i < container->children->length; ++i) { | 263 | for (i = 0; i < container->children->length; ++i) { |
241 | swayc_t *child = container->children->items[i]; | 264 | int *old_height = &((swayc_t *)container->children->items[i])->height; |
242 | double percent = child->weight / total_weight; | 265 | if (*old_height <= 0) { |
243 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); | 266 | if (container->children->length > 1) { |
244 | child->x = x + container->x; | 267 | *old_height = height / (container->children->length - 1); |
245 | child->y = y + container->y; | 268 | } else { |
246 | int w = width; | 269 | *old_height = height; |
247 | int h = height * percent; | 270 | } |
248 | arrange_windows(child, w, h); | 271 | } |
249 | y += h; | 272 | scale += *old_height; |
273 | } | ||
274 | // Resize | ||
275 | if (scale > 0.1) { | ||
276 | scale = height / scale; | ||
277 | sway_log(L_DEBUG, "Arranging %p vertically", container); | ||
278 | for (i = 0; i < container->children->length; ++i) { | ||
279 | swayc_t *child = container->children->items[i]; | ||
280 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, height, scale); | ||
281 | child->x = x + container->x; | ||
282 | child->y = y + container->y; | ||
283 | arrange_windows(child, width, child->height * scale); | ||
284 | y += child->height; | ||
285 | } | ||
250 | } | 286 | } |
251 | break; | 287 | break; |
252 | } | 288 | } |
@@ -268,20 +304,15 @@ void arrange_windows(swayc_t *container, int width, int height) { | |||
268 | } | 304 | } |
269 | }; | 305 | }; |
270 | if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { | 306 | if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { |
271 | swayc_t *parent = view; | 307 | swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT); |
272 | while (parent->type != C_OUTPUT) { | ||
273 | parent = parent->parent; | ||
274 | } | ||
275 | geometry.origin.x = 0; | 308 | geometry.origin.x = 0; |
276 | geometry.origin.y = 0; | 309 | geometry.origin.y = 0; |
277 | geometry.size.w = parent->width; | 310 | geometry.size.w = parent->width; |
278 | geometry.size.h = parent->height; | 311 | geometry.size.h = parent->height; |
279 | wlc_view_set_geometry(view->handle, &geometry); | 312 | wlc_view_set_geometry(view->handle, 0, &geometry); |
280 | wlc_view_bring_to_front(view->handle); | 313 | wlc_view_bring_to_front(view->handle); |
281 | } else { | 314 | } else { |
282 | wlc_view_set_geometry(view->handle, &geometry); | 315 | wlc_view_set_geometry(view->handle, 0, &geometry); |
283 | view->width = width; | ||
284 | view->height = height; | ||
285 | // Bring the views to the front in order of the list, the list | 316 | // Bring the views to the front in order of the list, the list |
286 | // will be kept up to date so that more recently focused views | 317 | // will be kept up to date so that more recently focused views |
287 | // have higher indexes | 318 | // have higher indexes |
@@ -326,3 +357,54 @@ swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) { | |||
326 | } | 357 | } |
327 | return NULL; | 358 | return NULL; |
328 | } | 359 | } |
360 | |||
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 1dff97bf..c39e2c34 100644 --- a/sway/stringop.c +++ b/sway/stringop.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "string.h" | 4 | #include "string.h" |
5 | #include "list.h" | 5 | #include "list.h" |
6 | #include <strings.h> | 6 | #include <strings.h> |
7 | #include <log.h> | ||
7 | 8 | ||
8 | /* Note: This returns 8 characters for trimmed_start per tab character. */ | 9 | /* Note: This returns 8 characters for trimmed_start per tab character. */ |
9 | char *strip_whitespace(char *_str, int *trimmed_start) { | 10 | char *strip_whitespace(char *_str, int *trimmed_start) { |
@@ -197,3 +198,41 @@ char *join_args(char **argv, int argc) { | |||
197 | res[len - 1] = '\0'; | 198 | res[len - 1] = '\0'; |
198 | return res; | 199 | return res; |
199 | } | 200 | } |
201 | |||
202 | /* | ||
203 | * Join a list of strings, adding separator in between. Separator can be NULL. | ||
204 | */ | ||
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 05a669fe..d436da8e 100644 --- a/sway/workspace.c +++ b/sway/workspace.c | |||
@@ -31,7 +31,7 @@ char *workspace_next_name(void) { | |||
31 | char* target = malloc(strlen(args->items[1]) + 1); | 31 | char* target = malloc(strlen(args->items[1]) + 1); |
32 | strcpy(target, args->items[1]); | 32 | strcpy(target, args->items[1]); |
33 | while (*target == ' ' || *target == '\t') | 33 | while (*target == ' ' || *target == '\t') |
34 | target++; | 34 | target++; |
35 | 35 | ||
36 | // Make sure that the command references an actual workspace | 36 | // Make sure that the command references an actual workspace |
37 | // not a command about workspaces | 37 | // not a command about workspaces |
@@ -42,11 +42,15 @@ char *workspace_next_name(void) { | |||
42 | strcmp(target, "number") == 0 || | 42 | strcmp(target, "number") == 0 || |
43 | strcmp(target, "back_and_forth") == 0 || | 43 | strcmp(target, "back_and_forth") == 0 || |
44 | strcmp(target, "current") == 0) | 44 | strcmp(target, "current") == 0) |
45 | { | ||
46 | list_free(args); | ||
45 | continue; | 47 | continue; |
46 | 48 | } | |
47 | //Make sure that the workspace doesn't already exist | 49 | |
50 | // Make sure that the workspace doesn't already exist | ||
48 | if (workspace_find_by_name(target)) { | 51 | if (workspace_find_by_name(target)) { |
49 | continue; | 52 | list_free(args); |
53 | continue; | ||
50 | } | 54 | } |
51 | 55 | ||
52 | list_free(args); | 56 | list_free(args); |
@@ -54,6 +58,7 @@ char *workspace_next_name(void) { | |||
54 | sway_log(L_DEBUG, "Workspace: Found free name %s", target); | 58 | sway_log(L_DEBUG, "Workspace: Found free name %s", target); |
55 | return target; | 59 | return target; |
56 | } | 60 | } |
61 | list_free(args); | ||
57 | } | 62 | } |
58 | // As a fall back, get the current number of active workspaces | 63 | // As a fall back, get the current number of active workspaces |
59 | // and return that + 1 for the next workspace's name | 64 | // and return that + 1 for the next workspace's name |
@@ -70,14 +75,12 @@ char *workspace_next_name(void) { | |||
70 | 75 | ||
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 | ||
@@ -180,62 +183,4 @@ void workspace_switch(swayc_t *workspace) { | |||
180 | sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); | 183 | sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); |
181 | set_focused_container(get_focused_view(workspace)); | 184 | set_focused_container(get_focused_view(workspace)); |
182 | arrange_windows(workspace, -1, -1); | 185 | arrange_windows(workspace, -1, -1); |
183 | active_workspace = workspace; | ||
184 | } | ||
185 | |||
186 | /* XXX:DEBUG:XXX */ | ||
187 | static void container_log(const swayc_t *c) { | ||
188 | fprintf(stderr, "focus:%c|", | ||
189 | c->is_focused ? 'F' : //Focused | ||
190 | c == active_workspace ? 'W' : //active workspace | ||
191 | c == &root_container ? 'R' : //root | ||
192 | 'X');//not any others | ||
193 | fprintf(stderr,"(%p)",c); | ||
194 | fprintf(stderr,"(p:%p)",c->parent); | ||
195 | fprintf(stderr,"(f:%p)",c->focused); | ||
196 | fprintf(stderr,"(h:%ld)",c->handle); | ||
197 | fprintf(stderr,"Type:"); | ||
198 | fprintf(stderr, | ||
199 | c->type == C_ROOT ? "Root|" : | ||
200 | c->type == C_OUTPUT ? "Output|" : | ||
201 | c->type == C_WORKSPACE ? "Workspace|" : | ||
202 | c->type == C_CONTAINER ? "Container|" : | ||
203 | c->type == C_VIEW ? "View|" : "Unknown|"); | ||
204 | fprintf(stderr,"layout:"); | ||
205 | fprintf(stderr, | ||
206 | c->layout == L_NONE ? "NONE|" : | ||
207 | c->layout == L_HORIZ ? "Horiz|": | ||
208 | c->layout == L_VERT ? "Vert|": | ||
209 | c->layout == L_STACKED ? "Stacked|": | ||
210 | c->layout == L_FLOATING ? "Floating|": | ||
211 | "Unknown|"); | ||
212 | fprintf(stderr, "w:%d|h:%d|", c->width, c->height); | ||
213 | fprintf(stderr, "x:%d|y:%d|", c->x, c->y); | ||
214 | fprintf(stderr, "vis:%c|", c->visible?'t':'f'); | ||
215 | fprintf(stderr, "wgt:%d|", c->weight); | ||
216 | fprintf(stderr, "name:%.16s|", c->name); | ||
217 | fprintf(stderr, "children:%d\n",c->children?c->children->length:0); | ||
218 | } | ||
219 | void layout_log(const swayc_t *c, int depth) { | ||
220 | int i, d; | ||
221 | int e = c->children ? c->children->length : 0; | ||
222 | container_log(c); | ||
223 | if (e) { | ||
224 | for (i = 0; i < e; ++i) { | ||
225 | fputc('|',stderr); | ||
226 | for (d = 0; d < depth; ++d) fputc('-', stderr); | ||
227 | layout_log(c->children->items[i], depth + 1); | ||
228 | } | ||
229 | } | ||
230 | if (c->type == C_WORKSPACE) { | ||
231 | e = c->floating?c->floating->length:0; | ||
232 | if (e) { | ||
233 | for (i = 0; i < e; ++i) { | ||
234 | fputc('|',stderr); | ||
235 | for (d = 0; d < depth; ++d) fputc('-', stderr); | ||
236 | layout_log(c->floating->items[i], depth + 1); | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | } | 186 | } |
241 | /* XXX:DEBUG:XXX */ | ||