diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-04-12 20:19:54 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-04-12 20:19:54 -0400 |
commit | cd1b32453a9296c18b28bff71607aeb22987b5cd (patch) | |
tree | c653c6d525b471914c01a9d7ae543f521b6138ed /sway/tree/view.c | |
parent | Merge pull request #1634 from aleksander/master (diff) | |
parent | Fix separator height calculation (diff) | |
download | sway-cd1b32453a9296c18b28bff71607aeb22987b5cd.tar.gz sway-cd1b32453a9296c18b28bff71607aeb22987b5cd.tar.zst sway-cd1b32453a9296c18b28bff71607aeb22987b5cd.zip |
Merge branch 'wlroots'
Diffstat (limited to 'sway/tree/view.c')
-rw-r--r-- | sway/tree/view.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/sway/tree/view.c b/sway/tree/view.c new file mode 100644 index 00000000..99b44720 --- /dev/null +++ b/sway/tree/view.c | |||
@@ -0,0 +1,329 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <wayland-server.h> | ||
3 | #include <wlr/types/wlr_output_layout.h> | ||
4 | #include "log.h" | ||
5 | #include "sway/output.h" | ||
6 | #include "sway/tree/container.h" | ||
7 | #include "sway/tree/layout.h" | ||
8 | #include "sway/tree/view.h" | ||
9 | |||
10 | void view_init(struct sway_view *view, enum sway_view_type type, | ||
11 | const struct sway_view_impl *impl) { | ||
12 | view->type = type; | ||
13 | view->impl = impl; | ||
14 | wl_signal_init(&view->events.unmap); | ||
15 | } | ||
16 | |||
17 | void view_destroy(struct sway_view *view) { | ||
18 | if (view == NULL) { | ||
19 | return; | ||
20 | } | ||
21 | |||
22 | if (view->surface != NULL) { | ||
23 | view_unmap(view); | ||
24 | } | ||
25 | |||
26 | container_destroy(view->swayc); | ||
27 | |||
28 | if (view->impl->destroy) { | ||
29 | view->impl->destroy(view); | ||
30 | } else { | ||
31 | free(view); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | const char *view_get_title(struct sway_view *view) { | ||
36 | if (view->impl->get_prop) { | ||
37 | return view->impl->get_prop(view, VIEW_PROP_TITLE); | ||
38 | } | ||
39 | return NULL; | ||
40 | } | ||
41 | |||
42 | const char *view_get_app_id(struct sway_view *view) { | ||
43 | if (view->impl->get_prop) { | ||
44 | return view->impl->get_prop(view, VIEW_PROP_APP_ID); | ||
45 | } | ||
46 | return NULL; | ||
47 | } | ||
48 | |||
49 | const char *view_get_class(struct sway_view *view) { | ||
50 | if (view->impl->get_prop) { | ||
51 | return view->impl->get_prop(view, VIEW_PROP_CLASS); | ||
52 | } | ||
53 | return NULL; | ||
54 | } | ||
55 | |||
56 | const char *view_get_instance(struct sway_view *view) { | ||
57 | if (view->impl->get_prop) { | ||
58 | return view->impl->get_prop(view, VIEW_PROP_INSTANCE); | ||
59 | } | ||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | void view_configure(struct sway_view *view, double ox, double oy, int width, | ||
64 | int height) { | ||
65 | if (view->impl->configure) { | ||
66 | view->impl->configure(view, ox, oy, width, height); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | void view_set_activated(struct sway_view *view, bool activated) { | ||
71 | if (view->impl->set_activated) { | ||
72 | view->impl->set_activated(view, activated); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | void view_close(struct sway_view *view) { | ||
77 | if (view->impl->close) { | ||
78 | view->impl->close(view); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | void view_damage(struct sway_view *view, bool whole) { | ||
83 | for (int i = 0; i < root_container.children->length; ++i) { | ||
84 | struct sway_container *cont = root_container.children->items[i]; | ||
85 | if (cont->type == C_OUTPUT) { | ||
86 | output_damage_view(cont->sway_output, view, whole); | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { | ||
92 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | ||
93 | |||
94 | box->x = output->x + view->swayc->x; | ||
95 | box->y = output->y + view->swayc->y; | ||
96 | box->width = view->width; | ||
97 | box->height = view->height; | ||
98 | } | ||
99 | |||
100 | void view_for_each_surface(struct sway_view *view, | ||
101 | wlr_surface_iterator_func_t iterator, void *user_data) { | ||
102 | if (view->impl->for_each_surface) { | ||
103 | view->impl->for_each_surface(view, iterator, user_data); | ||
104 | } else { | ||
105 | wlr_surface_for_each_surface(view->surface, iterator, user_data); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static void view_subsurface_create(struct sway_view *view, | ||
110 | struct wlr_subsurface *subsurface); | ||
111 | |||
112 | static void view_init_subsurfaces(struct sway_view *view, | ||
113 | struct wlr_surface *surface); | ||
114 | |||
115 | static void view_handle_surface_new_subsurface(struct wl_listener *listener, | ||
116 | void *data) { | ||
117 | struct sway_view *view = | ||
118 | wl_container_of(listener, view, surface_new_subsurface); | ||
119 | struct wlr_subsurface *subsurface = data; | ||
120 | view_subsurface_create(view, subsurface); | ||
121 | } | ||
122 | |||
123 | static void surface_send_enter_iterator(struct wlr_surface *surface, | ||
124 | int x, int y, void *data) { | ||
125 | struct wlr_output *wlr_output = data; | ||
126 | wlr_surface_send_enter(surface, wlr_output); | ||
127 | } | ||
128 | |||
129 | static void surface_send_leave_iterator(struct wlr_surface *surface, | ||
130 | int x, int y, void *data) { | ||
131 | struct wlr_output *wlr_output = data; | ||
132 | wlr_surface_send_leave(surface, wlr_output); | ||
133 | } | ||
134 | |||
135 | static void view_handle_container_reparent(struct wl_listener *listener, | ||
136 | void *data) { | ||
137 | struct sway_view *view = | ||
138 | wl_container_of(listener, view, container_reparent); | ||
139 | struct sway_container *old_parent = data; | ||
140 | |||
141 | struct sway_container *old_output = old_parent; | ||
142 | if (old_output != NULL && old_output->type != C_OUTPUT) { | ||
143 | old_output = container_parent(old_output, C_OUTPUT); | ||
144 | } | ||
145 | |||
146 | struct sway_container *new_output = view->swayc->parent; | ||
147 | if (new_output != NULL && new_output->type != C_OUTPUT) { | ||
148 | new_output = container_parent(new_output, C_OUTPUT); | ||
149 | } | ||
150 | |||
151 | if (old_output == new_output) { | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | if (old_output != NULL) { | ||
156 | view_for_each_surface(view, surface_send_leave_iterator, | ||
157 | old_output->sway_output->wlr_output); | ||
158 | } | ||
159 | if (new_output != NULL) { | ||
160 | view_for_each_surface(view, surface_send_enter_iterator, | ||
161 | new_output->sway_output->wlr_output); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | ||
166 | if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
171 | struct sway_container *focus = seat_get_focus_inactive(seat, | ||
172 | &root_container); | ||
173 | struct sway_container *cont = container_view_create(focus, view); | ||
174 | |||
175 | view->surface = wlr_surface; | ||
176 | view->swayc = cont; | ||
177 | |||
178 | view_init_subsurfaces(view, wlr_surface); | ||
179 | wl_signal_add(&wlr_surface->events.new_subsurface, | ||
180 | &view->surface_new_subsurface); | ||
181 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; | ||
182 | |||
183 | wl_signal_add(&view->swayc->events.reparent, &view->container_reparent); | ||
184 | view->container_reparent.notify = view_handle_container_reparent; | ||
185 | |||
186 | arrange_windows(cont->parent, -1, -1); | ||
187 | input_manager_set_focus(input_manager, cont); | ||
188 | |||
189 | view_damage(view, true); | ||
190 | view_handle_container_reparent(&view->container_reparent, NULL); | ||
191 | } | ||
192 | |||
193 | void view_unmap(struct sway_view *view) { | ||
194 | if (!sway_assert(view->surface != NULL, "cannot unmap unmapped view")) { | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | wl_signal_emit(&view->events.unmap, view); | ||
199 | |||
200 | view_damage(view, true); | ||
201 | |||
202 | wl_list_remove(&view->surface_new_subsurface.link); | ||
203 | wl_list_remove(&view->container_reparent.link); | ||
204 | |||
205 | struct sway_container *parent = container_destroy(view->swayc); | ||
206 | |||
207 | view->swayc = NULL; | ||
208 | view->surface = NULL; | ||
209 | |||
210 | arrange_windows(parent, -1, -1); | ||
211 | } | ||
212 | |||
213 | void view_update_position(struct sway_view *view, double ox, double oy) { | ||
214 | if (view->swayc->x == ox && view->swayc->y == oy) { | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | view_damage(view, true); | ||
219 | view->swayc->x = ox; | ||
220 | view->swayc->y = oy; | ||
221 | view_damage(view, true); | ||
222 | } | ||
223 | |||
224 | void view_update_size(struct sway_view *view, int width, int height) { | ||
225 | if (view->width == width && view->height == height) { | ||
226 | return; | ||
227 | } | ||
228 | |||
229 | view_damage(view, true); | ||
230 | view->width = width; | ||
231 | view->height = height; | ||
232 | view_damage(view, true); | ||
233 | } | ||
234 | |||
235 | |||
236 | static void view_subsurface_create(struct sway_view *view, | ||
237 | struct wlr_subsurface *subsurface) { | ||
238 | struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); | ||
239 | if (child == NULL) { | ||
240 | wlr_log(L_ERROR, "Allocation failed"); | ||
241 | return; | ||
242 | } | ||
243 | view_child_init(child, NULL, view, subsurface->surface); | ||
244 | } | ||
245 | |||
246 | static void view_child_handle_surface_commit(struct wl_listener *listener, | ||
247 | void *data) { | ||
248 | struct sway_view_child *child = | ||
249 | wl_container_of(listener, child, surface_commit); | ||
250 | // TODO: only accumulate damage from the child | ||
251 | view_damage(child->view, false); | ||
252 | } | ||
253 | |||
254 | static void view_child_handle_surface_new_subsurface( | ||
255 | struct wl_listener *listener, void *data) { | ||
256 | struct sway_view_child *child = | ||
257 | wl_container_of(listener, child, surface_new_subsurface); | ||
258 | struct wlr_subsurface *subsurface = data; | ||
259 | view_subsurface_create(child->view, subsurface); | ||
260 | } | ||
261 | |||
262 | static void view_child_handle_surface_destroy(struct wl_listener *listener, | ||
263 | void *data) { | ||
264 | struct sway_view_child *child = | ||
265 | wl_container_of(listener, child, surface_destroy); | ||
266 | view_child_destroy(child); | ||
267 | } | ||
268 | |||
269 | static void view_child_handle_view_unmap(struct wl_listener *listener, | ||
270 | void *data) { | ||
271 | struct sway_view_child *child = | ||
272 | wl_container_of(listener, child, view_unmap); | ||
273 | view_child_destroy(child); | ||
274 | } | ||
275 | |||
276 | static void view_init_subsurfaces(struct sway_view *view, | ||
277 | struct wlr_surface *surface) { | ||
278 | struct wlr_subsurface *subsurface; | ||
279 | wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { | ||
280 | view_subsurface_create(view, subsurface); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | void view_child_init(struct sway_view_child *child, | ||
285 | const struct sway_view_child_impl *impl, struct sway_view *view, | ||
286 | struct wlr_surface *surface) { | ||
287 | child->impl = impl; | ||
288 | child->view = view; | ||
289 | child->surface = surface; | ||
290 | |||
291 | wl_signal_add(&surface->events.commit, &child->surface_commit); | ||
292 | child->surface_commit.notify = view_child_handle_surface_commit; | ||
293 | wl_signal_add(&surface->events.new_subsurface, | ||
294 | &child->surface_new_subsurface); | ||
295 | child->surface_new_subsurface.notify = | ||
296 | view_child_handle_surface_new_subsurface; | ||
297 | wl_signal_add(&surface->events.destroy, &child->surface_destroy); | ||
298 | child->surface_destroy.notify = view_child_handle_surface_destroy; | ||
299 | wl_signal_add(&view->events.unmap, &child->view_unmap); | ||
300 | child->view_unmap.notify = view_child_handle_view_unmap; | ||
301 | |||
302 | struct sway_container *output = child->view->swayc->parent; | ||
303 | if (output != NULL) { | ||
304 | if (output->type != C_OUTPUT) { | ||
305 | output = container_parent(output, C_OUTPUT); | ||
306 | } | ||
307 | wlr_surface_send_enter(child->surface, output->sway_output->wlr_output); | ||
308 | } | ||
309 | |||
310 | view_init_subsurfaces(child->view, surface); | ||
311 | |||
312 | // TODO: only damage the whole child | ||
313 | view_damage(child->view, true); | ||
314 | } | ||
315 | |||
316 | void view_child_destroy(struct sway_view_child *child) { | ||
317 | // TODO: only damage the whole child | ||
318 | view_damage(child->view, true); | ||
319 | |||
320 | wl_list_remove(&child->surface_commit.link); | ||
321 | wl_list_remove(&child->surface_destroy.link); | ||
322 | wl_list_remove(&child->view_unmap.link); | ||
323 | |||
324 | if (child->impl && child->impl->destroy) { | ||
325 | child->impl->destroy(child); | ||
326 | } else { | ||
327 | free(child); | ||
328 | } | ||
329 | } | ||