1 #include <algorithm>
2 #include <map>
3 #include <wayfire/util/log.hpp>
4 #include "surface-impl.hpp"
5 #include "subsurface.hpp"
6 #include "wayfire/opengl.hpp"
7 #include "../core/core-impl.hpp"
8 #include "wayfire/output.hpp"
9 #include <wayfire/util/log.hpp>
10 #include "wayfire/render-manager.hpp"
11 #include "wayfire/signal-definitions.hpp"
12
13 /****************************
14 * surface_interface_t functions
15 ****************************/
surface_interface_t()16 wf::surface_interface_t::surface_interface_t()
17 {
18 this->priv = std::make_unique<impl>();
19 this->priv->parent_surface = nullptr;
20 }
21
add_subsurface(std::unique_ptr<surface_interface_t> subsurface,bool is_below_parent)22 void wf::surface_interface_t::add_subsurface(
23 std::unique_ptr<surface_interface_t> subsurface, bool is_below_parent)
24 {
25 subsurface->priv->parent_surface = this;
26 subsurface->set_output(get_output());
27 auto& container = is_below_parent ?
28 priv->surface_children_below : priv->surface_children_above;
29
30 wf::subsurface_added_signal ev;
31 ev.main_surface = this;
32 ev.subsurface = {subsurface};
33
34 container.insert(container.begin(), std::move(subsurface));
35 this->emit_signal("subsurface-added", &ev);
36 }
37
remove_subsurface(nonstd::observer_ptr<surface_interface_t> subsurface)38 void wf::surface_interface_t::remove_subsurface(
39 nonstd::observer_ptr<surface_interface_t> subsurface)
40 {
41 auto remove_from = [=] (auto& container)
42 {
43 auto it = std::remove_if(container.begin(), container.end(),
44 [=] (const auto& ptr) { return ptr.get() == subsurface.get(); });
45 container.erase(it, container.end());
46 };
47
48 wf::subsurface_removed_signal ev;
49 ev.main_surface = this;
50 ev.subsurface = subsurface;
51 this->emit_signal("subsurface-removed", &ev);
52
53 remove_from(priv->surface_children_above);
54 remove_from(priv->surface_children_below);
55 }
56
~surface_interface_t()57 wf::surface_interface_t::~surface_interface_t()
58 {}
59
get_main_surface()60 wf::surface_interface_t*wf::surface_interface_t::get_main_surface()
61 {
62 if (priv->parent_surface)
63 {
64 return priv->parent_surface->get_main_surface();
65 }
66
67 return this;
68 }
69
enumerate_surfaces(wf::point_t surface_origin)70 std::vector<wf::surface_iterator_t> wf::surface_interface_t::enumerate_surfaces(
71 wf::point_t surface_origin)
72 {
73 std::vector<wf::surface_iterator_t> result;
74 auto add_surfaces_recursive = [&] (surface_interface_t *child)
75 {
76 if (!child->is_mapped())
77 {
78 return;
79 }
80
81 auto child_surfaces = child->enumerate_surfaces(
82 child->get_offset() + surface_origin);
83 result.insert(result.end(),
84 child_surfaces.begin(), child_surfaces.end());
85 };
86
87 for (auto& child : priv->surface_children_above)
88 {
89 add_surfaces_recursive(child.get());
90 }
91
92 if (is_mapped())
93 {
94 result.push_back({this, surface_origin});
95 }
96
97 for (auto& child : priv->surface_children_below)
98 {
99 add_surfaces_recursive(child.get());
100 }
101
102 return result;
103 }
104
get_output()105 wf::output_t*wf::surface_interface_t::get_output()
106 {
107 return priv->output;
108 }
109
set_output(wf::output_t * output)110 void wf::surface_interface_t::set_output(wf::output_t *output)
111 {
112 priv->output = output;
113 for (auto& c : priv->surface_children_above)
114 {
115 c->set_output(output);
116 }
117
118 for (auto& c : priv->surface_children_below)
119 {
120 c->set_output(output);
121 }
122 }
123
124 /* Static method */
125 int wf::surface_interface_t::impl::active_shrink_constraint = 0;
126
set_opaque_shrink_constraint(std::string constraint_name,int value)127 void wf::surface_interface_t::set_opaque_shrink_constraint(
128 std::string constraint_name, int value)
129 {
130 static std::map<std::string, int> shrink_constraints;
131
132 shrink_constraints[constraint_name] = value;
133
134 impl::active_shrink_constraint = 0;
135 for (auto& constr : shrink_constraints)
136 {
137 impl::active_shrink_constraint =
138 std::max(impl::active_shrink_constraint, constr.second);
139 }
140 }
141
get_active_shrink_constraint()142 int wf::surface_interface_t::get_active_shrink_constraint()
143 {
144 return impl::active_shrink_constraint;
145 }
146
147 /****************************
148 * surface_interface_t functions for surfaces which are
149 * backed by a wlr_surface
150 ****************************/
send_frame_done(const timespec & time)151 void wf::surface_interface_t::send_frame_done(const timespec& time)
152 {
153 if (priv->wsurface)
154 {
155 wlr_surface_send_frame_done(priv->wsurface, &time);
156 }
157 }
158
accepts_input(int32_t sx,int32_t sy)159 bool wf::surface_interface_t::accepts_input(int32_t sx, int32_t sy)
160 {
161 if (!priv->wsurface)
162 {
163 return false;
164 }
165
166 return wlr_surface_point_accepts_input(priv->wsurface, sx, sy);
167 }
168
get_opaque_region(wf::point_t origin)169 wf::region_t wf::surface_interface_t::get_opaque_region(wf::point_t origin)
170 {
171 if (!priv->wsurface)
172 {
173 return {};
174 }
175
176 wf::region_t opaque{&priv->wsurface->opaque_region};
177 opaque += origin;
178 opaque.expand_edges(-get_active_shrink_constraint());
179
180 return opaque;
181 }
182
get_client()183 wl_client*wf::surface_interface_t::get_client()
184 {
185 if (priv->wsurface)
186 {
187 return wl_resource_get_client(priv->wsurface->resource);
188 }
189
190 return nullptr;
191 }
192
get_wlr_surface()193 wlr_surface*wf::surface_interface_t::get_wlr_surface()
194 {
195 return priv->wsurface;
196 }
197
damage_surface_region(const wf::region_t & dmg)198 void wf::surface_interface_t::damage_surface_region(
199 const wf::region_t& dmg)
200 {
201 for (const auto& rect : dmg)
202 {
203 damage_surface_box(wlr_box_from_pixman_box(rect));
204 }
205 }
206
damage_surface_box(const wlr_box & box)207 void wf::surface_interface_t::damage_surface_box(const wlr_box& box)
208 {
209 /* wlr_view_t overrides damage_surface_box and applies it to the output */
210 if (priv->parent_surface && priv->parent_surface->is_mapped())
211 {
212 wlr_box parent_box = box;
213 parent_box.x += get_offset().x;
214 parent_box.y += get_offset().y;
215 priv->parent_surface->damage_surface_box(parent_box);
216 }
217 }
218
clear_subsurfaces()219 void wf::surface_interface_t::clear_subsurfaces()
220 {
221 subsurface_removed_signal ev;
222 ev.main_surface = this;
223 const auto& finish_subsurfaces = [&] (auto& container)
224 {
225 for (auto& surface : container)
226 {
227 ev.subsurface = {surface};
228 this->emit_signal("subsurface-removed", &ev);
229 }
230
231 container.clear();
232 };
233
234 finish_subsurfaces(priv->surface_children_above);
235 finish_subsurfaces(priv->surface_children_below);
236 }
237
wlr_surface_base_t(surface_interface_t * self)238 wf::wlr_surface_base_t::wlr_surface_base_t(surface_interface_t *self)
239 {
240 _as_si = self;
241 handle_new_subsurface = [&] (void *data)
242 {
243 auto sub = static_cast<wlr_subsurface*>(data);
244 if (sub->data)
245 {
246 LOGE("Creating the same subsurface twice!");
247
248 return;
249 }
250
251 // parent isn't mapped yet
252 if (!sub->parent->data)
253 {
254 return;
255 }
256
257 auto subsurface = std::make_unique<subsurface_implementation_t>(sub);
258 nonstd::observer_ptr<subsurface_implementation_t> ptr{subsurface};
259 _as_si->add_subsurface(std::move(subsurface), false);
260 if (sub->mapped)
261 {
262 ptr->map(sub->surface);
263 }
264 };
265
266 on_new_subsurface.set_callback(handle_new_subsurface);
267 on_commit.set_callback([&] (void*) { commit(); });
268 }
269
~wlr_surface_base_t()270 wf::wlr_surface_base_t::~wlr_surface_base_t()
271 {}
272
273
274
get_window_offset()275 wf::point_t wf::wlr_surface_base_t::get_window_offset()
276 {
277 return {0, 0};
278 }
279
_is_mapped() const280 bool wf::wlr_surface_base_t::_is_mapped() const
281 {
282 return surface;
283 }
284
_get_size() const285 wf::dimensions_t wf::wlr_surface_base_t::_get_size() const
286 {
287 if (!_is_mapped())
288 {
289 return {0, 0};
290 }
291
292 return {
293 surface->current.width,
294 surface->current.height,
295 };
296 }
297
emit_map_state_change(wf::surface_interface_t * surface)298 void wf::emit_map_state_change(wf::surface_interface_t *surface)
299 {
300 std::string state =
301 surface->is_mapped() ? "surface-mapped" : "surface-unmapped";
302
303 surface_map_state_changed_signal data;
304 data.surface = surface;
305 wf::get_core().emit_signal(state, &data);
306 }
307
map(wlr_surface * surface)308 void wf::wlr_surface_base_t::map(wlr_surface *surface)
309 {
310 assert(!this->surface && surface);
311 this->surface = surface;
312
313 _as_si->priv->wsurface = surface;
314
315 /* force surface_send_enter(), and also check whether parent surface
316 * output hasn't changed while we were unmapped */
317 wf::output_t *output = _as_si->priv->parent_surface ?
318 _as_si->priv->parent_surface->get_output() : _as_si->get_output();
319 _as_si->set_output(output);
320
321 on_new_subsurface.connect(&surface->events.new_subsurface);
322 on_commit.connect(&surface->events.commit);
323
324 surface->data = _as_si;
325
326 /* Handle subsurfaces which were created before this surface was mapped */
327 wlr_subsurface *sub;
328 wl_list_for_each(sub, &surface->subsurfaces, parent_link)
329 handle_new_subsurface(sub);
330
331 emit_map_state_change(_as_si);
332 }
333
unmap()334 void wf::wlr_surface_base_t::unmap()
335 {
336 assert(this->surface);
337 apply_surface_damage();
338 _as_si->damage_surface_box({.x = 0, .y = 0,
339 .width = _get_size().width, .height = _get_size().height});
340
341 this->surface->data = NULL;
342 this->surface = nullptr;
343 this->_as_si->priv->wsurface = nullptr;
344 emit_map_state_change(_as_si);
345
346 on_new_subsurface.disconnect();
347 on_destroy.disconnect();
348 on_commit.disconnect();
349
350 // Clear all subsurfaces we have.
351 // This might remove subsurfaces that will be re-created again on map.
352 this->_as_si->clear_subsurfaces();
353 }
354
get_buffer()355 wlr_buffer*wf::wlr_surface_base_t::get_buffer()
356 {
357 if (surface && wlr_surface_has_buffer(surface))
358 {
359 return &surface->buffer->base;
360 }
361
362 return nullptr;
363 }
364
apply_surface_damage()365 void wf::wlr_surface_base_t::apply_surface_damage()
366 {
367 if (!_as_si->get_output() || !_is_mapped())
368 {
369 return;
370 }
371
372 wf::region_t dmg;
373 wlr_surface_get_effective_damage(surface, dmg.to_pixman());
374
375 if ((surface->current.scale != 1) ||
376 (surface->current.scale != _as_si->get_output()->handle->scale))
377 {
378 dmg.expand_edges(1);
379 }
380
381 _as_si->damage_surface_region(dmg);
382 }
383
commit()384 void wf::wlr_surface_base_t::commit()
385 {
386 apply_surface_damage();
387 if (_as_si->get_output())
388 {
389 /* we schedule redraw, because the surface might expect
390 * a frame callback */
391 _as_si->get_output()->render->schedule_redraw();
392 }
393 }
394
update_output(wf::output_t * old_output,wf::output_t * new_output)395 void wf::wlr_surface_base_t::update_output(wf::output_t *old_output,
396 wf::output_t *new_output)
397 {
398 /* We should send send_leave only if the output is different from the last. */
399 if (old_output && (old_output != new_output) && surface)
400 {
401 wlr_surface_send_leave(surface, old_output->handle);
402 }
403
404 if (new_output && surface)
405 {
406 wlr_surface_send_enter(surface, new_output->handle);
407 }
408 }
409
_simple_render(const wf::framebuffer_t & fb,int x,int y,const wf::region_t & damage)410 void wf::wlr_surface_base_t::_simple_render(const wf::framebuffer_t& fb,
411 int x, int y, const wf::region_t& damage)
412 {
413 if (!get_buffer())
414 {
415 return;
416 }
417
418 auto size = this->_get_size();
419 wf::geometry_t geometry = {x, y, size.width, size.height};
420 wf::texture_t texture{surface};
421
422 OpenGL::render_begin(fb);
423 for (const auto& rect : damage)
424 {
425 fb.logic_scissor(wlr_box_from_pixman_box(rect));
426 OpenGL::render_texture(texture, fb, geometry);
427 }
428
429 OpenGL::render_end();
430 }
431
wlr_child_surface_base_t(surface_interface_t * self)432 wf::wlr_child_surface_base_t::wlr_child_surface_base_t(
433 surface_interface_t *self) : wlr_surface_base_t(self)
434 {}
435
~wlr_child_surface_base_t()436 wf::wlr_child_surface_base_t::~wlr_child_surface_base_t()
437 {}
438