layout: Use the background's surface ivi_output when activating apps by
[src/agl-compositor.git] / src / layout.c
1 /*
2  * Copyright © 2019 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "ivi-compositor.h"
27
28 #include <assert.h>
29 #include <string.h>
30
31 #include <libweston-6/compositor.h>
32 #include <libweston-6/libweston-desktop.h>
33
34 #define AGL_COMP_DEBUG
35
36 static void
37 ivi_background_init(struct ivi_compositor *ivi, struct ivi_output *output)
38 {
39         struct weston_output *woutput = output->output;
40         struct ivi_surface *bg = output->background;
41         struct weston_view *view;
42
43         if (!bg) {
44                 weston_log("WARNING: Output does not have a background\n");
45                 return;
46         }
47
48         assert(bg->role == IVI_SURFACE_ROLE_BACKGROUND);
49
50         view = bg->view;
51
52         weston_view_set_output(view, woutput);
53         weston_view_set_position(view, woutput->x, woutput->y);
54
55 #ifdef AGL_COMP_DEBUG
56         weston_log("(background) position view %p, x %d, y %d\n", view,
57                         woutput->x, woutput->y);
58 #endif
59
60         view->is_mapped = true;
61         view->surface->is_mapped = true;
62
63         weston_layer_entry_insert(&ivi->background.view_list, &view->layer_link);
64 }
65
66 static void
67 ivi_panel_init(struct ivi_compositor *ivi, struct ivi_output *output,
68                struct ivi_surface *panel)
69 {
70         struct weston_output *woutput = output->output;
71         struct weston_desktop_surface *dsurface;
72         struct weston_view *view;
73         struct weston_geometry geom;
74         int x = woutput->x;
75         int y = woutput->y;
76
77         if (!panel)
78                 return;
79
80         assert(panel->role == IVI_SURFACE_ROLE_PANEL);
81         dsurface = panel->dsurface;
82         view = panel->view;
83         geom = weston_desktop_surface_get_geometry(dsurface);
84 #ifdef AGL_COMP_DEBUG
85         weston_log("geom.width %d, geom.height %d, geom.x %d, geom.y %d\n",
86                         geom.width, geom.height, geom.x, geom.y);
87 #endif
88         switch (panel->panel.edge) {
89         case AGL_SHELL_EDGE_TOP:
90                 output->area.y += geom.height;
91                 output->area.height -= geom.height;
92                 break;
93         case AGL_SHELL_EDGE_BOTTOM:
94                 y += woutput->height - geom.height;
95                 output->area.height -= geom.height;
96                 break;
97         case AGL_SHELL_EDGE_LEFT:
98                 output->area.x += geom.width;
99                 output->area.width -= geom.width;
100                 break;
101         case AGL_SHELL_EDGE_RIGHT:
102                 x += woutput->width - geom.width;
103                 output->area.width -= geom.width;
104                 break;
105         }
106
107         x -= geom.x;
108         y -= geom.y;
109
110         weston_view_set_output(view, woutput);
111         weston_view_set_position(view, x, y);
112 #ifdef AGL_COMP_DEBUG
113         weston_log("(panel) edge %d position view %p, x %d, y %d\n",
114                         panel->panel.edge, view, x, y);
115 #endif
116
117         view->is_mapped = true;
118         view->surface->is_mapped = true;
119
120         weston_layer_entry_insert(&ivi->panel.view_list, &view->layer_link);
121 }
122
123 /*
124  * Initializes all static parts of the layout, i.e. the background and panels.
125  */
126 void
127 ivi_layout_init(struct ivi_compositor *ivi, struct ivi_output *output)
128 {
129         ivi_background_init(ivi, output);
130
131         output->area.x = 0;
132         output->area.y = 0;
133         output->area.width = output->output->width;
134         output->area.height = output->output->height;
135
136         ivi_panel_init(ivi, output, output->top);
137         ivi_panel_init(ivi, output, output->bottom);
138         ivi_panel_init(ivi, output, output->left);
139         ivi_panel_init(ivi, output, output->right);
140
141         weston_compositor_schedule_repaint(ivi->compositor);
142
143         weston_log("Usable area: %dx%d+%d,%d\n",
144                    output->area.width, output->area.height,
145                    output->area.x, output->area.y);
146 }
147
148 static struct ivi_surface *
149 ivi_find_app(struct ivi_compositor *ivi, const char *app_id)
150 {
151         struct ivi_surface *surf;
152         const char *id;
153
154         wl_list_for_each(surf, &ivi->surfaces, link) {
155                 id = weston_desktop_surface_get_app_id(surf->dsurface);
156                 if (id && strcmp(app_id, id) == 0)
157                         return surf;
158         }
159
160         return NULL;
161 }
162
163 static void
164 ivi_layout_activate_complete(struct ivi_output *output,
165                              struct ivi_surface *surf)
166 {
167         struct ivi_compositor *ivi = output->ivi;
168         struct weston_output *woutput = output->output;
169         struct weston_view *view = surf->view;
170
171         if (weston_view_is_mapped(view)) {
172                 weston_layer_entry_remove(&view->layer_link);
173         }
174
175         weston_view_set_output(view, woutput);
176         weston_view_set_position(view,
177                                  woutput->x + output->area.x,
178                                  woutput->y + output->area.y);
179
180         view->is_mapped = true;
181         view->surface->is_mapped = true;
182
183         if (output->active) {
184                 output->active->view->is_mapped = false;
185                 output->active->view->surface->is_mapped = false;
186
187                 weston_layer_entry_remove(&output->active->view->layer_link);
188         }
189         output->active = surf;
190
191         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
192         weston_view_update_transform(view);
193
194         /* force repaint of the entire output */
195         weston_output_damage(output->output);
196         surf->desktop.pending_output = NULL;
197 }
198
199 static struct ivi_output *
200 ivi_layout_find_bg_output(struct ivi_compositor *ivi)
201 {
202         struct ivi_output *out;
203
204         wl_list_for_each(out, &ivi->outputs, link) {
205                 if (out->background &&
206                     out->background->role == IVI_SURFACE_ROLE_BACKGROUND)
207                         return out;
208         }
209
210         return NULL;
211 }
212
213 void
214 ivi_layout_desktop_committed(struct ivi_surface *surf)
215 {
216         struct weston_desktop_surface *dsurf = surf->dsurface;
217         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
218         struct ivi_output *output;
219
220         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP);
221
222         output = surf->desktop.pending_output;
223         if (!output) {
224                 struct ivi_output *ivi_bg_output;
225
226                 /* FIXME: This should be changed to determine if the policy
227                  * database allows that to happen */
228                 if (!surf->ivi->quirks.activate_apps_by_default)
229                         return;
230
231                 ivi_bg_output = ivi_layout_find_bg_output(surf->ivi);
232
233                 /* use the output of the bg to activate the app on start-up by
234                  * default */
235                 if (surf->view && ivi_bg_output) {
236                         const char *app_id =
237                                 weston_desktop_surface_get_app_id(dsurf);
238                         if (app_id && ivi_bg_output)
239                                 ivi_layout_activate(ivi_bg_output, app_id);
240                 }
241
242                 return;
243         }
244
245         if (!weston_desktop_surface_get_maximized(dsurf) ||
246             geom.width != output->area.width ||
247             geom.height != output->area.height)
248                 return;
249
250         ivi_layout_activate_complete(output, surf);
251 }
252
253 void
254 ivi_layout_activate(struct ivi_output *output, const char *app_id)
255 {
256         struct ivi_compositor *ivi = output->ivi;
257         struct ivi_surface *surf;
258         struct weston_desktop_surface *dsurf;
259         struct weston_view *view;
260         struct weston_geometry geom;
261
262         surf = ivi_find_app(ivi, app_id);
263         if (!surf)
264                 return;
265 #ifdef AGL_COMP_DEBUG
266         weston_log("Found app_id %s\n", app_id);
267 #endif
268         if (surf == output->active)
269                 return;
270
271         dsurf = surf->dsurface;
272         view = surf->view;
273         geom = weston_desktop_surface_get_geometry(dsurf);
274
275         if (weston_desktop_surface_get_maximized(dsurf) &&
276             geom.width == output->area.width &&
277             geom.height == output->area.height) {
278                 ivi_layout_activate_complete(output, surf);
279                 return;
280         }
281
282         weston_desktop_surface_set_maximized(dsurf, true);
283         weston_desktop_surface_set_size(dsurf,
284                                         output->area.width,
285                                         output->area.height);
286
287         /*
288          * If the view isn't mapped, we put it onto the hidden layer so it will
289          * start receiving frame events, and will be able to act on our
290          * configure event.
291          */
292         if (!weston_view_is_mapped(view)) {
293                 view->is_mapped = true;
294                 view->surface->is_mapped = true;
295
296                 weston_view_set_output(view, output->output);
297                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
298                 /* force repaint of the entire output */
299                 weston_output_damage(output->output);
300         }
301
302         surf->desktop.pending_output = output;
303 }