079325e9de0dc79fc940ca0010707085f2061605
[src/agl-compositor.git] / src / layout.c
1 /*
2  * Copyright © 2019 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "ivi-compositor.h"
27 #include "policy.h"
28 #include "shared/helpers.h"
29
30 #include <assert.h>
31 #include <string.h>
32
33 #include <libweston/libweston.h>
34 #include <libweston-desktop/libweston-desktop.h>
35
36 #include "agl-shell-desktop-server-protocol.h"
37
38 #define AGL_COMP_DEBUG
39
40 static const char *ivi_roles_as_string[] = {
41         [IVI_SURFACE_ROLE_NONE]         = "NONE",
42         [IVI_SURFACE_ROLE_BACKGROUND]   = "BACKGROUND",
43         [IVI_SURFACE_ROLE_PANEL]        = "PANEL",
44         [IVI_SURFACE_ROLE_DESKTOP]      = "DESKTOP",
45         [IVI_SURFACE_ROLE_POPUP]        = "POPUP",
46         [IVI_SURFACE_ROLE_SPLIT_H]      = "SPLIT_H",
47         [IVI_SURFACE_ROLE_SPLIT_V]      = "SPLIT_V",
48         [IVI_SURFACE_ROLE_FULLSCREEN]   = "FULLSCREEN",
49         [IVI_SURFACE_ROLE_REMOTE]       = "REMOTE",
50 };
51
52 const char *
53 ivi_layout_get_surface_role_name(struct ivi_surface *surf)
54 {
55         if (surf->role < 0 || surf->role >= ARRAY_LENGTH(ivi_roles_as_string))
56                 return " unknown surface role";
57
58         return ivi_roles_as_string[surf->role];
59 }
60
61 static void
62 ivi_background_init(struct ivi_compositor *ivi, struct ivi_output *output)
63 {
64         struct weston_output *woutput = output->output;
65         struct ivi_surface *bg = output->background;
66         struct weston_view *view;
67
68         if (!bg) {
69                 weston_log("WARNING: Output does not have a background\n");
70                 return;
71         }
72
73         assert(bg->role == IVI_SURFACE_ROLE_BACKGROUND);
74
75         view = bg->view;
76
77         weston_view_set_output(view, woutput);
78         weston_view_set_position(view, woutput->x, woutput->y);
79
80 #ifdef AGL_COMP_DEBUG
81         weston_log("(background) position view %p, x %d, y %d\n", view,
82                         woutput->x, woutput->y);
83 #endif
84
85         view->is_mapped = true;
86         view->surface->is_mapped = true;
87
88         weston_layer_entry_insert(&ivi->background.view_list, &view->layer_link);
89 }
90
91 static void
92 ivi_panel_init(struct ivi_compositor *ivi, struct ivi_output *output,
93                struct ivi_surface *panel)
94 {
95         struct weston_output *woutput = output->output;
96         struct weston_desktop_surface *dsurface;
97         struct weston_view *view;
98         struct weston_geometry geom;
99         int x = woutput->x;
100         int y = woutput->y;
101
102         if (!panel)
103                 return;
104
105         assert(panel->role == IVI_SURFACE_ROLE_PANEL);
106         dsurface = panel->dsurface;
107         view = panel->view;
108         geom = weston_desktop_surface_get_geometry(dsurface);
109 #ifdef AGL_COMP_DEBUG
110         weston_log("(panel) geom.width %d, geom.height %d, geom.x %d, geom.y %d\n",
111                         geom.width, geom.height, geom.x, geom.y);
112 #endif
113         switch (panel->panel.edge) {
114         case AGL_SHELL_EDGE_TOP:
115                 output->area.y += geom.height;
116                 output->area.height -= geom.height;
117                 break;
118         case AGL_SHELL_EDGE_BOTTOM:
119                 y += woutput->height - geom.height;
120                 output->area.height -= geom.height;
121                 break;
122         case AGL_SHELL_EDGE_LEFT:
123                 output->area.x += geom.width;
124                 output->area.width -= geom.width;
125                 break;
126         case AGL_SHELL_EDGE_RIGHT:
127                 x += woutput->width - geom.width;
128                 output->area.width -= geom.width;
129                 break;
130         }
131
132         x -= geom.x;
133         y -= geom.y;
134
135         weston_view_set_output(view, woutput);
136         weston_view_set_position(view, x, y);
137 #ifdef AGL_COMP_DEBUG
138         weston_log("(panel) edge %d position view %p, x %d, y %d\n",
139                         panel->panel.edge, view, x, y);
140 #endif
141
142         /* this is necessary for cases we already mapped it desktop_committed()
143          * but we not running the older qtwayland, so we still have a chance
144          * for this to run at the next test */
145         if (view->surface->is_mapped) {
146                 weston_layer_entry_remove(&view->layer_link);
147
148                 view->is_mapped = false;
149                 view->surface->is_mapped = false;
150         }
151
152         /* give ivi_layout_panel_committed() a chance to map the view/surface
153          * instead */
154         if ((geom.width == geom.height && geom.width == 0) &&
155             (geom.x == geom.y && geom.x == 0) &&
156             panel->panel.edge != AGL_SHELL_EDGE_TOP)
157                 return;
158
159         view->is_mapped = true;
160         view->surface->is_mapped = true;
161 #ifdef AGL_COMP_DEBUG
162         weston_log("panel type %d inited\n", panel->panel.edge);
163 #endif
164         weston_layer_entry_insert(&ivi->panel.view_list, &view->layer_link);
165 }
166
167 /*
168  * Initializes all static parts of the layout, i.e. the background and panels.
169  */
170 void
171 ivi_layout_init(struct ivi_compositor *ivi, struct ivi_output *output)
172 {
173         ivi_background_init(ivi, output);
174
175         output->area.x = 0;
176         output->area.y = 0;
177         output->area.width = output->output->width;
178         output->area.height = output->output->height;
179
180         ivi_panel_init(ivi, output, output->top);
181         ivi_panel_init(ivi, output, output->bottom);
182         ivi_panel_init(ivi, output, output->left);
183         ivi_panel_init(ivi, output, output->right);
184
185         weston_compositor_schedule_repaint(ivi->compositor);
186
187         weston_log("Usable area: %dx%d+%d,%d\n",
188                    output->area.width, output->area.height,
189                    output->area.x, output->area.y);
190 }
191
192 struct ivi_surface *
193 ivi_find_app(struct ivi_compositor *ivi, const char *app_id)
194 {
195         struct ivi_surface *surf;
196         const char *id;
197
198         wl_list_for_each(surf, &ivi->surfaces, link) {
199                 id = weston_desktop_surface_get_app_id(surf->dsurface);
200                 if (id && strcmp(app_id, id) == 0)
201                         return surf;
202         }
203
204         return NULL;
205 }
206
207 static void
208 ivi_layout_activate_complete(struct ivi_output *output,
209                              struct ivi_surface *surf)
210 {
211         struct ivi_compositor *ivi = output->ivi;
212         struct weston_output *woutput = output->output;
213         struct weston_view *view = surf->view;
214
215         if (weston_view_is_mapped(view)) {
216                 weston_layer_entry_remove(&view->layer_link);
217         }
218
219         weston_view_set_output(view, woutput);
220         weston_view_set_position(view,
221                                  woutput->x + output->area.x,
222                                  woutput->y + output->area.y);
223
224         view->is_mapped = true;
225         view->surface->is_mapped = true;
226
227         if (output->active) {
228                 output->active->view->is_mapped = false;
229                 output->active->view->surface->is_mapped = false;
230
231                 weston_layer_entry_remove(&output->active->view->layer_link);
232         }
233         output->previous_active = output->active;
234         output->active = surf;
235
236         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
237         weston_view_update_transform(view);
238
239         /* force repaint of the entire output */
240         weston_output_damage(output->output);
241
242         /*
243          * the 'remote' role now makes use of this part so make sure we don't
244          * trip the enum such that we might end up with a modified output for
245          * 'remote' role
246          */
247         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
248                 if (surf->desktop.pending_output)
249                         surf->desktop.last_output = surf->desktop.pending_output;
250                 surf->desktop.pending_output = NULL;
251         }
252
253         weston_log("Activation completed for app_id %s, role %s\n",
254                         weston_desktop_surface_get_app_id(surf->dsurface),
255                         ivi_layout_get_surface_role_name(surf));
256 }
257
258 static struct ivi_output *
259 ivi_layout_find_app_id(const char *app_id, struct ivi_compositor *ivi)
260 {
261         struct ivi_output *out;
262
263         wl_list_for_each(out, &ivi->outputs, link) {
264                 if (!out->app_id)
265                         continue;
266
267                 if (!strcmp(app_id, out->app_id))
268                         return out;
269         }
270
271         return NULL;
272 }
273
274
275 static struct ivi_output *
276 ivi_layout_find_bg_output(struct ivi_compositor *ivi)
277 {
278         struct ivi_output *out;
279
280         wl_list_for_each(out, &ivi->outputs, link) {
281                 if (out->background &&
282                     out->background->role == IVI_SURFACE_ROLE_BACKGROUND)
283                         return out;
284         }
285
286         return NULL;
287 }
288
289 void
290 ivi_layout_desktop_committed(struct ivi_surface *surf)
291 {
292         struct weston_desktop_surface *dsurf = surf->dsurface;
293         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
294         struct ivi_policy *policy = surf->ivi->policy;
295         struct ivi_output *output;
296         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
297
298         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP ||
299                surf->role == IVI_SURFACE_ROLE_REMOTE);
300
301         /*
302          * we can't make use here of the ivi_layout_get_output_from_surface()
303          * due to the fact that we'll always land here when a surface performs
304          * a commit and pending_output will not bet set. This works in tandem
305          * with 'activated_by_default' at this point to avoid tripping over
306          * to a surface that continuously updates its content
307          */
308         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
309                 output = surf->desktop.pending_output;
310         else
311                 output = surf->remote.output;
312
313         if (surf->role == IVI_SURFACE_ROLE_DESKTOP && !output) {
314                 struct ivi_output *r_output;
315
316                 if (policy && policy->api.surface_activate_by_default &&
317                     !policy->api.surface_activate_by_default(surf, surf->ivi))
318                         return;
319
320                 /* we can only activate it again by using the protocol */
321                 if (surf->activated_by_default)
322                         return;
323
324                 /* check first if there aren't any outputs being set */
325                 r_output = ivi_layout_find_app_id(app_id, surf->ivi);
326
327                 if (r_output) {
328                         struct weston_view *view = r_output->fullscreen_view.fs->view;
329                         if (view->is_mapped || view->surface->is_mapped)
330                                 remove_black_surface(r_output);
331                 }
332
333
334                 /* try finding an output with a background and use that */
335                 if (!r_output)
336                         r_output = ivi_layout_find_bg_output(surf->ivi);
337
338                 /* use the output of the bg to activate the app on start-up by
339                  * default */
340                 if (surf->view && r_output) {
341                         if (app_id && r_output) {
342                                 weston_log("Surface with app_id %s, role %s activating by default\n",
343                                         weston_desktop_surface_get_app_id(surf->dsurface),
344                                         ivi_layout_get_surface_role_name(surf));
345                                 ivi_layout_activate(r_output, app_id);
346                                 surf->activated_by_default = true;
347                         }
348                 }
349
350                 return;
351         }
352
353         if (surf->role == IVI_SURFACE_ROLE_REMOTE && output) {
354                 if (policy && policy->api.surface_activate_by_default &&
355                     !policy->api.surface_activate_by_default(surf, surf->ivi))
356                         return;
357
358                 /* we can only activate it again by using the protocol, but
359                  * additionally the output is not reset when
360                  * ivi_layout_activate_complete() terminates so we use the
361                  * current active surface to avoid hitting this again and again
362                  * */
363                 if (surf->activated_by_default && output->active == surf)
364                         return;
365
366                 if (app_id) {
367                         weston_log("Surface with app_id %s, role %s activating by default\n",
368                                         weston_desktop_surface_get_app_id(surf->dsurface),
369                                         ivi_layout_get_surface_role_name(surf));
370                         ivi_layout_activate(output, app_id);
371                         surf->activated_by_default = true;
372                 }
373                 return;
374         }
375
376         if (!weston_desktop_surface_get_maximized(dsurf) ||
377             geom.width != output->area.width ||
378             geom.height != output->area.height)
379                 return;
380
381         ivi_layout_activate_complete(output, surf);
382 }
383
384 void
385 ivi_layout_fullscreen_committed(struct ivi_surface *surface)
386 {
387         struct ivi_compositor *ivi = surface->ivi;
388
389         struct weston_desktop_surface *dsurface = surface->dsurface;
390         struct weston_surface *wsurface =
391                 weston_desktop_surface_get_surface(dsurface);
392
393         struct ivi_output *output = surface->split.output;
394         struct weston_output *woutput = output->output;
395
396         struct weston_view *view = surface->view;
397         struct weston_geometry geom;
398
399         if (surface->view->is_mapped)
400                 return;
401
402         geom = weston_desktop_surface_get_geometry(dsurface);
403         weston_log("(fs) geom x %d, y %d, width %d, height %d\n", geom.x, geom.y,
404                         geom.width, geom.height);
405
406         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
407
408         weston_desktop_surface_set_fullscreen(dsurface, true);
409
410         weston_view_set_output(view, woutput);
411         weston_view_set_position(view, woutput->x, woutput->y);
412         weston_layer_entry_insert(&ivi->fullscreen.view_list, &view->layer_link);
413
414         weston_view_update_transform(view);
415         weston_view_damage_below(view);
416
417         wsurface->is_mapped = true;
418         surface->view->is_mapped = true;
419 }
420
421 void
422 ivi_layout_desktop_resize(struct ivi_surface *surface,
423                           struct weston_geometry area)
424 {
425         struct weston_desktop_surface *dsurf = surface->dsurface;
426         struct weston_view *view = surface->view;
427
428         int x = area.x;
429         int y = area.y;
430         int width = area.width;
431         int height = area.height;
432
433         weston_desktop_surface_set_size(dsurf,
434                                         width, height);
435
436         weston_view_set_position(view, x, y);
437         weston_view_update_transform(view);
438         weston_view_damage_below(view);
439 }
440
441 void
442 ivi_layout_split_committed(struct ivi_surface *surface)
443 {
444         struct ivi_compositor *ivi = surface->ivi;
445
446         struct weston_desktop_surface *dsurface = surface->dsurface;
447         struct weston_surface *wsurface =
448                 weston_desktop_surface_get_surface(dsurface);
449
450         struct ivi_output *output = surface->split.output;
451         struct weston_output *woutput = output->output;
452
453         struct weston_view *view = surface->view;
454         struct weston_geometry geom;
455
456         int x, y;
457         int width, height;
458
459         x = woutput->x;
460         y = woutput->y;
461
462         if (surface->view->is_mapped)
463                 return;
464
465         geom = weston_desktop_surface_get_geometry(dsurface);
466
467         assert(surface->role == IVI_SURFACE_ROLE_SPLIT_H ||
468                surface->role == IVI_SURFACE_ROLE_SPLIT_V);
469
470         /* save the previous area in order to recover it back when if this kind
471          * of surface is being destroyed/removed */
472         output->area_saved = output->area;
473
474         switch (surface->role) {
475         case IVI_SURFACE_ROLE_SPLIT_V:
476                 if (geom.width == woutput->width &&
477                     geom.height == woutput->height)
478                         geom.width = (output->area.width / 2);
479
480                 x += woutput->width - geom.width;
481                 output->area.width -= geom.width;
482
483                 width = woutput->width - x;
484                 height = output->area.height;
485                 y = output->area.y;
486
487                 break;
488         case IVI_SURFACE_ROLE_SPLIT_H:
489                 if (geom.width == woutput->width &&
490                     geom.height == woutput->height)
491                         geom.height = (output->area.height / 2);
492
493                 y = output->area.y;
494                 output->area.y += geom.height;
495                 output->area.height -= geom.height;
496
497                 width = output->area.width;
498                 height = output->area.height;
499
500                 x = output->area.x;
501
502                 break;
503         default:
504                 assert(!"Invalid split orientation\n");
505         }
506
507         weston_desktop_surface_set_size(dsurface,
508                                         width, height);
509
510         /* resize the active surface first, output->area already contains
511          * correct area to resize to */
512         if (output->active)
513                 ivi_layout_desktop_resize(output->active, output->area);
514
515         weston_view_set_output(view, woutput);
516         weston_view_set_position(view, x, y);
517         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
518
519         weston_view_update_transform(view);
520         weston_view_damage_below(view);
521
522         wsurface->is_mapped = true;
523         surface->view->is_mapped = true;
524 }
525
526 void
527 ivi_layout_popup_committed(struct ivi_surface *surface)
528 {
529         struct ivi_compositor *ivi = surface->ivi;
530
531         struct weston_desktop_surface *dsurface = surface->dsurface;
532         struct weston_surface *wsurface =
533                 weston_desktop_surface_get_surface(dsurface);
534
535         struct ivi_output *output = surface->popup.output;
536         struct weston_output *woutput = output->output;
537
538         struct weston_view *view = surface->view;
539         struct weston_geometry geom;
540
541         if (surface->view->is_mapped)
542                 return;
543
544         geom = weston_desktop_surface_get_geometry(dsurface);
545         weston_log("(popup) geom x %d, y %d, width %d, height %d\n", geom.x, geom.y,
546                         geom.width, geom.height);
547
548         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
549
550         weston_view_set_output(view, woutput);
551         if (surface->popup.x || surface->popup.y)
552                 weston_view_set_position(view, surface->popup.x, surface->popup.y);
553         else
554                 weston_view_set_position(view, geom.x, geom.y);
555         weston_layer_entry_insert(&ivi->popup.view_list, &view->layer_link);
556
557         weston_view_update_transform(view);
558         weston_view_damage_below(view);
559
560         wsurface->is_mapped = true;
561         surface->view->is_mapped = true;
562 }
563
564 static void
565 ivi_layout_popup_re_add(struct ivi_surface *surface)
566 {
567         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
568         struct weston_view *view = surface->view;
569
570         if (weston_view_is_mapped(view)) {
571                 struct weston_desktop_surface *dsurface = surface->dsurface;
572                 struct weston_surface *wsurface =
573                         weston_desktop_surface_get_surface(dsurface);
574
575                 weston_layer_entry_remove(&view->layer_link);
576
577                 wsurface->is_mapped = false;
578                 view->is_mapped = false;
579         }
580
581         ivi_layout_popup_committed(surface);
582 }
583
584 void
585 ivi_layout_panel_committed(struct ivi_surface *surface)
586 {
587         struct ivi_compositor *ivi = surface->ivi;
588         struct ivi_output *output = surface->bg.output;
589         struct weston_output *woutput = output->output;
590         struct weston_desktop_surface *dsurface = surface->dsurface;
591         struct weston_surface *wsurface =
592                 weston_desktop_surface_get_surface(dsurface);
593         struct weston_geometry geom;
594         int x = woutput->x;
595         int y = woutput->y;
596
597         assert(surface->role == IVI_SURFACE_ROLE_PANEL);
598
599         /*
600          * If the desktop_surface geometry is not set and the panel is not a
601          * top one, we'll give this a chance to run, as some qtwayland version
602          * seem to have a 'problem', where the panel initilization part will
603          * have a desktop surface with 0 as geometry for *all* its members
604          * (width/height). Doing that will result in the panel not being
605          * displayed at all.
606          *
607          * Later versions of qtwayland do have the correct window geometry for
608          * the desktop surface so the weston_surface is already mapped in
609          * ivi_panel_init().
610          */
611         if (wsurface->is_mapped)
612                 return;
613
614         geom = weston_desktop_surface_get_geometry(dsurface);
615
616 #ifdef AGL_COMP_DEBUG
617         weston_log("geom.width %d, geom.height %d, geom.x %d, geom.y %d\n",
618                         geom.width, geom.height, geom.x, geom.y);
619 #endif
620
621         switch (surface->panel.edge) {
622         case AGL_SHELL_EDGE_TOP:
623                 /* Do nothing */
624                 break;
625         case AGL_SHELL_EDGE_BOTTOM:
626                 y += woutput->height - geom.height;
627                 break;
628         case AGL_SHELL_EDGE_LEFT:
629                 /* Do nothing */
630                 break;
631         case AGL_SHELL_EDGE_RIGHT:
632                 x += woutput->width - geom.width;
633                 break;
634         }
635 #ifndef AGL_COMP_DEBUG
636         weston_log("panel type %d commited\n", surface->panel.edge);
637 #endif
638
639         weston_view_set_output(surface->view, woutput);
640         weston_view_set_position(surface->view, x, y);
641         weston_layer_entry_insert(&ivi->panel.view_list,
642                                   &surface->view->layer_link);
643
644         weston_view_update_transform(surface->view);
645         weston_view_schedule_repaint(surface->view);
646
647         wsurface->is_mapped = true;
648         surface->view->is_mapped = true;
649 }
650
651 static bool
652 ivi_layout_surface_is_split_or_fullscreen(struct ivi_surface *surf)
653 {
654         struct ivi_compositor *ivi = surf->ivi;
655         struct ivi_surface *is;
656
657         if (surf->role != IVI_SURFACE_ROLE_SPLIT_H &&
658             surf->role != IVI_SURFACE_ROLE_SPLIT_V &&
659             surf->role != IVI_SURFACE_ROLE_FULLSCREEN)
660                 return false;
661
662         wl_list_for_each(is, &ivi->surfaces, link)
663                 if (is == surf)
664                         return true;
665
666         return false;
667 }
668
669 void
670 ivi_layout_activate(struct ivi_output *output, const char *app_id)
671 {
672         struct ivi_compositor *ivi = output->ivi;
673         struct ivi_surface *surf;
674         struct weston_desktop_surface *dsurf;
675         struct weston_view *view;
676         struct weston_geometry geom;
677         struct ivi_policy *policy = output->ivi->policy;
678
679         surf = ivi_find_app(ivi, app_id);
680         if (!surf)
681                 return;
682
683         if (policy && policy->api.surface_activate &&
684             !policy->api.surface_activate(surf, surf->ivi)) {
685                 return;
686         }
687
688 #ifdef AGL_COMP_DEBUG
689         weston_log("Activating app_id %s, type %s\n", app_id,
690                         ivi_layout_get_surface_role_name(surf));
691 #endif
692
693         if (surf->role == IVI_SURFACE_ROLE_POPUP) {
694                 ivi_layout_popup_re_add(surf);
695                 return;
696         }
697
698         /* do not 're'-activate surfaces that are split or active */
699         if (surf == output->active ||
700             ivi_layout_surface_is_split_or_fullscreen(surf))
701                 return;
702
703
704         dsurf = surf->dsurface;
705         view = surf->view;
706         geom = weston_desktop_surface_get_geometry(dsurf);
707
708         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
709                 surf->desktop.pending_output = output;
710         if (weston_desktop_surface_get_maximized(dsurf) &&
711             geom.width == output->area.width &&
712             geom.height == output->area.height) {
713                 ivi_layout_activate_complete(output, surf);
714                 return;
715         }
716
717         weston_desktop_surface_set_maximized(dsurf, true);
718         weston_desktop_surface_set_size(dsurf,
719                                         output->area.width,
720                                         output->area.height);
721
722         weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
723                         app_id, ivi_layout_get_surface_role_name(surf),
724                         output->area.width, output->area.height);
725         /*
726          * If the view isn't mapped, we put it onto the hidden layer so it will
727          * start receiving frame events, and will be able to act on our
728          * configure event.
729          */
730         if (!weston_view_is_mapped(view)) {
731                 view->is_mapped = true;
732                 view->surface->is_mapped = true;
733
734                 weston_view_set_output(view, output->output);
735                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
736                 /* force repaint of the entire output */
737
738                 weston_log("Placed app_id %s, type %s in hidden layer\n",
739                                 app_id, ivi_layout_get_surface_role_name(surf));
740                 weston_output_damage(output->output);
741         }
742 }
743
744 struct ivi_output *
745 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
746 {
747         struct ivi_output *ivi_output = NULL;
748
749         switch (surf->role) {
750         case IVI_SURFACE_ROLE_DESKTOP:
751                 if (surf->desktop.pending_output)
752                         ivi_output = surf->desktop.pending_output;
753                 else
754                         ivi_output = surf->desktop.last_output;
755                 break;
756         case IVI_SURFACE_ROLE_POPUP:
757                 ivi_output = surf->popup.output;
758                 break;
759         case IVI_SURFACE_ROLE_BACKGROUND:
760                 ivi_output = surf->bg.output;
761                 break;
762         case IVI_SURFACE_ROLE_PANEL:
763                 ivi_output = surf->panel.output;
764                 break;
765         case IVI_SURFACE_ROLE_FULLSCREEN:
766                 ivi_output = surf->fullscreen.output;
767                 break;
768         case IVI_SURFACE_ROLE_SPLIT_H:
769         case IVI_SURFACE_ROLE_SPLIT_V:
770                 ivi_output = surf->split.output;
771                 break;
772         case IVI_SURFACE_ROLE_REMOTE:
773                 ivi_output = surf->remote.output;
774                 break;
775         case IVI_SURFACE_ROLE_NONE:
776         default:
777                 break;
778         }
779
780         return ivi_output;
781 }
782
783 void
784 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
785 {
786         struct ivi_surface *surf;
787         struct ivi_output *ivi_output;
788         struct ivi_policy *policy = ivi->policy;
789
790         surf = ivi_find_app(ivi, app_id);
791         if (!surf)
792                 return;
793
794         if (policy && policy->api.surface_deactivate &&
795             !policy->api.surface_deactivate(surf, surf->ivi)) {
796                 return;
797         }
798
799         ivi_output = ivi_layout_get_output_from_surface(surf);
800         weston_log("Deactiving %s, role %s\n", app_id,
801                         ivi_layout_get_surface_role_name(surf));
802
803         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
804                 struct ivi_surface *previous_active;
805
806                 previous_active = ivi_output->previous_active;
807                 if (!previous_active) {
808                         /* we don't have a previous active it means we should
809                          * display the bg */
810                         if (ivi_output->active) {
811                                 struct weston_view *view;
812
813                                 view = ivi_output->active->view;
814                                 view->is_mapped = false;
815                                 view->surface->is_mapped = false;
816
817                                 weston_layer_entry_remove(&view->layer_link);
818                                 weston_output_damage(ivi_output->output);
819                         }
820                 } else {
821                         struct weston_desktop_surface *dsurface;
822                         const char *previous_active_app_id;
823
824                         dsurface = previous_active->dsurface;
825                         previous_active_app_id =
826                                 weston_desktop_surface_get_app_id(dsurface);
827                         ivi_layout_activate(ivi_output, previous_active_app_id);
828                 }
829         } else if (surf->role == IVI_SURFACE_ROLE_POPUP) {
830                 struct weston_view *view  = surf->view;
831
832                 weston_layer_entry_remove(&view->layer_link);
833                 weston_view_damage_below(view);
834         }
835 }