diff options
40 files changed, 800 insertions, 726 deletions
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..5f3bb6bb --- /dev/null +++ b/ISSUE_TEMPLATE.md | |||
@@ -0,0 +1,34 @@ | |||
1 | If you are using the nvidia proprietary driver for any reason, you have two choices: | ||
2 | |||
3 | 1. Uninstall it and use nouveau instead | ||
4 | 2. Use X11+i3 and close your browser tab | ||
5 | |||
6 | If `lsmod | grep nvidia | wc -l` shows anything other than zero, your bug report is not welcome here. | ||
7 | |||
8 | Otherwise, please include the following four components in your bug report: sway version, debug log, configuration (if applicable), and an explanation of steps taken to reproduce the issue. | ||
9 | |||
10 | Obtain your version like so: | ||
11 | |||
12 | swaymsg -t get_version | ||
13 | |||
14 | If this doesn't work, use: | ||
15 | |||
16 | sway -v | ||
17 | |||
18 | * Sway Version: | ||
19 | |||
20 | Obtain a debug log like so: | ||
21 | |||
22 | sway -d 2> ~/sway.log | ||
23 | |||
24 | This will record information about sway's activity when it's running. Briefly reproduce your problem and exit sway. When preparing a debug log, brevity is important - start up sway, do the minimum work necessary to reproduce the error, then close sway. | ||
25 | |||
26 | Upload the debug log to a pastebin service such as [gist.github.com](https://gist.github.com), and link to it below. | ||
27 | |||
28 | * Debug Log: | ||
29 | |||
30 | You should try to reproduce the issue with the default configuration. If you cannot, please reproduce with a minimal configuration, upload the config to a pastebin service, and link to it below. | ||
31 | |||
32 | * Configuration File: | ||
33 | |||
34 | Finally, explain the steps you took in plain English to reproduce the problem below. | ||
diff --git a/README.ja.md b/README.ja.md index ae2301fb..b9e541f0 100644 --- a/README.ja.md +++ b/README.ja.md | |||
@@ -29,24 +29,22 @@ Swayは沢山のディストリビューションで提供されています。" | |||
29 | 29 | ||
30 | 次の依存パッケージをインストールしてください: | 30 | 次の依存パッケージをインストールしてください: |
31 | 31 | ||
32 | * meson | 32 | * meson \* |
33 | * [wlc](https://github.com/Cloudef/wlc) | 33 | * [wlroots](https://github.com/swaywm/wlroots) |
34 | * wayland | 34 | * wayland |
35 | * xwayland | 35 | * wayland-protocols \* |
36 | * libinput >= 1.6.0 | ||
37 | * libcap | ||
38 | * pcre | 36 | * pcre |
39 | * json-c >= 0.13 | 37 | * json-c |
40 | * pango | 38 | * pango |
41 | * cairo | 39 | * cairo |
42 | * gdk-pixbuf2 * | 40 | * gdk-pixbuf2 \*\* |
43 | * pam ** | 41 | * pam (オプション: swaylockとPAMで必要) |
44 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (manで必要です) | 42 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (manで必要です) \* |
45 | * git | 43 | * git \* |
46 | 44 | ||
47 | _\*swaybar,swaybg,swaylock必要す_ | 45 | _\*_ |
48 | 46 | ||
49 | _\*\*swaylockでのみ必要です_ | 47 | _\*\*オプション: swaybgとswaylockでのみ必要です_ |
50 | 48 | ||
51 | 次のコマンドを実行してください: | 49 | 次のコマンドを実行してください: |
52 | 50 | ||
@@ -32,27 +32,22 @@ channel or shoot an email to sir@cmpwn.com for advice. | |||
32 | 32 | ||
33 | Install dependencies: | 33 | Install dependencies: |
34 | 34 | ||
35 | * meson | 35 | * meson \* |
36 | * [wlroots](https://github.com/swaywm/wlroots) | 36 | * [wlroots](https://github.com/swaywm/wlroots) |
37 | * wayland | 37 | * wayland |
38 | * xwayland | 38 | * wayland-protocols \* |
39 | * libinput >= 1.6.0 | ||
40 | * libcap | ||
41 | * pcre | 39 | * pcre |
42 | * json-c >= 0.13 | 40 | * json-c |
43 | * pango | 41 | * pango |
44 | * cairo | 42 | * cairo |
45 | * gdk-pixbuf2 * | 43 | * gdk-pixbuf2 \*\* |
46 | * pam ** | 44 | * pam (optional: PAM support for swaylock) |
47 | * dbus >= 1.10 *** | 45 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optional: man pages) \* |
48 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages) | 46 | * git \* |
49 | * git | ||
50 | 47 | ||
51 | _\*Only required for swaybar, swaybg, and swaylock_ | 48 | _\*Compile-time dep_ |
52 | 49 | ||
53 | _\*\*Only required for swaylock_ | 50 | _\*\*optional: required for swaybg and swaylock_ |
54 | |||
55 | _\*\*\*Only required for tray support_ | ||
56 | 51 | ||
57 | Run these commands: | 52 | Run these commands: |
58 | 53 | ||
diff --git a/common/util.c b/common/util.c index 561b3804..f4588b57 100644 --- a/common/util.c +++ b/common/util.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 700 | 1 | #define _XOPEN_SOURCE 700 |
2 | #include <assert.h> | ||
2 | #include <sys/types.h> | 3 | #include <sys/types.h> |
3 | #include <sys/stat.h> | 4 | #include <sys/stat.h> |
4 | #include <unistd.h> | 5 | #include <unistd.h> |
@@ -139,60 +140,17 @@ bool parse_boolean(const char *boolean, bool current) { | |||
139 | return false; | 140 | return false; |
140 | } | 141 | } |
141 | 142 | ||
142 | char* resolve_path(const char* path) { | 143 | enum wlr_direction opposite_direction(enum wlr_direction d) { |
143 | struct stat sb; | 144 | switch (d) { |
144 | ssize_t r; | 145 | case WLR_DIRECTION_UP: |
145 | int i; | 146 | return WLR_DIRECTION_DOWN; |
146 | char *current = NULL; | 147 | case WLR_DIRECTION_DOWN: |
147 | char *resolved = NULL; | 148 | return WLR_DIRECTION_UP; |
148 | 149 | case WLR_DIRECTION_RIGHT: | |
149 | if(!(current = strdup(path))) { | 150 | return WLR_DIRECTION_LEFT; |
150 | return NULL; | 151 | case WLR_DIRECTION_LEFT: |
151 | } | 152 | return WLR_DIRECTION_RIGHT; |
152 | for (i = 0; i < 16; ++i) { | ||
153 | if (lstat(current, &sb) == -1) { | ||
154 | goto failed; | ||
155 | } | ||
156 | if((sb.st_mode & S_IFMT) != S_IFLNK) { | ||
157 | return current; | ||
158 | } | ||
159 | if (!(resolved = malloc(sb.st_size + 1))) { | ||
160 | goto failed; | ||
161 | } | ||
162 | r = readlink(current, resolved, sb.st_size); | ||
163 | if (r == -1 || r > sb.st_size) { | ||
164 | goto failed; | ||
165 | } | ||
166 | resolved[r] = '\0'; | ||
167 | free(current); | ||
168 | current = strdup(resolved); | ||
169 | free(resolved); | ||
170 | resolved = NULL; | ||
171 | } | 153 | } |
172 | 154 | assert(false); | |
173 | failed: | 155 | return 0; |
174 | free(resolved); | ||
175 | free(current); | ||
176 | return NULL; | ||
177 | } | ||
178 | |||
179 | bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out) { | ||
180 | switch (dir) { | ||
181 | case MOVE_UP: | ||
182 | *out = WLR_DIRECTION_UP; | ||
183 | break; | ||
184 | case MOVE_DOWN: | ||
185 | *out = WLR_DIRECTION_DOWN; | ||
186 | break; | ||
187 | case MOVE_LEFT: | ||
188 | *out = WLR_DIRECTION_LEFT; | ||
189 | break; | ||
190 | case MOVE_RIGHT: | ||
191 | *out = WLR_DIRECTION_RIGHT; | ||
192 | break; | ||
193 | default: | ||
194 | return false; | ||
195 | } | ||
196 | |||
197 | return true; | ||
198 | } | 156 | } |
diff --git a/completions/fish/swayidle.fish b/completions/fish/swayidle.fish new file mode 100644 index 00000000..71279925 --- /dev/null +++ b/completions/fish/swayidle.fish | |||
@@ -0,0 +1,3 @@ | |||
1 | # swayidle | ||
2 | complete -c swayidle -s h --description 'show help' | ||
3 | complete -c swayidle -s d --description 'debug' | ||
diff --git a/completions/fish/swaylock.fish b/completions/fish/swaylock.fish index 965a22d2..99dff48f 100644 --- a/completions/fish/swaylock.fish +++ b/completions/fish/swaylock.fish | |||
@@ -1,11 +1,39 @@ | |||
1 | # swaylock(1) completion | 1 | # swaylock(1) completion |
2 | 2 | ||
3 | complete -c swaylock -s C -l config --description 'The config file to use. Default: $HOME/.swaylock/config, $XDG_CONFIG_HOME/swaylock/config, and SYSCONFDIR/swaylock/config.' | ||
3 | complete -c swaylock -s h -l help --description "Show help message and quit." | 4 | complete -c swaylock -s h -l help --description "Show help message and quit." |
4 | complete -c swaylock -s c -l color --description "Turn the screen into the given color. If -i is used, this sets the background of the image into the given color. Defaults to white (ffffff), or transparent (00000000) if an image is in use." | ||
5 | complete -c swaylock -s f -l daemonize --description "Fork into the background after spawning. Note: this is the default bahavior of i3lock." | 5 | complete -c swaylock -s f -l daemonize --description "Fork into the background after spawning. Note: this is the default bahavior of i3lock." |
6 | complete -c swaylock -s v -l version --description "Show the version number and quit." | ||
7 | complete -c swaylock -s s -l socket --description "Use the specified socket path. Otherwise, swaymsg will as sway where the socket is (which is the value of $SWAYSOCK, then of $I350CK)." | ||
8 | complete -c swaylock -s e -l ignore-empty-password --description 'When an empty password is provided by the user, do not validate it.' | ||
9 | |||
10 | # Appearance | ||
11 | complete -c swaylock -s u -l no-unlock-indicator --description "Disable the unlock indicator." | ||
6 | complete -c swaylock -s i -l image --description "Display the given image, optionally on the given output. Use -c to set a background color." | 12 | complete -c swaylock -s i -l image --description "Display the given image, optionally on the given output. Use -c to set a background color." |
7 | complete -c swaylock -l scaling --description "Scaling mode for images: stretch, fill, fit, center, or tile." | 13 | complete -c swaylock -s s -l scaling --description "Scaling mode for images: stretch, fill, fit, center, or tile." |
8 | complete -c swaylock -s t -l tiling --description "Same as --scaling=tile." | 14 | complete -c swaylock -s t -l tiling --description "Same as --scaling=tile." |
9 | complete -c swaylock -s u -l no-unlock-indicator --description "Disable the unlock indicator." | 15 | complete -c swaylock -s c -l color --description "Turn the screen into the given color. If -i is used, this sets the background of the image into the given color. Defaults to white (ffffff), or transparent (00000000) if an image is in use." |
10 | complete -c swaylock -s v -l version --description "Show the version number and quit." | 16 | complete -c swaylock -l bs-hl-color --description 'Sets the color of backspace highlight segments.' |
11 | complete -c swaylock -l socket --description "Use the specified socket path. Othherwise, swaymsg will as sway where the socket is (which is the value of $SWAYSOCK, then of $I350CK)." | 17 | complete -c swaylock -l font --description 'Sets the font of the text inside the indicator.' |
18 | complete -c swaylock -l indicator-radius --description 'Sets the radius of the indicator to radius pixels. Default: 50' | ||
19 | complete -c swaylock -l indicator-thickness --description 'Sets the thickness of the indicator to thickness pixels. Default: 10' | ||
20 | complete -c swaylock -l inside-color --description 'Sets the color of the inside of the indicator when typing or idle.' | ||
21 | complete -c swaylock -l inside-clear-color --description 'Sets the color of the inside of the indicator when cleared.' | ||
22 | complete -c swaylock -l inside-ver-color --description 'Sets the color of the inside of the indicator when verifying.' | ||
23 | complete -c swaylock -l inside-wrong-color --description 'Sets the color of the inside of the indicator when invalid.' | ||
24 | complete -c swaylock -l key-hl-color --description 'Sets the color of key press highlight segments.' | ||
25 | complete -c swaylock -l line-color --description 'Sets the color of the lines that separate the inside and outside of the indicator when typing or idle.' | ||
26 | complete -c swaylock -l line-clear-color --description 'Sets the color of the lines that separate the inside and outside of the indicator when cleared.' | ||
27 | complete -c swaylock -l line-ver-color --description 'Sets the color of the lines that separate the inside and outside of the indicator when verifying.' | ||
28 | complete -c swaylock -l line-wrong-color --description 'Sets the color of the lines that separate the inside and outside of the indicator when invalid.' | ||
29 | complete -c swaylock -s n -l line-uses-inside --description 'Use the color of the inside of the indicator for the line separating the inside and outside of the indicator.' | ||
30 | complete -c swaylock -s r -l line-uses-ring --description 'Use the outer ring\'s color for the line separating the inside and outside of the indicator.' | ||
31 | complete -c swaylock -l ring-color --description 'Sets the color of the outside of the indicator when typing or idle.' | ||
32 | complete -c swaylock -l ring-clear-color --description 'Sets the color of the outside of the indicator when cleared.' | ||
33 | complete -c swaylock -l ring-ver-color --description 'Sets the color of the outside of the indicator when verifying.' | ||
34 | complete -c swaylock -l ring-wrong-color --description 'Sets the color of the outside of the indicator when invalid.' | ||
35 | complete -c swaylock -l separator-color --description 'Sets the color of the lines that separate highlight segments.' | ||
36 | complete -c swaylock -l text-color --description 'Sets the color of the text inside the indicator when typing or idle.' | ||
37 | complete -c swaylock -l text-clear-color --description 'Sets the color of the text inside the indicator when cleared.' | ||
38 | complete -c swaylock -l text-ver-color --description 'Sets the color of the text inside the indicator when verifying.' | ||
39 | complete -c swaylock -l text-wrong-color --description 'Sets the color of the text inside the indicator when invalid.' | ||
diff --git a/completions/fish/swaymsg.fish b/completions/fish/swaymsg.fish index e798db77..1e5bf3da 100644 --- a/completions/fish/swaymsg.fish +++ b/completions/fish/swaymsg.fish | |||
@@ -2,7 +2,18 @@ | |||
2 | 2 | ||
3 | complete -c swaymsg -s h -l help --description "Show help message and quit." | 3 | complete -c swaymsg -s h -l help --description "Show help message and quit." |
4 | complete -c swaymsg -s q -l quiet --description "Sends the IPC message but does not print the response from sway." | 4 | complete -c swaymsg -s q -l quiet --description "Sends the IPC message but does not print the response from sway." |
5 | complete -c swaymsg -s r -l raw --description "Use raw output even if using tty." | ||
6 | complete -c swaymsg -s s -l socket --description "Use the specified socket path. Otherwise, swaymsg will ask where the socket is (which is the value of $SWAYSOCK, then of $I3SOCK)." | ||
7 | complete -c swaymsg -s t -l type --description "Specify the type of IPC message." | ||
8 | complete -c swaymsg -s v -l version --description "Print the version (of swaymsg) and quit." | 5 | complete -c swaymsg -s v -l version --description "Print the version (of swaymsg) and quit." |
6 | complete -c swaymsg -s r -l raw --description "Use raw output even if using tty." | ||
7 | complete -c swaymsg -s s -l socket -r --description "Use the specified socket path. Otherwise, swaymsg will ask where the socket is (which is the value of $SWAYSOCK, then of $I3SOCK)." | ||
8 | |||
9 | complete -c swaymsg -s t -l type -fr --description "Specify the type of IPC message." | ||
10 | complete -c swaymsg -s t -l type -fra 'get_workspaces' --description "Gets a JSON-encoded list of workspaces and their status." | ||
11 | complete -c swaymsg -s t -l type -fra 'get_inputs' --description "Gets a JSON-encoded list of current inputs." | ||
12 | complete -c swaymsg -s t -l type -fra 'get_outputs' --description "Gets a JSON-encoded list of current outputs." | ||
13 | complete -c swaymsg -s t -l type -fra 'get_tree' --description "Gets a JSON-encoded layout tree of all open windows, containers, outputs, workspaces, and so on." | ||
14 | complete -c swaymsg -s t -l type -fra 'get_marks' --description "Get a JSON-encoded list of marks." | ||
15 | complete -c swaymsg -s t -l type -fra 'get_bar_config' --description "Get a JSON-encoded configuration for swaybar." | ||
16 | complete -c swaymsg -s t -l type -fra 'get_version' --description "Get JSON-encoded version information for the running instance of sway." | ||
17 | complete -c swaymsg -s t -l type -fra 'get_binding_modes' --description "Gets a JSON-encoded list of currently configured binding modes." | ||
18 | complete -c swaymsg -s t -l type -fra 'get_config' --description "Gets a JSON-encoded copy of the current configuration." | ||
19 | complete -c swaymsg -s t -l type -fra 'send_tick' --description "Sends a tick event to all subscribed clients." | ||
diff --git a/completions/fish/swaynag.fish b/completions/fish/swaynag.fish new file mode 100644 index 00000000..784d7fad --- /dev/null +++ b/completions/fish/swaynag.fish | |||
@@ -0,0 +1,29 @@ | |||
1 | # swaynag | ||
2 | complete -c swaynag -s C -l config --description 'The config file to use. Default: $HOME/.swaylock/config, $XDG_CONFIG_HOME/swaylock/config, and SYSCONFDIR/swaylock/config.' | ||
3 | complete -c swaynag -s d -l debug --description 'Enable debugging.' | ||
4 | complete -c swaynag -s e -l edge --description 'Set the edge to use: top or bottom' | ||
5 | complete -c swaynag -s f -l font --description 'Set the font to use.' | ||
6 | complete -c swaynag -s h -l help --description 'Show help message and quit.' | ||
7 | complete -c swaynag -s b -l button --description 'Create a button with a text and an action which is executed when pressed. Multiple buttons can be defined by providing the flag multiple times.' | ||
8 | complete -c swaynag -s l -l detailed-message --description 'Read a detailed message from stdin. A button to toggle details will be added. Details are shown in a scrollable multi-line text area.' | ||
9 | complete -c swaynag -s L -l detailed-button --description 'Set the text for the button that toggles details. This has no effect if there is not a detailed message. The default is "Toggle details".' | ||
10 | complete -c swaynag -s m -l message --description 'Set the message text.' | ||
11 | complete -c swaynag -s o -l output --description 'Set the output to use.' | ||
12 | complete -c swaynag -s s -l dismiss-button --description 'Sets the text for the dismiss nagbar button. The default is "X".' | ||
13 | complete -c swaynag -s t -l type --description 'Set the message type. Two types are created by default "error" and "warning". Custom types can be defined in the config file.' | ||
14 | complete -c swaynag -s v -l version --description 'Show the version number and quit.' | ||
15 | |||
16 | # Appearance | ||
17 | complete -c swaynag -l background --description 'Set the color of the background.' | ||
18 | complete -c swaynag -l border --description 'Set the color of the border.' | ||
19 | complete -c swaynag -l border-bottom --description 'Set the color of the bottom border.' | ||
20 | complete -c swaynag -l button-background --description 'Set the color for the background for buttons.' | ||
21 | complete -c swaynag -l text --description 'Set the text color.' | ||
22 | complete -c swaynag -l border-bottom-size --description 'Set the thickness of the bottom border.' | ||
23 | complete -c swaynag -l message-padding --description 'Set the padding for the message.' | ||
24 | complete -c swaynag -l details-border-size --description 'Set the thickness for the details border.' | ||
25 | complete -c swaynag -l button-border-size --description 'Set the thickness for the button border.' | ||
26 | complete -c swaynag -l button-gap --description 'Set the size of the gap between buttons.' | ||
27 | complete -c swaynag -l button-dismiss-gap --description 'Set the size of the gap between the dismiss button and another button.' | ||
28 | complete -c swaynag -l button-margin-right --description 'Set the margin from the right of the dismiss button to edge.' | ||
29 | complete -c swaynag -l button-padding --description 'Set the padding for the button text.' | ||
diff --git a/include/sway/output.h b/include/sway/output.h index 369e62ce..5efe1660 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -62,7 +62,7 @@ void output_begin_destroy(struct sway_output *output); | |||
62 | struct sway_output *output_from_wlr_output(struct wlr_output *output); | 62 | struct sway_output *output_from_wlr_output(struct wlr_output *output); |
63 | 63 | ||
64 | struct sway_output *output_get_in_direction(struct sway_output *reference, | 64 | struct sway_output *output_get_in_direction(struct sway_output *reference, |
65 | enum movement_direction direction); | 65 | enum wlr_direction direction); |
66 | 66 | ||
67 | void output_add_workspace(struct sway_output *output, | 67 | void output_add_workspace(struct sway_output *output, |
68 | struct sway_workspace *workspace); | 68 | struct sway_workspace *workspace); |
@@ -86,6 +86,8 @@ void output_damage_whole_container(struct sway_output *output, | |||
86 | 86 | ||
87 | struct sway_output *output_by_name(const char *name); | 87 | struct sway_output *output_by_name(const char *name); |
88 | 88 | ||
89 | struct sway_output *output_by_identifier(const char *identifier); | ||
90 | |||
89 | void output_sort_workspaces(struct sway_output *output); | 91 | void output_sort_workspaces(struct sway_output *output); |
90 | 92 | ||
91 | struct output_config *output_find_config(struct sway_output *output); | 93 | struct output_config *output_find_config(struct sway_output *output); |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 920ef038..4366a010 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -36,7 +36,6 @@ struct sway_output; | |||
36 | struct sway_workspace; | 36 | struct sway_workspace; |
37 | struct sway_view; | 37 | struct sway_view; |
38 | 38 | ||
39 | enum movement_direction; | ||
40 | enum wlr_direction; | 39 | enum wlr_direction; |
41 | 40 | ||
42 | struct sway_container_state { | 41 | struct sway_container_state { |
@@ -54,16 +53,16 @@ struct sway_container_state { | |||
54 | struct sway_container *focused_inactive_child; | 53 | struct sway_container *focused_inactive_child; |
55 | bool focused; | 54 | bool focused; |
56 | 55 | ||
57 | // View properties | ||
58 | double view_x, view_y; | ||
59 | double view_width, view_height; | ||
60 | |||
61 | enum sway_container_border border; | 56 | enum sway_container_border border; |
62 | int border_thickness; | 57 | int border_thickness; |
63 | bool border_top; | 58 | bool border_top; |
64 | bool border_bottom; | 59 | bool border_bottom; |
65 | bool border_left; | 60 | bool border_left; |
66 | bool border_right; | 61 | bool border_right; |
62 | |||
63 | // View properties | ||
64 | double view_x, view_y; | ||
65 | double view_width, view_height; | ||
67 | }; | 66 | }; |
68 | 67 | ||
69 | struct sway_container { | 68 | struct sway_container { |
@@ -92,6 +91,18 @@ struct sway_container { | |||
92 | 91 | ||
93 | bool is_fullscreen; | 92 | bool is_fullscreen; |
94 | 93 | ||
94 | enum sway_container_border border; | ||
95 | |||
96 | // Used when the view changes to CSD unexpectedly. This will be a non-B_CSD | ||
97 | // border which we use to restore when the view returns to SSD. | ||
98 | enum sway_container_border saved_border; | ||
99 | |||
100 | int border_thickness; | ||
101 | bool border_top; | ||
102 | bool border_bottom; | ||
103 | bool border_left; | ||
104 | bool border_right; | ||
105 | |||
95 | // The gaps currently applied to the container. | 106 | // The gaps currently applied to the container. |
96 | double current_gaps; | 107 | double current_gaps; |
97 | 108 | ||
@@ -116,6 +127,12 @@ struct sway_container { | |||
116 | size_t title_height; | 127 | size_t title_height; |
117 | size_t title_baseline; | 128 | size_t title_baseline; |
118 | 129 | ||
130 | list_t *marks; // char * | ||
131 | struct wlr_texture *marks_focused; | ||
132 | struct wlr_texture *marks_focused_inactive; | ||
133 | struct wlr_texture *marks_unfocused; | ||
134 | struct wlr_texture *marks_urgent; | ||
135 | |||
119 | struct { | 136 | struct { |
120 | struct wl_signal destroy; | 137 | struct wl_signal destroy; |
121 | } events; | 138 | } events; |
@@ -287,12 +304,32 @@ void container_detach(struct sway_container *child); | |||
287 | void container_replace(struct sway_container *container, | 304 | void container_replace(struct sway_container *container, |
288 | struct sway_container *replacement); | 305 | struct sway_container *replacement); |
289 | 306 | ||
290 | bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out); | ||
291 | |||
292 | struct sway_container *container_split(struct sway_container *child, | 307 | struct sway_container *container_split(struct sway_container *child, |
293 | enum sway_container_layout layout); | 308 | enum sway_container_layout layout); |
294 | 309 | ||
295 | bool container_is_transient_for(struct sway_container *child, | 310 | bool container_is_transient_for(struct sway_container *child, |
296 | struct sway_container *ancestor); | 311 | struct sway_container *ancestor); |
297 | 312 | ||
313 | /** | ||
314 | * Find any container that has the given mark and return it. | ||
315 | */ | ||
316 | struct sway_container *container_find_mark(char *mark); | ||
317 | |||
318 | /** | ||
319 | * Find any container that has the given mark and remove the mark from the | ||
320 | * container. Returns true if it matched a container. | ||
321 | */ | ||
322 | bool container_find_and_unmark(char *mark); | ||
323 | |||
324 | /** | ||
325 | * Remove all marks from the container. | ||
326 | */ | ||
327 | void container_clear_marks(struct sway_container *container); | ||
328 | |||
329 | bool container_has_mark(struct sway_container *container, char *mark); | ||
330 | |||
331 | void container_add_mark(struct sway_container *container, char *mark); | ||
332 | |||
333 | void container_update_marks_textures(struct sway_container *container); | ||
334 | |||
298 | #endif | 335 | #endif |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 0240f294..4a8c3cb1 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -80,24 +80,8 @@ struct sway_view { | |||
80 | 80 | ||
81 | char *title_format; | 81 | char *title_format; |
82 | 82 | ||
83 | // Our border types are B_NONE, B_PIXEL, B_NORMAL and B_CSD. We normally | ||
84 | // just assign this to the border property and ignore the other two. | ||
85 | // However, when a view using CSD is tiled, we want to render our own | ||
86 | // borders as well. So in this case the border property becomes one of the | ||
87 | // first three, and using_csd is true. | ||
88 | // Lastly, views can change their decoration mode at any time. When an SSD | ||
89 | // view becomes CSD without our approval, we save the SSD border type so it | ||
90 | // can be restored if/when the view returns from CSD to SSD. | ||
91 | enum sway_container_border border; | ||
92 | enum sway_container_border saved_border; | ||
93 | bool using_csd; | 83 | bool using_csd; |
94 | 84 | ||
95 | int border_thickness; | ||
96 | bool border_top; | ||
97 | bool border_bottom; | ||
98 | bool border_left; | ||
99 | bool border_right; | ||
100 | |||
101 | struct timespec urgent; | 85 | struct timespec urgent; |
102 | bool allow_request_urgent; | 86 | bool allow_request_urgent; |
103 | struct wl_event_source *urgent_timer; | 87 | struct wl_event_source *urgent_timer; |
@@ -116,12 +100,6 @@ struct sway_view { | |||
116 | bool destroying; | 100 | bool destroying; |
117 | 101 | ||
118 | list_t *executed_criteria; // struct criteria * | 102 | list_t *executed_criteria; // struct criteria * |
119 | list_t *marks; // char * | ||
120 | |||
121 | struct wlr_texture *marks_focused; | ||
122 | struct wlr_texture *marks_focused_inactive; | ||
123 | struct wlr_texture *marks_unfocused; | ||
124 | struct wlr_texture *marks_urgent; | ||
125 | 103 | ||
126 | union { | 104 | union { |
127 | struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; | 105 | struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; |
@@ -369,28 +347,6 @@ void view_update_title(struct sway_view *view, bool force); | |||
369 | void view_execute_criteria(struct sway_view *view); | 347 | void view_execute_criteria(struct sway_view *view); |
370 | 348 | ||
371 | /** | 349 | /** |
372 | * Find any view that has the given mark and return it. | ||
373 | */ | ||
374 | struct sway_view *view_find_mark(char *mark); | ||
375 | |||
376 | /** | ||
377 | * Find any view that has the given mark and remove the mark from the view. | ||
378 | * Returns true if it matched a view. | ||
379 | */ | ||
380 | bool view_find_and_unmark(char *mark); | ||
381 | |||
382 | /** | ||
383 | * Remove all marks from the view. | ||
384 | */ | ||
385 | void view_clear_marks(struct sway_view *view); | ||
386 | |||
387 | bool view_has_mark(struct sway_view *view, char *mark); | ||
388 | |||
389 | void view_add_mark(struct sway_view *view, char *mark); | ||
390 | |||
391 | void view_update_marks_textures(struct sway_view *view); | ||
392 | |||
393 | /** | ||
394 | * Returns true if there's a possibility the view may be rendered on screen. | 350 | * Returns true if there's a possibility the view may be rendered on screen. |
395 | * Intended for damage tracking. | 351 | * Intended for damage tracking. |
396 | */ | 352 | */ |
diff --git a/include/util.h b/include/util.h index 19d2e7cf..f143d0c0 100644 --- a/include/util.h +++ b/include/util.h | |||
@@ -7,15 +7,6 @@ | |||
7 | #include <wlr/types/wlr_output_layout.h> | 7 | #include <wlr/types/wlr_output_layout.h> |
8 | #include <xkbcommon/xkbcommon.h> | 8 | #include <xkbcommon/xkbcommon.h> |
9 | 9 | ||
10 | enum movement_direction { | ||
11 | MOVE_LEFT, | ||
12 | MOVE_RIGHT, | ||
13 | MOVE_UP, | ||
14 | MOVE_DOWN, | ||
15 | MOVE_PARENT, | ||
16 | MOVE_CHILD, | ||
17 | }; | ||
18 | |||
19 | /** | 10 | /** |
20 | * Wrap i into the range [0, max[ | 11 | * Wrap i into the range [0, max[ |
21 | */ | 12 | */ |
@@ -68,15 +59,6 @@ uint32_t parse_color(const char *color); | |||
68 | */ | 59 | */ |
69 | bool parse_boolean(const char *boolean, bool current); | 60 | bool parse_boolean(const char *boolean, bool current); |
70 | 61 | ||
71 | /** | 62 | enum wlr_direction opposite_direction(enum wlr_direction d); |
72 | * Given a path string, recurseively resolves any symlinks to their targets | ||
73 | * (which may be a file, directory) and returns the result. | ||
74 | * argument is returned. Caller must free the returned buffer. | ||
75 | * If an error occures, if the path does not exist or if the path corresponds | ||
76 | * to a dangling symlink, NULL is returned. | ||
77 | */ | ||
78 | char* resolve_path(const char* path); | ||
79 | |||
80 | bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out); | ||
81 | 63 | ||
82 | #endif | 64 | #endif |
diff --git a/meson.build b/meson.build index 1e2b53fa..6b23b4e3 100644 --- a/meson.build +++ b/meson.build | |||
@@ -244,8 +244,10 @@ endif | |||
244 | if (get_option('fish-completions')) | 244 | if (get_option('fish-completions')) |
245 | fish_files = files( | 245 | fish_files = files( |
246 | 'completions/fish/sway.fish', | 246 | 'completions/fish/sway.fish', |
247 | 'completions/fish/swayidle.fish', | ||
247 | 'completions/fish/swaylock.fish', | 248 | 'completions/fish/swaylock.fish', |
248 | 'completions/fish/swaymsg.fish', | 249 | 'completions/fish/swaymsg.fish', |
250 | 'completions/fish/swaynag.fish', | ||
249 | ) | 251 | ) |
250 | fish_install_dir = datadir + '/fish/completions' | 252 | fish_install_dir = datadir + '/fish/completions' |
251 | 253 | ||
diff --git a/sway/commands/border.c b/sway/commands/border.c index 37047812..b6eab550 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -12,37 +12,41 @@ | |||
12 | // in use (we set using_csd instead and render a sway border). | 12 | // in use (we set using_csd instead and render a sway border). |
13 | // - view->saved_border should be the last applied border when switching to CSD. | 13 | // - view->saved_border should be the last applied border when switching to CSD. |
14 | // - view->using_csd should always reflect whether CSD is applied or not. | 14 | // - view->using_csd should always reflect whether CSD is applied or not. |
15 | static void set_border(struct sway_view *view, | 15 | static void set_border(struct sway_container *con, |
16 | enum sway_container_border new_border) { | 16 | enum sway_container_border new_border) { |
17 | if (view->using_csd && new_border != B_CSD) { | 17 | if (con->view) { |
18 | view_set_csd_from_server(view, false); | 18 | if (con->view->using_csd && new_border != B_CSD) { |
19 | } else if (!view->using_csd && new_border == B_CSD) { | 19 | view_set_csd_from_server(con->view, false); |
20 | view_set_csd_from_server(view, true); | 20 | } else if (!con->view->using_csd && new_border == B_CSD) { |
21 | view->saved_border = view->border; | 21 | view_set_csd_from_server(con->view, true); |
22 | con->saved_border = con->border; | ||
23 | } | ||
24 | } | ||
25 | if (new_border != B_CSD || container_is_floating(con)) { | ||
26 | con->border = new_border; | ||
22 | } | 27 | } |
23 | if (new_border != B_CSD || container_is_floating(view->container)) { | 28 | if (con->view) { |
24 | view->border = new_border; | 29 | con->view->using_csd = new_border == B_CSD; |
25 | } | 30 | } |
26 | view->using_csd = new_border == B_CSD; | ||
27 | } | 31 | } |
28 | 32 | ||
29 | static void border_toggle(struct sway_view *view) { | 33 | static void border_toggle(struct sway_container *con) { |
30 | if (view->using_csd) { | 34 | if (con->view && con->view->using_csd) { |
31 | set_border(view, B_NONE); | 35 | set_border(con, B_NONE); |
32 | return; | 36 | return; |
33 | } | 37 | } |
34 | switch (view->border) { | 38 | switch (con->border) { |
35 | case B_NONE: | 39 | case B_NONE: |
36 | set_border(view, B_PIXEL); | 40 | set_border(con, B_PIXEL); |
37 | break; | 41 | break; |
38 | case B_PIXEL: | 42 | case B_PIXEL: |
39 | set_border(view, B_NORMAL); | 43 | set_border(con, B_NORMAL); |
40 | break; | 44 | break; |
41 | case B_NORMAL: | 45 | case B_NORMAL: |
42 | if (view->xdg_decoration) { | 46 | if (con->view && con->view->xdg_decoration) { |
43 | set_border(view, B_CSD); | 47 | set_border(con, B_CSD); |
44 | } else { | 48 | } else { |
45 | set_border(view, B_NONE); | 49 | set_border(con, B_NONE); |
46 | } | 50 | } |
47 | break; | 51 | break; |
48 | case B_CSD: | 52 | case B_CSD: |
@@ -66,33 +70,33 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
66 | struct sway_view *view = container->view; | 70 | struct sway_view *view = container->view; |
67 | 71 | ||
68 | if (strcmp(argv[0], "none") == 0) { | 72 | if (strcmp(argv[0], "none") == 0) { |
69 | set_border(view, B_NONE); | 73 | set_border(container, B_NONE); |
70 | } else if (strcmp(argv[0], "normal") == 0) { | 74 | } else if (strcmp(argv[0], "normal") == 0) { |
71 | set_border(view, B_NORMAL); | 75 | set_border(container, B_NORMAL); |
72 | } else if (strcmp(argv[0], "pixel") == 0) { | 76 | } else if (strcmp(argv[0], "pixel") == 0) { |
73 | set_border(view, B_PIXEL); | 77 | set_border(container, B_PIXEL); |
74 | } else if (strcmp(argv[0], "csd") == 0) { | 78 | } else if (strcmp(argv[0], "csd") == 0) { |
75 | if (!view->xdg_decoration) { | 79 | if (!view || !view->xdg_decoration) { |
76 | return cmd_results_new(CMD_INVALID, "border", | 80 | return cmd_results_new(CMD_INVALID, "border", |
77 | "This window doesn't support client side decorations"); | 81 | "This window doesn't support client side decorations"); |
78 | } | 82 | } |
79 | set_border(view, B_CSD); | 83 | set_border(container, B_CSD); |
80 | } else if (strcmp(argv[0], "toggle") == 0) { | 84 | } else if (strcmp(argv[0], "toggle") == 0) { |
81 | border_toggle(view); | 85 | border_toggle(container); |
82 | } else { | 86 | } else { |
83 | return cmd_results_new(CMD_INVALID, "border", | 87 | return cmd_results_new(CMD_INVALID, "border", |
84 | "Expected 'border <none|normal|pixel|csd|toggle>' " | 88 | "Expected 'border <none|normal|pixel|csd|toggle>' " |
85 | "or 'border pixel <px>'"); | 89 | "or 'border pixel <px>'"); |
86 | } | 90 | } |
87 | if (argc == 2) { | 91 | if (argc == 2) { |
88 | view->border_thickness = atoi(argv[1]); | 92 | container->border_thickness = atoi(argv[1]); |
89 | } | 93 | } |
90 | 94 | ||
91 | if (container_is_floating(view->container)) { | 95 | if (container_is_floating(container)) { |
92 | container_set_geometry_from_floating_view(view->container); | 96 | container_set_geometry_from_floating_view(container); |
93 | } | 97 | } |
94 | 98 | ||
95 | arrange_container(view->container); | 99 | arrange_container(container); |
96 | 100 | ||
97 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 101 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
98 | } | 102 | } |
diff --git a/sway/commands/client.c b/sway/commands/client.c index 9f54fa94..746e8713 100644 --- a/sway/commands/client.c +++ b/sway/commands/client.c | |||
@@ -5,9 +5,7 @@ | |||
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | 6 | ||
7 | static void rebuild_textures_iterator(struct sway_container *con, void *data) { | 7 | static void rebuild_textures_iterator(struct sway_container *con, void *data) { |
8 | if (con->view) { | 8 | container_update_marks_textures(con); |
9 | view_update_marks_textures(con->view); | ||
10 | } | ||
11 | container_update_title_textures(con); | 9 | container_update_title_textures(con); |
12 | } | 10 | } |
13 | 11 | ||
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 2204f722..cef92144 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <strings.h> | 1 | #include <strings.h> |
2 | #include <wlr/types/wlr_output_layout.h> | ||
2 | #include <wlr/util/log.h> | 3 | #include <wlr/util/log.h> |
3 | #include "log.h" | 4 | #include "log.h" |
4 | #include "sway/commands.h" | 5 | #include "sway/commands.h" |
@@ -13,20 +14,16 @@ | |||
13 | #include "stringop.h" | 14 | #include "stringop.h" |
14 | #include "util.h" | 15 | #include "util.h" |
15 | 16 | ||
16 | static bool parse_movement_direction(const char *name, | 17 | static bool parse_direction(const char *name, |
17 | enum movement_direction *out) { | 18 | enum wlr_direction *out) { |
18 | if (strcasecmp(name, "left") == 0) { | 19 | if (strcasecmp(name, "left") == 0) { |
19 | *out = MOVE_LEFT; | 20 | *out = WLR_DIRECTION_LEFT; |
20 | } else if (strcasecmp(name, "right") == 0) { | 21 | } else if (strcasecmp(name, "right") == 0) { |
21 | *out = MOVE_RIGHT; | 22 | *out = WLR_DIRECTION_RIGHT; |
22 | } else if (strcasecmp(name, "up") == 0) { | 23 | } else if (strcasecmp(name, "up") == 0) { |
23 | *out = MOVE_UP; | 24 | *out = WLR_DIRECTION_UP; |
24 | } else if (strcasecmp(name, "down") == 0) { | 25 | } else if (strcasecmp(name, "down") == 0) { |
25 | *out = MOVE_DOWN; | 26 | *out = WLR_DIRECTION_DOWN; |
26 | } else if (strcasecmp(name, "parent") == 0) { | ||
27 | *out = MOVE_PARENT; | ||
28 | } else if (strcasecmp(name, "child") == 0) { | ||
29 | *out = MOVE_CHILD; | ||
30 | } else { | 27 | } else { |
31 | return false; | 28 | return false; |
32 | } | 29 | } |
@@ -38,7 +35,7 @@ static bool parse_movement_direction(const char *name, | |||
38 | * Get node in the direction of newly entered output. | 35 | * Get node in the direction of newly entered output. |
39 | */ | 36 | */ |
40 | static struct sway_node *get_node_in_output_direction( | 37 | static struct sway_node *get_node_in_output_direction( |
41 | struct sway_output *output, enum movement_direction dir) { | 38 | struct sway_output *output, enum wlr_direction dir) { |
42 | struct sway_seat *seat = config->handler_context.seat; | 39 | struct sway_seat *seat = config->handler_context.seat; |
43 | struct sway_workspace *ws = output_get_active_workspace(output); | 40 | struct sway_workspace *ws = output_get_active_workspace(output); |
44 | if (ws->fullscreen) { | 41 | if (ws->fullscreen) { |
@@ -48,7 +45,7 @@ static struct sway_node *get_node_in_output_direction( | |||
48 | 45 | ||
49 | if (ws->tiling->length > 0) { | 46 | if (ws->tiling->length > 0) { |
50 | switch (dir) { | 47 | switch (dir) { |
51 | case MOVE_LEFT: | 48 | case WLR_DIRECTION_LEFT: |
52 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { | 49 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { |
53 | // get most right child of new output | 50 | // get most right child of new output |
54 | container = ws->tiling->items[ws->tiling->length-1]; | 51 | container = ws->tiling->items[ws->tiling->length-1]; |
@@ -56,7 +53,7 @@ static struct sway_node *get_node_in_output_direction( | |||
56 | container = seat_get_focus_inactive_tiling(seat, ws); | 53 | container = seat_get_focus_inactive_tiling(seat, ws); |
57 | } | 54 | } |
58 | break; | 55 | break; |
59 | case MOVE_RIGHT: | 56 | case WLR_DIRECTION_RIGHT: |
60 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { | 57 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { |
61 | // get most left child of new output | 58 | // get most left child of new output |
62 | container = ws->tiling->items[0]; | 59 | container = ws->tiling->items[0]; |
@@ -64,7 +61,7 @@ static struct sway_node *get_node_in_output_direction( | |||
64 | container = seat_get_focus_inactive_tiling(seat, ws); | 61 | container = seat_get_focus_inactive_tiling(seat, ws); |
65 | } | 62 | } |
66 | break; | 63 | break; |
67 | case MOVE_UP: | 64 | case WLR_DIRECTION_UP: |
68 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { | 65 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { |
69 | // get most bottom child of new output | 66 | // get most bottom child of new output |
70 | container = ws->tiling->items[ws->tiling->length-1]; | 67 | container = ws->tiling->items[ws->tiling->length-1]; |
@@ -72,7 +69,7 @@ static struct sway_node *get_node_in_output_direction( | |||
72 | container = seat_get_focus_inactive_tiling(seat, ws); | 69 | container = seat_get_focus_inactive_tiling(seat, ws); |
73 | } | 70 | } |
74 | break; | 71 | break; |
75 | case MOVE_DOWN: { | 72 | case WLR_DIRECTION_DOWN: |
76 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { | 73 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { |
77 | // get most top child of new output | 74 | // get most top child of new output |
78 | container = ws->tiling->items[0]; | 75 | container = ws->tiling->items[0]; |
@@ -81,9 +78,6 @@ static struct sway_node *get_node_in_output_direction( | |||
81 | } | 78 | } |
82 | break; | 79 | break; |
83 | } | 80 | } |
84 | default: | ||
85 | break; | ||
86 | } | ||
87 | } | 81 | } |
88 | 82 | ||
89 | if (container) { | 83 | if (container) { |
@@ -95,11 +89,8 @@ static struct sway_node *get_node_in_output_direction( | |||
95 | } | 89 | } |
96 | 90 | ||
97 | static struct sway_node *node_get_in_direction(struct sway_container *container, | 91 | static struct sway_node *node_get_in_direction(struct sway_container *container, |
98 | struct sway_seat *seat, enum movement_direction dir) { | 92 | struct sway_seat *seat, enum wlr_direction dir) { |
99 | if (container->is_fullscreen) { | 93 | if (container->is_fullscreen) { |
100 | if (dir == MOVE_PARENT) { | ||
101 | return NULL; | ||
102 | } | ||
103 | // Fullscreen container with a direction - go straight to outputs | 94 | // Fullscreen container with a direction - go straight to outputs |
104 | struct sway_output *output = container->workspace->output; | 95 | struct sway_output *output = container->workspace->output; |
105 | struct sway_output *new_output = output_get_in_direction(output, dir); | 96 | struct sway_output *new_output = output_get_in_direction(output, dir); |
@@ -108,9 +99,6 @@ static struct sway_node *node_get_in_direction(struct sway_container *container, | |||
108 | } | 99 | } |
109 | return get_node_in_output_direction(new_output, dir); | 100 | return get_node_in_output_direction(new_output, dir); |
110 | } | 101 | } |
111 | if (dir == MOVE_PARENT) { | ||
112 | return node_get_parent(&container->node); | ||
113 | } | ||
114 | 102 | ||
115 | struct sway_container *wrap_candidate = NULL; | 103 | struct sway_container *wrap_candidate = NULL; |
116 | struct sway_container *current = container; | 104 | struct sway_container *current = container; |
@@ -122,15 +110,15 @@ static struct sway_node *node_get_in_direction(struct sway_container *container, | |||
122 | container_parent_layout(current); | 110 | container_parent_layout(current); |
123 | list_t *siblings = container_get_siblings(current); | 111 | list_t *siblings = container_get_siblings(current); |
124 | 112 | ||
125 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { | 113 | if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT) { |
126 | if (parent_layout == L_HORIZ || parent_layout == L_TABBED) { | 114 | if (parent_layout == L_HORIZ || parent_layout == L_TABBED) { |
127 | can_move = true; | 115 | can_move = true; |
128 | desired = idx + (dir == MOVE_LEFT ? -1 : 1); | 116 | desired = idx + (dir == WLR_DIRECTION_LEFT ? -1 : 1); |
129 | } | 117 | } |
130 | } else { | 118 | } else { |
131 | if (parent_layout == L_VERT || parent_layout == L_STACKED) { | 119 | if (parent_layout == L_VERT || parent_layout == L_STACKED) { |
132 | can_move = true; | 120 | can_move = true; |
133 | desired = idx + (dir == MOVE_UP ? -1 : 1); | 121 | desired = idx + (dir == WLR_DIRECTION_UP ? -1 : 1); |
134 | } | 122 | } |
135 | } | 123 | } |
136 | 124 | ||
@@ -200,15 +188,25 @@ static struct cmd_results *focus_output(struct sway_seat *seat, | |||
200 | struct sway_output *output = output_by_name(identifier); | 188 | struct sway_output *output = output_by_name(identifier); |
201 | 189 | ||
202 | if (!output) { | 190 | if (!output) { |
203 | enum movement_direction direction; | 191 | enum wlr_direction direction; |
204 | if (!parse_movement_direction(identifier, &direction) || | 192 | if (!parse_direction(identifier, &direction)) { |
205 | direction == MOVE_PARENT || direction == MOVE_CHILD) { | ||
206 | free(identifier); | 193 | free(identifier); |
207 | return cmd_results_new(CMD_INVALID, "focus", | 194 | return cmd_results_new(CMD_INVALID, "focus", |
208 | "There is no output with that name"); | 195 | "There is no output with that name"); |
209 | } | 196 | } |
210 | struct sway_workspace *ws = seat_get_focused_workspace(seat); | 197 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
211 | output = output_get_in_direction(ws->output, direction); | 198 | output = output_get_in_direction(ws->output, direction); |
199 | |||
200 | if (!output) { | ||
201 | int center_lx = ws->output->lx + ws->output->width / 2; | ||
202 | int center_ly = ws->output->ly + ws->output->height / 2; | ||
203 | struct wlr_output *target = wlr_output_layout_farthest_output( | ||
204 | root->output_layout, opposite_direction(direction), | ||
205 | ws->output->wlr_output, center_lx, center_ly); | ||
206 | if (target) { | ||
207 | output = output_from_wlr_output(target); | ||
208 | } | ||
209 | } | ||
212 | } | 210 | } |
213 | 211 | ||
214 | free(identifier); | 212 | free(identifier); |
@@ -220,6 +218,31 @@ static struct cmd_results *focus_output(struct sway_seat *seat, | |||
220 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 218 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
221 | } | 219 | } |
222 | 220 | ||
221 | static struct cmd_results *focus_parent(void) { | ||
222 | struct sway_seat *seat = config->handler_context.seat; | ||
223 | struct sway_container *con = config->handler_context.container; | ||
224 | if (!con || con->is_fullscreen) { | ||
225 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
226 | } | ||
227 | struct sway_node *parent = node_get_parent(&con->node); | ||
228 | if (parent) { | ||
229 | seat_set_focus(seat, parent); | ||
230 | seat_consider_warp_to_focus(seat); | ||
231 | } | ||
232 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
233 | } | ||
234 | |||
235 | static struct cmd_results *focus_child(void) { | ||
236 | struct sway_seat *seat = config->handler_context.seat; | ||
237 | struct sway_node *node = config->handler_context.node; | ||
238 | struct sway_node *focus = seat_get_active_tiling_child(seat, node); | ||
239 | if (focus) { | ||
240 | seat_set_focus(seat, focus); | ||
241 | seat_consider_warp_to_focus(seat); | ||
242 | } | ||
243 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
244 | } | ||
245 | |||
223 | struct cmd_results *cmd_focus(int argc, char **argv) { | 246 | struct cmd_results *cmd_focus(int argc, char **argv) { |
224 | if (config->reading || !config->active) { | 247 | if (config->reading || !config->active) { |
225 | return cmd_results_new(CMD_DEFER, NULL, NULL); | 248 | return cmd_results_new(CMD_DEFER, NULL, NULL); |
@@ -257,27 +280,21 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
257 | return focus_output(seat, argc, argv); | 280 | return focus_output(seat, argc, argv); |
258 | } | 281 | } |
259 | 282 | ||
260 | enum movement_direction direction = 0; | 283 | if (strcasecmp(argv[0], "parent") == 0) { |
261 | if (!parse_movement_direction(argv[0], &direction)) { | 284 | return focus_parent(); |
285 | } | ||
286 | if (strcasecmp(argv[0], "child") == 0) { | ||
287 | return focus_child(); | ||
288 | } | ||
289 | |||
290 | enum wlr_direction direction = 0; | ||
291 | if (!parse_direction(argv[0], &direction)) { | ||
262 | return cmd_results_new(CMD_INVALID, "focus", | 292 | return cmd_results_new(CMD_INVALID, "focus", |
263 | "Expected 'focus <direction|parent|child|mode_toggle|floating|tiling>' " | 293 | "Expected 'focus <direction|parent|child|mode_toggle|floating|tiling>' " |
264 | "or 'focus output <direction|name>'"); | 294 | "or 'focus output <direction|name>'"); |
265 | } | 295 | } |
266 | 296 | ||
267 | if (direction == MOVE_CHILD) { | ||
268 | struct sway_node *focus = seat_get_active_tiling_child(seat, node); | ||
269 | if (focus) { | ||
270 | seat_set_focus(seat, focus); | ||
271 | seat_consider_warp_to_focus(seat); | ||
272 | } | ||
273 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
274 | } | ||
275 | |||
276 | if (node->type == N_WORKSPACE) { | 297 | if (node->type == N_WORKSPACE) { |
277 | if (direction == MOVE_PARENT) { | ||
278 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
279 | } | ||
280 | |||
281 | // Jump to the next output | 298 | // Jump to the next output |
282 | struct sway_output *new_output = | 299 | struct sway_output *new_output = |
283 | output_get_in_direction(workspace->output, direction); | 300 | output_get_in_direction(workspace->output, direction); |
diff --git a/sway/commands/mark.c b/sway/commands/mark.c index b1f47be1..c76e1d63 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c | |||
@@ -19,11 +19,10 @@ struct cmd_results *cmd_mark(int argc, char **argv) { | |||
19 | return error; | 19 | return error; |
20 | } | 20 | } |
21 | struct sway_container *container = config->handler_context.container; | 21 | struct sway_container *container = config->handler_context.container; |
22 | if (!container || !container->view) { | 22 | if (!container) { |
23 | return cmd_results_new(CMD_INVALID, "mark", | 23 | return cmd_results_new(CMD_INVALID, "mark", |
24 | "Only views can have marks"); | 24 | "Only containers can have marks"); |
25 | } | 25 | } |
26 | struct sway_view *view = container->view; | ||
27 | 26 | ||
28 | bool add = false, toggle = false; | 27 | bool add = false, toggle = false; |
29 | while (argc > 0 && strncmp(*argv, "--", 2) == 0) { | 28 | while (argc > 0 && strncmp(*argv, "--", 2) == 0) { |
@@ -47,22 +46,24 @@ struct cmd_results *cmd_mark(int argc, char **argv) { | |||
47 | } | 46 | } |
48 | 47 | ||
49 | char *mark = join_args(argv, argc); | 48 | char *mark = join_args(argv, argc); |
50 | bool had_mark = view_has_mark(view, mark); | 49 | bool had_mark = container_has_mark(container, mark); |
51 | 50 | ||
52 | if (!add) { | 51 | if (!add) { |
53 | // Replacing | 52 | // Replacing |
54 | view_clear_marks(view); | 53 | container_clear_marks(container); |
55 | } | 54 | } |
56 | 55 | ||
57 | view_find_and_unmark(mark); | 56 | container_find_and_unmark(mark); |
58 | 57 | ||
59 | if (!toggle || !had_mark) { | 58 | if (!toggle || !had_mark) { |
60 | view_add_mark(view, mark); | 59 | container_add_mark(container, mark); |
61 | } | 60 | } |
62 | 61 | ||
63 | free(mark); | 62 | free(mark); |
64 | view_update_marks_textures(view); | 63 | container_update_marks_textures(container); |
65 | view_execute_criteria(view); | 64 | if (container->view) { |
65 | view_execute_criteria(container->view); | ||
66 | } | ||
66 | 67 | ||
67 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 68 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
68 | } | 69 | } |
diff --git a/sway/commands/move.c b/sway/commands/move.c index ffe12d41..7d8c1f1a 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -27,19 +27,6 @@ static const char *expected_syntax = | |||
27 | "'move <container|window|workspace> [to] output <name|direction>' or " | 27 | "'move <container|window|workspace> [to] output <name|direction>' or " |
28 | "'move <container|window> [to] mark <mark>'"; | 28 | "'move <container|window> [to] mark <mark>'"; |
29 | 29 | ||
30 | enum wlr_direction opposite_direction(enum wlr_direction d) { | ||
31 | switch (d) { | ||
32 | case WLR_DIRECTION_UP: | ||
33 | return WLR_DIRECTION_DOWN; | ||
34 | case WLR_DIRECTION_DOWN: | ||
35 | return WLR_DIRECTION_UP; | ||
36 | case WLR_DIRECTION_RIGHT: | ||
37 | return WLR_DIRECTION_LEFT; | ||
38 | default: | ||
39 | return WLR_DIRECTION_RIGHT; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static struct sway_output *output_in_direction(const char *direction_string, | 30 | static struct sway_output *output_in_direction(const char *direction_string, |
44 | struct sway_output *reference, int ref_lx, int ref_ly) { | 31 | struct sway_output *reference, int ref_lx, int ref_ly) { |
45 | struct { | 32 | struct { |
@@ -81,14 +68,14 @@ static struct sway_output *output_in_direction(const char *direction_string, | |||
81 | } | 68 | } |
82 | 69 | ||
83 | static bool is_parallel(enum sway_container_layout layout, | 70 | static bool is_parallel(enum sway_container_layout layout, |
84 | enum movement_direction dir) { | 71 | enum wlr_direction dir) { |
85 | switch (layout) { | 72 | switch (layout) { |
86 | case L_TABBED: | 73 | case L_TABBED: |
87 | case L_HORIZ: | 74 | case L_HORIZ: |
88 | return dir == MOVE_LEFT || dir == MOVE_RIGHT; | 75 | return dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT; |
89 | case L_STACKED: | 76 | case L_STACKED: |
90 | case L_VERT: | 77 | case L_VERT: |
91 | return dir == MOVE_UP || dir == MOVE_DOWN; | 78 | return dir == WLR_DIRECTION_UP || dir == WLR_DIRECTION_DOWN; |
92 | default: | 79 | default: |
93 | return false; | 80 | return false; |
94 | } | 81 | } |
@@ -115,7 +102,7 @@ static void workspace_focus_fullscreen(struct sway_workspace *workspace) { | |||
115 | 102 | ||
116 | static void container_move_to_container_from_direction( | 103 | static void container_move_to_container_from_direction( |
117 | struct sway_container *container, struct sway_container *destination, | 104 | struct sway_container *container, struct sway_container *destination, |
118 | enum movement_direction move_dir) { | 105 | enum wlr_direction move_dir) { |
119 | if (destination->view) { | 106 | if (destination->view) { |
120 | if (destination->parent == container->parent && | 107 | if (destination->parent == container->parent && |
121 | destination->workspace == container->workspace) { | 108 | destination->workspace == container->workspace) { |
@@ -126,7 +113,8 @@ static void container_move_to_container_from_direction( | |||
126 | list_swap(siblings, container_index, destination_index); | 113 | list_swap(siblings, container_index, destination_index); |
127 | } else { | 114 | } else { |
128 | wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); | 115 | wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); |
129 | int offset = move_dir == MOVE_LEFT || move_dir == MOVE_UP; | 116 | int offset = |
117 | move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP; | ||
130 | int index = container_sibling_index(destination) + offset; | 118 | int index = container_sibling_index(destination) + offset; |
131 | if (destination->parent) { | 119 | if (destination->parent) { |
132 | container_insert_child(destination->parent, container, index); | 120 | container_insert_child(destination->parent, container, index); |
@@ -141,7 +129,8 @@ static void container_move_to_container_from_direction( | |||
141 | 129 | ||
142 | if (is_parallel(destination->layout, move_dir)) { | 130 | if (is_parallel(destination->layout, move_dir)) { |
143 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); | 131 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); |
144 | int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? | 132 | int index = |
133 | move_dir == WLR_DIRECTION_RIGHT || move_dir == WLR_DIRECTION_DOWN ? | ||
145 | 0 : destination->children->length; | 134 | 0 : destination->children->length; |
146 | container_insert_child(destination, container, index); | 135 | container_insert_child(destination, container, index); |
147 | container->width = container->height = 0; | 136 | container->width = container->height = 0; |
@@ -164,10 +153,11 @@ static void container_move_to_container_from_direction( | |||
164 | 153 | ||
165 | static void container_move_to_workspace_from_direction( | 154 | static void container_move_to_workspace_from_direction( |
166 | struct sway_container *container, struct sway_workspace *workspace, | 155 | struct sway_container *container, struct sway_workspace *workspace, |
167 | enum movement_direction move_dir) { | 156 | enum wlr_direction move_dir) { |
168 | if (is_parallel(workspace->layout, move_dir)) { | 157 | if (is_parallel(workspace->layout, move_dir)) { |
169 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); | 158 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); |
170 | int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? | 159 | int index = |
160 | move_dir == WLR_DIRECTION_RIGHT || move_dir == WLR_DIRECTION_DOWN ? | ||
171 | 0 : workspace->tiling->length; | 161 | 0 : workspace->tiling->length; |
172 | workspace_insert_tiling(workspace, container, index); | 162 | workspace_insert_tiling(workspace, container, index); |
173 | return; | 163 | return; |
@@ -258,28 +248,31 @@ static void container_move_to_container(struct sway_container *container, | |||
258 | * container, switches the layout of the workspace, and drops the child back in. | 248 | * container, switches the layout of the workspace, and drops the child back in. |
259 | * In other words, rejigger it. */ | 249 | * In other words, rejigger it. */ |
260 | static void workspace_rejigger(struct sway_workspace *ws, | 250 | static void workspace_rejigger(struct sway_workspace *ws, |
261 | struct sway_container *child, enum movement_direction move_dir) { | 251 | struct sway_container *child, enum wlr_direction move_dir) { |
262 | if (!child->parent && ws->tiling->length == 1) { | 252 | if (!child->parent && ws->tiling->length == 1) { |
263 | ws->layout = | 253 | ws->layout = |
264 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 254 | move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_RIGHT ? |
255 | L_HORIZ : L_VERT; | ||
265 | workspace_update_representation(ws); | 256 | workspace_update_representation(ws); |
266 | return; | 257 | return; |
267 | } | 258 | } |
268 | container_detach(child); | 259 | container_detach(child); |
269 | struct sway_container *new_parent = workspace_wrap_children(ws); | 260 | struct sway_container *new_parent = workspace_wrap_children(ws); |
270 | 261 | ||
271 | int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1; | 262 | int index = |
263 | move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP ? 0 : 1; | ||
272 | workspace_insert_tiling(ws, child, index); | 264 | workspace_insert_tiling(ws, child, index); |
273 | container_flatten(new_parent); | 265 | container_flatten(new_parent); |
274 | ws->layout = | 266 | ws->layout = |
275 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 267 | move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_RIGHT ? |
268 | L_HORIZ : L_VERT; | ||
276 | workspace_update_representation(ws); | 269 | workspace_update_representation(ws); |
277 | child->width = child->height = 0; | 270 | child->width = child->height = 0; |
278 | } | 271 | } |
279 | 272 | ||
280 | // Returns true if moved | 273 | // Returns true if moved |
281 | static bool container_move_in_direction(struct sway_container *container, | 274 | static bool container_move_in_direction(struct sway_container *container, |
282 | enum movement_direction move_dir) { | 275 | enum wlr_direction move_dir) { |
283 | // If moving a fullscreen view, only consider outputs | 276 | // If moving a fullscreen view, only consider outputs |
284 | if (container->is_fullscreen) { | 277 | if (container->is_fullscreen) { |
285 | struct sway_output *new_output = | 278 | struct sway_output *new_output = |
@@ -305,7 +298,8 @@ static bool container_move_in_direction(struct sway_container *container, | |||
305 | // The below loop stops once we hit the workspace because current->parent | 298 | // The below loop stops once we hit the workspace because current->parent |
306 | // is NULL for the topmost containers in a workspace. | 299 | // is NULL for the topmost containers in a workspace. |
307 | struct sway_container *current = container; | 300 | struct sway_container *current = container; |
308 | int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; | 301 | int offs = |
302 | move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP ? -1 : 1; | ||
309 | 303 | ||
310 | while (current) { | 304 | while (current) { |
311 | list_t *siblings = container_get_siblings(current); | 305 | list_t *siblings = container_get_siblings(current); |
@@ -494,12 +488,12 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { | |||
494 | } | 488 | } |
495 | destination = seat_get_focus_inactive(seat, &new_output->node); | 489 | destination = seat_get_focus_inactive(seat, &new_output->node); |
496 | } else if (strcasecmp(argv[1], "mark") == 0) { | 490 | } else if (strcasecmp(argv[1], "mark") == 0) { |
497 | struct sway_view *dest_view = view_find_mark(argv[2]); | 491 | struct sway_container *dest_con = container_find_mark(argv[2]); |
498 | if (dest_view == NULL) { | 492 | if (dest_con == NULL) { |
499 | return cmd_results_new(CMD_FAILURE, "move", | 493 | return cmd_results_new(CMD_FAILURE, "move", |
500 | "Mark '%s' not found", argv[2]); | 494 | "Mark '%s' not found", argv[2]); |
501 | } | 495 | } |
502 | destination = &dest_view->container->node; | 496 | destination = &dest_con->node; |
503 | } else { | 497 | } else { |
504 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 498 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
505 | } | 499 | } |
@@ -642,7 +636,7 @@ static struct cmd_results *cmd_move_workspace(int argc, char **argv) { | |||
642 | } | 636 | } |
643 | 637 | ||
644 | static struct cmd_results *cmd_move_in_direction( | 638 | static struct cmd_results *cmd_move_in_direction( |
645 | enum movement_direction direction, int argc, char **argv) { | 639 | enum wlr_direction direction, int argc, char **argv) { |
646 | int move_amt = 10; | 640 | int move_amt = 10; |
647 | if (argc > 1) { | 641 | if (argc > 1) { |
648 | char *inv; | 642 | char *inv; |
@@ -666,22 +660,18 @@ static struct cmd_results *cmd_move_in_direction( | |||
666 | double lx = container->x; | 660 | double lx = container->x; |
667 | double ly = container->y; | 661 | double ly = container->y; |
668 | switch (direction) { | 662 | switch (direction) { |
669 | case MOVE_LEFT: | 663 | case WLR_DIRECTION_LEFT: |
670 | lx -= move_amt; | 664 | lx -= move_amt; |
671 | break; | 665 | break; |
672 | case MOVE_RIGHT: | 666 | case WLR_DIRECTION_RIGHT: |
673 | lx += move_amt; | 667 | lx += move_amt; |
674 | break; | 668 | break; |
675 | case MOVE_UP: | 669 | case WLR_DIRECTION_UP: |
676 | ly -= move_amt; | 670 | ly -= move_amt; |
677 | break; | 671 | break; |
678 | case MOVE_DOWN: | 672 | case WLR_DIRECTION_DOWN: |
679 | ly += move_amt; | 673 | ly += move_amt; |
680 | break; | 674 | break; |
681 | case MOVE_PARENT: | ||
682 | case MOVE_CHILD: | ||
683 | return cmd_results_new(CMD_FAILURE, "move", | ||
684 | "Cannot move floating container to parent or child"); | ||
685 | } | 675 | } |
686 | container_floating_move_to(container, lx, ly); | 676 | container_floating_move_to(container, lx, ly); |
687 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 677 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
@@ -850,13 +840,13 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
850 | } | 840 | } |
851 | 841 | ||
852 | if (strcasecmp(argv[0], "left") == 0) { | 842 | if (strcasecmp(argv[0], "left") == 0) { |
853 | return cmd_move_in_direction(MOVE_LEFT, argc, argv); | 843 | return cmd_move_in_direction(WLR_DIRECTION_LEFT, argc, argv); |
854 | } else if (strcasecmp(argv[0], "right") == 0) { | 844 | } else if (strcasecmp(argv[0], "right") == 0) { |
855 | return cmd_move_in_direction(MOVE_RIGHT, argc, argv); | 845 | return cmd_move_in_direction(WLR_DIRECTION_RIGHT, argc, argv); |
856 | } else if (strcasecmp(argv[0], "up") == 0) { | 846 | } else if (strcasecmp(argv[0], "up") == 0) { |
857 | return cmd_move_in_direction(MOVE_UP, argc, argv); | 847 | return cmd_move_in_direction(WLR_DIRECTION_UP, argc, argv); |
858 | } else if (strcasecmp(argv[0], "down") == 0) { | 848 | } else if (strcasecmp(argv[0], "down") == 0) { |
859 | return cmd_move_in_direction(MOVE_DOWN, argc, argv); | 849 | return cmd_move_in_direction(WLR_DIRECTION_DOWN, argc, argv); |
860 | } else if ((strcasecmp(argv[0], "container") == 0 | 850 | } else if ((strcasecmp(argv[0], "container") == 0 |
861 | || strcasecmp(argv[0], "window") == 0) || | 851 | || strcasecmp(argv[0], "window") == 0) || |
862 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && argc >= 2 | 852 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && argc >= 2 |
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 791081a8..62105cdc 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -10,9 +10,7 @@ | |||
10 | #include "log.h" | 10 | #include "log.h" |
11 | 11 | ||
12 | static void rebuild_textures_iterator(struct sway_container *con, void *data) { | 12 | static void rebuild_textures_iterator(struct sway_container *con, void *data) { |
13 | if (con->view) { | 13 | container_update_marks_textures(con); |
14 | view_update_marks_textures(con->view); | ||
15 | } | ||
16 | container_update_title_textures(con); | 14 | container_update_title_textures(con); |
17 | } | 15 | } |
18 | 16 | ||
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index d501584a..0baf6852 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c | |||
@@ -11,9 +11,7 @@ | |||
11 | #include "util.h" | 11 | #include "util.h" |
12 | 12 | ||
13 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { | 13 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { |
14 | if (con->view) { | 14 | container_update_marks_textures(con); |
15 | view_update_marks_textures(con->view); | ||
16 | } | ||
17 | } | 15 | } |
18 | 16 | ||
19 | struct cmd_results *cmd_show_marks(int argc, char **argv) { | 17 | struct cmd_results *cmd_show_marks(int argc, char **argv) { |
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index a70a6cdd..23e8d583 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -159,8 +159,8 @@ static bool test_id(struct sway_container *container, void *id) { | |||
159 | } | 159 | } |
160 | 160 | ||
161 | static bool test_mark(struct sway_container *container, void *mark) { | 161 | static bool test_mark(struct sway_container *container, void *mark) { |
162 | if (container->view && container->view->marks->length) { | 162 | if (container->marks->length) { |
163 | return !list_seq_find(container->view->marks, | 163 | return !list_seq_find(container->marks, |
164 | (int (*)(const void *, const void *))strcmp, mark); | 164 | (int (*)(const void *, const void *))strcmp, mark); |
165 | } | 165 | } |
166 | return false; | 166 | return false; |
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index c671ed4e..98ac6ff2 100644 --- a/sway/commands/unmark.c +++ b/sway/commands/unmark.c | |||
@@ -9,10 +9,8 @@ | |||
9 | #include "stringop.h" | 9 | #include "stringop.h" |
10 | 10 | ||
11 | static void remove_all_marks_iterator(struct sway_container *con, void *data) { | 11 | static void remove_all_marks_iterator(struct sway_container *con, void *data) { |
12 | if (con->view) { | 12 | container_clear_marks(con); |
13 | view_clear_marks(con->view); | 13 | container_update_marks_textures(con); |
14 | view_update_marks_textures(con->view); | ||
15 | } | ||
16 | } | 14 | } |
17 | 15 | ||
18 | // unmark Remove all marks from all views | 16 | // unmark Remove all marks from all views |
@@ -21,15 +19,10 @@ static void remove_all_marks_iterator(struct sway_container *con, void *data) { | |||
21 | // [criteria] unmark foo Remove single mark from matched view | 19 | // [criteria] unmark foo Remove single mark from matched view |
22 | 20 | ||
23 | struct cmd_results *cmd_unmark(int argc, char **argv) { | 21 | struct cmd_results *cmd_unmark(int argc, char **argv) { |
24 | // Determine the view | 22 | // Determine the container |
25 | struct sway_view *view = NULL; | 23 | struct sway_container *con = NULL; |
26 | if (config->handler_context.using_criteria) { | 24 | if (config->handler_context.using_criteria) { |
27 | struct sway_container *container = config->handler_context.container; | 25 | con = config->handler_context.container; |
28 | if (!container || !container->view) { | ||
29 | return cmd_results_new(CMD_INVALID, "unmark", | ||
30 | "Only views can have marks"); | ||
31 | } | ||
32 | view = container->view; | ||
33 | } | 26 | } |
34 | 27 | ||
35 | // Determine the mark | 28 | // Determine the mark |
@@ -38,20 +31,20 @@ struct cmd_results *cmd_unmark(int argc, char **argv) { | |||
38 | mark = join_args(argv, argc); | 31 | mark = join_args(argv, argc); |
39 | } | 32 | } |
40 | 33 | ||
41 | if (view && mark) { | 34 | if (con && mark) { |
42 | // Remove the mark from the given view | 35 | // Remove the mark from the given container |
43 | if (view_has_mark(view, mark)) { | 36 | if (container_has_mark(con, mark)) { |
44 | view_find_and_unmark(mark); | 37 | container_find_and_unmark(mark); |
45 | } | 38 | } |
46 | } else if (view && !mark) { | 39 | } else if (con && !mark) { |
47 | // Clear all marks from the given view | 40 | // Clear all marks from the given container |
48 | view_clear_marks(view); | 41 | container_clear_marks(con); |
49 | view_update_marks_textures(view); | 42 | container_update_marks_textures(con); |
50 | } else if (!view && mark) { | 43 | } else if (!con && mark) { |
51 | // Remove mark from whichever view has it | 44 | // Remove mark from whichever container has it |
52 | view_find_and_unmark(mark); | 45 | container_find_and_unmark(mark); |
53 | } else { | 46 | } else { |
54 | // Remove all marks from all views | 47 | // Remove all marks from all containers |
55 | root_for_each_container(remove_all_marks_iterator, NULL); | 48 | root_for_each_container(remove_all_marks_iterator, NULL); |
56 | } | 49 | } |
57 | free(mark); | 50 | free(mark); |
diff --git a/sway/criteria.c b/sway/criteria.c index 89630d90..2f9992e9 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -121,8 +121,9 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
121 | 121 | ||
122 | if (criteria->con_mark) { | 122 | if (criteria->con_mark) { |
123 | bool exists = false; | 123 | bool exists = false; |
124 | for (int i = 0; i < view->marks->length; ++i) { | 124 | struct sway_container *con = view->container; |
125 | if (regex_cmp(view->marks->items[i], criteria->con_mark) == 0) { | 125 | for (int i = 0; i < con->marks->length; ++i) { |
126 | if (regex_cmp(con->marks->items[i], criteria->con_mark) == 0) { | ||
126 | exists = true; | 127 | exists = true; |
127 | break; | 128 | break; |
128 | } | 129 | } |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index ed9300bb..2b90f151 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -39,6 +39,19 @@ struct sway_output *output_by_name(const char *name) { | |||
39 | return NULL; | 39 | return NULL; |
40 | } | 40 | } |
41 | 41 | ||
42 | struct sway_output *output_by_identifier(const char *identifier) { | ||
43 | for (int i = 0; i < root->outputs->length; ++i) { | ||
44 | struct sway_output *output = root->outputs->items[i]; | ||
45 | char output_identifier[128]; | ||
46 | snprintf(output_identifier, sizeof(output_identifier), "%s %s %s", output->wlr_output->make, | ||
47 | output->wlr_output->model, output->wlr_output->serial); | ||
48 | if (strcasecmp(output_identifier, identifier) == 0) { | ||
49 | return output; | ||
50 | } | ||
51 | } | ||
52 | return NULL; | ||
53 | } | ||
54 | |||
42 | /** | 55 | /** |
43 | * Rotate a child's position relative to a parent. The parent size is (pw, ph), | 56 | * Rotate a child's position relative to a parent. The parent size is (pw, ph), |
44 | * the child position is (*sx, *sy) and its size is (sw, sh). | 57 | * the child position is (*sx, *sy) and its size is (sw, sh). |
@@ -519,9 +532,7 @@ static void handle_transform(struct wl_listener *listener, void *data) { | |||
519 | 532 | ||
520 | static void update_textures(struct sway_container *con, void *data) { | 533 | static void update_textures(struct sway_container *con, void *data) { |
521 | container_update_title_textures(con); | 534 | container_update_title_textures(con); |
522 | if (con->view) { | 535 | container_update_marks_textures(con); |
523 | view_update_marks_textures(con->view); | ||
524 | } | ||
525 | } | 536 | } |
526 | 537 | ||
527 | static void handle_scale(struct wl_listener *listener, void *data) { | 538 | static void handle_scale(struct wl_listener *listener, void *data) { |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 1a72f752..cf6da682 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -625,19 +625,19 @@ static void render_containers_linear(struct sway_output *output, | |||
625 | if (view_is_urgent(view)) { | 625 | if (view_is_urgent(view)) { |
626 | colors = &config->border_colors.urgent; | 626 | colors = &config->border_colors.urgent; |
627 | title_texture = child->title_urgent; | 627 | title_texture = child->title_urgent; |
628 | marks_texture = view->marks_urgent; | 628 | marks_texture = child->marks_urgent; |
629 | } else if (state->focused || parent->focused) { | 629 | } else if (state->focused || parent->focused) { |
630 | colors = &config->border_colors.focused; | 630 | colors = &config->border_colors.focused; |
631 | title_texture = child->title_focused; | 631 | title_texture = child->title_focused; |
632 | marks_texture = view->marks_focused; | 632 | marks_texture = child->marks_focused; |
633 | } else if (child == parent->active_child) { | 633 | } else if (child == parent->active_child) { |
634 | colors = &config->border_colors.focused_inactive; | 634 | colors = &config->border_colors.focused_inactive; |
635 | title_texture = child->title_focused_inactive; | 635 | title_texture = child->title_focused_inactive; |
636 | marks_texture = view->marks_focused_inactive; | 636 | marks_texture = child->marks_focused_inactive; |
637 | } else { | 637 | } else { |
638 | colors = &config->border_colors.unfocused; | 638 | colors = &config->border_colors.unfocused; |
639 | title_texture = child->title_unfocused; | 639 | title_texture = child->title_unfocused; |
640 | marks_texture = view->marks_unfocused; | 640 | marks_texture = child->marks_unfocused; |
641 | } | 641 | } |
642 | 642 | ||
643 | if (state->border == B_NORMAL) { | 643 | if (state->border == B_NORMAL) { |
@@ -681,19 +681,19 @@ static void render_containers_tabbed(struct sway_output *output, | |||
681 | if (urgent) { | 681 | if (urgent) { |
682 | colors = &config->border_colors.urgent; | 682 | colors = &config->border_colors.urgent; |
683 | title_texture = child->title_urgent; | 683 | title_texture = child->title_urgent; |
684 | marks_texture = view ? view->marks_urgent : NULL; | 684 | marks_texture = child->marks_urgent; |
685 | } else if (cstate->focused || parent->focused) { | 685 | } else if (cstate->focused || parent->focused) { |
686 | colors = &config->border_colors.focused; | 686 | colors = &config->border_colors.focused; |
687 | title_texture = child->title_focused; | 687 | title_texture = child->title_focused; |
688 | marks_texture = view ? view->marks_focused : NULL; | 688 | marks_texture = child->marks_focused; |
689 | } else if (child == parent->active_child) { | 689 | } else if (child == parent->active_child) { |
690 | colors = &config->border_colors.focused_inactive; | 690 | colors = &config->border_colors.focused_inactive; |
691 | title_texture = child->title_focused_inactive; | 691 | title_texture = child->title_focused_inactive; |
692 | marks_texture = view ? view->marks_focused_inactive : NULL; | 692 | marks_texture = child->marks_focused_inactive; |
693 | } else { | 693 | } else { |
694 | colors = &config->border_colors.unfocused; | 694 | colors = &config->border_colors.unfocused; |
695 | title_texture = child->title_unfocused; | 695 | title_texture = child->title_unfocused; |
696 | marks_texture = view ? view->marks_unfocused : NULL; | 696 | marks_texture = child->marks_unfocused; |
697 | } | 697 | } |
698 | 698 | ||
699 | int x = cstate->con_x + tab_width * i; | 699 | int x = cstate->con_x + tab_width * i; |
@@ -746,19 +746,19 @@ static void render_containers_stacked(struct sway_output *output, | |||
746 | if (urgent) { | 746 | if (urgent) { |
747 | colors = &config->border_colors.urgent; | 747 | colors = &config->border_colors.urgent; |
748 | title_texture = child->title_urgent; | 748 | title_texture = child->title_urgent; |
749 | marks_texture = view ? view->marks_urgent : NULL; | 749 | marks_texture = child->marks_urgent; |
750 | } else if (cstate->focused || parent->focused) { | 750 | } else if (cstate->focused || parent->focused) { |
751 | colors = &config->border_colors.focused; | 751 | colors = &config->border_colors.focused; |
752 | title_texture = child->title_focused; | 752 | title_texture = child->title_focused; |
753 | marks_texture = view ? view->marks_focused : NULL; | 753 | marks_texture = child->marks_focused; |
754 | } else if (child == parent->active_child) { | 754 | } else if (child == parent->active_child) { |
755 | colors = &config->border_colors.focused_inactive; | 755 | colors = &config->border_colors.focused_inactive; |
756 | title_texture = child->title_focused_inactive; | 756 | title_texture = child->title_focused_inactive; |
757 | marks_texture = view ? view->marks_focused_inactive : NULL; | 757 | marks_texture = child->marks_focused_inactive; |
758 | } else { | 758 | } else { |
759 | colors = &config->border_colors.unfocused; | 759 | colors = &config->border_colors.unfocused; |
760 | title_texture = child->title_unfocused; | 760 | title_texture = child->title_unfocused; |
761 | marks_texture = view ? view->marks_unfocused : NULL; | 761 | marks_texture = child->marks_unfocused; |
762 | } | 762 | } |
763 | 763 | ||
764 | int y = parent->box.y + titlebar_height * i; | 764 | int y = parent->box.y + titlebar_height * i; |
@@ -841,15 +841,15 @@ static void render_floating_container(struct sway_output *soutput, | |||
841 | if (view_is_urgent(view)) { | 841 | if (view_is_urgent(view)) { |
842 | colors = &config->border_colors.urgent; | 842 | colors = &config->border_colors.urgent; |
843 | title_texture = con->title_urgent; | 843 | title_texture = con->title_urgent; |
844 | marks_texture = view->marks_urgent; | 844 | marks_texture = con->marks_urgent; |
845 | } else if (con->current.focused) { | 845 | } else if (con->current.focused) { |
846 | colors = &config->border_colors.focused; | 846 | colors = &config->border_colors.focused; |
847 | title_texture = con->title_focused; | 847 | title_texture = con->title_focused; |
848 | marks_texture = view->marks_focused; | 848 | marks_texture = con->marks_focused; |
849 | } else { | 849 | } else { |
850 | colors = &config->border_colors.unfocused; | 850 | colors = &config->border_colors.unfocused; |
851 | title_texture = con->title_unfocused; | 851 | title_texture = con->title_unfocused; |
852 | marks_texture = view->marks_unfocused; | 852 | marks_texture = con->marks_unfocused; |
853 | } | 853 | } |
854 | 854 | ||
855 | if (con->current.border == B_NORMAL) { | 855 | if (con->current.border == B_NORMAL) { |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 955b05d6..44156d41 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -137,6 +137,12 @@ static void copy_container_state(struct sway_container *container, | |||
137 | state->is_fullscreen = container->is_fullscreen; | 137 | state->is_fullscreen = container->is_fullscreen; |
138 | state->parent = container->parent; | 138 | state->parent = container->parent; |
139 | state->workspace = container->workspace; | 139 | state->workspace = container->workspace; |
140 | state->border = container->border; | ||
141 | state->border_thickness = container->border_thickness; | ||
142 | state->border_top = container->border_top; | ||
143 | state->border_left = container->border_left; | ||
144 | state->border_right = container->border_right; | ||
145 | state->border_bottom = container->border_bottom; | ||
140 | 146 | ||
141 | if (container->view) { | 147 | if (container->view) { |
142 | struct sway_view *view = container->view; | 148 | struct sway_view *view = container->view; |
@@ -144,12 +150,6 @@ static void copy_container_state(struct sway_container *container, | |||
144 | state->view_y = view->y; | 150 | state->view_y = view->y; |
145 | state->view_width = view->width; | 151 | state->view_width = view->width; |
146 | state->view_height = view->height; | 152 | state->view_height = view->height; |
147 | state->border = view->border; | ||
148 | state->border_thickness = view->border_thickness; | ||
149 | state->border_top = view->border_top; | ||
150 | state->border_left = view->border_left; | ||
151 | state->border_right = view->border_right; | ||
152 | state->border_bottom = view->border_bottom; | ||
153 | } else { | 153 | } else { |
154 | state->children = create_list(); | 154 | state->children = create_list(); |
155 | list_cat(state->children, container->children); | 155 | list_cat(state->children, container->children); |
@@ -301,7 +301,9 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
301 | if (root->outputs->length) { | 301 | if (root->outputs->length) { |
302 | struct sway_seat *seat; | 302 | struct sway_seat *seat; |
303 | wl_list_for_each(seat, &server.input->seats, link) { | 303 | wl_list_for_each(seat, &server.input->seats, link) { |
304 | cursor_rebase(seat->cursor); | 304 | if (seat->operation == OP_NONE) { |
305 | cursor_rebase(seat->cursor); | ||
306 | } | ||
305 | } | 307 | } |
306 | } | 308 | } |
307 | } | 309 | } |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 3942b64f..c539df40 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -187,23 +187,22 @@ static enum wlr_edges find_edge(struct sway_container *cont, | |||
187 | if (!cont->view) { | 187 | if (!cont->view) { |
188 | return WLR_EDGE_NONE; | 188 | return WLR_EDGE_NONE; |
189 | } | 189 | } |
190 | struct sway_view *view = cont->view; | 190 | if (cont->border == B_NONE || !cont->border_thickness || |
191 | if (view->border == B_NONE || !view->border_thickness || | 191 | cont->border == B_CSD) { |
192 | view->border == B_CSD) { | ||
193 | return WLR_EDGE_NONE; | 192 | return WLR_EDGE_NONE; |
194 | } | 193 | } |
195 | 194 | ||
196 | enum wlr_edges edge = 0; | 195 | enum wlr_edges edge = 0; |
197 | if (cursor->cursor->x < cont->x + view->border_thickness) { | 196 | if (cursor->cursor->x < cont->x + cont->border_thickness) { |
198 | edge |= WLR_EDGE_LEFT; | 197 | edge |= WLR_EDGE_LEFT; |
199 | } | 198 | } |
200 | if (cursor->cursor->y < cont->y + view->border_thickness) { | 199 | if (cursor->cursor->y < cont->y + cont->border_thickness) { |
201 | edge |= WLR_EDGE_TOP; | 200 | edge |= WLR_EDGE_TOP; |
202 | } | 201 | } |
203 | if (cursor->cursor->x >= cont->x + cont->width - view->border_thickness) { | 202 | if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) { |
204 | edge |= WLR_EDGE_RIGHT; | 203 | edge |= WLR_EDGE_RIGHT; |
205 | } | 204 | } |
206 | if (cursor->cursor->y >= cont->y + cont->height - view->border_thickness) { | 205 | if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) { |
207 | edge |= WLR_EDGE_BOTTOM; | 206 | edge |= WLR_EDGE_BOTTOM; |
208 | } | 207 | } |
209 | 208 | ||
@@ -585,7 +584,7 @@ static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec, | |||
585 | 584 | ||
586 | void cursor_rebase(struct sway_cursor *cursor) { | 585 | void cursor_rebase(struct sway_cursor *cursor) { |
587 | uint32_t time_msec = get_current_time_msec(); | 586 | uint32_t time_msec = get_current_time_msec(); |
588 | struct wlr_surface *surface; | 587 | struct wlr_surface *surface = NULL; |
589 | double sx, sy; | 588 | double sx, sy; |
590 | cursor->previous.node = node_at_coords(cursor->seat, | 589 | cursor->previous.node = node_at_coords(cursor->seat, |
591 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | 590 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); |
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 91c45dd1..68445d68 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c | |||
@@ -431,6 +431,7 @@ void input_manager_set_focus(struct sway_node *node) { | |||
431 | struct sway_seat *seat; | 431 | struct sway_seat *seat; |
432 | wl_list_for_each(seat, &server.input->seats, link) { | 432 | wl_list_for_each(seat, &server.input->seats, link) { |
433 | seat_set_focus(seat, node); | 433 | seat_set_focus(seat, node); |
434 | seat_consider_warp_to_focus(seat); | ||
434 | } | 435 | } |
435 | } | 436 | } |
436 | 437 | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 577619a7..64419afa 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -185,7 +185,11 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { | |||
185 | seat_set_focus(seat, next_focus); | 185 | seat_set_focus(seat, next_focus); |
186 | } else { | 186 | } else { |
187 | // Setting focus_inactive | 187 | // Setting focus_inactive |
188 | focus = seat_get_focus_inactive(seat, &root->node); | ||
188 | seat_set_raw_focus(seat, next_focus); | 189 | seat_set_raw_focus(seat, next_focus); |
190 | if (focus->type == N_CONTAINER) { | ||
191 | seat_set_raw_focus(seat, &focus->sway_container->workspace->node); | ||
192 | } | ||
189 | seat_set_raw_focus(seat, focus); | 193 | seat_set_raw_focus(seat, focus); |
190 | } | 194 | } |
191 | } | 195 | } |
@@ -944,7 +948,7 @@ struct sway_node *seat_get_focus(struct sway_seat *seat) { | |||
944 | if (!seat->has_focus) { | 948 | if (!seat->has_focus) { |
945 | return NULL; | 949 | return NULL; |
946 | } | 950 | } |
947 | if (wl_list_length(&seat->focus_stack) == 0) { | 951 | if (wl_list_empty(&seat->focus_stack)) { |
948 | return NULL; | 952 | return NULL; |
949 | } | 953 | } |
950 | struct sway_seat_node *current = | 954 | struct sway_seat_node *current = |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 2cd0cb2d..7cc965c8 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -136,13 +136,18 @@ static void ipc_json_describe_output(struct sway_output *output, | |||
136 | json_object_new_int(mode->width)); | 136 | json_object_new_int(mode->width)); |
137 | json_object_object_add(mode_object, "height", | 137 | json_object_object_add(mode_object, "height", |
138 | json_object_new_int(mode->height)); | 138 | json_object_new_int(mode->height)); |
139 | json_object_object_add(mode_object, "refresh", | ||
140 | json_object_new_int(mode->refresh)); | ||
141 | json_object_array_add(modes_array, mode_object); | 139 | json_object_array_add(modes_array, mode_object); |
142 | } | 140 | } |
143 | 141 | ||
144 | json_object_object_add(object, "modes", modes_array); | 142 | json_object_object_add(object, "modes", modes_array); |
145 | 143 | ||
144 | json_object *current_mode_object = json_object_new_object(); | ||
145 | json_object_object_add(current_mode_object, "width", | ||
146 | json_object_new_int(wlr_output->width)); | ||
147 | json_object_object_add(current_mode_object, "height", | ||
148 | json_object_new_int(wlr_output->height)); | ||
149 | json_object_object_add(object, "current_mode", current_mode_object); | ||
150 | |||
146 | struct sway_node *parent = node_get_parent(&output->node); | 151 | struct sway_node *parent = node_get_parent(&output->node); |
147 | struct wlr_box parent_box = {0, 0, 0, 0}; | 152 | struct wlr_box parent_box = {0, 0, 0, 0}; |
148 | 153 | ||
@@ -229,14 +234,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
229 | json_object_object_add(object, "app_id", | 234 | json_object_object_add(object, "app_id", |
230 | app_id ? json_object_new_string(app_id) : NULL); | 235 | app_id ? json_object_new_string(app_id) : NULL); |
231 | 236 | ||
232 | const char *class = view_get_class(c->view); | ||
233 | json_object_object_add(object, "class", | ||
234 | class ? json_object_new_string(class) : NULL); | ||
235 | |||
236 | json_object *marks = json_object_new_array(); | 237 | json_object *marks = json_object_new_array(); |
237 | list_t *view_marks = c->view->marks; | 238 | list_t *con_marks = c->marks; |
238 | for (int i = 0; i < view_marks->length; ++i) { | 239 | for (int i = 0; i < con_marks->length; ++i) { |
239 | json_object_array_add(marks, json_object_new_string(view_marks->items[i])); | 240 | json_object_array_add(marks, json_object_new_string(con_marks->items[i])); |
240 | } | 241 | } |
241 | 242 | ||
242 | json_object_object_add(object, "marks", marks); | 243 | json_object_object_add(object, "marks", marks); |
@@ -269,13 +270,17 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
269 | 270 | ||
270 | json_object *window_props = json_object_new_object(); | 271 | json_object *window_props = json_object_new_object(); |
271 | 272 | ||
272 | json_object_object_add(window_props, "class", | 273 | const char *class = view_get_class(c->view); |
273 | class ? json_object_new_string(class) : NULL); | 274 | if (class) { |
275 | json_object_object_add(window_props, "class", json_object_new_string(class)); | ||
276 | } | ||
274 | const char *instance = view_get_instance(c->view); | 277 | const char *instance = view_get_instance(c->view); |
275 | json_object_object_add(window_props, "instance", | 278 | if (instance) { |
276 | instance ? json_object_new_string(instance) : NULL); | 279 | json_object_object_add(window_props, "instance", json_object_new_string(instance)); |
277 | json_object_object_add(window_props, "title", | 280 | } |
278 | c->title ? json_object_new_string(c->title) : NULL); | 281 | if (c->title) { |
282 | json_object_object_add(window_props, "title", json_object_new_string(c->title)); | ||
283 | } | ||
279 | 284 | ||
280 | // the transient_for key is always present in i3's output | 285 | // the transient_for key is always present in i3's output |
281 | uint32_t parent_id = view_get_x11_parent_id(c->view); | 286 | uint32_t parent_id = view_get_x11_parent_id(c->view); |
@@ -284,8 +289,7 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
284 | 289 | ||
285 | const char *role = view_get_window_role(c->view); | 290 | const char *role = view_get_window_role(c->view); |
286 | if (role) { | 291 | if (role) { |
287 | json_object_object_add(window_props, "window_role", | 292 | json_object_object_add(window_props, "window_role", json_object_new_string(role)); |
288 | json_object_new_string(role)); | ||
289 | } | 293 | } |
290 | 294 | ||
291 | json_object_object_add(object, "window_properties", window_props); | 295 | json_object_object_add(object, "window_properties", window_props); |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 21f431be..6466d263 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -563,11 +563,9 @@ static void ipc_get_workspaces_callback(struct sway_workspace *workspace, | |||
563 | 563 | ||
564 | static void ipc_get_marks_callback(struct sway_container *con, void *data) { | 564 | static void ipc_get_marks_callback(struct sway_container *con, void *data) { |
565 | json_object *marks = (json_object *)data; | 565 | json_object *marks = (json_object *)data; |
566 | if (con->view && con->view->marks) { | 566 | for (int i = 0; i < con->marks->length; ++i) { |
567 | for (int i = 0; i < con->view->marks->length; ++i) { | 567 | char *mark = (char *)con->marks->items[i]; |
568 | char *mark = (char *)con->view->marks->items[i]; | 568 | json_object_array_add(marks, json_object_new_string(mark)); |
569 | json_object_array_add(marks, json_object_new_string(mark)); | ||
570 | } | ||
571 | } | 569 | } |
572 | } | 570 | } |
573 | 571 | ||
diff --git a/sway/main.c b/sway/main.c index cc5f7187..920cea11 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | ||
30 | static bool terminate_request = false; | 30 | static bool terminate_request = false; |
31 | static int exit_value = 0; | 31 | static int exit_value = 0; |
32 | struct sway_server server; | 32 | struct sway_server server = {0}; |
33 | 33 | ||
34 | void sway_terminate(int exit_code) { | 34 | void sway_terminate(int exit_code) { |
35 | terminate_request = true; | 35 | terminate_request = true; |
@@ -194,21 +194,23 @@ static void log_kernel(void) { | |||
194 | } | 194 | } |
195 | 195 | ||
196 | 196 | ||
197 | static void drop_permissions(void) { | 197 | static bool drop_permissions(void) { |
198 | if (getuid() != geteuid() || getgid() != getegid()) { | 198 | if (getuid() != geteuid() || getgid() != getegid()) { |
199 | if (setgid(getgid()) != 0) { | 199 | if (setgid(getgid()) != 0) { |
200 | wlr_log(WLR_ERROR, "Unable to drop root"); | 200 | wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); |
201 | exit(EXIT_FAILURE); | 201 | return false; |
202 | } | 202 | } |
203 | if (setuid(getuid()) != 0) { | 203 | if (setuid(getuid()) != 0) { |
204 | wlr_log(WLR_ERROR, "Unable to drop root"); | 204 | wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); |
205 | exit(EXIT_FAILURE); | 205 | return false; |
206 | } | 206 | } |
207 | } | 207 | } |
208 | if (setuid(0) != -1) { | 208 | if (setuid(0) != -1) { |
209 | wlr_log(WLR_ERROR, "Root privileges can be restored."); | 209 | wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to " |
210 | exit(EXIT_FAILURE); | 210 | "restore it after setuid), refusing to start"); |
211 | return false; | ||
211 | } | 212 | } |
213 | return true; | ||
212 | } | 214 | } |
213 | 215 | ||
214 | void enable_debug_flag(const char *flag) { | 216 | void enable_debug_flag(const char *flag) { |
@@ -317,11 +319,13 @@ int main(int argc, char **argv) { | |||
317 | } | 319 | } |
318 | 320 | ||
319 | if (optind < argc) { // Behave as IPC client | 321 | if (optind < argc) { // Behave as IPC client |
320 | if(optind != 1) { | 322 | if (optind != 1) { |
321 | wlr_log(WLR_ERROR, "Don't use options with the IPC client"); | 323 | wlr_log(WLR_ERROR, "Don't use options with the IPC client"); |
322 | exit(EXIT_FAILURE); | 324 | exit(EXIT_FAILURE); |
323 | } | 325 | } |
324 | drop_permissions(); | 326 | if (!drop_permissions()) { |
327 | exit(EXIT_FAILURE); | ||
328 | } | ||
325 | char *socket_path = getenv("SWAYSOCK"); | 329 | char *socket_path = getenv("SWAYSOCK"); |
326 | if (!socket_path) { | 330 | if (!socket_path) { |
327 | wlr_log(WLR_ERROR, "Unable to retrieve socket path"); | 331 | wlr_log(WLR_ERROR, "Unable to retrieve socket path"); |
@@ -341,7 +345,10 @@ int main(int argc, char **argv) { | |||
341 | detect_proprietary(allow_unsupported_gpu); | 345 | detect_proprietary(allow_unsupported_gpu); |
342 | detect_raspi(); | 346 | detect_raspi(); |
343 | 347 | ||
344 | drop_permissions(); | 348 | if (!drop_permissions()) { |
349 | server_fini(&server); | ||
350 | exit(EXIT_FAILURE); | ||
351 | } | ||
345 | 352 | ||
346 | // handle SIGTERM signals | 353 | // handle SIGTERM signals |
347 | signal(SIGTERM, sig_handler); | 354 | signal(SIGTERM, sig_handler); |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 58d3df34..458ed7ff 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -39,6 +39,7 @@ struct sway_container *container_create(struct sway_view *view) { | |||
39 | c->children = create_list(); | 39 | c->children = create_list(); |
40 | c->current.children = create_list(); | 40 | c->current.children = create_list(); |
41 | } | 41 | } |
42 | c->marks = create_list(); | ||
42 | c->outputs = create_list(); | 43 | c->outputs = create_list(); |
43 | 44 | ||
44 | wl_signal_init(&c->events.destroy); | 45 | wl_signal_init(&c->events.destroy); |
@@ -66,6 +67,13 @@ void container_destroy(struct sway_container *con) { | |||
66 | list_free(con->current.children); | 67 | list_free(con->current.children); |
67 | list_free(con->outputs); | 68 | list_free(con->outputs); |
68 | 69 | ||
70 | list_foreach(con->marks, free); | ||
71 | list_free(con->marks); | ||
72 | wlr_texture_destroy(con->marks_focused); | ||
73 | wlr_texture_destroy(con->marks_focused_inactive); | ||
74 | wlr_texture_destroy(con->marks_unfocused); | ||
75 | wlr_texture_destroy(con->marks_urgent); | ||
76 | |||
69 | if (con->view) { | 77 | if (con->view) { |
70 | if (con->view->container == con) { | 78 | if (con->view->container == con) { |
71 | con->view->container = NULL; | 79 | con->view->container = NULL; |
@@ -639,8 +647,8 @@ void container_init_floating(struct sway_container *con) { | |||
639 | view->y = ws->y + (ws->height - view->height) / 2; | 647 | view->y = ws->y + (ws->height - view->height) / 2; |
640 | 648 | ||
641 | // If the view's border is B_NONE then these properties are ignored. | 649 | // If the view's border is B_NONE then these properties are ignored. |
642 | view->border_top = view->border_bottom = true; | 650 | con->border_top = con->border_bottom = true; |
643 | view->border_left = view->border_right = true; | 651 | con->border_left = con->border_right = true; |
644 | 652 | ||
645 | container_set_geometry_from_floating_view(con); | 653 | container_set_geometry_from_floating_view(con); |
646 | } | 654 | } |
@@ -662,7 +670,7 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
662 | if (container->view) { | 670 | if (container->view) { |
663 | view_set_tiled(container->view, false); | 671 | view_set_tiled(container->view, false); |
664 | if (container->view->using_csd) { | 672 | if (container->view->using_csd) { |
665 | container->view->border = B_CSD; | 673 | container->border = B_CSD; |
666 | } | 674 | } |
667 | } | 675 | } |
668 | if (old_parent) { | 676 | if (old_parent) { |
@@ -676,11 +684,8 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
676 | container_detach(container); | 684 | container_detach(container); |
677 | struct sway_container *reference = | 685 | struct sway_container *reference = |
678 | seat_get_focus_inactive_tiling(seat, workspace); | 686 | seat_get_focus_inactive_tiling(seat, workspace); |
679 | if (reference && reference->view) { | ||
680 | reference = reference->parent; | ||
681 | } | ||
682 | if (reference) { | 687 | if (reference) { |
683 | container_add_child(reference, container); | 688 | container_add_sibling(reference, container, 1); |
684 | container->width = reference->width; | 689 | container->width = reference->width; |
685 | container->height = reference->height; | 690 | container->height = reference->height; |
686 | } else { | 691 | } else { |
@@ -691,7 +696,7 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
691 | if (container->view) { | 696 | if (container->view) { |
692 | view_set_tiled(container->view, true); | 697 | view_set_tiled(container->view, true); |
693 | if (container->view->using_csd) { | 698 | if (container->view->using_csd) { |
694 | container->view->border = container->view->saved_border; | 699 | container->border = container->saved_border; |
695 | } | 700 | } |
696 | } | 701 | } |
697 | container->is_sticky = false; | 702 | container->is_sticky = false; |
@@ -713,9 +718,9 @@ void container_set_geometry_from_floating_view(struct sway_container *con) { | |||
713 | size_t border_width = 0; | 718 | size_t border_width = 0; |
714 | size_t top = 0; | 719 | size_t top = 0; |
715 | 720 | ||
716 | if (view->border != B_CSD) { | 721 | if (con->border != B_CSD) { |
717 | border_width = view->border_thickness * (view->border != B_NONE); | 722 | border_width = con->border_thickness * (con->border != B_NONE); |
718 | top = view->border == B_NORMAL ? | 723 | top = con->border == B_NORMAL ? |
719 | container_titlebar_height() : border_width; | 724 | container_titlebar_height() : border_width; |
720 | } | 725 | } |
721 | 726 | ||
@@ -999,9 +1004,7 @@ void container_discover_outputs(struct sway_container *con) { | |||
999 | double new_scale = new_output ? new_output->wlr_output->scale : -1; | 1004 | double new_scale = new_output ? new_output->wlr_output->scale : -1; |
1000 | if (old_scale != new_scale) { | 1005 | if (old_scale != new_scale) { |
1001 | container_update_title_textures(con); | 1006 | container_update_title_textures(con); |
1002 | if (con->view) { | 1007 | container_update_marks_textures(con); |
1003 | view_update_marks_textures(con->view); | ||
1004 | } | ||
1005 | } | 1008 | } |
1006 | } | 1009 | } |
1007 | 1010 | ||
@@ -1221,3 +1224,142 @@ bool container_is_transient_for(struct sway_container *child, | |||
1221 | child->view && ancestor->view && | 1224 | child->view && ancestor->view && |
1222 | view_is_transient_for(child->view, ancestor->view); | 1225 | view_is_transient_for(child->view, ancestor->view); |
1223 | } | 1226 | } |
1227 | |||
1228 | static bool find_by_mark_iterator(struct sway_container *con, void *data) { | ||
1229 | char *mark = data; | ||
1230 | return container_has_mark(con, mark); | ||
1231 | } | ||
1232 | |||
1233 | struct sway_container *container_find_mark(char *mark) { | ||
1234 | return root_find_container(find_by_mark_iterator, mark); | ||
1235 | } | ||
1236 | |||
1237 | bool container_find_and_unmark(char *mark) { | ||
1238 | struct sway_container *con = root_find_container( | ||
1239 | find_by_mark_iterator, mark); | ||
1240 | if (!con) { | ||
1241 | return false; | ||
1242 | } | ||
1243 | |||
1244 | for (int i = 0; i < con->marks->length; ++i) { | ||
1245 | char *con_mark = con->marks->items[i]; | ||
1246 | if (strcmp(con_mark, mark) == 0) { | ||
1247 | free(con_mark); | ||
1248 | list_del(con->marks, i); | ||
1249 | container_update_marks_textures(con); | ||
1250 | ipc_event_window(con, "mark"); | ||
1251 | return true; | ||
1252 | } | ||
1253 | } | ||
1254 | return false; | ||
1255 | } | ||
1256 | |||
1257 | void container_clear_marks(struct sway_container *con) { | ||
1258 | list_foreach(con->marks, free); | ||
1259 | con->marks->length = 0; | ||
1260 | ipc_event_window(con, "mark"); | ||
1261 | } | ||
1262 | |||
1263 | bool container_has_mark(struct sway_container *con, char *mark) { | ||
1264 | for (int i = 0; i < con->marks->length; ++i) { | ||
1265 | char *item = con->marks->items[i]; | ||
1266 | if (strcmp(item, mark) == 0) { | ||
1267 | return true; | ||
1268 | } | ||
1269 | } | ||
1270 | return false; | ||
1271 | } | ||
1272 | |||
1273 | void container_add_mark(struct sway_container *con, char *mark) { | ||
1274 | list_add(con->marks, strdup(mark)); | ||
1275 | ipc_event_window(con, "mark"); | ||
1276 | } | ||
1277 | |||
1278 | static void update_marks_texture(struct sway_container *con, | ||
1279 | struct wlr_texture **texture, struct border_colors *class) { | ||
1280 | struct sway_output *output = container_get_effective_output(con); | ||
1281 | if (!output) { | ||
1282 | return; | ||
1283 | } | ||
1284 | if (*texture) { | ||
1285 | wlr_texture_destroy(*texture); | ||
1286 | *texture = NULL; | ||
1287 | } | ||
1288 | if (!con->marks->length) { | ||
1289 | return; | ||
1290 | } | ||
1291 | |||
1292 | size_t len = 0; | ||
1293 | for (int i = 0; i < con->marks->length; ++i) { | ||
1294 | char *mark = con->marks->items[i]; | ||
1295 | if (mark[0] != '_') { | ||
1296 | len += strlen(mark) + 2; | ||
1297 | } | ||
1298 | } | ||
1299 | char *buffer = calloc(len + 1, 1); | ||
1300 | char *part = malloc(len + 1); | ||
1301 | |||
1302 | if (!sway_assert(buffer && part, "Unable to allocate memory")) { | ||
1303 | free(buffer); | ||
1304 | return; | ||
1305 | } | ||
1306 | |||
1307 | for (int i = 0; i < con->marks->length; ++i) { | ||
1308 | char *mark = con->marks->items[i]; | ||
1309 | if (mark[0] != '_') { | ||
1310 | sprintf(part, "[%s]", mark); | ||
1311 | strcat(buffer, part); | ||
1312 | } | ||
1313 | } | ||
1314 | free(part); | ||
1315 | |||
1316 | double scale = output->wlr_output->scale; | ||
1317 | int width = 0; | ||
1318 | int height = con->title_height * scale; | ||
1319 | |||
1320 | cairo_t *c = cairo_create(NULL); | ||
1321 | get_text_size(c, config->font, &width, NULL, NULL, scale, false, | ||
1322 | "%s", buffer); | ||
1323 | cairo_destroy(c); | ||
1324 | |||
1325 | cairo_surface_t *surface = cairo_image_surface_create( | ||
1326 | CAIRO_FORMAT_ARGB32, width, height); | ||
1327 | cairo_t *cairo = cairo_create(surface); | ||
1328 | cairo_set_source_rgba(cairo, class->background[0], class->background[1], | ||
1329 | class->background[2], class->background[3]); | ||
1330 | cairo_paint(cairo); | ||
1331 | PangoContext *pango = pango_cairo_create_context(cairo); | ||
1332 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); | ||
1333 | cairo_set_source_rgba(cairo, class->text[0], class->text[1], | ||
1334 | class->text[2], class->text[3]); | ||
1335 | cairo_move_to(cairo, 0, 0); | ||
1336 | |||
1337 | pango_printf(cairo, config->font, scale, false, "%s", buffer); | ||
1338 | |||
1339 | cairo_surface_flush(surface); | ||
1340 | unsigned char *data = cairo_image_surface_get_data(surface); | ||
1341 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); | ||
1342 | struct wlr_renderer *renderer = wlr_backend_get_renderer( | ||
1343 | output->wlr_output->backend); | ||
1344 | *texture = wlr_texture_from_pixels( | ||
1345 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); | ||
1346 | cairo_surface_destroy(surface); | ||
1347 | g_object_unref(pango); | ||
1348 | cairo_destroy(cairo); | ||
1349 | free(buffer); | ||
1350 | } | ||
1351 | |||
1352 | void container_update_marks_textures(struct sway_container *con) { | ||
1353 | if (!config->show_marks) { | ||
1354 | return; | ||
1355 | } | ||
1356 | update_marks_texture(con, &con->marks_focused, | ||
1357 | &config->border_colors.focused); | ||
1358 | update_marks_texture(con, &con->marks_focused_inactive, | ||
1359 | &config->border_colors.focused_inactive); | ||
1360 | update_marks_texture(con, &con->marks_unfocused, | ||
1361 | &config->border_colors.unfocused); | ||
1362 | update_marks_texture(con, &con->marks_urgent, | ||
1363 | &config->border_colors.urgent); | ||
1364 | container_damage_whole(con); | ||
1365 | } | ||
diff --git a/sway/tree/output.c b/sway/tree/output.c index e5794b8a..2704920d 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -65,8 +65,13 @@ void output_enable(struct sway_output *output, struct output_config *oc) { | |||
65 | return; | 65 | return; |
66 | } | 66 | } |
67 | struct wlr_output *wlr_output = output->wlr_output; | 67 | struct wlr_output *wlr_output = output->wlr_output; |
68 | size_t len = sizeof(output->layers) / sizeof(output->layers[0]); | ||
69 | for (size_t i = 0; i < len; ++i) { | ||
70 | wl_list_init(&output->layers[i]); | ||
71 | } | ||
72 | wl_signal_init(&output->events.destroy); | ||
73 | |||
68 | output->enabled = true; | 74 | output->enabled = true; |
69 | apply_output_config(oc, output); | ||
70 | list_add(root->outputs, output); | 75 | list_add(root->outputs, output); |
71 | 76 | ||
72 | output->lx = wlr_output->lx; | 77 | output->lx = wlr_output->lx; |
@@ -92,11 +97,8 @@ void output_enable(struct sway_output *output, struct output_config *oc) { | |||
92 | ipc_event_workspace(NULL, ws, "init"); | 97 | ipc_event_workspace(NULL, ws, "init"); |
93 | } | 98 | } |
94 | 99 | ||
95 | size_t len = sizeof(output->layers) / sizeof(output->layers[0]); | 100 | |
96 | for (size_t i = 0; i < len; ++i) { | 101 | apply_output_config(oc, output); |
97 | wl_list_init(&output->layers[i]); | ||
98 | } | ||
99 | wl_signal_init(&output->events.destroy); | ||
100 | 102 | ||
101 | input_manager_configure_xcursor(); | 103 | input_manager_configure_xcursor(); |
102 | 104 | ||
@@ -274,16 +276,14 @@ struct sway_output *output_from_wlr_output(struct wlr_output *output) { | |||
274 | } | 276 | } |
275 | 277 | ||
276 | struct sway_output *output_get_in_direction(struct sway_output *reference, | 278 | struct sway_output *output_get_in_direction(struct sway_output *reference, |
277 | enum movement_direction direction) { | 279 | enum wlr_direction direction) { |
278 | enum wlr_direction wlr_dir = 0; | 280 | if (!sway_assert(direction, "got invalid direction: %d", direction)) { |
279 | if (!sway_assert(sway_dir_to_wlr(direction, &wlr_dir), | ||
280 | "got invalid direction: %d", direction)) { | ||
281 | return NULL; | 281 | return NULL; |
282 | } | 282 | } |
283 | int lx = reference->wlr_output->lx + reference->width / 2; | 283 | int lx = reference->wlr_output->lx + reference->width / 2; |
284 | int ly = reference->wlr_output->ly + reference->height / 2; | 284 | int ly = reference->wlr_output->ly + reference->height / 2; |
285 | struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output( | 285 | struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output( |
286 | root->output_layout, wlr_dir, reference->wlr_output, lx, ly); | 286 | root->output_layout, direction, reference->wlr_output, lx, ly); |
287 | if (!wlr_adjacent) { | 287 | if (!wlr_adjacent) { |
288 | return NULL; | 288 | return NULL; |
289 | } | 289 | } |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 4bc9e0f3..1aa59e68 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -35,7 +35,6 @@ void view_init(struct sway_view *view, enum sway_view_type type, | |||
35 | view->type = type; | 35 | view->type = type; |
36 | view->impl = impl; | 36 | view->impl = impl; |
37 | view->executed_criteria = create_list(); | 37 | view->executed_criteria = create_list(); |
38 | view->marks = create_list(); | ||
39 | view->allow_request_urgent = true; | 38 | view->allow_request_urgent = true; |
40 | wl_signal_init(&view->events.unmap); | 39 | wl_signal_init(&view->events.unmap); |
41 | } | 40 | } |
@@ -55,13 +54,6 @@ void view_destroy(struct sway_view *view) { | |||
55 | } | 54 | } |
56 | list_free(view->executed_criteria); | 55 | list_free(view->executed_criteria); |
57 | 56 | ||
58 | list_foreach(view->marks, free); | ||
59 | list_free(view->marks); | ||
60 | |||
61 | wlr_texture_destroy(view->marks_focused); | ||
62 | wlr_texture_destroy(view->marks_focused_inactive); | ||
63 | wlr_texture_destroy(view->marks_unfocused); | ||
64 | wlr_texture_destroy(view->marks_urgent); | ||
65 | free(view->title_format); | 57 | free(view->title_format); |
66 | 58 | ||
67 | if (view->impl->destroy) { | 59 | if (view->impl->destroy) { |
@@ -225,21 +217,21 @@ void view_autoconfigure(struct sway_view *view) { | |||
225 | bool no_gaps = config->hide_edge_borders != E_SMART_NO_GAPS | 217 | bool no_gaps = config->hide_edge_borders != E_SMART_NO_GAPS |
226 | || !gaps_to_edge(view); | 218 | || !gaps_to_edge(view); |
227 | 219 | ||
228 | view->border_top = view->border_bottom = true; | 220 | con->border_top = con->border_bottom = true; |
229 | view->border_left = view->border_right = true; | 221 | con->border_left = con->border_right = true; |
230 | if (config->hide_edge_borders == E_BOTH | 222 | if (config->hide_edge_borders == E_BOTH |
231 | || config->hide_edge_borders == E_VERTICAL | 223 | || config->hide_edge_borders == E_VERTICAL |
232 | || (smart && !other_views && no_gaps)) { | 224 | || (smart && !other_views && no_gaps)) { |
233 | view->border_left = con->x - con->current_gaps != ws->x; | 225 | con->border_left = con->x - con->current_gaps != ws->x; |
234 | int right_x = con->x + con->width + con->current_gaps; | 226 | int right_x = con->x + con->width + con->current_gaps; |
235 | view->border_right = right_x != ws->x + ws->width; | 227 | con->border_right = right_x != ws->x + ws->width; |
236 | } | 228 | } |
237 | if (config->hide_edge_borders == E_BOTH | 229 | if (config->hide_edge_borders == E_BOTH |
238 | || config->hide_edge_borders == E_HORIZONTAL | 230 | || config->hide_edge_borders == E_HORIZONTAL |
239 | || (smart && !other_views && no_gaps)) { | 231 | || (smart && !other_views && no_gaps)) { |
240 | view->border_top = con->y - con->current_gaps != ws->y; | 232 | con->border_top = con->y - con->current_gaps != ws->y; |
241 | int bottom_y = con->y + con->height + con->current_gaps; | 233 | int bottom_y = con->y + con->height + con->current_gaps; |
242 | view->border_bottom = bottom_y != ws->y + ws->height; | 234 | con->border_bottom = bottom_y != ws->y + ws->height; |
243 | } | 235 | } |
244 | 236 | ||
245 | double x, y, width, height; | 237 | double x, y, width, height; |
@@ -252,14 +244,14 @@ void view_autoconfigure(struct sway_view *view) { | |||
252 | enum sway_container_layout layout = container_parent_layout(con); | 244 | enum sway_container_layout layout = container_parent_layout(con); |
253 | if (layout == L_TABBED && !container_is_floating(con)) { | 245 | if (layout == L_TABBED && !container_is_floating(con)) { |
254 | y_offset = container_titlebar_height(); | 246 | y_offset = container_titlebar_height(); |
255 | view->border_top = false; | 247 | con->border_top = false; |
256 | } else if (layout == L_STACKED && !container_is_floating(con)) { | 248 | } else if (layout == L_STACKED && !container_is_floating(con)) { |
257 | list_t *siblings = container_get_siblings(con); | 249 | list_t *siblings = container_get_siblings(con); |
258 | y_offset = container_titlebar_height() * siblings->length; | 250 | y_offset = container_titlebar_height() * siblings->length; |
259 | view->border_top = false; | 251 | con->border_top = false; |
260 | } | 252 | } |
261 | 253 | ||
262 | switch (view->border) { | 254 | switch (con->border) { |
263 | case B_CSD: | 255 | case B_CSD: |
264 | case B_NONE: | 256 | case B_NONE: |
265 | x = con->x; | 257 | x = con->x; |
@@ -268,29 +260,29 @@ void view_autoconfigure(struct sway_view *view) { | |||
268 | height = con->height - y_offset; | 260 | height = con->height - y_offset; |
269 | break; | 261 | break; |
270 | case B_PIXEL: | 262 | case B_PIXEL: |
271 | x = con->x + view->border_thickness * view->border_left; | 263 | x = con->x + con->border_thickness * con->border_left; |
272 | y = con->y + view->border_thickness * view->border_top + y_offset; | 264 | y = con->y + con->border_thickness * con->border_top + y_offset; |
273 | width = con->width | 265 | width = con->width |
274 | - view->border_thickness * view->border_left | 266 | - con->border_thickness * con->border_left |
275 | - view->border_thickness * view->border_right; | 267 | - con->border_thickness * con->border_right; |
276 | height = con->height - y_offset | 268 | height = con->height - y_offset |
277 | - view->border_thickness * view->border_top | 269 | - con->border_thickness * con->border_top |
278 | - view->border_thickness * view->border_bottom; | 270 | - con->border_thickness * con->border_bottom; |
279 | break; | 271 | break; |
280 | case B_NORMAL: | 272 | case B_NORMAL: |
281 | // Height is: 1px border + 3px pad + title height + 3px pad + 1px border | 273 | // Height is: 1px border + 3px pad + title height + 3px pad + 1px border |
282 | x = con->x + view->border_thickness * view->border_left; | 274 | x = con->x + con->border_thickness * con->border_left; |
283 | width = con->width | 275 | width = con->width |
284 | - view->border_thickness * view->border_left | 276 | - con->border_thickness * con->border_left |
285 | - view->border_thickness * view->border_right; | 277 | - con->border_thickness * con->border_right; |
286 | if (y_offset) { | 278 | if (y_offset) { |
287 | y = con->y + y_offset; | 279 | y = con->y + y_offset; |
288 | height = con->height - y_offset | 280 | height = con->height - y_offset |
289 | - view->border_thickness * view->border_bottom; | 281 | - con->border_thickness * con->border_bottom; |
290 | } else { | 282 | } else { |
291 | y = con->y + container_titlebar_height(); | 283 | y = con->y + container_titlebar_height(); |
292 | height = con->height - container_titlebar_height() | 284 | height = con->height - container_titlebar_height() |
293 | - view->border_thickness * view->border_bottom; | 285 | - con->border_thickness * con->border_bottom; |
294 | } | 286 | } |
295 | break; | 287 | break; |
296 | } | 288 | } |
@@ -347,13 +339,14 @@ void view_set_csd_from_server(struct sway_view *view, bool enabled) { | |||
347 | 339 | ||
348 | void view_update_csd_from_client(struct sway_view *view, bool enabled) { | 340 | void view_update_csd_from_client(struct sway_view *view, bool enabled) { |
349 | wlr_log(WLR_DEBUG, "View %p updated CSD to %i", view, enabled); | 341 | wlr_log(WLR_DEBUG, "View %p updated CSD to %i", view, enabled); |
350 | if (enabled && view->border != B_CSD) { | 342 | struct sway_container *con = view->container; |
351 | view->saved_border = view->border; | 343 | if (enabled && con && con->border != B_CSD) { |
352 | if (view->container && container_is_floating(view->container)) { | 344 | con->saved_border = con->border; |
353 | view->border = B_CSD; | 345 | if (container_is_floating(con)) { |
346 | con->border = B_CSD; | ||
354 | } | 347 | } |
355 | } else if (!enabled && view->border == B_CSD) { | 348 | } else if (!enabled && con && con->border == B_CSD) { |
356 | view->border = view->saved_border; | 349 | con->border = con->saved_border; |
357 | } | 350 | } |
358 | view->using_csd = enabled; | 351 | view->using_csd = enabled; |
359 | } | 352 | } |
@@ -584,12 +577,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
584 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; | 577 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; |
585 | 578 | ||
586 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { | 579 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { |
587 | view->border = config->floating_border; | 580 | view->container->border = config->floating_border; |
588 | view->border_thickness = config->floating_border_thickness; | 581 | view->container->border_thickness = config->floating_border_thickness; |
589 | container_set_floating(view->container, true); | 582 | container_set_floating(view->container, true); |
590 | } else { | 583 | } else { |
591 | view->border = config->border; | 584 | view->container->border = config->border; |
592 | view->border_thickness = config->border_thickness; | 585 | view->container->border_thickness = config->border_thickness; |
593 | view_set_tiled(view, true); | 586 | view_set_tiled(view, true); |
594 | } | 587 | } |
595 | 588 | ||
@@ -936,153 +929,6 @@ void view_update_title(struct sway_view *view, bool force) { | |||
936 | ipc_event_window(view->container, "title"); | 929 | ipc_event_window(view->container, "title"); |
937 | } | 930 | } |
938 | 931 | ||
939 | static bool find_by_mark_iterator(struct sway_container *con, | ||
940 | void *data) { | ||
941 | char *mark = data; | ||
942 | return con->view && view_has_mark(con->view, mark); | ||
943 | } | ||
944 | |||
945 | struct sway_view *view_find_mark(char *mark) { | ||
946 | struct sway_container *container = root_find_container( | ||
947 | find_by_mark_iterator, mark); | ||
948 | if (!container) { | ||
949 | return NULL; | ||
950 | } | ||
951 | return container->view; | ||
952 | } | ||
953 | |||
954 | bool view_find_and_unmark(char *mark) { | ||
955 | struct sway_container *container = root_find_container( | ||
956 | find_by_mark_iterator, mark); | ||
957 | if (!container) { | ||
958 | return false; | ||
959 | } | ||
960 | struct sway_view *view = container->view; | ||
961 | |||
962 | for (int i = 0; i < view->marks->length; ++i) { | ||
963 | char *view_mark = view->marks->items[i]; | ||
964 | if (strcmp(view_mark, mark) == 0) { | ||
965 | free(view_mark); | ||
966 | list_del(view->marks, i); | ||
967 | view_update_marks_textures(view); | ||
968 | ipc_event_window(container, "mark"); | ||
969 | return true; | ||
970 | } | ||
971 | } | ||
972 | return false; | ||
973 | } | ||
974 | |||
975 | void view_clear_marks(struct sway_view *view) { | ||
976 | list_foreach(view->marks, free); | ||
977 | view->marks->length = 0; | ||
978 | ipc_event_window(view->container, "mark"); | ||
979 | } | ||
980 | |||
981 | bool view_has_mark(struct sway_view *view, char *mark) { | ||
982 | for (int i = 0; i < view->marks->length; ++i) { | ||
983 | char *item = view->marks->items[i]; | ||
984 | if (strcmp(item, mark) == 0) { | ||
985 | return true; | ||
986 | } | ||
987 | } | ||
988 | return false; | ||
989 | } | ||
990 | |||
991 | void view_add_mark(struct sway_view *view, char *mark) { | ||
992 | list_add(view->marks, strdup(mark)); | ||
993 | ipc_event_window(view->container, "mark"); | ||
994 | } | ||
995 | |||
996 | static void update_marks_texture(struct sway_view *view, | ||
997 | struct wlr_texture **texture, struct border_colors *class) { | ||
998 | struct sway_output *output = | ||
999 | container_get_effective_output(view->container); | ||
1000 | if (!output) { | ||
1001 | return; | ||
1002 | } | ||
1003 | if (*texture) { | ||
1004 | wlr_texture_destroy(*texture); | ||
1005 | *texture = NULL; | ||
1006 | } | ||
1007 | if (!view->marks->length) { | ||
1008 | return; | ||
1009 | } | ||
1010 | |||
1011 | size_t len = 0; | ||
1012 | for (int i = 0; i < view->marks->length; ++i) { | ||
1013 | char *mark = view->marks->items[i]; | ||
1014 | if (mark[0] != '_') { | ||
1015 | len += strlen(mark) + 2; | ||
1016 | } | ||
1017 | } | ||
1018 | char *buffer = calloc(len + 1, 1); | ||
1019 | char *part = malloc(len + 1); | ||
1020 | |||
1021 | if (!sway_assert(buffer && part, "Unable to allocate memory")) { | ||
1022 | free(buffer); | ||
1023 | return; | ||
1024 | } | ||
1025 | |||
1026 | for (int i = 0; i < view->marks->length; ++i) { | ||
1027 | char *mark = view->marks->items[i]; | ||
1028 | if (mark[0] != '_') { | ||
1029 | sprintf(part, "[%s]", mark); | ||
1030 | strcat(buffer, part); | ||
1031 | } | ||
1032 | } | ||
1033 | free(part); | ||
1034 | |||
1035 | double scale = output->wlr_output->scale; | ||
1036 | int width = 0; | ||
1037 | int height = view->container->title_height * scale; | ||
1038 | |||
1039 | cairo_t *c = cairo_create(NULL); | ||
1040 | get_text_size(c, config->font, &width, NULL, NULL, scale, false, | ||
1041 | "%s", buffer); | ||
1042 | cairo_destroy(c); | ||
1043 | |||
1044 | cairo_surface_t *surface = cairo_image_surface_create( | ||
1045 | CAIRO_FORMAT_ARGB32, width, height); | ||
1046 | cairo_t *cairo = cairo_create(surface); | ||
1047 | cairo_set_source_rgba(cairo, class->background[0], class->background[1], | ||
1048 | class->background[2], class->background[3]); | ||
1049 | cairo_paint(cairo); | ||
1050 | PangoContext *pango = pango_cairo_create_context(cairo); | ||
1051 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); | ||
1052 | cairo_set_source_rgba(cairo, class->text[0], class->text[1], | ||
1053 | class->text[2], class->text[3]); | ||
1054 | cairo_move_to(cairo, 0, 0); | ||
1055 | |||
1056 | pango_printf(cairo, config->font, scale, false, "%s", buffer); | ||
1057 | |||
1058 | cairo_surface_flush(surface); | ||
1059 | unsigned char *data = cairo_image_surface_get_data(surface); | ||
1060 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); | ||
1061 | struct wlr_renderer *renderer = wlr_backend_get_renderer( | ||
1062 | output->wlr_output->backend); | ||
1063 | *texture = wlr_texture_from_pixels( | ||
1064 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); | ||
1065 | cairo_surface_destroy(surface); | ||
1066 | g_object_unref(pango); | ||
1067 | cairo_destroy(cairo); | ||
1068 | free(buffer); | ||
1069 | } | ||
1070 | |||
1071 | void view_update_marks_textures(struct sway_view *view) { | ||
1072 | if (!config->show_marks) { | ||
1073 | return; | ||
1074 | } | ||
1075 | update_marks_texture(view, &view->marks_focused, | ||
1076 | &config->border_colors.focused); | ||
1077 | update_marks_texture(view, &view->marks_focused_inactive, | ||
1078 | &config->border_colors.focused_inactive); | ||
1079 | update_marks_texture(view, &view->marks_unfocused, | ||
1080 | &config->border_colors.unfocused); | ||
1081 | update_marks_texture(view, &view->marks_urgent, | ||
1082 | &config->border_colors.urgent); | ||
1083 | container_damage_whole(view->container); | ||
1084 | } | ||
1085 | |||
1086 | bool view_is_visible(struct sway_view *view) { | 932 | bool view_is_visible(struct sway_view *view) { |
1087 | if (view->container->node.destroying) { | 933 | if (view->container->node.destroying) { |
1088 | return false; | 934 | return false; |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 27e9ac7a..05cda5c0 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -35,6 +35,10 @@ struct sway_output *workspace_get_initial_output(const char *name) { | |||
35 | struct workspace_config *wsc = workspace_find_config(name); | 35 | struct workspace_config *wsc = workspace_find_config(name); |
36 | if (wsc && wsc->output) { | 36 | if (wsc && wsc->output) { |
37 | struct sway_output *output = output_by_name(wsc->output); | 37 | struct sway_output *output = output_by_name(wsc->output); |
38 | if (!output) { | ||
39 | output = output_by_identifier(wsc->output); | ||
40 | } | ||
41 | |||
38 | if (output) { | 42 | if (output) { |
39 | return output; | 43 | return output; |
40 | } | 44 | } |
@@ -143,7 +147,11 @@ void workspace_consider_destroy(struct sway_workspace *ws) { | |||
143 | static bool workspace_valid_on_output(const char *output_name, | 147 | static bool workspace_valid_on_output(const char *output_name, |
144 | const char *ws_name) { | 148 | const char *ws_name) { |
145 | struct workspace_config *wsc = workspace_find_config(ws_name); | 149 | struct workspace_config *wsc = workspace_find_config(ws_name); |
146 | return !wsc || !wsc->output || strcmp(wsc->output, output_name) == 0; | 150 | char identifier[128]; |
151 | struct sway_output *output = output_by_name(output_name); | ||
152 | output_get_identifier(identifier, sizeof(identifier), output); | ||
153 | |||
154 | return !wsc || !wsc->output || strcmp(wsc->output, output_name) == 0 || strcasecmp(identifier, output_name) == 0; | ||
147 | } | 155 | } |
148 | 156 | ||
149 | static void workspace_name_from_binding(const struct sway_binding * binding, | 157 | static void workspace_name_from_binding(const struct sway_binding * binding, |
diff --git a/swayidle/main.c b/swayidle/main.c index 93f4c94b..7d0f23f4 100644 --- a/swayidle/main.c +++ b/swayidle/main.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | ||
2 | #include <errno.h> | 3 | #include <errno.h> |
3 | #include <getopt.h> | 4 | #include <getopt.h> |
4 | #include <pthread.h> | 5 | #include <pthread.h> |
@@ -25,38 +26,24 @@ | |||
25 | #include <elogind/sd-login.h> | 26 | #include <elogind/sd-login.h> |
26 | #endif | 27 | #endif |
27 | 28 | ||
28 | typedef void (*timer_callback_func)(void *data); | ||
29 | |||
30 | static struct org_kde_kwin_idle *idle_manager = NULL; | 29 | static struct org_kde_kwin_idle *idle_manager = NULL; |
31 | static struct wl_seat *seat = NULL; | 30 | static struct wl_seat *seat = NULL; |
32 | bool debug = false; | ||
33 | 31 | ||
34 | struct swayidle_state { | 32 | struct swayidle_state { |
35 | struct wl_display *display; | 33 | struct wl_display *display; |
36 | struct org_kde_kwin_idle_timeout *idle_timer; | ||
37 | struct org_kde_kwin_idle_timeout *lock_timer; | ||
38 | struct wl_event_loop *event_loop; | 34 | struct wl_event_loop *event_loop; |
39 | list_t *timeout_cmds; | 35 | list_t *timeout_cmds; // struct swayidle_timeout_cmd * |
36 | char *lock_cmd; | ||
40 | } state; | 37 | } state; |
41 | 38 | ||
42 | struct swayidle_cmd { | ||
43 | timer_callback_func callback; | ||
44 | char *param; | ||
45 | }; | ||
46 | |||
47 | struct swayidle_cmd *lock_cmd = NULL; | ||
48 | |||
49 | struct swayidle_timeout_cmd { | 39 | struct swayidle_timeout_cmd { |
50 | uint32_t timeout; | 40 | int timeout, registered_timeout; |
51 | struct swayidle_cmd *idle_cmd; | 41 | struct org_kde_kwin_idle_timeout *idle_timer; |
52 | struct swayidle_cmd *resume_cmd; | 42 | char *idle_cmd; |
43 | char *resume_cmd; | ||
53 | }; | 44 | }; |
54 | 45 | ||
55 | static void cmd_exec(void *data) { | 46 | static void cmd_exec(char *param) { |
56 | if (data == NULL) { | ||
57 | return; | ||
58 | } | ||
59 | char *param = (char *)data; | ||
60 | wlr_log(WLR_DEBUG, "Cmd exec %s", param); | 47 | wlr_log(WLR_DEBUG, "Cmd exec %s", param); |
61 | pid_t pid = fork(); | 48 | pid_t pid = fork(); |
62 | if (pid == 0) { | 49 | if (pid == 0) { |
@@ -82,6 +69,7 @@ static void cmd_exec(void *data) { | |||
82 | #if defined(SWAY_IDLE_HAS_SYSTEMD) || defined(SWAY_IDLE_HAS_ELOGIND) | 69 | #if defined(SWAY_IDLE_HAS_SYSTEMD) || defined(SWAY_IDLE_HAS_ELOGIND) |
83 | static int lock_fd = -1; | 70 | static int lock_fd = -1; |
84 | static int ongoing_fd = -1; | 71 | static int ongoing_fd = -1; |
72 | static struct sd_bus *bus = NULL; | ||
85 | 73 | ||
86 | static int release_lock(void *data) { | 74 | static int release_lock(void *data) { |
87 | wlr_log(WLR_INFO, "Releasing sleep lock %d", ongoing_fd); | 75 | wlr_log(WLR_INFO, "Releasing sleep lock %d", ongoing_fd); |
@@ -92,19 +80,10 @@ static int release_lock(void *data) { | |||
92 | return 0; | 80 | return 0; |
93 | } | 81 | } |
94 | 82 | ||
95 | void acquire_sleep_lock(void) { | 83 | static void acquire_sleep_lock(void) { |
96 | sd_bus_message *msg = NULL; | 84 | sd_bus_message *msg; |
97 | sd_bus_error error = SD_BUS_ERROR_NULL; | 85 | sd_bus_error error; |
98 | struct sd_bus *bus; | 86 | int ret = sd_bus_call_method(bus, "org.freedesktop.login1", |
99 | int ret = sd_bus_default_system(&bus); | ||
100 | |||
101 | if (ret < 0) { | ||
102 | wlr_log(WLR_ERROR, "Failed to open D-Bus connection: %s", | ||
103 | strerror(-ret)); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | ret = sd_bus_call_method(bus, "org.freedesktop.login1", | ||
108 | "/org/freedesktop/login1", | 87 | "/org/freedesktop/login1", |
109 | "org.freedesktop.login1.Manager", "Inhibit", | 88 | "org.freedesktop.login1.Manager", "Inhibit", |
110 | &error, &msg, "ssss", "sleep", "swayidle", | 89 | &error, &msg, "ssss", "sleep", "swayidle", |
@@ -112,14 +91,16 @@ void acquire_sleep_lock(void) { | |||
112 | if (ret < 0) { | 91 | if (ret < 0) { |
113 | wlr_log(WLR_ERROR, "Failed to send Inhibit signal: %s", | 92 | wlr_log(WLR_ERROR, "Failed to send Inhibit signal: %s", |
114 | strerror(-ret)); | 93 | strerror(-ret)); |
115 | } else { | 94 | return; |
116 | ret = sd_bus_message_read(msg, "h", &lock_fd); | 95 | } |
117 | if (ret < 0) { | 96 | |
118 | wlr_log(WLR_ERROR, | 97 | ret = sd_bus_message_read(msg, "h", &lock_fd); |
119 | "Failed to parse D-Bus response for Inhibit: %s", | 98 | if (ret < 0) { |
120 | strerror(-ret)); | 99 | wlr_log(WLR_ERROR, "Failed to parse D-Bus response for Inhibit: %s", |
121 | } | 100 | strerror(-ret)); |
101 | return; | ||
122 | } | 102 | } |
103 | |||
123 | wlr_log(WLR_INFO, "Got sleep lock: %d", lock_fd); | 104 | wlr_log(WLR_INFO, "Got sleep lock: %d", lock_fd); |
124 | } | 105 | } |
125 | 106 | ||
@@ -140,8 +121,8 @@ static int prepare_for_sleep(sd_bus_message *msg, void *userdata, | |||
140 | 121 | ||
141 | ongoing_fd = lock_fd; | 122 | ongoing_fd = lock_fd; |
142 | 123 | ||
143 | if (lock_cmd && lock_cmd->callback) { | 124 | if (state.lock_cmd) { |
144 | lock_cmd->callback(lock_cmd->param); | 125 | cmd_exec(state.lock_cmd); |
145 | } | 126 | } |
146 | 127 | ||
147 | if (ongoing_fd >= 0) { | 128 | if (ongoing_fd >= 0) { |
@@ -149,6 +130,7 @@ static int prepare_for_sleep(sd_bus_message *msg, void *userdata, | |||
149 | wl_event_loop_add_timer(state.event_loop, release_lock, NULL); | 130 | wl_event_loop_add_timer(state.event_loop, release_lock, NULL); |
150 | wl_event_source_timer_update(source, 1000); | 131 | wl_event_source_timer_update(source, 1000); |
151 | } | 132 | } |
133 | |||
152 | wlr_log(WLR_DEBUG, "Prepare for sleep done"); | 134 | wlr_log(WLR_DEBUG, "Prepare for sleep done"); |
153 | return 0; | 135 | return 0; |
154 | } | 136 | } |
@@ -161,9 +143,7 @@ static int dbus_event(int fd, uint32_t mask, void *data) { | |||
161 | return 1; | 143 | return 1; |
162 | } | 144 | } |
163 | 145 | ||
164 | void setup_sleep_listener(void) { | 146 | static void setup_sleep_listener(void) { |
165 | struct sd_bus *bus; | ||
166 | |||
167 | int ret = sd_bus_default_system(&bus); | 147 | int ret = sd_bus_default_system(&bus); |
168 | if (ret < 0) { | 148 | if (ret < 0) { |
169 | wlr_log(WLR_ERROR, "Failed to open D-Bus connection: %s", | 149 | wlr_log(WLR_ERROR, "Failed to open D-Bus connection: %s", |
@@ -203,6 +183,7 @@ static void handle_global(void *data, struct wl_registry *registry, | |||
203 | 183 | ||
204 | static void handle_global_remove(void *data, struct wl_registry *registry, | 184 | static void handle_global_remove(void *data, struct wl_registry *registry, |
205 | uint32_t name) { | 185 | uint32_t name) { |
186 | // Who cares | ||
206 | } | 187 | } |
207 | 188 | ||
208 | static const struct wl_registry_listener registry_listener = { | 189 | static const struct wl_registry_listener registry_listener = { |
@@ -210,19 +191,42 @@ static const struct wl_registry_listener registry_listener = { | |||
210 | .global_remove = handle_global_remove, | 191 | .global_remove = handle_global_remove, |
211 | }; | 192 | }; |
212 | 193 | ||
194 | static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener; | ||
195 | |||
196 | static void register_timeout(struct swayidle_timeout_cmd *cmd, | ||
197 | int timeout) { | ||
198 | if (cmd->idle_timer != NULL) { | ||
199 | org_kde_kwin_idle_timeout_destroy(cmd->idle_timer); | ||
200 | cmd->idle_timer = NULL; | ||
201 | } | ||
202 | if (timeout < 0) { | ||
203 | wlr_log(WLR_DEBUG, "Not registering idle timeout"); | ||
204 | return; | ||
205 | } | ||
206 | wlr_log(WLR_DEBUG, "Register with timeout: %d", timeout); | ||
207 | cmd->idle_timer = | ||
208 | org_kde_kwin_idle_get_idle_timeout(idle_manager, seat, timeout); | ||
209 | org_kde_kwin_idle_timeout_add_listener(cmd->idle_timer, | ||
210 | &idle_timer_listener, cmd); | ||
211 | cmd->registered_timeout = timeout; | ||
212 | } | ||
213 | |||
213 | static void handle_idle(void *data, struct org_kde_kwin_idle_timeout *timer) { | 214 | static void handle_idle(void *data, struct org_kde_kwin_idle_timeout *timer) { |
214 | struct swayidle_timeout_cmd *cmd = data; | 215 | struct swayidle_timeout_cmd *cmd = data; |
215 | wlr_log(WLR_DEBUG, "idle state"); | 216 | wlr_log(WLR_DEBUG, "idle state"); |
216 | if (cmd && cmd->idle_cmd && cmd->idle_cmd->callback) { | 217 | if (cmd->idle_cmd) { |
217 | cmd->idle_cmd->callback(cmd->idle_cmd->param); | 218 | cmd_exec(cmd->idle_cmd); |
218 | } | 219 | } |
219 | } | 220 | } |
220 | 221 | ||
221 | static void handle_resume(void *data, struct org_kde_kwin_idle_timeout *timer) { | 222 | static void handle_resume(void *data, struct org_kde_kwin_idle_timeout *timer) { |
222 | struct swayidle_timeout_cmd *cmd = data; | 223 | struct swayidle_timeout_cmd *cmd = data; |
223 | wlr_log(WLR_DEBUG, "active state"); | 224 | wlr_log(WLR_DEBUG, "active state"); |
224 | if (cmd && cmd->resume_cmd && cmd->resume_cmd->callback) { | 225 | if (cmd->registered_timeout != cmd->timeout) { |
225 | cmd->resume_cmd->callback(cmd->resume_cmd->param); | 226 | register_timeout(cmd, cmd->timeout); |
227 | } | ||
228 | if (cmd->resume_cmd) { | ||
229 | cmd_exec(cmd->resume_cmd); | ||
226 | } | 230 | } |
227 | } | 231 | } |
228 | 232 | ||
@@ -231,20 +235,17 @@ static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = { | |||
231 | .resumed = handle_resume, | 235 | .resumed = handle_resume, |
232 | }; | 236 | }; |
233 | 237 | ||
234 | struct swayidle_cmd *parse_command(int argc, char **argv) { | 238 | static char *parse_command(int argc, char **argv) { |
235 | if (argc < 1) { | 239 | if (argc < 1) { |
236 | wlr_log(WLR_ERROR, "Too few parameters for command in parse_command"); | 240 | wlr_log(WLR_ERROR, "Missing command"); |
237 | return NULL; | 241 | return NULL; |
238 | } | 242 | } |
239 | 243 | ||
240 | struct swayidle_cmd *cmd = calloc(1, sizeof(struct swayidle_cmd)); | ||
241 | wlr_log(WLR_DEBUG, "Command: %s", argv[0]); | 244 | wlr_log(WLR_DEBUG, "Command: %s", argv[0]); |
242 | cmd->callback = cmd_exec; | 245 | return strdup(argv[0]); |
243 | cmd->param = argv[0]; | ||
244 | return cmd; | ||
245 | } | 246 | } |
246 | 247 | ||
247 | int parse_timeout(int argc, char **argv) { | 248 | static int parse_timeout(int argc, char **argv) { |
248 | if (argc < 3) { | 249 | if (argc < 3) { |
249 | wlr_log(WLR_ERROR, "Too few parameters to timeout command. " | 250 | wlr_log(WLR_ERROR, "Too few parameters to timeout command. " |
250 | "Usage: timeout <seconds> <command>"); | 251 | "Usage: timeout <seconds> <command>"); |
@@ -258,9 +259,15 @@ int parse_timeout(int argc, char **argv) { | |||
258 | "numeric value representing seconds", optarg); | 259 | "numeric value representing seconds", optarg); |
259 | exit(-1); | 260 | exit(-1); |
260 | } | 261 | } |
262 | |||
261 | struct swayidle_timeout_cmd *cmd = | 263 | struct swayidle_timeout_cmd *cmd = |
262 | calloc(1, sizeof(struct swayidle_timeout_cmd)); | 264 | calloc(1, sizeof(struct swayidle_timeout_cmd)); |
263 | cmd->timeout = seconds * 1000; | 265 | |
266 | if (seconds > 0) { | ||
267 | cmd->timeout = seconds * 1000; | ||
268 | } else { | ||
269 | cmd->timeout = -1; | ||
270 | } | ||
264 | 271 | ||
265 | wlr_log(WLR_DEBUG, "Register idle timeout at %d ms", cmd->timeout); | 272 | wlr_log(WLR_DEBUG, "Register idle timeout at %d ms", cmd->timeout); |
266 | wlr_log(WLR_DEBUG, "Setup idle"); | 273 | wlr_log(WLR_DEBUG, "Setup idle"); |
@@ -276,27 +283,27 @@ int parse_timeout(int argc, char **argv) { | |||
276 | return result; | 283 | return result; |
277 | } | 284 | } |
278 | 285 | ||
279 | int parse_sleep(int argc, char **argv) { | 286 | static int parse_sleep(int argc, char **argv) { |
280 | if (argc < 2) { | 287 | if (argc < 2) { |
281 | wlr_log(WLR_ERROR, "Too few parameters to before-sleep command. " | 288 | wlr_log(WLR_ERROR, "Too few parameters to before-sleep command. " |
282 | "Usage: before-sleep <command>"); | 289 | "Usage: before-sleep <command>"); |
283 | exit(-1); | 290 | exit(-1); |
284 | } | 291 | } |
285 | 292 | ||
286 | lock_cmd = parse_command(argc - 1, &argv[1]); | 293 | state.lock_cmd = parse_command(argc - 1, &argv[1]); |
287 | if (lock_cmd) { | 294 | if (state.lock_cmd) { |
288 | wlr_log(WLR_DEBUG, "Setup sleep lock: %s", lock_cmd->param); | 295 | wlr_log(WLR_DEBUG, "Setup sleep lock: %s", state.lock_cmd); |
289 | } | 296 | } |
290 | 297 | ||
291 | return 2; | 298 | return 2; |
292 | } | 299 | } |
293 | 300 | ||
301 | static int parse_args(int argc, char *argv[]) { | ||
302 | bool debug = false; | ||
294 | 303 | ||
295 | int parse_args(int argc, char *argv[]) { | ||
296 | int c; | 304 | int c; |
297 | 305 | while ((c = getopt(argc, argv, "hd")) != -1) { | |
298 | while ((c = getopt(argc, argv, "hs:d")) != -1) { | 306 | switch (c) { |
299 | switch(c) { | ||
300 | case 'd': | 307 | case 'd': |
301 | debug = true; | 308 | debug = true; |
302 | break; | 309 | break; |
@@ -311,13 +318,7 @@ int parse_args(int argc, char *argv[]) { | |||
311 | } | 318 | } |
312 | } | 319 | } |
313 | 320 | ||
314 | if (debug) { | 321 | wlr_log_init(debug ? WLR_DEBUG : WLR_INFO, NULL); |
315 | wlr_log_init(WLR_DEBUG, NULL); | ||
316 | wlr_log(WLR_DEBUG, "Loglevel debug"); | ||
317 | } else { | ||
318 | wlr_log_init(WLR_INFO, NULL); | ||
319 | } | ||
320 | |||
321 | 322 | ||
322 | state.timeout_cmds = create_list(); | 323 | state.timeout_cmds = create_list(); |
323 | 324 | ||
@@ -331,24 +332,36 @@ int parse_args(int argc, char *argv[]) { | |||
331 | i += parse_sleep(argc - i, &argv[i]); | 332 | i += parse_sleep(argc - i, &argv[i]); |
332 | } else { | 333 | } else { |
333 | wlr_log(WLR_ERROR, "Unsupported command '%s'", argv[i]); | 334 | wlr_log(WLR_ERROR, "Unsupported command '%s'", argv[i]); |
334 | exit(-1); | 335 | return 1; |
335 | } | 336 | } |
336 | } | 337 | } |
338 | |||
337 | return 0; | 339 | return 0; |
338 | } | 340 | } |
339 | 341 | ||
340 | void sway_terminate(int exit_code) { | 342 | void sway_terminate(int exit_code) { |
341 | if (state.event_loop) { | 343 | wl_display_disconnect(state.display); |
342 | wl_event_loop_destroy(state.event_loop); | 344 | wl_event_loop_destroy(state.event_loop); |
343 | } | ||
344 | if (state.display) { | ||
345 | wl_display_disconnect(state.display); | ||
346 | } | ||
347 | exit(exit_code); | 345 | exit(exit_code); |
348 | } | 346 | } |
349 | 347 | ||
350 | void sig_handler(int signal) { | 348 | static void register_zero_idle_timeout(void *item) { |
351 | sway_terminate(0); | 349 | struct swayidle_timeout_cmd *cmd = item; |
350 | register_timeout(cmd, 0); | ||
351 | } | ||
352 | |||
353 | static int handle_signal(int sig, void *data) { | ||
354 | switch (sig) { | ||
355 | case SIGINT: | ||
356 | case SIGTERM: | ||
357 | sway_terminate(0); | ||
358 | return 0; | ||
359 | case SIGUSR1: | ||
360 | wlr_log(WLR_DEBUG, "Got SIGUSR1"); | ||
361 | list_foreach(state.timeout_cmds, register_zero_idle_timeout); | ||
362 | return 1; | ||
363 | } | ||
364 | assert(false); // not reached | ||
352 | } | 365 | } |
353 | 366 | ||
354 | static int display_event(int fd, uint32_t mask, void *data) { | 367 | static int display_event(int fd, uint32_t mask, void *data) { |
@@ -359,33 +372,26 @@ static int display_event(int fd, uint32_t mask, void *data) { | |||
359 | wlr_log_errno(WLR_ERROR, "wl_display_dispatch failed, exiting"); | 372 | wlr_log_errno(WLR_ERROR, "wl_display_dispatch failed, exiting"); |
360 | sway_terminate(0); | 373 | sway_terminate(0); |
361 | } | 374 | } |
375 | wl_display_flush(state.display); | ||
362 | return 0; | 376 | return 0; |
363 | } | 377 | } |
364 | 378 | ||
365 | void register_idle_timeout(void *item) { | 379 | static void register_idle_timeout(void *item) { |
366 | struct swayidle_timeout_cmd *cmd = item; | 380 | struct swayidle_timeout_cmd *cmd = item; |
367 | if (cmd == NULL || !cmd->timeout) { | 381 | register_timeout(cmd, cmd->timeout); |
368 | wlr_log(WLR_ERROR, "Invalid idle cmd, will not register"); | ||
369 | return; | ||
370 | } | ||
371 | state.idle_timer = | ||
372 | org_kde_kwin_idle_get_idle_timeout(idle_manager, seat, cmd->timeout); | ||
373 | if (state.idle_timer != NULL) { | ||
374 | org_kde_kwin_idle_timeout_add_listener(state.idle_timer, | ||
375 | &idle_timer_listener, cmd); | ||
376 | } else { | ||
377 | wlr_log(WLR_ERROR, "Could not create idle timer"); | ||
378 | } | ||
379 | } | 382 | } |
380 | 383 | ||
381 | int main(int argc, char *argv[]) { | 384 | int main(int argc, char *argv[]) { |
382 | signal(SIGINT, sig_handler); | ||
383 | signal(SIGTERM, sig_handler); | ||
384 | |||
385 | if (parse_args(argc, argv) != 0) { | 385 | if (parse_args(argc, argv) != 0) { |
386 | return -1; | 386 | return -1; |
387 | } | 387 | } |
388 | 388 | ||
389 | state.event_loop = wl_event_loop_create(); | ||
390 | |||
391 | wl_event_loop_add_signal(state.event_loop, SIGINT, handle_signal, NULL); | ||
392 | wl_event_loop_add_signal(state.event_loop, SIGTERM, handle_signal, NULL); | ||
393 | wl_event_loop_add_signal(state.event_loop, SIGUSR1, handle_signal, NULL); | ||
394 | |||
389 | state.display = wl_display_connect(NULL); | 395 | state.display = wl_display_connect(NULL); |
390 | if (state.display == NULL) { | 396 | if (state.display == NULL) { |
391 | wlr_log(WLR_ERROR, "Unable to connect to the compositor. " | 397 | wlr_log(WLR_ERROR, "Unable to connect to the compositor. " |
@@ -397,7 +403,6 @@ int main(int argc, char *argv[]) { | |||
397 | struct wl_registry *registry = wl_display_get_registry(state.display); | 403 | struct wl_registry *registry = wl_display_get_registry(state.display); |
398 | wl_registry_add_listener(registry, ®istry_listener, NULL); | 404 | wl_registry_add_listener(registry, ®istry_listener, NULL); |
399 | wl_display_roundtrip(state.display); | 405 | wl_display_roundtrip(state.display); |
400 | state.event_loop = wl_event_loop_create(); | ||
401 | 406 | ||
402 | if (idle_manager == NULL) { | 407 | if (idle_manager == NULL) { |
403 | wlr_log(WLR_ERROR, "Display doesn't support idle protocol"); | 408 | wlr_log(WLR_ERROR, "Display doesn't support idle protocol"); |
@@ -410,7 +415,7 @@ int main(int argc, char *argv[]) { | |||
410 | 415 | ||
411 | bool should_run = state.timeout_cmds->length > 0; | 416 | bool should_run = state.timeout_cmds->length > 0; |
412 | #if defined(SWAY_IDLE_HAS_SYSTEMD) || defined(SWAY_IDLE_HAS_ELOGIND) | 417 | #if defined(SWAY_IDLE_HAS_SYSTEMD) || defined(SWAY_IDLE_HAS_ELOGIND) |
413 | if (lock_cmd) { | 418 | if (state.lock_cmd) { |
414 | should_run = true; | 419 | should_run = true; |
415 | setup_sleep_listener(); | 420 | setup_sleep_listener(); |
416 | } | 421 | } |
@@ -419,12 +424,15 @@ int main(int argc, char *argv[]) { | |||
419 | wlr_log(WLR_INFO, "No command specified! Nothing to do, will exit"); | 424 | wlr_log(WLR_INFO, "No command specified! Nothing to do, will exit"); |
420 | sway_terminate(0); | 425 | sway_terminate(0); |
421 | } | 426 | } |
427 | |||
422 | list_foreach(state.timeout_cmds, register_idle_timeout); | 428 | list_foreach(state.timeout_cmds, register_idle_timeout); |
423 | 429 | ||
424 | wl_display_roundtrip(state.display); | 430 | wl_display_roundtrip(state.display); |
425 | 431 | ||
426 | wl_event_loop_add_fd(state.event_loop, wl_display_get_fd(state.display), | 432 | struct wl_event_source *source = wl_event_loop_add_fd(state.event_loop, |
427 | WL_EVENT_READABLE, display_event, NULL); | 433 | wl_display_get_fd(state.display), WL_EVENT_READABLE, |
434 | display_event, NULL); | ||
435 | wl_event_source_check(source); | ||
428 | 436 | ||
429 | while (wl_event_loop_dispatch(state.event_loop, -1) != 1) { | 437 | while (wl_event_loop_dispatch(state.event_loop, -1) != 1) { |
430 | // This space intentionally left blank | 438 | // This space intentionally left blank |
diff --git a/swayidle/swayidle.1.scd b/swayidle/swayidle.1.scd index 7c1b138a..3083163f 100644 --- a/swayidle/swayidle.1.scd +++ b/swayidle/swayidle.1.scd | |||
@@ -22,11 +22,13 @@ swayidle listens for idle activity on your Wayland compositor and executes tasks | |||
22 | on various idle-related events. You can specify any number of events at the | 22 | on various idle-related events. You can specify any number of events at the |
23 | command line. | 23 | command line. |
24 | 24 | ||
25 | Sending SIGUSR1 to swayidle will immediately enter idle state. | ||
26 | |||
25 | # EVENTS | 27 | # EVENTS |
26 | 28 | ||
27 | *timeout* <timeout> <timeout command> [resume <resume command>] | 29 | *timeout* <timeout> <timeout command> [resume <resume command>] |
28 | Execute _timeout command_ if there is no activity for <timeout> seconds. | 30 | Execute _timeout command_ if there is no activity for <timeout> seconds. |
29 | 31 | ||
30 | If you specify "resume <resume command>", _resume command_ will be run when | 32 | If you specify "resume <resume command>", _resume command_ will be run when |
31 | there is activity again. | 33 | there is activity again. |
32 | 34 | ||
@@ -39,11 +41,11 @@ All commands are executed in a shell. | |||
39 | # EXAMPLE | 41 | # EXAMPLE |
40 | 42 | ||
41 | ``` | 43 | ``` |
42 | swayidle \ | 44 | swayidle \ |
43 | timeout 300 'swaylock -c 000000' \ | 45 | timeout 300 'swaylock -c 000000' \ |
44 | timeout 600 'swaymsg "output * dpms off"' \ | 46 | timeout 600 'swaymsg "output * dpms off"' \ |
45 | resume 'swaymsg "output * dpms on"' \ | 47 | resume 'swaymsg "output * dpms on"' \ |
46 | before-sleep 'swaylock -c 000000' | 48 | before-sleep 'swaylock -c 000000' |
47 | ``` | 49 | ``` |
48 | 50 | ||
49 | This will lock your screen after 300 seconds of inactivity, then turn off your | 51 | This will lock your screen after 300 seconds of inactivity, then turn off your |
@@ -58,4 +60,4 @@ https://github.com/swaywm/sway. | |||
58 | 60 | ||
59 | # SEE ALSO | 61 | # SEE ALSO |
60 | 62 | ||
61 | *sway*(5) *swaymsg*(1) *sway-input*(5) *sway-bar*(5) | 63 | *sway*(5) *swaymsg*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) |
diff --git a/swaylock/swaylock.1.scd b/swaylock/swaylock.1.scd index 3107124f..8ddc7d3a 100644 --- a/swaylock/swaylock.1.scd +++ b/swaylock/swaylock.1.scd | |||
@@ -21,20 +21,25 @@ Locks your Wayland session. | |||
21 | All leading dashes should be omitted and the equals sign is required for | 21 | All leading dashes should be omitted and the equals sign is required for |
22 | flags that take an argument. | 22 | flags that take an argument. |
23 | 23 | ||
24 | *-c, --color* <rrggbb[aa]> | ||
25 | Turn the screen into the given color. If -i is used, this sets the | ||
26 | background of the image to the given color. Defaults to white (FFFFFF), or | ||
27 | transparent (00000000) if an image is in use. | ||
28 | |||
29 | *-e, --ignore-empty-password* | 24 | *-e, --ignore-empty-password* |
30 | When an empty password is provided by the user, do not validate it. | 25 | When an empty password is provided by the user, do not validate it. |
31 | 26 | ||
32 | *-f, --daemonize* | 27 | *-f, --daemonize* |
33 | Detach from the controlling terminal after locking. | 28 | Detach from the controlling terminal after locking. |
34 | 29 | ||
30 | Note: this is the default bahavior of i3lock. | ||
31 | |||
35 | *-h, --help* | 32 | *-h, --help* |
36 | Show help message and quit. | 33 | Show help message and quit. |
37 | 34 | ||
35 | *-v, --version* | ||
36 | Show the version number and quit. | ||
37 | |||
38 | # APPEARANCE | ||
39 | |||
40 | *-u, --no-unlock-indicator* | ||
41 | Disable the unlock indicator. | ||
42 | |||
38 | *-i, --image* [<output>:]<path> | 43 | *-i, --image* [<output>:]<path> |
39 | Display the given image, optionally only on the given output. Use -c to set | 44 | Display the given image, optionally only on the given output. Use -c to set |
40 | a background color. | 45 | a background color. |
@@ -45,13 +50,10 @@ Locks your Wayland session. | |||
45 | *-t, --tiling* | 50 | *-t, --tiling* |
46 | Same as --scaling=tile. | 51 | Same as --scaling=tile. |
47 | 52 | ||
48 | *-u, --no-unlock-indicator* | 53 | *-c, --color* <rrggbb[aa]> |
49 | Disable the unlock indicator. | 54 | Turn the screen into the given color. If -i is used, this sets the |
50 | 55 | background of the image to the given color. Defaults to white (FFFFFF), or | |
51 | *-v, --version* | 56 | transparent (00000000) if an image is in use. |
52 | Show the version number and quit. | ||
53 | |||
54 | # APPEARANCE | ||
55 | 57 | ||
56 | *--bs-hl-color* <rrggbb[aa]> | 58 | *--bs-hl-color* <rrggbb[aa]> |
57 | Sets the color of backspace highlight segments. | 59 | Sets the color of backspace highlight segments. |
diff --git a/swaymsg/main.c b/swaymsg/main.c index 4688737c..e13dd7ec 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c | |||
@@ -23,7 +23,7 @@ static bool success_object(json_object *result) { | |||
23 | json_object *success; | 23 | json_object *success; |
24 | 24 | ||
25 | if (!json_object_object_get_ex(result, "success", &success)) { | 25 | if (!json_object_object_get_ex(result, "success", &success)) { |
26 | return false; | 26 | return true; |
27 | } | 27 | } |
28 | 28 | ||
29 | return json_object_get_boolean(success); | 29 | return json_object_get_boolean(success); |
@@ -183,13 +183,15 @@ static void pretty_print_output(json_object *o) { | |||
183 | json_object_object_get_ex(rect, "height", &height); | 183 | json_object_object_get_ex(rect, "height", &height); |
184 | json_object *modes; | 184 | json_object *modes; |
185 | json_object_object_get_ex(o, "modes", &modes); | 185 | json_object_object_get_ex(o, "modes", &modes); |
186 | json_object *current_mode; | ||
187 | json_object_object_get_ex(o, "current_mode", ¤t_mode); | ||
186 | 188 | ||
187 | if (json_object_get_boolean(active)) { | 189 | if (json_object_get_boolean(active)) { |
188 | printf( | 190 | printf( |
189 | "Output %s '%s %s %s'%s\n" | 191 | "Output %s '%s %s %s'%s\n" |
190 | " Current mode: %dx%d @ %f Hz\n" | 192 | " Current mode: %dx%d @ %f Hz\n" |
191 | " Position: %d,%d\n" | 193 | " Position: %d,%d\n" |
192 | " Scale factor: %dx\n" | 194 | " Scale factor: %f\n" |
193 | " Transform: %s\n" | 195 | " Transform: %s\n" |
194 | " Workspace: %s\n", | 196 | " Workspace: %s\n", |
195 | json_object_get_string(name), | 197 | json_object_get_string(name), |
@@ -197,10 +199,13 @@ static void pretty_print_output(json_object *o) { | |||
197 | json_object_get_string(model), | 199 | json_object_get_string(model), |
198 | json_object_get_string(serial), | 200 | json_object_get_string(serial), |
199 | json_object_get_boolean(focused) ? " (focused)" : "", | 201 | json_object_get_boolean(focused) ? " (focused)" : "", |
200 | json_object_get_int(width), json_object_get_int(height), | 202 | json_object_get_int( |
203 | json_object_object_get(current_mode, "width")), | ||
204 | json_object_get_int( | ||
205 | json_object_object_get(current_mode, "height")), | ||
201 | (float)json_object_get_int(refresh) / 1000, | 206 | (float)json_object_get_int(refresh) / 1000, |
202 | json_object_get_int(x), json_object_get_int(y), | 207 | json_object_get_int(x), json_object_get_int(y), |
203 | json_object_get_int(scale), | 208 | json_object_get_double(scale), |
204 | json_object_get_string(transform), | 209 | json_object_get_string(transform), |
205 | json_object_get_string(ws) | 210 | json_object_get_string(ws) |
206 | ); | 211 | ); |