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         struct weston_surface *wsurface =
104                 weston_desktop_surface_get_surface(panel->dsurface);
105
106         if (!panel)
107                 return;
108
109         assert(panel->role == IVI_SURFACE_ROLE_PANEL);
110         dsurface = panel->dsurface;
111         view = panel->view;
112         geom = weston_desktop_surface_get_geometry(dsurface);
113
114         weston_log("(panel) geom.width %d, geom.height %d, geom.x %d, geom.y %d\n",
115                         geom.width, geom.height, geom.x, geom.y);
116
117         switch (panel->panel.edge) {
118         case AGL_SHELL_EDGE_TOP:
119                 output->area.y += geom.height;
120                 output->area.height -= geom.height;
121                 break;
122         case AGL_SHELL_EDGE_BOTTOM:
123                 pos.c.y += woutput->height - geom.height;
124                 output->area.height -= geom.height;
125                 break;
126         case AGL_SHELL_EDGE_LEFT:
127                 output->area.x += geom.width;
128                 output->area.width -= geom.width;
129                 break;
130         case AGL_SHELL_EDGE_RIGHT:
131                 pos.c.x += woutput->width - geom.width;
132                 output->area.width -= geom.width;
133                 break;
134         }
135
136         pos.c.x -= geom.x;
137         pos.c.y -= geom.y;
138
139         weston_view_set_output(view, woutput);
140         weston_view_set_position(view, pos);
141
142         weston_surface_map(wsurface);
143         weston_view_move_to_layer(view, &ivi->panel.view_list);
144
145         weston_log("(panel) edge %d position view %p, x %f, y %f\n",
146                         panel->panel.edge, view, pos.c.x, pos.c.y);
147
148         weston_log("panel type %d inited on output %s\n", panel->panel.edge,
149                         output->name);
150 }
151
152 /*
153  * Initializes all static parts of the layout, i.e. the background and panels.
154  */
155 void
156 ivi_layout_init(struct ivi_compositor *ivi, struct ivi_output *output)
157 {
158         bool use_default_area = true;
159         struct weston_config_section *section = output->config;
160         char *t;
161
162         weston_config_section_get_string(section, "activation-area", &t, NULL);
163         if (t) {
164                 if (output->area_activation.width == 0 &&
165                     output->area_activation.height == 0 &&
166                     output->area_activation.x == 0 &&
167                     output->area_activation.y == 0) {
168                         weston_log("WARNING: activation-area set in "
169                                         "configuration file, but yet applied!\n");
170                         if (parse_activation_area(t, output) < 0)
171                                 weston_log("Invalid activation-area \"%s\" for output %s\n",
172                                            t, output->name);
173                 } else {
174                         weston_log("WARNING: activation-area detected in ini file, "
175                                         "but agl_shell override detected!\n");
176                         if (parse_activation_area(t, output) < 0)
177                                 weston_log("Invalid activation-area \"%s\" for output %s\n",
178                                            t, output->name);
179                 }
180         }
181         free(t);
182
183         ivi_background_init(ivi, output);
184
185         if (output->area_activation.width ||
186             output->area_activation.height ||
187             output->area_activation.x ||
188             output->area_activation.y) {
189                 /* Sanity check target area is within output bounds */
190                 if ((output->area_activation.x + output->area_activation.width) < output->output->width ||
191                     (output->area_activation.y + output->area_activation.height) < output->output->height) {
192                         weston_log("Using specified area for output %s, ignoring panels\n",
193                                    output->name);
194                         output->area.x = output->area_activation.x;
195                         output->area.y = output->area_activation.y;
196                         output->area.width = output->area_activation.width;
197                         output->area.height = output->area_activation.height;
198                         use_default_area = false;
199                 } else {
200                         weston_log("Invalid activation-area position for output %s, ignoring\n",
201                                    output->name);
202                 }
203         }
204         if (use_default_area) {
205                 output->area.x = 0;
206                 output->area.y = 0;
207                 output->area.width = output->output->width;
208                 output->area.height = output->output->height;
209
210                 ivi_panel_init(ivi, output, output->top);
211                 ivi_panel_init(ivi, output, output->bottom);
212                 ivi_panel_init(ivi, output, output->left);
213                 ivi_panel_init(ivi, output, output->right);
214         }
215
216         weston_compositor_schedule_repaint(ivi->compositor);
217
218         weston_log("Usable area: %dx%d+%d,%d\n",
219                    output->area.width, output->area.height,
220                    output->area.x, output->area.y);
221 }
222
223 struct ivi_surface *
224 ivi_find_app(struct ivi_compositor *ivi, const char *app_id)
225 {
226         struct ivi_surface *surf;
227         const char *id;
228
229         wl_list_for_each(surf, &ivi->surfaces, link) {
230                 id = weston_desktop_surface_get_app_id(surf->dsurface);
231                 if (id && strcmp(app_id, id) == 0)
232                         return surf;
233         }
234
235         return NULL;
236 }
237
238 static void
239 ivi_layout_activate_complete(struct ivi_output *output,
240                              struct ivi_surface *surf)
241 {
242         struct ivi_compositor *ivi = output->ivi;
243         struct weston_output *woutput = output->output;
244         struct weston_view *view = surf->view;
245         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
246         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
247         const char *app_id = weston_desktop_surface_get_app_id(surf->dsurface);
248         bool update_previous = true;
249         struct weston_coord_global pos;
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                 pos.c.x = woutput->pos.c.x + output->area.x;
285                 pos.c.y = woutput->pos.c.y + output->area.y;
286                 weston_view_set_position(view, pos);
287         }
288
289         /* reset any previous orientation */
290         if (surf->orientation != AGL_SHELL_TILE_ORIENTATION_NONE &&
291             !surf->sticky) {
292                 weston_log("%s() resetting itself to none orientation\n", __func__);
293                 surf->orientation = AGL_SHELL_TILE_ORIENTATION_NONE;
294                 weston_desktop_surface_set_orientation(surf->dsurface,
295                                                        surf->orientation);
296         }
297         view->is_mapped = true;
298         surf->mapped = true;
299         view->surface->is_mapped = true;
300
301         /* handle a movement from one output to another */
302         if (surf->current_completed_output &&
303             surf->current_completed_output != output) {
304
305                 /* we're migrating the same surface but to another output */
306                 if (surf->current_completed_output->active == surf) {
307                         struct weston_view *ev =
308                                 surf->current_completed_output->active->view;
309
310                         weston_layer_entry_remove(&ev->layer_link);
311                         surf->current_completed_output->previous_active =
312                                 surf->current_completed_output->active;
313                         surf->current_completed_output->active = NULL;
314
315                         /* damage all possible outputs to avoid stale views */
316                         weston_compositor_damage_all(ivi->compositor);
317                 }
318         }
319
320         if (output->active) {
321                 /* keep the background surface mapped at all times */
322                 if (output->active->role != IVI_SURFACE_ROLE_BACKGROUND &&
323                     !output->active->sticky) {
324
325                         output->active->view->is_mapped = false;
326                         output->active->view->surface->is_mapped = false;
327
328                         weston_layer_entry_remove(&output->active->view->layer_link);
329                 }
330         }
331
332         if (output->previous_active && output->active) {
333                 const char *c_app_id =
334                         weston_desktop_surface_get_app_id(output->active->dsurface);
335
336                 /* if the currently activated app_id is the same as the one
337                  * we're trying to complete activation with means we're
338                  * operating on the same app_id so do update previous_active as
339                  * it will overwrite it with the same value */
340                 if (app_id && !strcmp(c_app_id, app_id)) {
341                         update_previous = false;
342                 }
343         }
344
345         if (update_previous)
346                 output->previous_active = output->active;
347         output->active = surf;
348         surf->current_completed_output = output;
349
350         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
351         weston_view_geometry_dirty(view);
352         weston_surface_damage(view->surface);
353
354         if (ivi_seat)
355                 ivi_shell_activate_surface(surf, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
356
357         /*
358          * the 'remote' role now makes use of this part so make sure we don't
359          * trip the enum such that we might end up with a modified output for
360          * 'remote' role
361          */
362         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
363                 if (surf->desktop.pending_output)
364                         surf->desktop.last_output = surf->desktop.pending_output;
365                 surf->desktop.pending_output = NULL;
366         }
367
368         weston_log("Activation completed for app_id %s, role %s, output %s\n",
369                         app_id,
370                         ivi_layout_get_surface_role_name(surf), output->name);
371
372         shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_ACTIVATED);
373 }
374
375 static bool
376 ivi_layout_find_output_with_app_id(const char *app_id, struct ivi_output *output)
377 {
378         char *cur;
379         size_t app_id_len;
380
381         cur = output->app_ids;
382         app_id_len = strlen(app_id);
383
384         while ((cur = strstr(cur, app_id))) {
385                 if ((cur[app_id_len] == ',' || cur[app_id_len] == '\0') &&
386                     (cur == output->app_ids || cur[-1] == ','))
387                         return true;
388                 cur++;
389         }
390
391         return false;
392 }
393
394 struct ivi_output *
395 ivi_layout_find_with_app_id(const char *app_id, struct ivi_compositor *ivi)
396 {
397         struct ivi_output *out;
398
399         if (!app_id)
400                 return NULL;
401
402         wl_list_for_each(out, &ivi->outputs, link) {
403                 if (!out->app_ids)
404                         continue;
405
406                 if (ivi_layout_find_output_with_app_id(app_id, out))
407                         return out;
408         }
409         return NULL;
410 }
411
412 struct ivi_output *
413 ivi_layout_find_bg_output(struct ivi_compositor *ivi)
414 {
415         struct ivi_output *out;
416
417         wl_list_for_each(out, &ivi->outputs, link) {
418                 if (out->background &&
419                     out->background->role == IVI_SURFACE_ROLE_BACKGROUND)
420                         return out;
421         }
422
423         return NULL;
424 }
425
426
427 static void
428 ivi_layout_add_to_hidden_layer(struct ivi_surface *surf,
429                                struct ivi_output *ivi_output)
430 {
431         struct weston_desktop_surface *dsurf = surf->dsurface;
432         struct weston_view *ev = surf->view;
433         struct ivi_compositor *ivi = surf->ivi;
434         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
435
436         /*
437          * If the view isn't mapped, we put it onto the hidden layer so it will
438          * start receiving frame events, and will be able to act on our
439          * configure event.
440          */
441         if (!weston_view_is_mapped(ev)) {
442                 ev->is_mapped = true;
443                 ev->surface->is_mapped = true;
444
445                 weston_desktop_surface_set_maximized(dsurf, true);
446                 weston_desktop_surface_set_size(dsurf,
447                                                 ivi_output->area.width,
448                                                 ivi_output->area.height);
449
450                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
451                            app_id, ivi_layout_get_surface_role_name(surf),
452                            ivi_output->area.width, ivi_output->area.height);
453
454                 surf->hidden_layer_output = ivi_output;
455                 weston_view_set_output(ev, ivi_output->output);
456                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
457                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
458                                 app_id, ivi_layout_get_surface_role_name(surf),
459                                 ivi_output->output->name);
460
461                 weston_compositor_schedule_repaint(ivi->compositor);
462                 return;
463         }
464
465         /* we might have another output to activate */
466         if (surf->hidden_layer_output &&
467             surf->hidden_layer_output != ivi_output) {
468                 weston_layer_entry_remove(&ev->layer_link);
469                 weston_view_geometry_dirty(ev);
470                 weston_surface_damage(ev->surface);
471
472                 if (ivi_output->area.width != surf->hidden_layer_output->area.width ||
473                     ivi_output->area.height != surf->hidden_layer_output->area.height) {
474                         weston_desktop_surface_set_maximized(dsurf, true);
475                         weston_desktop_surface_set_size(dsurf,
476                                                         ivi_output->area.width,
477                                                         ivi_output->area.height);
478                 }
479
480                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
481                                 app_id, ivi_layout_get_surface_role_name(surf),
482                                 ivi_output->area.width, ivi_output->area.height);
483
484                 surf->hidden_layer_output = ivi_output;
485                 weston_view_set_output(ev, ivi_output->output);
486                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
487                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
488                                 app_id, ivi_layout_get_surface_role_name(surf),
489                                 ivi_output->output->name);
490         }
491
492         weston_compositor_schedule_repaint(ivi->compositor);
493 }
494
495 void
496 ivi_layout_remote_committed(struct ivi_surface *surf)
497 {
498         struct weston_desktop_surface *dsurf = surf->dsurface;
499         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
500         struct ivi_policy *policy = surf->ivi->policy;
501         struct ivi_output *output;
502         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
503
504         assert(surf->role == IVI_SURFACE_ROLE_REMOTE);
505
506         output = surf->remote.output;
507
508         if (policy && policy->api.surface_activate_by_default &&
509             !policy->api.surface_activate_by_default(surf, surf->ivi))
510                 return;
511
512         /* we can only activate it again by using the protocol, but
513          * additionally the output is not reset when
514          * ivi_layout_activate_complete() terminates so we use the
515          * current active surface to avoid hitting this again and again
516          * */
517         if (surf->mapped && output->active == surf)
518                 return;
519
520         if (!surf->ivi->activate_by_default &&
521             !ivi_surf_in_hidden_layer(surf->ivi, surf)) {
522                 weston_log("Refusing to activate surface role %d, "
523                             "app_id %s\n", surf->role, app_id);
524
525                 if (!weston_desktop_surface_get_maximized(dsurf) ||
526                     geom.width != output->area.width ||
527                     geom.height != output->area.height) {
528                         ivi_layout_add_to_hidden_layer(surf, output);
529                 }
530
531                 return;
532         }
533
534         if (!weston_desktop_surface_get_maximized(dsurf) ||
535             geom.width != output->area.width ||
536             geom.height != output->area.height)
537                 return;
538
539         ivi_layout_activate_complete(output, surf);
540 }
541
542 void
543 ivi_layout_desktop_committed(struct ivi_surface *surf)
544 {
545         struct weston_desktop_surface *dsurf = surf->dsurface;
546         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
547         struct ivi_policy *policy = surf->ivi->policy;
548         struct ivi_output *output;
549         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
550
551         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP);
552
553         /*
554          * we can't make use here of the ivi_layout_get_output_from_surface()
555          * due to the fact that we'll always land here when a surface performs
556          * a commit and pending_output will not bet set. This works in tandem
557          * with 'mapped' at this point to avoid tripping over
558          * to a surface that continuously updates its content
559          */
560         output = surf->desktop.pending_output;
561
562         if (!output) {
563                 struct ivi_output *r_output;
564
565                 if (policy && policy->api.surface_activate_by_default &&
566                     !policy->api.surface_activate_by_default(surf, surf->ivi))
567                         return;
568
569                 /* we can only activate it again by using the protocol */
570                 if (surf->mapped)
571                         return;
572
573                 /* check first if there aren't any outputs being set */
574                 r_output = ivi_layout_find_with_app_id(app_id, surf->ivi);
575
576                 if (r_output) {
577                         struct weston_view *view = r_output->fullscreen_view.fs->view;
578                         if (view->is_mapped || view->surface->is_mapped)
579                                 remove_black_curtain(r_output);
580                 }
581
582
583                 /* try finding an output with a background and use that */
584                 if (!r_output)
585                         r_output = ivi_layout_find_bg_output(surf->ivi);
586
587                 /* if we couldn't still find an output by this point, there's
588                  * something wrong so we abort with a protocol error */
589                 if (!r_output) {
590                         wl_resource_post_error(surf->ivi->shell_client.resource,
591                                                AGL_SHELL_ERROR_INVALID_ARGUMENT,
592                                                "No valid output found to activate surface by default");
593                         return;
594                 }
595
596                 if (!surf->ivi->activate_by_default &&
597                     (!surf->xwayland.is_set && !is_shell_surface_xwayland(surf))) {
598                         weston_log("Refusing to activate surface role %d, app_id %s, type %s\n",
599                                         surf->role, app_id,
600                                         is_shell_surface_xwayland(surf) ?
601                                         "xwayland" : "regular");
602
603                         if (!weston_desktop_surface_get_maximized(dsurf) ||
604                             geom.width != r_output->area.width ||
605                             geom.height != r_output->area.height)
606                                 ivi_layout_add_to_hidden_layer(surf, r_output);
607
608                         return;
609                 }
610
611                 /* use the output of the bg to activate the app on start-up by
612                  * default */
613                 if (surf->view && r_output) {
614                         if (app_id && r_output) {
615                                 weston_log("Surface with app_id %s, role %s activating by default\n",
616                                         weston_desktop_surface_get_app_id(surf->dsurface),
617                                         ivi_layout_get_surface_role_name(surf));
618                                 ivi_layout_activate(r_output, app_id);
619                         } else if (!app_id) {
620                                 /*
621                                  * applications not setting an app_id, or
622                                  * setting an app_id but at a later point in
623                                  * time, might fall-back here so give them a
624                                  * chance to receive the configure event and
625                                  * act upon it
626                                  */
627                                 weston_log("Surface no app_id, role %s activating by default\n",
628                                         ivi_layout_get_surface_role_name(surf));
629                                 if (surf->xwayland.is_set || is_shell_surface_xwayland(surf)) {
630                                         ivi_layout_activate_by_surf(r_output, surf);
631                                         ivi_layout_activate_complete(r_output, surf);
632                                 } else {
633                                         ivi_layout_activate_by_surf(r_output, surf);
634                                 }
635                         }
636                 }
637
638                 return;
639         }
640
641         if (!weston_desktop_surface_get_maximized(dsurf) ||
642             geom.width != output->area.width ||
643             geom.height != output->area.height)
644                 return;
645
646         ivi_layout_activate_complete(output, surf);
647 }
648
649 void
650 ivi_layout_fullscreen_committed(struct ivi_surface *surface)
651 {
652         struct ivi_compositor *ivi = surface->ivi;
653         struct ivi_policy *policy = ivi->policy;
654
655         struct weston_desktop_surface *dsurface = surface->dsurface;
656         struct weston_surface *wsurface =
657                 weston_desktop_surface_get_surface(dsurface);
658         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
659
660         struct ivi_output *output = surface->split.output;
661         struct weston_output *woutput = output->output;
662         struct ivi_output *bg_output = ivi_layout_find_bg_output(ivi);
663
664         struct weston_view *view = surface->view;
665         struct weston_geometry geom =
666                 weston_desktop_surface_get_geometry(dsurface);
667
668         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
669         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
670
671         bool is_fullscreen = weston_desktop_surface_get_fullscreen(dsurface);
672         bool is_dim_same =
673                 geom.width == bg_output->output->width &&
674                 geom.height == bg_output->output->height;
675
676         if (policy && policy->api.surface_activate_by_default &&
677             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
678             !surface->mapped)
679                 return;
680
681         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
682
683
684         if (surface->state == FULLSCREEN && weston_view_is_mapped(view))
685                 return;
686
687         /* if we still get here but we haven't resized so far, send configure
688          * events to do so */
689         if (surface->state != RESIZING && (!is_fullscreen || !is_dim_same)) {
690                 struct ivi_output *bg_output =
691                         ivi_layout_find_bg_output(surface->ivi);
692
693                 weston_log("Placing fullscreen app_id %s, type %s in hidden layer\n",
694                                 app_id, ivi_layout_get_surface_role_name(surface));
695                 weston_desktop_surface_set_fullscreen(dsurface, true);
696                 weston_desktop_surface_set_size(dsurface,
697                                                 bg_output->output->width,
698                                                 bg_output->output->height);
699
700                 surface->state = RESIZING;
701                 weston_view_set_output(view, output->output);
702                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
703                 return;
704         }
705
706         /* eventually, we would set the surface fullscreen, but the client
707          * hasn't resized correctly by this point, so terminate connection */
708         if (surface->state == RESIZING && is_fullscreen && !is_dim_same) {
709                 struct weston_desktop_client *desktop_client =
710                         weston_desktop_surface_get_client(dsurface);
711                 struct wl_client *client =
712                         weston_desktop_client_get_client(desktop_client);
713                 wl_client_post_implementation_error(client,
714                                 "can not display surface due to invalid geometry."
715                                 " Client should perform a geometry resize!");
716                 return;
717         }
718
719         /* this implies we resized correctly */
720         if (!weston_view_is_mapped(view) || surface->state != FULLSCREEN) {
721                 weston_layer_entry_remove(&view->layer_link);
722
723                 weston_view_set_output(view, woutput);
724                 weston_view_set_position(view, woutput->pos);
725                 weston_layer_entry_insert(&ivi->fullscreen.view_list, &view->layer_link);
726
727                 wsurface->is_mapped = true;
728                 surface->view->is_mapped = true;
729                 surface->state = FULLSCREEN;
730
731                 weston_view_geometry_dirty(view);
732                 weston_surface_damage(view->surface);
733
734                 if (ivi_seat)
735                         ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
736
737                 shell_advertise_app_state(ivi, app_id,
738                                 NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
739
740                 weston_log("Activation completed for app_id %s, role %s, "
741                            "output %s\n", app_id,
742                            ivi_layout_get_surface_role_name(surface),
743                            output->name);
744
745                 weston_compositor_schedule_repaint(ivi->compositor);
746         }
747 }
748
749 void
750 ivi_layout_desktop_resize(struct ivi_surface *surface,
751                           struct weston_geometry area)
752 {
753         struct weston_desktop_surface *dsurf = surface->dsurface;
754         struct weston_view *view = surface->view;
755
756         struct weston_coord_global pos;
757         int width = area.width;
758         int height = area.height;
759
760         pos.c.x = area.x;
761         pos.c.y = area.y;
762
763         weston_desktop_surface_set_size(dsurf,
764                                         width, height);
765
766         weston_view_set_position(view, pos);
767
768         weston_view_geometry_dirty(view);
769         weston_surface_damage(view->surface);
770 }
771
772 void
773 ivi_layout_split_committed(struct ivi_surface *surface)
774 {
775         struct ivi_compositor *ivi = surface->ivi;
776         struct ivi_policy *policy = ivi->policy;
777
778         struct weston_desktop_surface *dsurface = surface->dsurface;
779         struct weston_surface *wsurface =
780                 weston_desktop_surface_get_surface(dsurface);
781         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
782
783         struct ivi_output *output = surface->split.output;
784         struct weston_output *woutput = output->output;
785
786         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
787         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
788
789         struct weston_view *view = surface->view;
790         struct weston_geometry geom;
791
792         struct weston_coord_global pos = woutput->pos;
793         int width, height;
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                 pos.c.x += woutput->width - geom.width;
817                 output->area.width -= geom.width;
818
819                 width = woutput->width - pos.c.x;
820                 height = output->area.height;
821                 pos.c.y = output->area.y;
822
823                 break;
824         case IVI_SURFACE_ROLE_SPLIT_H:
825                 geom.height = (output->area.height / 2);
826
827                 pos.c.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                 pos.c.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, pos);
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, double *new_x, double *new_y)
872 {
873         *new_x = output->pos.c.x + initial_x;
874         *new_y = output->pos.c.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         struct weston_coord_global pos;
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, &pos.c.x, &pos.c.y);
935         weston_view_set_position(view, pos);
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 && output->active == surf) {
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             output->active->role != IVI_SURFACE_ROLE_TILE) {
1184                 ivi_layout_activate_complete(output, surf);
1185                 return;
1186         }
1187
1188         ivi_layout_add_to_hidden_layer(surf, output);
1189 }
1190
1191 void
1192 ivi_layout_activate(struct ivi_output *output, const char *app_id)
1193 {
1194         struct ivi_surface *surf;
1195         struct ivi_compositor *ivi = output->ivi;
1196
1197         if (!app_id)
1198                 return;
1199
1200         surf = ivi_find_app(ivi, app_id);
1201         if (!surf)
1202                 return;
1203
1204         ivi_layout_activate_by_surf(output, surf);
1205 }
1206
1207 struct ivi_output *
1208 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
1209 {
1210         struct ivi_output *ivi_output = NULL;
1211
1212         switch (surf->role) {
1213         case IVI_SURFACE_ROLE_DESKTOP:
1214                 if (surf->desktop.pending_output)
1215                         ivi_output = surf->desktop.pending_output;
1216                 else
1217                         ivi_output = surf->desktop.last_output;
1218                 break;
1219         case IVI_SURFACE_ROLE_POPUP:
1220                 ivi_output = surf->popup.output;
1221                 break;
1222         case IVI_SURFACE_ROLE_BACKGROUND:
1223                 ivi_output = surf->bg.output;
1224                 break;
1225         case IVI_SURFACE_ROLE_PANEL:
1226                 ivi_output = surf->panel.output;
1227                 break;
1228         case IVI_SURFACE_ROLE_FULLSCREEN:
1229                 ivi_output = surf->fullscreen.output;
1230                 break;
1231         case IVI_SURFACE_ROLE_SPLIT_H:
1232         case IVI_SURFACE_ROLE_SPLIT_V:
1233                 ivi_output = surf->split.output;
1234                 break;
1235         case IVI_SURFACE_ROLE_REMOTE:
1236                 ivi_output = surf->remote.output;
1237                 break;
1238         case IVI_SURFACE_ROLE_TILE:
1239                 ivi_output = surf->current_completed_output;
1240                 break;
1241         case IVI_SURFACE_ROLE_NONE:
1242         default:
1243                 if (surf->view->output)
1244                         return to_ivi_output(surf->view->output);
1245                 break;
1246         }
1247
1248         return ivi_output;
1249 }
1250
1251 void
1252 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
1253 {
1254         struct ivi_surface *surf;
1255         struct ivi_output *ivi_output;
1256         struct ivi_policy *policy = ivi->policy;
1257
1258         if (!app_id)
1259                 return;
1260
1261         surf = ivi_find_app(ivi, app_id);
1262         if (!surf)
1263                 return;
1264
1265         if (policy && policy->api.surface_deactivate &&
1266             !policy->api.surface_deactivate(surf, surf->ivi)) {
1267                 return;
1268         }
1269
1270         ivi_output = ivi_layout_get_output_from_surface(surf);
1271         weston_log("Deactiving %s, role %s\n", app_id,
1272                         ivi_layout_get_surface_role_name(surf));
1273
1274         if (surf->role == IVI_SURFACE_ROLE_DESKTOP ||
1275             surf->role == IVI_SURFACE_ROLE_REMOTE) {
1276                 struct ivi_surface *previous_active;
1277
1278                 previous_active = ivi_output->previous_active;
1279                 if (!previous_active) {
1280                         /* we don't have a previous active it means we should
1281                          * display the bg */
1282                         if (ivi_output->active) {
1283                                 struct weston_view *view;
1284
1285                                 view = ivi_output->active->view;
1286                                 view->is_mapped = false;
1287                                 view->surface->is_mapped = false;
1288
1289                                 weston_layer_entry_remove(&view->layer_link);
1290                                 weston_view_geometry_dirty(view);
1291                                 weston_surface_damage(view->surface);
1292                                 ivi_output->active = NULL;
1293                         }
1294                 } else {
1295                         struct weston_desktop_surface *dsurface;
1296                         const char *previous_active_app_id;
1297
1298                         dsurface = previous_active->dsurface;
1299                         previous_active_app_id =
1300                                 weston_desktop_surface_get_app_id(dsurface);
1301                         ivi_layout_activate(ivi_output, previous_active_app_id);
1302                 }
1303         } else if (surf->role == IVI_SURFACE_ROLE_POPUP ||
1304                    surf->role == IVI_SURFACE_ROLE_FULLSCREEN) {
1305                 struct weston_view *view  = surf->view;
1306
1307                 weston_view_unmap(view);
1308                 surf->state = HIDDEN;
1309
1310                 weston_layer_entry_remove(&view->layer_link);
1311                 weston_view_geometry_dirty(view);
1312                 weston_surface_damage(view->surface);
1313         }
1314
1315         shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_DEACTIVATED);
1316 }