a2cf48c8b96803506709da5d5b0f3f75024d28e4
[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 #include "policy.h"
28 #include "shared/helpers.h"
29
30 #include <assert.h>
31 #include <string.h>
32
33 #include <libweston/config-parser.h>
34 #include <libweston/libweston.h>
35 #include <libweston-desktop/libweston-desktop.h>
36
37 #include "agl-shell-desktop-server-protocol.h"
38
39 #define AGL_COMP_DEBUG
40
41 static const char *ivi_roles_as_string[] = {
42         [IVI_SURFACE_ROLE_NONE]         = "NONE",
43         [IVI_SURFACE_ROLE_BACKGROUND]   = "BACKGROUND",
44         [IVI_SURFACE_ROLE_PANEL]        = "PANEL",
45         [IVI_SURFACE_ROLE_DESKTOP]      = "DESKTOP",
46         [IVI_SURFACE_ROLE_POPUP]        = "POPUP",
47         [IVI_SURFACE_ROLE_SPLIT_H]      = "SPLIT_H",
48         [IVI_SURFACE_ROLE_SPLIT_V]      = "SPLIT_V",
49         [IVI_SURFACE_ROLE_FULLSCREEN]   = "FULLSCREEN",
50         [IVI_SURFACE_ROLE_REMOTE]       = "REMOTE",
51         [IVI_SURFACE_ROLE_TILE]         = "SPLIT",
52 };
53
54 bool
55 ivi_surf_in_hidden_layer(struct ivi_compositor *ivi, struct ivi_surface *surface);
56
57 const char *
58 ivi_layout_get_surface_role_name(struct ivi_surface *surf)
59 {
60         if (surf->role < 0 || surf->role >= ARRAY_LENGTH(ivi_roles_as_string))
61                 return " unknown surface role";
62
63         return ivi_roles_as_string[surf->role];
64 }
65
66 static void
67 ivi_background_init(struct ivi_compositor *ivi, struct ivi_output *output)
68 {
69         struct weston_output *woutput = output->output;
70         struct ivi_surface *bg = output->background;
71         struct weston_view *view;
72
73         if (!bg) {
74                 weston_log("WARNING: Output does not have a background\n");
75                 return;
76         }
77
78         assert(bg->role == IVI_SURFACE_ROLE_BACKGROUND);
79
80         view = bg->view;
81
82         weston_view_set_output(view, woutput);
83         weston_view_set_position(view, woutput->x, woutput->y);
84
85         weston_log("(background) position view %p, x %d, y %d, on output %s\n", view,
86                         woutput->x, woutput->y, output->name);
87
88         view->is_mapped = true;
89         view->surface->is_mapped = true;
90
91         weston_layer_entry_insert(&ivi->background.view_list, &view->layer_link);
92 }
93
94 static void
95 ivi_panel_init(struct ivi_compositor *ivi, struct ivi_output *output,
96                struct ivi_surface *panel)
97 {
98         struct weston_output *woutput = output->output;
99         struct weston_desktop_surface *dsurface;
100         struct weston_view *view;
101         struct weston_geometry geom;
102         int x = woutput->x;
103         int y = woutput->y;
104
105         if (!panel)
106                 return;
107
108         assert(panel->role == IVI_SURFACE_ROLE_PANEL);
109         dsurface = panel->dsurface;
110         view = panel->view;
111         geom = weston_desktop_surface_get_geometry(dsurface);
112
113         weston_log("(panel) geom.width %d, geom.height %d, geom.x %d, geom.y %d\n",
114                         geom.width, geom.height, geom.x, geom.y);
115
116         switch (panel->panel.edge) {
117         case AGL_SHELL_EDGE_TOP:
118                 output->area.y += geom.height;
119                 output->area.height -= geom.height;
120                 break;
121         case AGL_SHELL_EDGE_BOTTOM:
122                 y += woutput->height - geom.height;
123                 output->area.height -= geom.height;
124                 break;
125         case AGL_SHELL_EDGE_LEFT:
126                 output->area.x += geom.width;
127                 output->area.width -= geom.width;
128                 break;
129         case AGL_SHELL_EDGE_RIGHT:
130                 x += woutput->width - geom.width;
131                 output->area.width -= geom.width;
132                 break;
133         }
134
135         x -= geom.x;
136         y -= geom.y;
137
138         weston_view_set_output(view, woutput);
139         weston_view_set_position(view, x, y);
140
141         weston_log("(panel) edge %d position view %p, x %d, y %d\n",
142                         panel->panel.edge, view, x, y);
143
144         view->is_mapped = true;
145         view->surface->is_mapped = true;
146
147         weston_log("panel type %d inited on output %s\n", panel->panel.edge,
148                         output->name);
149
150         weston_layer_entry_insert(&ivi->panel.view_list, &view->layer_link);
151 }
152
153 /*
154  * Initializes all static parts of the layout, i.e. the background and panels.
155  */
156 void
157 ivi_layout_init(struct ivi_compositor *ivi, struct ivi_output *output)
158 {
159         bool use_default_area = true;
160         struct weston_config_section *section = output->config;
161         char *t;
162
163         weston_config_section_get_string(section, "activation-area", &t, NULL);
164         if (t) {
165                 if (output->area_activation.width == 0 &&
166                     output->area_activation.height == 0 &&
167                     output->area_activation.x == 0 &&
168                     output->area_activation.y == 0) {
169                         weston_log("WARNING: activation-area set in "
170                                         "configuration file, but yet applied!\n");
171                         if (parse_activation_area(t, output) < 0)
172                                 weston_log("Invalid activation-area \"%s\" for output %s\n",
173                                            t, output->name);
174                 } else {
175                         weston_log("WARNING: activation-area detected in ini file, "
176                                         "but agl_shell override detected!\n");
177                         if (parse_activation_area(t, output) < 0)
178                                 weston_log("Invalid activation-area \"%s\" for output %s\n",
179                                            t, output->name);
180                 }
181         }
182         free(t);
183
184         ivi_background_init(ivi, output);
185
186         if (output->area_activation.width ||
187             output->area_activation.height ||
188             output->area_activation.x ||
189             output->area_activation.y) {
190                 /* Sanity check target area is within output bounds */
191                 if ((output->area_activation.x + output->area_activation.width) < output->output->width ||
192                     (output->area_activation.y + output->area_activation.height) < output->output->height) {
193                         weston_log("Using specified area for output %s, ignoring panels\n",
194                                    output->name);
195                         output->area.x = output->area_activation.x;
196                         output->area.y = output->area_activation.y;
197                         output->area.width = output->area_activation.width;
198                         output->area.height = output->area_activation.height;
199                         use_default_area = false;
200                 } else {
201                         weston_log("Invalid activation-area position for output %s, ignoring\n",
202                                    output->name);
203                 }
204         }
205         if (use_default_area) {
206                 output->area.x = 0;
207                 output->area.y = 0;
208                 output->area.width = output->output->width;
209                 output->area.height = output->output->height;
210
211                 ivi_panel_init(ivi, output, output->top);
212                 ivi_panel_init(ivi, output, output->bottom);
213                 ivi_panel_init(ivi, output, output->left);
214                 ivi_panel_init(ivi, output, output->right);
215         }
216
217         weston_compositor_schedule_repaint(ivi->compositor);
218
219         weston_log("Usable area: %dx%d+%d,%d\n",
220                    output->area.width, output->area.height,
221                    output->area.x, output->area.y);
222 }
223
224 struct ivi_surface *
225 ivi_find_app(struct ivi_compositor *ivi, const char *app_id)
226 {
227         struct ivi_surface *surf;
228         const char *id;
229
230         wl_list_for_each(surf, &ivi->surfaces, link) {
231                 id = weston_desktop_surface_get_app_id(surf->dsurface);
232                 if (id && strcmp(app_id, id) == 0)
233                         return surf;
234         }
235
236         return NULL;
237 }
238
239 static void
240 ivi_layout_activate_complete(struct ivi_output *output,
241                              struct ivi_surface *surf)
242 {
243         struct ivi_compositor *ivi = output->ivi;
244         struct weston_output *woutput = output->output;
245         struct weston_view *view = surf->view;
246         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
247         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
248         const char *app_id = weston_desktop_surface_get_app_id(surf->dsurface);
249         bool update_previous = true;
250
251         if (weston_view_is_mapped(view)) {
252                 weston_layer_entry_remove(&view->layer_link);
253         } else {
254                 weston_view_update_transform(view);
255         }
256
257         if (output_has_black_curtain(output)) {
258                 if (!output->background) {
259                         weston_log("Found that we have no background surface "
260                                     "for output %s. Using black curtain as background\n",
261                                     output->output->name);
262
263                         struct weston_view *ev =
264                                 output->fullscreen_view.fs->view;
265
266                         /* use the black curtain as background when we have
267                          * none added by the shell client. */
268                         weston_layer_entry_remove(&ev->layer_link);
269                         weston_layer_entry_insert(&ivi->normal.view_list,
270                                                   &ev->layer_link);
271                         weston_view_geometry_dirty(ev);
272                         weston_surface_damage(ev->surface);
273                 } else {
274                         remove_black_curtain(output);
275                 }
276         }
277
278
279         weston_view_set_output(view, woutput);
280         /* drop any previous masks set on this view */
281         weston_view_set_mask_infinite(view);
282
283         if (surf->role != IVI_SURFACE_ROLE_BACKGROUND)
284                 weston_view_set_position(view,
285                                          woutput->x + output->area.x,
286                                          woutput->y + output->area.y);
287
288         /* reset any previous orientation */
289         if (surf->orientation != AGL_SHELL_TILE_ORIENTATION_NONE &&
290             !surf->sticky) {
291                 weston_log("%s() resetting itself to none orientation\n", __func__);
292                 surf->orientation = AGL_SHELL_TILE_ORIENTATION_NONE;
293                 weston_desktop_surface_set_orientation(surf->dsurface,
294                                                        surf->orientation);
295         }
296         view->is_mapped = true;
297         surf->mapped = true;
298         view->surface->is_mapped = true;
299
300         /* handle a movement from one output to another */
301         if (surf->current_completed_output &&
302             surf->current_completed_output != output) {
303
304                 /* we're migrating the same surface but to another output */
305                 if (surf->current_completed_output->active == surf) {
306                         struct weston_view *ev =
307                                 surf->current_completed_output->active->view;
308
309                         weston_layer_entry_remove(&ev->layer_link);
310                         surf->current_completed_output->previous_active =
311                                 surf->current_completed_output->active;
312                         surf->current_completed_output->active = NULL;
313
314                         /* damage all possible outputs to avoid stale views */
315                         weston_compositor_damage_all(ivi->compositor);
316                 }
317         }
318
319         if (output->active) {
320                 /* keep the background surface mapped at all times */
321                 if (output->active->role != IVI_SURFACE_ROLE_BACKGROUND &&
322                     !output->active->sticky) {
323
324                         output->active->view->is_mapped = false;
325                         output->active->view->surface->is_mapped = false;
326
327                         weston_layer_entry_remove(&output->active->view->layer_link);
328                 }
329         }
330
331         if (output->previous_active && output->active) {
332                 const char *c_app_id =
333                         weston_desktop_surface_get_app_id(output->active->dsurface);
334
335                 /* if the currently activated app_id is the same as the one
336                  * we're trying to complete activation with means we're
337                  * operating on the same app_id so do update previous_active as
338                  * it will overwrite it with the same value */
339                 if (app_id && !strcmp(c_app_id, app_id)) {
340                         update_previous = false;
341                 }
342         }
343
344         if (update_previous)
345                 output->previous_active = output->active;
346         output->active = surf;
347         surf->current_completed_output = output;
348
349         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
350         weston_view_geometry_dirty(view);
351         weston_surface_damage(view->surface);
352
353         if (ivi_seat)
354                 ivi_shell_activate_surface(surf, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
355
356         /*
357          * the 'remote' role now makes use of this part so make sure we don't
358          * trip the enum such that we might end up with a modified output for
359          * 'remote' role
360          */
361         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
362                 if (surf->desktop.pending_output)
363                         surf->desktop.last_output = surf->desktop.pending_output;
364                 surf->desktop.pending_output = NULL;
365         }
366
367         weston_log("Activation completed for app_id %s, role %s, output %s\n",
368                         app_id,
369                         ivi_layout_get_surface_role_name(surf), output->name);
370
371         shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_ACTIVATED);
372 }
373
374 static bool
375 ivi_layout_find_output_with_app_id(const char *app_id, struct ivi_output *output)
376 {
377         char *cur;
378         size_t app_id_len;
379
380         cur = output->app_ids;
381         app_id_len = strlen(app_id);
382
383         while ((cur = strstr(cur, app_id))) {
384                 if ((cur[app_id_len] == ',' || cur[app_id_len] == '\0') &&
385                     (cur == output->app_ids || cur[-1] == ','))
386                         return true;
387                 cur++;
388         }
389
390         return false;
391 }
392
393 struct ivi_output *
394 ivi_layout_find_with_app_id(const char *app_id, struct ivi_compositor *ivi)
395 {
396         struct ivi_output *out;
397
398         if (!app_id)
399                 return NULL;
400
401         wl_list_for_each(out, &ivi->outputs, link) {
402                 if (!out->app_ids)
403                         continue;
404
405                 if (ivi_layout_find_output_with_app_id(app_id, out))
406                         return out;
407         }
408         return NULL;
409 }
410
411 struct ivi_output *
412 ivi_layout_find_bg_output(struct ivi_compositor *ivi)
413 {
414         struct ivi_output *out;
415
416         wl_list_for_each(out, &ivi->outputs, link) {
417                 if (out->background &&
418                     out->background->role == IVI_SURFACE_ROLE_BACKGROUND)
419                         return out;
420         }
421
422         return NULL;
423 }
424
425
426 static void
427 ivi_layout_add_to_hidden_layer(struct ivi_surface *surf,
428                                struct ivi_output *ivi_output)
429 {
430         struct weston_desktop_surface *dsurf = surf->dsurface;
431         struct weston_view *ev = surf->view;
432         struct ivi_compositor *ivi = surf->ivi;
433         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
434
435         /*
436          * If the view isn't mapped, we put it onto the hidden layer so it will
437          * start receiving frame events, and will be able to act on our
438          * configure event.
439          */
440         if (!weston_view_is_mapped(ev)) {
441                 ev->is_mapped = true;
442                 ev->surface->is_mapped = true;
443
444                 weston_desktop_surface_set_maximized(dsurf, true);
445                 weston_desktop_surface_set_size(dsurf,
446                                                 ivi_output->area.width,
447                                                 ivi_output->area.height);
448
449                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
450                            app_id, ivi_layout_get_surface_role_name(surf),
451                            ivi_output->area.width, ivi_output->area.height);
452
453                 surf->hidden_layer_output = ivi_output;
454                 weston_view_set_output(ev, ivi_output->output);
455                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
456                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
457                                 app_id, ivi_layout_get_surface_role_name(surf),
458                                 ivi_output->output->name);
459
460                 weston_compositor_schedule_repaint(ivi->compositor);
461                 return;
462         }
463
464         /* we might have another output to activate */
465         if (surf->hidden_layer_output &&
466             surf->hidden_layer_output != ivi_output) {
467                 weston_layer_entry_remove(&ev->layer_link);
468                 weston_view_geometry_dirty(ev);
469                 weston_surface_damage(ev->surface);
470
471                 if (ivi_output->area.width != surf->hidden_layer_output->area.width ||
472                     ivi_output->area.height != surf->hidden_layer_output->area.height) {
473                         weston_desktop_surface_set_maximized(dsurf, true);
474                         weston_desktop_surface_set_size(dsurf,
475                                                         ivi_output->area.width,
476                                                         ivi_output->area.height);
477                 }
478
479                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
480                                 app_id, ivi_layout_get_surface_role_name(surf),
481                                 ivi_output->area.width, ivi_output->area.height);
482
483                 surf->hidden_layer_output = ivi_output;
484                 weston_view_set_output(ev, ivi_output->output);
485                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
486                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
487                                 app_id, ivi_layout_get_surface_role_name(surf),
488                                 ivi_output->output->name);
489         }
490
491         weston_compositor_schedule_repaint(ivi->compositor);
492 }
493
494 void
495 ivi_layout_remote_committed(struct ivi_surface *surf)
496 {
497         struct weston_desktop_surface *dsurf = surf->dsurface;
498         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
499         struct ivi_policy *policy = surf->ivi->policy;
500         struct ivi_output *output;
501         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
502
503         assert(surf->role == IVI_SURFACE_ROLE_REMOTE);
504
505         output = surf->remote.output;
506
507         if (policy && policy->api.surface_activate_by_default &&
508             !policy->api.surface_activate_by_default(surf, surf->ivi))
509                 return;
510
511         /* we can only activate it again by using the protocol, but
512          * additionally the output is not reset when
513          * ivi_layout_activate_complete() terminates so we use the
514          * current active surface to avoid hitting this again and again
515          * */
516         if (surf->mapped && output->active == surf)
517                 return;
518
519         if (!surf->ivi->activate_by_default &&
520             !ivi_surf_in_hidden_layer(surf->ivi, surf)) {
521                 weston_log("Refusing to activate surface role %d, "
522                             "app_id %s\n", surf->role, app_id);
523
524                 if (!weston_desktop_surface_get_maximized(dsurf) ||
525                     geom.width != output->area.width ||
526                     geom.height != output->area.height) {
527                         ivi_layout_add_to_hidden_layer(surf, output);
528                 }
529
530                 return;
531         }
532
533         if (!weston_desktop_surface_get_maximized(dsurf) ||
534             geom.width != output->area.width ||
535             geom.height != output->area.height)
536                 return;
537
538         ivi_layout_activate_complete(output, surf);
539 }
540
541 void
542 ivi_layout_desktop_committed(struct ivi_surface *surf)
543 {
544         struct weston_desktop_surface *dsurf = surf->dsurface;
545         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
546         struct ivi_policy *policy = surf->ivi->policy;
547         struct ivi_output *output;
548         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
549
550         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP);
551
552         /*
553          * we can't make use here of the ivi_layout_get_output_from_surface()
554          * due to the fact that we'll always land here when a surface performs
555          * a commit and pending_output will not bet set. This works in tandem
556          * with 'mapped' at this point to avoid tripping over
557          * to a surface that continuously updates its content
558          */
559         output = surf->desktop.pending_output;
560
561         if (!output) {
562                 struct ivi_output *r_output;
563
564                 if (policy && policy->api.surface_activate_by_default &&
565                     !policy->api.surface_activate_by_default(surf, surf->ivi))
566                         return;
567
568                 /* we can only activate it again by using the protocol */
569                 if (surf->mapped)
570                         return;
571
572                 /* check first if there aren't any outputs being set */
573                 r_output = ivi_layout_find_with_app_id(app_id, surf->ivi);
574
575                 if (r_output) {
576                         struct weston_view *view = r_output->fullscreen_view.fs->view;
577                         if (view->is_mapped || view->surface->is_mapped)
578                                 remove_black_curtain(r_output);
579                 }
580
581
582                 /* try finding an output with a background and use that */
583                 if (!r_output)
584                         r_output = ivi_layout_find_bg_output(surf->ivi);
585
586                 /* if we couldn't still find an output by this point, there's
587                  * something wrong so we abort with a protocol error */
588                 if (!r_output) {
589                         wl_resource_post_error(surf->ivi->shell_client.resource,
590                                                AGL_SHELL_ERROR_INVALID_ARGUMENT,
591                                                "No valid output found to activate surface by default");
592                         return;
593                 }
594
595                 if (!surf->ivi->activate_by_default &&
596                     (!surf->xwayland.is_set && !is_shell_surface_xwayland(surf))) {
597                         weston_log("Refusing to activate surface role %d, app_id %s, type %s\n",
598                                         surf->role, app_id,
599                                         is_shell_surface_xwayland(surf) ?
600                                         "xwayland" : "regular");
601
602                         if (!weston_desktop_surface_get_maximized(dsurf) ||
603                             geom.width != r_output->area.width ||
604                             geom.height != r_output->area.height)
605                                 ivi_layout_add_to_hidden_layer(surf, r_output);
606
607                         return;
608                 }
609
610                 /* use the output of the bg to activate the app on start-up by
611                  * default */
612                 if (surf->view && r_output) {
613                         if (app_id && r_output) {
614                                 weston_log("Surface with app_id %s, role %s activating by default\n",
615                                         weston_desktop_surface_get_app_id(surf->dsurface),
616                                         ivi_layout_get_surface_role_name(surf));
617                                 ivi_layout_activate(r_output, app_id);
618                         } else if (!app_id) {
619                                 /*
620                                  * applications not setting an app_id, or
621                                  * setting an app_id but at a later point in
622                                  * time, might fall-back here so give them a
623                                  * chance to receive the configure event and
624                                  * act upon it
625                                  */
626                                 weston_log("Surface no app_id, role %s activating by default\n",
627                                         ivi_layout_get_surface_role_name(surf));
628                                 if (surf->xwayland.is_set || is_shell_surface_xwayland(surf)) {
629                                         ivi_layout_activate_by_surf(r_output, surf);
630                                         ivi_layout_activate_complete(r_output, surf);
631                                 } else {
632                                         ivi_layout_activate_by_surf(r_output, surf);
633                                 }
634                         }
635                 }
636
637                 return;
638         }
639
640         if (!weston_desktop_surface_get_maximized(dsurf) ||
641             geom.width != output->area.width ||
642             geom.height != output->area.height)
643                 return;
644
645         ivi_layout_activate_complete(output, surf);
646 }
647
648 void
649 ivi_layout_fullscreen_committed(struct ivi_surface *surface)
650 {
651         struct ivi_compositor *ivi = surface->ivi;
652         struct ivi_policy *policy = ivi->policy;
653
654         struct weston_desktop_surface *dsurface = surface->dsurface;
655         struct weston_surface *wsurface =
656                 weston_desktop_surface_get_surface(dsurface);
657         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
658
659         struct ivi_output *output = surface->split.output;
660         struct weston_output *woutput = output->output;
661         struct ivi_output *bg_output = ivi_layout_find_bg_output(ivi);
662
663         struct weston_view *view = surface->view;
664         struct weston_geometry geom =
665                 weston_desktop_surface_get_geometry(dsurface);
666
667         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
668         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
669
670         bool is_fullscreen = weston_desktop_surface_get_fullscreen(dsurface);
671         bool is_dim_same =
672                 geom.width == bg_output->output->width &&
673                 geom.height == bg_output->output->height;
674
675         if (policy && policy->api.surface_activate_by_default &&
676             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
677             !surface->mapped)
678                 return;
679
680         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
681
682
683         if (surface->state == FULLSCREEN && weston_view_is_mapped(view))
684                 return;
685
686         /* if we still get here but we haven't resized so far, send configure
687          * events to do so */
688         if (surface->state != RESIZING && (!is_fullscreen || !is_dim_same)) {
689                 struct ivi_output *bg_output =
690                         ivi_layout_find_bg_output(surface->ivi);
691
692                 weston_log("Placing fullscreen app_id %s, type %s in hidden layer\n",
693                                 app_id, ivi_layout_get_surface_role_name(surface));
694                 weston_desktop_surface_set_fullscreen(dsurface, true);
695                 weston_desktop_surface_set_size(dsurface,
696                                                 bg_output->output->width,
697                                                 bg_output->output->height);
698
699                 surface->state = RESIZING;
700                 weston_view_set_output(view, output->output);
701                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
702                 return;
703         }
704
705         /* eventually, we would set the surface fullscreen, but the client
706          * hasn't resized correctly by this point, so terminate connection */
707         if (surface->state == RESIZING && is_fullscreen && !is_dim_same) {
708                 struct weston_desktop_client *desktop_client =
709                         weston_desktop_surface_get_client(dsurface);
710                 struct wl_client *client =
711                         weston_desktop_client_get_client(desktop_client);
712                 wl_client_post_implementation_error(client,
713                                 "can not display surface due to invalid geometry."
714                                 " Client should perform a geometry resize!");
715                 return;
716         }
717
718         /* this implies we resized correctly */
719         if (!weston_view_is_mapped(view) || surface->state != FULLSCREEN) {
720                 weston_layer_entry_remove(&view->layer_link);
721
722                 weston_view_set_output(view, woutput);
723                 weston_view_set_position(view, woutput->x, woutput->y);
724                 weston_layer_entry_insert(&ivi->fullscreen.view_list, &view->layer_link);
725
726                 wsurface->is_mapped = true;
727                 surface->view->is_mapped = true;
728                 surface->state = FULLSCREEN;
729
730                 weston_view_geometry_dirty(view);
731                 weston_surface_damage(view->surface);
732
733                 if (ivi_seat)
734                         ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
735
736                 shell_advertise_app_state(ivi, app_id,
737                                 NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
738
739                 weston_log("Activation completed for app_id %s, role %s, "
740                            "output %s\n", app_id,
741                            ivi_layout_get_surface_role_name(surface),
742                            output->name);
743
744                 weston_compositor_schedule_repaint(ivi->compositor);
745         }
746 }
747
748 void
749 ivi_layout_desktop_resize(struct ivi_surface *surface,
750                           struct weston_geometry area)
751 {
752         struct weston_desktop_surface *dsurf = surface->dsurface;
753         struct weston_view *view = surface->view;
754
755         int x = area.x;
756         int y = area.y;
757         int width = area.width;
758         int height = area.height;
759
760         weston_desktop_surface_set_size(dsurf,
761                                         width, height);
762
763         weston_view_set_position(view, x, y);
764
765         weston_view_geometry_dirty(view);
766         weston_surface_damage(view->surface);
767 }
768
769 void
770 ivi_layout_split_committed(struct ivi_surface *surface)
771 {
772         struct ivi_compositor *ivi = surface->ivi;
773         struct ivi_policy *policy = ivi->policy;
774
775         struct weston_desktop_surface *dsurface = surface->dsurface;
776         struct weston_surface *wsurface =
777                 weston_desktop_surface_get_surface(dsurface);
778         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
779
780         struct ivi_output *output = surface->split.output;
781         struct weston_output *woutput = output->output;
782
783         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
784         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
785
786         struct weston_view *view = surface->view;
787         struct weston_geometry geom;
788
789         int x, y;
790         int width, height;
791
792         x = woutput->x;
793         y = woutput->y;
794
795         if (policy && policy->api.surface_activate_by_default &&
796             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
797             !surface->mapped)
798                 return;
799
800         if (surface->view->is_mapped)
801                 return;
802
803         geom = weston_desktop_surface_get_geometry(dsurface);
804
805         assert(surface->role == IVI_SURFACE_ROLE_SPLIT_H ||
806                surface->role == IVI_SURFACE_ROLE_SPLIT_V);
807
808         /* save the previous area in order to recover it back when if this kind
809          * of surface is being destroyed/removed */
810         output->area_saved = output->area;
811
812         switch (surface->role) {
813         case IVI_SURFACE_ROLE_SPLIT_V:
814                 geom.width = (output->area.width / 2);
815
816                 x += woutput->width - geom.width;
817                 output->area.width -= geom.width;
818
819                 width = woutput->width - x;
820                 height = output->area.height;
821                 y = output->area.y;
822
823                 break;
824         case IVI_SURFACE_ROLE_SPLIT_H:
825                 geom.height = (output->area.height / 2);
826
827                 y = output->area.y;
828                 output->area.y += geom.height;
829                 output->area.height -= geom.height;
830
831                 width = output->area.width;
832                 height = output->area.height;
833
834                 x = output->area.x;
835
836                 break;
837         default:
838                 assert(!"Invalid split orientation\n");
839         }
840
841         weston_desktop_surface_set_size(dsurface,
842                                         width, height);
843
844         /* resize the active surface first, output->area already contains
845          * correct area to resize to */
846         if (output->active)
847                 ivi_layout_desktop_resize(output->active, output->area);
848
849         weston_view_set_output(view, woutput);
850         weston_view_set_position(view, x, y);
851         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
852
853         weston_view_geometry_dirty(view);
854         weston_surface_damage(view->surface);
855
856         if (ivi_seat)
857                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
858
859         wsurface->is_mapped = true;
860         surface->view->is_mapped = true;
861
862         shell_advertise_app_state(ivi, app_id,
863                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
864
865         weston_log("Activation completed for app_id %s, role %s, output %s\n",
866                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
867 }
868
869 static void
870 ivi_compute_popup_position(const struct weston_output *output, struct weston_view *view,
871                            int initial_x, int initial_y, int *new_x, int *new_y)
872 {
873         *new_x = output->x + initial_x;
874         *new_y = output->y + initial_y;
875 }
876
877
878 bool
879 ivi_surf_in_hidden_layer(struct ivi_compositor *ivi, struct ivi_surface *surface)
880 {
881         struct weston_view *ev;
882
883         wl_list_for_each(ev, &ivi->hidden.view_list.link, layer_link.link) {
884                 if (ev == surface->view)
885                         return true;
886         }
887
888         wl_list_for_each(ev, &ivi->fullscreen.view_list.link, layer_link.link) {
889                 if (ev == surface->view)
890                         return true;
891         }
892
893         return false;
894 }
895
896 void
897 ivi_layout_popup_committed(struct ivi_surface *surface)
898 {
899         struct ivi_compositor *ivi = surface->ivi;
900         struct ivi_policy *policy = ivi->policy;
901
902         struct weston_desktop_surface *dsurface = surface->dsurface;
903         struct weston_surface *wsurface =
904                 weston_desktop_surface_get_surface(dsurface);
905         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
906
907         int new_x, new_y;
908
909         struct ivi_output *output = surface->popup.output;
910         struct weston_output *woutput = output->output;
911
912         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
913         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
914
915         struct weston_view *view = surface->view;
916
917         if (policy && policy->api.surface_activate_by_default &&
918             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
919             !surface->mapped)
920                 return;
921
922         if (surface->view->is_mapped || surface->state == HIDDEN)
923                 return;
924
925         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
926
927         /* remove it from hidden layer if present */
928         if (ivi_surf_in_hidden_layer(ivi, surface))
929                 weston_layer_entry_remove(&view->layer_link);
930
931         weston_view_set_output(view, woutput);
932
933         ivi_compute_popup_position(woutput, view,
934                                    surface->popup.x, surface->popup.y, &new_x, &new_y);
935         weston_view_set_position(view, new_x, new_y);
936         weston_view_update_transform(view);
937
938         /* only clip the pop-up dialog window if we have a valid
939          * width and height being passed on. Users might not want to have one
940          * set-up so only enfore it is really passed on. */
941         if (surface->popup.bb.width > 0 && surface->popup.bb.height > 0)
942                 weston_view_set_mask(view, surface->popup.bb.x, surface->popup.bb.y,
943                                      surface->popup.bb.width, surface->popup.bb.height);
944
945         weston_layer_entry_insert(&ivi->popup.view_list, &view->layer_link);
946
947         weston_view_geometry_dirty(view);
948         weston_surface_damage(view->surface);
949
950         if (ivi_seat)
951                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
952
953         wsurface->is_mapped = true;
954         surface->view->is_mapped = true;
955
956         shell_advertise_app_state(ivi, app_id,
957                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
958
959         weston_log("Activation completed for app_id %s, role %s, output %s\n",
960                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
961 }
962
963 static void
964 ivi_layout_popup_re_add(struct ivi_surface *surface)
965 {
966         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
967         struct weston_view *view = surface->view;
968
969         if (weston_view_is_mapped(view)) {
970                 struct weston_desktop_surface *dsurface = surface->dsurface;
971                 struct weston_surface *wsurface =
972                         weston_desktop_surface_get_surface(dsurface);
973
974                 weston_layer_entry_remove(&view->layer_link);
975
976                 wsurface->is_mapped = false;
977                 view->is_mapped = false;
978         }
979
980         /* reset the activate by default in order to (still) allow the surface
981          * to be activaved using the request */
982         if (!surface->mapped)
983                 surface->mapped = true;
984
985         surface->state = NORMAL;
986         ivi_layout_popup_committed(surface);
987 }
988
989 static void
990 ivi_layout_fullscreen_re_add(struct ivi_surface *surface)
991 {
992         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
993         struct weston_view *view = surface->view;
994
995         if (weston_view_is_mapped(view)) {
996                 struct weston_desktop_surface *dsurface = surface->dsurface;
997                 struct weston_surface *wsurface =
998                         weston_desktop_surface_get_surface(dsurface);
999
1000                 weston_layer_entry_remove(&view->layer_link);
1001
1002                 wsurface->is_mapped = false;
1003                 view->is_mapped = false;
1004         }
1005
1006         /* reset the activate by default in order to (still) allow the surface
1007          * to be activaved using the request */
1008         if (!surface->mapped)
1009                 surface->mapped = true;
1010
1011         surface->state = NORMAL;
1012         ivi_layout_fullscreen_committed(surface);
1013 }
1014
1015 static bool
1016 ivi_layout_surface_is_split_or_fullscreen(struct ivi_surface *surf)
1017 {
1018         struct ivi_compositor *ivi = surf->ivi;
1019         struct ivi_surface *is;
1020
1021         if (surf->role != IVI_SURFACE_ROLE_SPLIT_H &&
1022             surf->role != IVI_SURFACE_ROLE_SPLIT_V &&
1023             surf->role != IVI_SURFACE_ROLE_FULLSCREEN)
1024                 return false;
1025
1026         /* reset the activate by default in order to (still) allow the surface
1027          * to be activaved using the request */
1028         if (!surf->mapped)
1029                 surf->mapped = true;
1030
1031         wl_list_for_each(is, &ivi->surfaces, link)
1032                 if (is == surf)
1033                         return true;
1034
1035         return false;
1036 }
1037
1038 void
1039 ivi_layout_reset_split_surfaces(struct ivi_compositor *ivi)
1040 {
1041         struct ivi_surface *ivisurf;
1042         struct ivi_surface *found_ivi_surf = NULL;
1043         bool found_split_surface = false;
1044         struct ivi_output *output = NULL;
1045
1046         wl_list_for_each(ivisurf, &ivi->surfaces, link) {
1047                 if (ivisurf->orientation != AGL_SHELL_TILE_ORIENTATION_NONE) {
1048                         found_ivi_surf = ivisurf;
1049                         found_split_surface = true;
1050                         break;
1051                 }
1052         }
1053
1054         if (!found_split_surface)
1055                 return;
1056
1057         output = found_ivi_surf->current_completed_output;
1058
1059         if (found_ivi_surf->sticky)
1060                 return;
1061
1062         if (output->previous_active && output->background != output->previous_active) {
1063                 struct weston_view *ev = output->previous_active->view;
1064                 struct weston_output *woutput = output->output;
1065
1066                 if (!weston_view_is_mapped(ev))
1067                         weston_view_update_transform(ev);
1068                 else
1069                         weston_layer_entry_remove(&ev->layer_link);
1070
1071                 ev->is_mapped = true;
1072                 ev->surface->is_mapped = true;
1073                 output->previous_active->mapped = true;
1074
1075                 weston_view_set_output(ev, woutput);
1076
1077                 weston_layer_entry_insert(&ivi->normal.view_list, &ev->layer_link);
1078
1079                 _ivi_set_shell_surface_split(output->previous_active, NULL, 0,
1080                                              AGL_SHELL_TILE_ORIENTATION_NONE, false, false);
1081
1082                 if (output->active == ivisurf) {
1083                         output->active = output->previous_active;
1084                 }
1085         }
1086
1087         _ivi_set_shell_surface_split(ivisurf, NULL, 0,
1088                                      AGL_SHELL_TILE_ORIENTATION_NONE, false, false);
1089 }
1090
1091 void
1092 ivi_layout_activate_by_surf(struct ivi_output *output, struct ivi_surface *surf)
1093 {
1094         struct ivi_compositor *ivi = output->ivi;
1095         struct weston_desktop_surface *dsurf;
1096         struct weston_geometry geom;
1097         struct ivi_policy *policy = output->ivi->policy;
1098
1099         dsurf = surf->dsurface;
1100
1101         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
1102
1103         if (!surf)
1104                 return;
1105
1106         if (policy && policy->api.surface_activate &&
1107             !policy->api.surface_activate(surf, surf->ivi)) {
1108                 return;
1109         }
1110
1111 #ifdef AGL_COMP_DEBUG
1112         weston_log("Activating app_id %s, type %s, on output %s\n", app_id,
1113                         ivi_layout_get_surface_role_name(surf), output->output->name);
1114 #endif
1115
1116         if (surf->role == IVI_SURFACE_ROLE_POPUP) {
1117                 ivi_layout_popup_re_add(surf);
1118                 return;
1119         }
1120
1121         if (surf->role == IVI_SURFACE_ROLE_FULLSCREEN) {
1122                 ivi_layout_fullscreen_re_add(surf);
1123                 return;
1124         }
1125 #if 0
1126         /* reset tile to desktop to allow to resize correctly */
1127         if (surf->role == IVI_SURFACE_ROLE_TILE && output->active == surf) {
1128                 weston_log("%s() resetting tile role!\n", __func__);
1129                 surf->role = IVI_SURFACE_ROLE_DESKTOP;
1130         }
1131 #endif
1132
1133         /* do not 're'-activate surfaces that are split or active */
1134         if (surf == output->active) {
1135                 weston_log("Application %s is already active on output %s\n",
1136                                 app_id, output->output->name);
1137                 return;
1138         }
1139
1140         if (surf->sticky && surf->role == IVI_SURFACE_ROLE_TILE) {
1141                 weston_log("Application %s is already active on output %s (split role)\n",
1142                                 app_id, output->output->name);
1143                 return;
1144         }
1145
1146         if (ivi_layout_surface_is_split_or_fullscreen(surf)) {
1147                 weston_log("Application %s is fullscreen or split on output %s\n",
1148                                 app_id, output->output->name);
1149                 return;
1150         }
1151
1152         // destroy any split types to allow correct re-activation
1153         ivi_layout_reset_split_surfaces(surf->ivi);
1154
1155         if (surf->role == IVI_SURFACE_ROLE_REMOTE) {
1156                 struct ivi_output *remote_output =
1157                         ivi_layout_find_with_app_id(app_id, ivi);
1158
1159                 weston_log("Changed activation for app_id %s, type %s, on output %s\n", app_id,
1160                                 ivi_layout_get_surface_role_name(surf), output->output->name);
1161
1162                 /* if already active on a remote output do not
1163                  * attempt to activate it again */
1164                 if (remote_output && remote_output->active == surf)
1165                         return;
1166         }
1167
1168
1169         geom = weston_desktop_surface_get_geometry(dsurf);
1170
1171         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
1172                 surf->desktop.pending_output = output;
1173         if (weston_desktop_surface_get_maximized(dsurf) &&
1174             geom.width == output->area.width &&
1175             geom.height == output->area.height) {
1176                 ivi_layout_activate_complete(output, surf);
1177                 return;
1178         }
1179
1180         /* the background surface is already "maximized" so we don't need to
1181          * add to the hidden layer */
1182         if (surf->role == IVI_SURFACE_ROLE_BACKGROUND) {
1183                 ivi_layout_activate_complete(output, surf);
1184                 return;
1185         }
1186
1187         ivi_layout_add_to_hidden_layer(surf, output);
1188 }
1189
1190 void
1191 ivi_layout_activate(struct ivi_output *output, const char *app_id)
1192 {
1193         struct ivi_surface *surf;
1194         struct ivi_compositor *ivi = output->ivi;
1195
1196         if (!app_id)
1197                 return;
1198
1199         surf = ivi_find_app(ivi, app_id);
1200         if (!surf)
1201                 return;
1202
1203         ivi_layout_activate_by_surf(output, surf);
1204 }
1205
1206 struct ivi_output *
1207 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
1208 {
1209         struct ivi_output *ivi_output = NULL;
1210
1211         switch (surf->role) {
1212         case IVI_SURFACE_ROLE_DESKTOP:
1213                 if (surf->desktop.pending_output)
1214                         ivi_output = surf->desktop.pending_output;
1215                 else
1216                         ivi_output = surf->desktop.last_output;
1217                 break;
1218         case IVI_SURFACE_ROLE_POPUP:
1219                 ivi_output = surf->popup.output;
1220                 break;
1221         case IVI_SURFACE_ROLE_BACKGROUND:
1222                 ivi_output = surf->bg.output;
1223                 break;
1224         case IVI_SURFACE_ROLE_PANEL:
1225                 ivi_output = surf->panel.output;
1226                 break;
1227         case IVI_SURFACE_ROLE_FULLSCREEN:
1228                 ivi_output = surf->fullscreen.output;
1229                 break;
1230         case IVI_SURFACE_ROLE_SPLIT_H:
1231         case IVI_SURFACE_ROLE_SPLIT_V:
1232                 ivi_output = surf->split.output;
1233                 break;
1234         case IVI_SURFACE_ROLE_REMOTE:
1235                 ivi_output = surf->remote.output;
1236                 break;
1237         case IVI_SURFACE_ROLE_TILE:
1238                 ivi_output = surf->current_completed_output;
1239                 break;
1240         case IVI_SURFACE_ROLE_NONE:
1241         default:
1242                 if (surf->view->output)
1243                         return to_ivi_output(surf->view->output);
1244                 break;
1245         }
1246
1247         return ivi_output;
1248 }
1249
1250 void
1251 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
1252 {
1253         struct ivi_surface *surf;
1254         struct ivi_output *ivi_output;
1255         struct ivi_policy *policy = ivi->policy;
1256
1257         if (!app_id)
1258                 return;
1259
1260         surf = ivi_find_app(ivi, app_id);
1261         if (!surf)
1262                 return;
1263
1264         if (policy && policy->api.surface_deactivate &&
1265             !policy->api.surface_deactivate(surf, surf->ivi)) {
1266                 return;
1267         }
1268
1269         ivi_output = ivi_layout_get_output_from_surface(surf);
1270         weston_log("Deactiving %s, role %s\n", app_id,
1271                         ivi_layout_get_surface_role_name(surf));
1272
1273         if (surf->role == IVI_SURFACE_ROLE_DESKTOP ||
1274             surf->role == IVI_SURFACE_ROLE_REMOTE) {
1275                 struct ivi_surface *previous_active;
1276
1277                 previous_active = ivi_output->previous_active;
1278                 if (!previous_active) {
1279                         /* we don't have a previous active it means we should
1280                          * display the bg */
1281                         if (ivi_output->active) {
1282                                 struct weston_view *view;
1283
1284                                 view = ivi_output->active->view;
1285                                 view->is_mapped = false;
1286                                 view->surface->is_mapped = false;
1287
1288                                 weston_layer_entry_remove(&view->layer_link);
1289                                 weston_view_geometry_dirty(view);
1290                                 weston_surface_damage(view->surface);
1291                                 ivi_output->active = NULL;
1292                         }
1293                 } else {
1294                         struct weston_desktop_surface *dsurface;
1295                         const char *previous_active_app_id;
1296
1297                         dsurface = previous_active->dsurface;
1298                         previous_active_app_id =
1299                                 weston_desktop_surface_get_app_id(dsurface);
1300                         ivi_layout_activate(ivi_output, previous_active_app_id);
1301                 }
1302         } else if (surf->role == IVI_SURFACE_ROLE_POPUP ||
1303                    surf->role == IVI_SURFACE_ROLE_FULLSCREEN) {
1304                 struct weston_view *view  = surf->view;
1305
1306                 weston_view_unmap(view);
1307                 surf->state = HIDDEN;
1308
1309                 weston_layer_entry_remove(&view->layer_link);
1310                 weston_view_geometry_dirty(view);
1311                 weston_surface_damage(view->surface);
1312         }
1313
1314         shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_DEACTIVATED);
1315 }