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