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*)©, (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