diff options
-rw-r--r-- | include/sway/container.h | 2 | ||||
-rw-r--r-- | include/sway/layout.h | 1 | ||||
-rw-r--r-- | include/sway/output.h | 1 | ||||
-rw-r--r-- | include/sway/view.h | 2 | ||||
-rw-r--r-- | sway/desktop/output.c | 15 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 20 | ||||
-rw-r--r-- | sway/tree/container.c | 13 | ||||
-rw-r--r-- | sway/tree/layout.c | 205 |
8 files changed, 253 insertions, 6 deletions
diff --git a/include/sway/container.h b/include/sway/container.h index 96e4db69..1a173f3e 100644 --- a/include/sway/container.h +++ b/include/sway/container.h | |||
@@ -132,4 +132,6 @@ swayc_t *new_output(struct sway_output *sway_output); | |||
132 | swayc_t *new_workspace(swayc_t *output, const char *name); | 132 | swayc_t *new_workspace(swayc_t *output, const char *name); |
133 | swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view); | 133 | swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view); |
134 | 134 | ||
135 | swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); | ||
136 | |||
135 | #endif | 137 | #endif |
diff --git a/include/sway/layout.h b/include/sway/layout.h index 6356ad00..505036a0 100644 --- a/include/sway/layout.h +++ b/include/sway/layout.h | |||
@@ -7,5 +7,6 @@ void init_layout(void); | |||
7 | void add_child(struct sway_container *parent, struct sway_container *child); | 7 | void add_child(struct sway_container *parent, struct sway_container *child); |
8 | enum swayc_layouts default_layout(struct sway_container *output); | 8 | enum swayc_layouts default_layout(struct sway_container *output); |
9 | void sort_workspaces(struct sway_container *output); | 9 | void sort_workspaces(struct sway_container *output); |
10 | void arrange_windows(struct sway_container *container, double width, double height); | ||
10 | 11 | ||
11 | #endif | 12 | #endif |
diff --git a/include/sway/output.h b/include/sway/output.h index e2f81bcb..895cb07d 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -13,6 +13,7 @@ struct sway_output { | |||
13 | struct sway_server *server; | 13 | struct sway_server *server; |
14 | struct timespec last_frame; | 14 | struct timespec last_frame; |
15 | struct wl_listener frame; | 15 | struct wl_listener frame; |
16 | struct wl_listener resolution; | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | #endif | 19 | #endif |
diff --git a/include/sway/view.h b/include/sway/view.h index 2675a6f5..9d503674 100644 --- a/include/sway/view.h +++ b/include/sway/view.h | |||
@@ -52,6 +52,8 @@ struct sway_view { | |||
52 | struct { | 52 | struct { |
53 | const char *(*get_prop)(struct sway_view *view, | 53 | const char *(*get_prop)(struct sway_view *view, |
54 | enum sway_view_prop prop); | 54 | enum sway_view_prop prop); |
55 | void (*set_dimensions)(struct sway_view *view, | ||
56 | int width, int height); | ||
55 | } iface; | 57 | } iface; |
56 | }; | 58 | }; |
57 | 59 | ||
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 9e0c18e4..033a4c44 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <wlr/render/matrix.h> | 8 | #include <wlr/render/matrix.h> |
9 | #include "log.h" | 9 | #include "log.h" |
10 | #include "sway/container.h" | 10 | #include "sway/container.h" |
11 | #include "sway/layout.h" | ||
11 | #include "sway/output.h" | 12 | #include "sway/output.h" |
12 | #include "sway/server.h" | 13 | #include "sway/server.h" |
13 | #include "sway/view.h" | 14 | #include "sway/view.h" |
@@ -25,10 +26,9 @@ static void output_frame_view(swayc_t *view, void *data) { | |||
25 | return; | 26 | return; |
26 | } | 27 | } |
27 | // TODO | 28 | // TODO |
28 | // - Force sway's resolution | ||
29 | // - Deal with wlr_output_layout | 29 | // - Deal with wlr_output_layout |
30 | int width = surface->current->width; | 30 | int width = sway_view->swayc->width; |
31 | int height = surface->current->height; | 31 | int height = sway_view->swayc->height; |
32 | int render_width = width * wlr_output->scale; | 32 | int render_width = width * wlr_output->scale; |
33 | int render_height = height * wlr_output->scale; | 33 | int render_height = height * wlr_output->scale; |
34 | double ox = view->x, oy = view->y; | 34 | double ox = view->x, oy = view->y; |
@@ -101,6 +101,12 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { | |||
101 | soutput->last_frame = now; | 101 | soutput->last_frame = now; |
102 | } | 102 | } |
103 | 103 | ||
104 | static void output_resolution_notify(struct wl_listener *listener, void *data) { | ||
105 | struct sway_output *soutput = wl_container_of( | ||
106 | listener, soutput, resolution); | ||
107 | arrange_windows(soutput->swayc, -1, -1); | ||
108 | } | ||
109 | |||
104 | void output_add_notify(struct wl_listener *listener, void *data) { | 110 | void output_add_notify(struct wl_listener *listener, void *data) { |
105 | struct sway_server *server = wl_container_of(listener, server, output_add); | 111 | struct sway_server *server = wl_container_of(listener, server, output_add); |
106 | struct wlr_output *wlr_output = data; | 112 | struct wlr_output *wlr_output = data; |
@@ -113,6 +119,9 @@ void output_add_notify(struct wl_listener *listener, void *data) { | |||
113 | 119 | ||
114 | output->frame.notify = output_frame_notify; | 120 | output->frame.notify = output_frame_notify; |
115 | wl_signal_add(&wlr_output->events.frame, &output->frame); | 121 | wl_signal_add(&wlr_output->events.frame, &output->frame); |
122 | |||
123 | output->resolution.notify = output_resolution_notify; | ||
124 | wl_signal_add(&wlr_output->events.resolution, &output->resolution); | ||
116 | } | 125 | } |
117 | 126 | ||
118 | void output_remove_notify(struct wl_listener *listener, void *data) { | 127 | void output_remove_notify(struct wl_listener *listener, void *data) { |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index e2a61ebf..8f1885c1 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -1,15 +1,21 @@ | |||
1 | #define _POSIX_C_SOURCE 199309L | 1 | #define _POSIX_C_SOURCE 199309L |
2 | #include <stdbool.h> | ||
2 | #include <stdlib.h> | 3 | #include <stdlib.h> |
3 | #include <wayland-server.h> | 4 | #include <wayland-server.h> |
4 | #include <wlr/types/wlr_xdg_shell_v6.h> | 5 | #include <wlr/types/wlr_xdg_shell_v6.h> |
5 | #include "sway/container.h" | 6 | #include "sway/container.h" |
7 | #include "sway/layout.h" | ||
6 | #include "sway/server.h" | 8 | #include "sway/server.h" |
7 | #include "sway/view.h" | 9 | #include "sway/view.h" |
8 | #include "log.h" | 10 | #include "log.h" |
9 | 11 | ||
12 | static bool assert_xdg(struct sway_view *view) { | ||
13 | return sway_assert(view->type == SWAY_XDG_SHELL_V6_VIEW, | ||
14 | "Expected xdg shell v6 view!"); | ||
15 | } | ||
16 | |||
10 | static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { | 17 | static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { |
11 | if (!sway_assert(view->type == SWAY_XDG_SHELL_V6_VIEW, | 18 | if (!assert_xdg(view)) { |
12 | "xdg get_prop for non-xdg view!")) { | ||
13 | return NULL; | 19 | return NULL; |
14 | } | 20 | } |
15 | switch (prop) { | 21 | switch (prop) { |
@@ -22,6 +28,12 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { | |||
22 | } | 28 | } |
23 | } | 29 | } |
24 | 30 | ||
31 | static void set_dimensions(struct sway_view *view, int width, int height) { | ||
32 | if (assert_xdg(view)) { | ||
33 | wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height); | ||
34 | } | ||
35 | } | ||
36 | |||
25 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | 37 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { |
26 | struct sway_server *server = wl_container_of( | 38 | struct sway_server *server = wl_container_of( |
27 | listener, server, xdg_shell_v6_surface); | 39 | listener, server, xdg_shell_v6_surface); |
@@ -48,13 +60,13 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | |||
48 | } | 60 | } |
49 | sway_view->type = SWAY_XDG_SHELL_V6_VIEW; | 61 | sway_view->type = SWAY_XDG_SHELL_V6_VIEW; |
50 | sway_view->iface.get_prop = get_prop; | 62 | sway_view->iface.get_prop = get_prop; |
63 | sway_view->iface.set_dimensions = set_dimensions; | ||
51 | sway_view->wlr_xdg_surface_v6 = xdg_surface; | 64 | sway_view->wlr_xdg_surface_v6 = xdg_surface; |
52 | sway_view->sway_xdg_surface_v6 = sway_surface; | 65 | sway_view->sway_xdg_surface_v6 = sway_surface; |
53 | sway_view->surface = xdg_surface->surface; | 66 | sway_view->surface = xdg_surface->surface; |
54 | sway_surface->view = sway_view; | 67 | sway_surface->view = sway_view; |
55 | 68 | ||
56 | // TODO: | 69 | // TODO: |
57 | // - Add to tree | ||
58 | // - Wire up listeners | 70 | // - Wire up listeners |
59 | // - Handle popups | 71 | // - Handle popups |
60 | // - Look up pid and open on appropriate workspace | 72 | // - Look up pid and open on appropriate workspace |
@@ -67,4 +79,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | |||
67 | 79 | ||
68 | swayc_t *cont = new_view(parent, sway_view); | 80 | swayc_t *cont = new_view(parent, sway_view); |
69 | sway_view->swayc = cont; | 81 | sway_view->swayc = cont; |
82 | |||
83 | arrange_windows(cont->parent, -1, -1); | ||
70 | } | 84 | } |
diff --git a/sway/tree/container.c b/sway/tree/container.c index d3931612..a83c0f6b 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -108,3 +108,16 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) { | |||
108 | } | 108 | } |
109 | return swayc; | 109 | return swayc; |
110 | } | 110 | } |
111 | |||
112 | swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { | ||
113 | if (!sway_assert(container, "container is NULL")) { | ||
114 | return NULL; | ||
115 | } | ||
116 | if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) { | ||
117 | return NULL; | ||
118 | } | ||
119 | do { | ||
120 | container = container->parent; | ||
121 | } while (container && container->type != type); | ||
122 | return container; | ||
123 | } | ||
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 5a70c570..3d6b404d 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -1,10 +1,14 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <math.h> | ||
3 | #include <stdbool.h> | 4 | #include <stdbool.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <string.h> | 6 | #include <string.h> |
7 | #include <wlr/types/wlr_output.h> | ||
6 | #include <wlr/types/wlr_output_layout.h> | 8 | #include <wlr/types/wlr_output_layout.h> |
7 | #include "sway/container.h" | 9 | #include "sway/container.h" |
10 | #include "sway/output.h" | ||
11 | #include "sway/view.h" | ||
8 | #include "list.h" | 12 | #include "list.h" |
9 | #include "log.h" | 13 | #include "log.h" |
10 | 14 | ||
@@ -70,3 +74,204 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | |||
70 | void sort_workspaces(swayc_t *output) { | 74 | void sort_workspaces(swayc_t *output) { |
71 | list_stable_sort(output->children, sort_workspace_cmp_qsort); | 75 | list_stable_sort(output->children, sort_workspace_cmp_qsort); |
72 | } | 76 | } |
77 | |||
78 | static void apply_horiz_layout(swayc_t *container, const double x, | ||
79 | const double y, const double width, | ||
80 | const double height, const int start, | ||
81 | const int end); | ||
82 | |||
83 | static void apply_vert_layout(swayc_t *container, const double x, | ||
84 | const double y, const double width, | ||
85 | const double height, const int start, | ||
86 | const int end); | ||
87 | |||
88 | void arrange_windows(swayc_t *container, double width, double height) { | ||
89 | int i; | ||
90 | if (width == -1 || height == -1) { | ||
91 | width = container->width; | ||
92 | height = container->height; | ||
93 | } | ||
94 | // pixels are indivisible. if we don't round the pixels, then the view | ||
95 | // calculations will be off (e.g. 50.5 + 50.5 = 101, but in reality it's | ||
96 | // 50 + 50 = 100). doing it here cascades properly to all width/height/x/y. | ||
97 | width = floor(width); | ||
98 | height = floor(height); | ||
99 | |||
100 | sway_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, | ||
101 | container->name, container->width, container->height, container->x, | ||
102 | container->y); | ||
103 | |||
104 | double x = 0, y = 0; | ||
105 | switch (container->type) { | ||
106 | case C_ROOT: | ||
107 | // TODO: wlr_output_layout probably | ||
108 | for (i = 0; i < container->children->length; ++i) { | ||
109 | swayc_t *output = container->children->items[i]; | ||
110 | sway_log(L_DEBUG, "Arranging output '%s' at %f,%f", | ||
111 | output->name, output->x, output->y); | ||
112 | arrange_windows(output, -1, -1); | ||
113 | } | ||
114 | return; | ||
115 | case C_OUTPUT: | ||
116 | { | ||
117 | int _width, _height; | ||
118 | wlr_output_effective_resolution( | ||
119 | container->sway_output->wlr_output, &_width, &_height); | ||
120 | width = container->width = _width; | ||
121 | height = container->height = _height; | ||
122 | } | ||
123 | // arrange all workspaces: | ||
124 | for (i = 0; i < container->children->length; ++i) { | ||
125 | swayc_t *child = container->children->items[i]; | ||
126 | arrange_windows(child, -1, -1); | ||
127 | } | ||
128 | return; | ||
129 | case C_WORKSPACE: | ||
130 | { | ||
131 | swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); | ||
132 | width = output->width, height = output->height; | ||
133 | container->x = x; | ||
134 | container->y = y; | ||
135 | width = container->width; | ||
136 | height = container->height; | ||
137 | sway_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", | ||
138 | container->name, container->x, container->y); | ||
139 | } | ||
140 | // children are properly handled below | ||
141 | break; | ||
142 | case C_VIEW: | ||
143 | { | ||
144 | container->width = width; | ||
145 | container->height = height; | ||
146 | container->sway_view->iface.set_dimensions(container->sway_view, | ||
147 | container->width, container->height); | ||
148 | sway_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", | ||
149 | container->width, container->height, | ||
150 | container->x, container->y); | ||
151 | } | ||
152 | return; | ||
153 | default: | ||
154 | container->width = width; | ||
155 | container->height = height; | ||
156 | x = container->x; | ||
157 | y = container->y; | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | switch (container->layout) { | ||
162 | case L_HORIZ: | ||
163 | apply_horiz_layout(container, x, y, width, height, 0, | ||
164 | container->children->length); | ||
165 | break; | ||
166 | case L_VERT: | ||
167 | apply_vert_layout(container, x, y, width, height, 0, | ||
168 | container->children->length); | ||
169 | break; | ||
170 | default: | ||
171 | sway_log(L_DEBUG, "TODO: arrange layout type %d", container->layout); | ||
172 | apply_horiz_layout(container, x, y, width, height, 0, | ||
173 | container->children->length); | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | static void apply_horiz_layout(swayc_t *container, | ||
179 | const double x, const double y, | ||
180 | const double width, const double height, | ||
181 | const int start, const int end) { | ||
182 | double scale = 0; | ||
183 | // Calculate total width | ||
184 | for (int i = start; i < end; ++i) { | ||
185 | double *old_width = &((swayc_t *)container->children->items[i])->width; | ||
186 | if (*old_width <= 0) { | ||
187 | if (end - start > 1) { | ||
188 | *old_width = width / (end - start - 1); | ||
189 | } else { | ||
190 | *old_width = width; | ||
191 | } | ||
192 | } | ||
193 | scale += *old_width; | ||
194 | } | ||
195 | scale = width / scale; | ||
196 | |||
197 | // Resize windows | ||
198 | double child_x = x; | ||
199 | if (scale > 0.1) { | ||
200 | sway_log(L_DEBUG, "Arranging %p horizontally", container); | ||
201 | for (int i = start; i < end; ++i) { | ||
202 | swayc_t *child = container->children->items[i]; | ||
203 | sway_log(L_DEBUG, | ||
204 | "Calculating arrangement for %p:%d (will scale %f by %f)", | ||
205 | child, child->type, width, scale); | ||
206 | child->x = child_x; | ||
207 | child->y = y; | ||
208 | |||
209 | if (i == end - 1) { | ||
210 | double remaining_width = x + width - child_x; | ||
211 | arrange_windows(child, remaining_width, height); | ||
212 | } else { | ||
213 | arrange_windows(child, child->width * scale, height); | ||
214 | } | ||
215 | child_x += child->width; | ||
216 | } | ||
217 | |||
218 | // update focused view border last because it may | ||
219 | // depend on the title bar geometry of its siblings. | ||
220 | /* TODO WLR | ||
221 | if (focused && container->children->length > 1) { | ||
222 | update_container_border(focused); | ||
223 | } | ||
224 | */ | ||
225 | } | ||
226 | } | ||
227 | |||
228 | void apply_vert_layout(swayc_t *container, | ||
229 | const double x, const double y, | ||
230 | const double width, const double height, const int start, | ||
231 | const int end) { | ||
232 | int i; | ||
233 | double scale = 0; | ||
234 | // Calculate total height | ||
235 | for (i = start; i < end; ++i) { | ||
236 | double *old_height = &((swayc_t *)container->children->items[i])->height; | ||
237 | if (*old_height <= 0) { | ||
238 | if (end - start > 1) { | ||
239 | *old_height = height / (end - start - 1); | ||
240 | } else { | ||
241 | *old_height = height; | ||
242 | } | ||
243 | } | ||
244 | scale += *old_height; | ||
245 | } | ||
246 | scale = height / scale; | ||
247 | |||
248 | // Resize | ||
249 | double child_y = y; | ||
250 | if (scale > 0.1) { | ||
251 | sway_log(L_DEBUG, "Arranging %p vertically", container); | ||
252 | for (i = start; i < end; ++i) { | ||
253 | swayc_t *child = container->children->items[i]; | ||
254 | sway_log(L_DEBUG, | ||
255 | "Calculating arrangement for %p:%d (will scale %f by %f)", | ||
256 | child, child->type, height, scale); | ||
257 | child->x = x; | ||
258 | child->y = child_y; | ||
259 | |||
260 | if (i == end - 1) { | ||
261 | double remaining_height = y + height - child_y; | ||
262 | arrange_windows(child, width, remaining_height); | ||
263 | } else { | ||
264 | arrange_windows(child, width, child->height * scale); | ||
265 | } | ||
266 | child_y += child->height; | ||
267 | } | ||
268 | |||
269 | // update focused view border last because it may | ||
270 | // depend on the title bar geometry of its siblings. | ||
271 | /* TODO WLR | ||
272 | if (focused && container->children->length > 1) { | ||
273 | update_container_border(focused); | ||
274 | } | ||
275 | */ | ||
276 | } | ||
277 | } | ||