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