1 #include <wayfire/core.hpp>
2 #include <wayfire/output.hpp>
3 #include <wayfire/opengl.hpp>
4 #include <wayfire/compositor-view.hpp>
5 #include <wayfire/signal-definitions.hpp>
6 #include <cstring>
7 
8 #include <glm/gtc/matrix_transform.hpp>
9 
10 /* Implementation of mirror_view_t */
mirror_view_t(wayfire_view base_view)11 wf::mirror_view_t::mirror_view_t(wayfire_view base_view) :
12     wf::view_interface_t()
13 {
14     this->base_view = base_view;
15 
16     base_view_unmapped = [=] (wf::signal_data_t*)
17     {
18         close();
19     };
20 
21     base_view->connect_signal("unmapped", &base_view_unmapped);
22 
23     base_view_damaged = [=] (wf::signal_data_t*)
24     {
25         damage();
26     };
27 
28     base_view->connect_signal("region-damaged", &base_view_damaged);
29 }
30 
~mirror_view_t()31 wf::mirror_view_t::~mirror_view_t()
32 {}
33 
close()34 void wf::mirror_view_t::close()
35 {
36     if (!base_view)
37     {
38         return;
39     }
40 
41     emit_view_pre_unmap();
42 
43     base_view->disconnect_signal("unmapped", &base_view_unmapped);
44     base_view->disconnect_signal("region-damaged", &base_view_damaged);
45     base_view = nullptr;
46 
47     emit_map_state_change(this);
48     emit_view_unmap();
49 
50     unref();
51 }
52 
is_mapped() const53 bool wf::mirror_view_t::is_mapped() const
54 {
55     return base_view && base_view->is_mapped();
56 }
57 
get_size() const58 wf::dimensions_t wf::mirror_view_t::get_size() const
59 {
60     if (!is_mapped())
61     {
62         return {0, 0};
63     }
64 
65     auto box = base_view->get_bounding_box();
66 
67     return {box.width, box.height};
68 }
69 
simple_render(const wf::framebuffer_t & fb,int x,int y,const wf::region_t & damage)70 void wf::mirror_view_t::simple_render(const wf::framebuffer_t& fb, int x, int y,
71     const wf::region_t& damage)
72 {
73     if (!is_mapped())
74     {
75         return;
76     }
77 
78     /* Normally we shouldn't copy framebuffers. But in this case we can assume
79      * nothing will break, because the copy will be destroyed immediately */
80     wf::framebuffer_t copy;
81     std::memcpy((void*)&copy, (void*)&fb, sizeof(wf::framebuffer_t));
82 
83     /* The base view is in another coordinate system, we need to calculate the
84      * difference between the two, so that it appears at the correct place.
85      *
86      * Note that this simply means we need to change fb's geometry. Damage is
87      * calculated for this mirror view, and needs to stay as it is */
88     auto base_bbox = base_view->get_bounding_box();
89 
90     wf::point_t offset = {base_bbox.x - x, base_bbox.y - y};
91     copy.geometry = copy.geometry + offset;
92     base_view->render_transformed(copy, damage + offset);
93     copy.reset();
94 }
95 
move(int x,int y)96 void wf::mirror_view_t::move(int x, int y)
97 {
98     damage();
99     view_geometry_changed_signal data;
100     data.old_geometry = get_wm_geometry();
101 
102     this->x = x;
103     this->y = y;
104 
105     damage();
106     emit_signal("geometry-changed", &data);
107 }
108 
get_output_geometry()109 wf::geometry_t wf::mirror_view_t::get_output_geometry()
110 {
111     if (!is_mapped())
112     {
113         return get_bounding_box();
114     }
115 
116     wf::geometry_t geometry;
117     geometry.x = this->x;
118     geometry.y = this->y;
119 
120     auto dims = get_size();
121     geometry.width  = dims.width;
122     geometry.height = dims.height;
123 
124     return geometry;
125 }
126 
get_keyboard_focus_surface()127 wlr_surface*wf::mirror_view_t::get_keyboard_focus_surface()
128 {
129     return nullptr;
130 }
131 
is_focuseable() const132 bool wf::mirror_view_t::is_focuseable() const
133 {
134     return false;
135 }
136 
should_be_decorated()137 bool wf::mirror_view_t::should_be_decorated()
138 {
139     return false;
140 }
141 
142 /* Implementation of color_rect_view_t */
143 
color_rect_view_t()144 wf::color_rect_view_t::color_rect_view_t() : wf::view_interface_t()
145 {
146     this->geometry   = {0, 0, 1, 1};
147     this->_color     = {0, 0, 0, 1};
148     this->border     = 0;
149     this->_is_mapped = true;
150 }
151 
close()152 void wf::color_rect_view_t::close()
153 {
154     this->_is_mapped = false;
155 
156     emit_view_unmap();
157     emit_map_state_change(this);
158 
159     unref();
160 }
161 
set_color(wf::color_t color)162 void wf::color_rect_view_t::set_color(wf::color_t color)
163 {
164     this->_color = color;
165     damage();
166 }
167 
set_border_color(wf::color_t border)168 void wf::color_rect_view_t::set_border_color(wf::color_t border)
169 {
170     this->_border_color = border;
171     damage();
172 }
173 
set_border(int width)174 void wf::color_rect_view_t::set_border(int width)
175 {
176     this->border = width;
177     damage();
178 }
179 
is_mapped() const180 bool wf::color_rect_view_t::is_mapped() const
181 {
182     return _is_mapped;
183 }
184 
get_size() const185 wf::dimensions_t wf::color_rect_view_t::get_size() const
186 {
187     return {
188         geometry.width,
189         geometry.height,
190     };
191 }
192 
render_colored_rect(const wf::framebuffer_t & fb,int x,int y,int w,int h,const wf::color_t & color)193 static void render_colored_rect(const wf::framebuffer_t& fb,
194     int x, int y, int w, int h, const wf::color_t& color)
195 {
196     wf::color_t premultiply{
197         color.r * color.a,
198         color.g * color.a,
199         color.b * color.a,
200         color.a};
201 
202     OpenGL::render_rectangle({x, y, w, h}, premultiply,
203         fb.get_orthographic_projection());
204 }
205 
simple_render(const wf::framebuffer_t & fb,int x,int y,const wf::region_t & damage)206 void wf::color_rect_view_t::simple_render(const wf::framebuffer_t& fb, int x, int y,
207     const wf::region_t& damage)
208 {
209     OpenGL::render_begin(fb);
210     for (const auto& box : damage)
211     {
212         fb.logic_scissor(wlr_box_from_pixman_box(box));
213 
214         /* Draw the border, making sure border parts don't overlap, otherwise
215          * we will get wrong corners if border has alpha != 1.0 */
216         // top
217         render_colored_rect(fb, x, y, geometry.width, border,
218             _border_color);
219         // bottom
220         render_colored_rect(fb, x, y + geometry.height - border,
221             geometry.width, border, _border_color);
222         // left
223         render_colored_rect(fb, x, y + border, border,
224             geometry.height - 2 * border, _border_color);
225         // right
226         render_colored_rect(fb, x + geometry.width - border,
227             y + border, border, geometry.height - 2 * border, _border_color);
228 
229         /* Draw the inside of the rect */
230         render_colored_rect(fb, x + border, y + border,
231             geometry.width - 2 * border, geometry.height - 2 * border,
232             _color);
233     }
234 
235     OpenGL::render_end();
236 }
237 
move(int x,int y)238 void wf::color_rect_view_t::move(int x, int y)
239 {
240     damage();
241     view_geometry_changed_signal data;
242     data.old_geometry = get_wm_geometry();
243 
244     this->geometry.x = x;
245     this->geometry.y = y;
246 
247     damage();
248     emit_signal("geometry-changed", &data);
249 }
250 
resize(int w,int h)251 void wf::color_rect_view_t::resize(int w, int h)
252 {
253     damage();
254     view_geometry_changed_signal data;
255     data.old_geometry = get_wm_geometry();
256 
257     this->geometry.width  = w;
258     this->geometry.height = h;
259 
260     damage();
261     emit_signal("geometry-changed", &data);
262 }
263 
get_output_geometry()264 wf::geometry_t wf::color_rect_view_t::get_output_geometry()
265 {
266     return geometry;
267 }
268 
get_keyboard_focus_surface()269 wlr_surface*wf::color_rect_view_t::get_keyboard_focus_surface()
270 {
271     return nullptr;
272 }
273 
is_focuseable() const274 bool wf::color_rect_view_t::is_focuseable() const
275 {
276     return false;
277 }
278 
should_be_decorated()279 bool wf::color_rect_view_t::should_be_decorated()
280 {
281     return false;
282 }
283