5d24a1fc0c6373b94c8ed5267cedd22f5e82efb1
[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         weston_log("(background) position view %p, x %d, y %d, on output %s\n", view,
81                         woutput->x, woutput->y, output->name);
82
83         view->is_mapped = true;
84         view->surface->is_mapped = true;
85
86         weston_layer_entry_insert(&ivi->background.view_list, &view->layer_link);
87 }
88
89 static void
90 ivi_panel_init(struct ivi_compositor *ivi, struct ivi_output *output,
91                struct ivi_surface *panel)
92 {
93         struct weston_output *woutput = output->output;
94         struct weston_desktop_surface *dsurface;
95         struct weston_view *view;
96         struct weston_geometry geom;
97         int x = woutput->x;
98         int y = woutput->y;
99
100         if (!panel)
101                 return;
102
103         assert(panel->role == IVI_SURFACE_ROLE_PANEL);
104         dsurface = panel->dsurface;
105         view = panel->view;
106         geom = weston_desktop_surface_get_geometry(dsurface);
107
108         weston_log("(panel) geom.width %d, geom.height %d, geom.x %d, geom.y %d\n",
109                         geom.width, geom.height, geom.x, geom.y);
110
111         switch (panel->panel.edge) {
112         case AGL_SHELL_EDGE_TOP:
113                 output->area.y += geom.height;
114                 output->area.height -= geom.height;
115                 break;
116         case AGL_SHELL_EDGE_BOTTOM:
117                 y += woutput->height - geom.height;
118                 output->area.height -= geom.height;
119                 break;
120         case AGL_SHELL_EDGE_LEFT:
121                 output->area.x += geom.width;
122                 output->area.width -= geom.width;
123                 break;
124         case AGL_SHELL_EDGE_RIGHT:
125                 x += woutput->width - geom.width;
126                 output->area.width -= geom.width;
127                 break;
128         }
129
130         x -= geom.x;
131         y -= geom.y;
132
133         weston_view_set_output(view, woutput);
134         weston_view_set_position(view, x, y);
135
136         weston_log("(panel) edge %d position view %p, x %d, y %d\n",
137                         panel->panel.edge, view, x, y);
138
139         view->is_mapped = true;
140         view->surface->is_mapped = true;
141
142         weston_log("panel type %d inited on output %s\n", panel->panel.edge,
143                         output->name);
144
145         weston_layer_entry_insert(&ivi->panel.view_list, &view->layer_link);
146 }
147
148 /*
149  * Initializes all static parts of the layout, i.e. the background and panels.
150  */
151 void
152 ivi_layout_init(struct ivi_compositor *ivi, struct ivi_output *output)
153 {
154         ivi_background_init(ivi, output);
155
156         output->area.x = 0;
157         output->area.y = 0;
158         output->area.width = output->output->width;
159         output->area.height = output->output->height;
160
161         ivi_panel_init(ivi, output, output->top);
162         ivi_panel_init(ivi, output, output->bottom);
163         ivi_panel_init(ivi, output, output->left);
164         ivi_panel_init(ivi, output, output->right);
165
166         weston_compositor_schedule_repaint(ivi->compositor);
167
168         weston_log("Usable area: %dx%d+%d,%d\n",
169                    output->area.width, output->area.height,
170                    output->area.x, output->area.y);
171 }
172
173 struct ivi_surface *
174 ivi_find_app(struct ivi_compositor *ivi, const char *app_id)
175 {
176         struct ivi_surface *surf;
177         const char *id;
178
179         wl_list_for_each(surf, &ivi->surfaces, link) {
180                 id = weston_desktop_surface_get_app_id(surf->dsurface);
181                 if (id && strcmp(app_id, id) == 0)
182                         return surf;
183         }
184
185         return NULL;
186 }
187
188 static void
189 ivi_layout_activate_complete(struct ivi_output *output,
190                              struct ivi_surface *surf)
191 {
192         struct ivi_compositor *ivi = output->ivi;
193         struct weston_output *woutput = output->output;
194         struct weston_view *view = surf->view;
195         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
196         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
197
198         if (weston_view_is_mapped(view)) {
199                 weston_layer_entry_remove(&view->layer_link);
200         } else {
201                 weston_view_update_transform(view);
202         }
203
204         weston_view_set_output(view, woutput);
205         weston_view_set_position(view,
206                                  woutput->x + output->area.x,
207                                  woutput->y + output->area.y);
208
209         view->is_mapped = true;
210         surf->mapped = true;
211         view->surface->is_mapped = true;
212
213         if (output->active) {
214                 output->active->view->is_mapped = false;
215                 output->active->view->surface->is_mapped = false;
216
217                 weston_layer_entry_remove(&output->active->view->layer_link);
218         }
219         output->previous_active = output->active;
220         output->active = surf;
221
222         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
223         weston_view_geometry_dirty(view);
224         weston_surface_damage(view->surface);
225
226         if (ivi_seat)
227                 ivi_shell_activate_surface(surf, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
228
229         /*
230          * the 'remote' role now makes use of this part so make sure we don't
231          * trip the enum such that we might end up with a modified output for
232          * 'remote' role
233          */
234         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
235                 if (surf->desktop.pending_output)
236                         surf->desktop.last_output = surf->desktop.pending_output;
237                 surf->desktop.pending_output = NULL;
238         }
239
240         weston_log("Activation completed for app_id %s, role %s, output %s\n",
241                         weston_desktop_surface_get_app_id(surf->dsurface),
242                         ivi_layout_get_surface_role_name(surf), output->name);
243 }
244
245 struct ivi_output *
246 ivi_layout_find_with_app_id(const char *app_id, struct ivi_compositor *ivi)
247 {
248         struct ivi_output *out;
249
250         if (!app_id)
251                 return NULL;
252
253         wl_list_for_each(out, &ivi->outputs, link) {
254                 if (!out->app_id)
255                         continue;
256
257                 if (!strcmp(app_id, out->app_id))
258                         return out;
259         }
260
261         return NULL;
262 }
263
264 struct ivi_output *
265 ivi_layout_find_bg_output(struct ivi_compositor *ivi)
266 {
267         struct ivi_output *out;
268
269         wl_list_for_each(out, &ivi->outputs, link) {
270                 if (out->background &&
271                     out->background->role == IVI_SURFACE_ROLE_BACKGROUND)
272                         return out;
273         }
274
275         return NULL;
276 }
277
278
279 static void
280 ivi_layout_add_to_hidden_layer(struct ivi_surface *surf,
281                                struct ivi_output *ivi_output)
282 {
283         struct weston_desktop_surface *dsurf = surf->dsurface;
284         struct weston_view *ev = surf->view;
285         struct ivi_compositor *ivi = surf->ivi;
286         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
287
288         weston_desktop_surface_set_maximized(dsurf, true);
289         weston_desktop_surface_set_size(dsurf,
290                                         ivi_output->area.width,
291                                         ivi_output->area.height);
292
293         weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
294                         app_id, ivi_layout_get_surface_role_name(surf),
295                         ivi_output->area.width, ivi_output->area.height);
296         /*
297          * If the view isn't mapped, we put it onto the hidden layer so it will
298          * start receiving frame events, and will be able to act on our
299          * configure event.
300          */
301         if (!weston_view_is_mapped(ev)) {
302                 ev->is_mapped = true;
303                 ev->surface->is_mapped = true;
304
305                 weston_view_set_output(ev, ivi_output->output);
306                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
307                 weston_log("Placed app_id %s, type %s in hidden layer\n",
308                                 app_id, ivi_layout_get_surface_role_name(surf));
309         }
310 }
311
312 void
313 ivi_layout_desktop_committed(struct ivi_surface *surf)
314 {
315         struct weston_desktop_surface *dsurf = surf->dsurface;
316         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
317         struct ivi_policy *policy = surf->ivi->policy;
318         struct ivi_output *output;
319         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
320
321         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP ||
322                surf->role == IVI_SURFACE_ROLE_REMOTE);
323
324         /*
325          * we can't make use here of the ivi_layout_get_output_from_surface()
326          * due to the fact that we'll always land here when a surface performs
327          * a commit and pending_output will not bet set. This works in tandem
328          * with 'mapped' at this point to avoid tripping over
329          * to a surface that continuously updates its content
330          */
331         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
332                 output = surf->desktop.pending_output;
333         else
334                 output = surf->remote.output;
335
336         if (surf->role == IVI_SURFACE_ROLE_DESKTOP && !output) {
337                 struct ivi_output *r_output;
338
339                 if (policy && policy->api.surface_activate_by_default &&
340                     !policy->api.surface_activate_by_default(surf, surf->ivi))
341                         return;
342
343                 /* we can only activate it again by using the protocol */
344                 if (surf->mapped)
345                         return;
346
347                 /* check first if there aren't any outputs being set */
348                 r_output = ivi_layout_find_with_app_id(app_id, surf->ivi);
349
350                 if (r_output) {
351                         struct weston_view *view = r_output->fullscreen_view.fs->view;
352                         if (view->is_mapped || view->surface->is_mapped)
353                                 remove_black_surface(r_output);
354                 }
355
356
357                 /* try finding an output with a background and use that */
358                 if (!r_output)
359                         r_output = ivi_layout_find_bg_output(surf->ivi);
360
361                 /* if we couldn't still find an output by this point, there's
362                  * something wrong so we abort with a protocol error */
363                 if (!r_output) {
364                         wl_resource_post_error(surf->ivi->shell_client.resource,
365                                                AGL_SHELL_ERROR_INVALID_ARGUMENT,
366                                                "No valid output found to activate surface by default");
367                         return;
368                 }
369
370                 if (!surf->ivi->activate_by_default) {
371                         weston_log("Refusing to activate surface role %d, app_id %s\n",
372                                         surf->role, app_id);
373
374                         if (!weston_desktop_surface_get_maximized(dsurf) ||
375                             geom.width != r_output->area.width ||
376                             geom.height != r_output->area.height)
377                                 ivi_layout_add_to_hidden_layer(surf, r_output);
378
379                         return;
380                 }
381
382                 /* use the output of the bg to activate the app on start-up by
383                  * default */
384                 if (surf->view && r_output) {
385                         if (app_id && r_output) {
386                                 weston_log("Surface with app_id %s, role %s activating by default\n",
387                                         weston_desktop_surface_get_app_id(surf->dsurface),
388                                         ivi_layout_get_surface_role_name(surf));
389                                 ivi_layout_activate(r_output, app_id);
390                         } else if (!app_id) {
391                                 /*
392                                  * applications not setting an app_id, or
393                                  * setting an app_id but at a later point in
394                                  * time, might fall-back here so give them a
395                                  * chance to receive the configure event and
396                                  * act upon it
397                                  */
398                                 weston_log("Surface no app_id, role %s activating by default\n",
399                                         ivi_layout_get_surface_role_name(surf));
400                                 ivi_layout_activate_by_surf(r_output, surf);
401                         }
402                 }
403
404                 return;
405         }
406
407         if (surf->role == IVI_SURFACE_ROLE_REMOTE && output) {
408                 if (policy && policy->api.surface_activate_by_default &&
409                     !policy->api.surface_activate_by_default(surf, surf->ivi))
410                         return;
411
412                 /* we can only activate it again by using the protocol, but
413                  * additionally the output is not reset when
414                  * ivi_layout_activate_complete() terminates so we use the
415                  * current active surface to avoid hitting this again and again
416                  * */
417                 if (surf->mapped && output->active == surf)
418                         return;
419
420                 if (app_id) {
421                         weston_log("Surface with app_id %s, role %s activating by default\n",
422                                         weston_desktop_surface_get_app_id(surf->dsurface),
423                                         ivi_layout_get_surface_role_name(surf));
424                         ivi_layout_activate(output, app_id);
425                 }
426                 return;
427         }
428
429         if (!weston_desktop_surface_get_maximized(dsurf) ||
430             geom.width != output->area.width ||
431             geom.height != output->area.height)
432                 return;
433
434         ivi_layout_activate_complete(output, surf);
435 }
436
437 void
438 ivi_layout_fullscreen_committed(struct ivi_surface *surface)
439 {
440         struct ivi_compositor *ivi = surface->ivi;
441         struct ivi_policy *policy = ivi->policy;
442
443         struct weston_desktop_surface *dsurface = surface->dsurface;
444         struct weston_surface *wsurface =
445                 weston_desktop_surface_get_surface(dsurface);
446         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
447
448         struct ivi_output *output = surface->split.output;
449         struct weston_output *woutput = output->output;
450         struct ivi_output *bg_output = ivi_layout_find_bg_output(ivi);
451
452         struct weston_view *view = surface->view;
453         struct weston_geometry geom =
454                 weston_desktop_surface_get_geometry(dsurface);
455
456         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
457         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
458
459         bool is_fullscreen = weston_desktop_surface_get_fullscreen(dsurface);
460         bool is_dim_same =
461                 geom.width == bg_output->output->width &&
462                 geom.height == bg_output->output->height;
463
464         if (policy && policy->api.surface_activate_by_default &&
465             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
466             !surface->mapped)
467                 return;
468
469         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
470
471         if (weston_view_is_mapped(view))
472                 return;
473
474         /* if we still get here but we haven't resized so far, send configure
475          * events to do so */
476         if (surface->state != RESIZING && (!is_fullscreen || !is_dim_same)) {
477                 struct ivi_output *bg_output =
478                         ivi_layout_find_bg_output(surface->ivi);
479
480                 weston_log("Placing fullscreen app_id %s, type %s in hidden layer\n",
481                                 app_id, ivi_layout_get_surface_role_name(surface));
482                 weston_desktop_surface_set_fullscreen(dsurface, true);
483                 weston_desktop_surface_set_size(dsurface,
484                                                 bg_output->output->width,
485                                                 bg_output->output->height);
486
487                 surface->state = RESIZING;
488                 weston_view_set_output(view, output->output);
489                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
490                 return;
491         }
492
493         /* eventually, we would set the surface fullscreen, but the client
494          * hasn't resized correctly by this point, so terminate connection */
495         if (surface->state == RESIZING && is_fullscreen && !is_dim_same) {
496                 struct weston_desktop_client *desktop_client =
497                         weston_desktop_surface_get_client(dsurface);
498                 struct wl_client *client =
499                         weston_desktop_client_get_client(desktop_client);
500                 wl_client_post_implementation_error(client,
501                                 "can not display surface due to invalid geometry."
502                                 " Client should perform a geometry resize!");
503                 return;
504         }
505
506         /* this implies we resized correctly */
507         if (!weston_view_is_mapped(view)) {
508                 weston_layer_entry_remove(&view->layer_link);
509
510                 weston_view_set_output(view, woutput);
511                 weston_view_set_position(view, woutput->x, woutput->y);
512                 weston_layer_entry_insert(&ivi->fullscreen.view_list, &view->layer_link);
513
514                 wsurface->is_mapped = true;
515                 surface->view->is_mapped = true;
516                 surface->state = FULLSCREEN;
517
518                 weston_view_geometry_dirty(view);
519                 weston_surface_damage(view->surface);
520
521                 if (ivi_seat)
522                         ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
523
524                 shell_advertise_app_state(ivi, app_id,
525                                 NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
526
527                 weston_log("Activation completed for app_id %s, role %s, "
528                            "output %s\n", app_id,
529                            ivi_layout_get_surface_role_name(surface),
530                            output->name);
531
532         }
533 }
534
535 void
536 ivi_layout_desktop_resize(struct ivi_surface *surface,
537                           struct weston_geometry area)
538 {
539         struct weston_desktop_surface *dsurf = surface->dsurface;
540         struct weston_view *view = surface->view;
541
542         int x = area.x;
543         int y = area.y;
544         int width = area.width;
545         int height = area.height;
546
547         weston_desktop_surface_set_size(dsurf,
548                                         width, height);
549
550         weston_view_set_position(view, x, y);
551
552         weston_view_geometry_dirty(view);
553         weston_surface_damage(view->surface);
554 }
555
556 void
557 ivi_layout_split_committed(struct ivi_surface *surface)
558 {
559         struct ivi_compositor *ivi = surface->ivi;
560         struct ivi_policy *policy = ivi->policy;
561
562         struct weston_desktop_surface *dsurface = surface->dsurface;
563         struct weston_surface *wsurface =
564                 weston_desktop_surface_get_surface(dsurface);
565         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
566
567         struct ivi_output *output = surface->split.output;
568         struct weston_output *woutput = output->output;
569
570         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
571         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
572
573         struct weston_view *view = surface->view;
574         struct weston_geometry geom;
575
576         int x, y;
577         int width, height;
578
579         x = woutput->x;
580         y = woutput->y;
581
582         if (policy && policy->api.surface_activate_by_default &&
583             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
584             !surface->mapped)
585                 return;
586
587         if (surface->view->is_mapped)
588                 return;
589
590         geom = weston_desktop_surface_get_geometry(dsurface);
591
592         assert(surface->role == IVI_SURFACE_ROLE_SPLIT_H ||
593                surface->role == IVI_SURFACE_ROLE_SPLIT_V);
594
595         /* save the previous area in order to recover it back when if this kind
596          * of surface is being destroyed/removed */
597         output->area_saved = output->area;
598
599         switch (surface->role) {
600         case IVI_SURFACE_ROLE_SPLIT_V:
601                 geom.width = (output->area.width / 2);
602
603                 x += woutput->width - geom.width;
604                 output->area.width -= geom.width;
605
606                 width = woutput->width - x;
607                 height = output->area.height;
608                 y = output->area.y;
609
610                 break;
611         case IVI_SURFACE_ROLE_SPLIT_H:
612                 geom.height = (output->area.height / 2);
613
614                 y = output->area.y;
615                 output->area.y += geom.height;
616                 output->area.height -= geom.height;
617
618                 width = output->area.width;
619                 height = output->area.height;
620
621                 x = output->area.x;
622
623                 break;
624         default:
625                 assert(!"Invalid split orientation\n");
626         }
627
628         weston_desktop_surface_set_size(dsurface,
629                                         width, height);
630
631         /* resize the active surface first, output->area already contains
632          * correct area to resize to */
633         if (output->active)
634                 ivi_layout_desktop_resize(output->active, output->area);
635
636         weston_view_set_output(view, woutput);
637         weston_view_set_position(view, x, y);
638         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
639
640         weston_view_geometry_dirty(view);
641         weston_surface_damage(view->surface);
642
643         if (ivi_seat)
644                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
645
646         wsurface->is_mapped = true;
647         surface->view->is_mapped = true;
648
649         shell_advertise_app_state(ivi, app_id,
650                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
651
652         weston_log("Activation completed for app_id %s, role %s, output %s\n",
653                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
654 }
655
656 static void
657 ivi_compute_popup_position(const struct weston_output *output, struct weston_view *view,
658                            int initial_x, int initial_y, int *new_x, int *new_y)
659 {
660         *new_x = output->x + initial_x;
661         *new_y = output->y + initial_y;
662 }
663
664
665 void
666 ivi_layout_popup_committed(struct ivi_surface *surface)
667 {
668         struct ivi_compositor *ivi = surface->ivi;
669         struct ivi_policy *policy = ivi->policy;
670
671         struct weston_desktop_surface *dsurface = surface->dsurface;
672         struct weston_surface *wsurface =
673                 weston_desktop_surface_get_surface(dsurface);
674         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
675
676         int new_x, new_y;
677
678         struct ivi_output *output = surface->popup.output;
679         struct weston_output *woutput = output->output;
680
681         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
682         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
683
684         struct weston_view *view = surface->view;
685
686         if (policy && policy->api.surface_activate_by_default &&
687             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
688             !surface->mapped)
689                 return;
690
691         if (surface->view->is_mapped || surface->state == HIDDEN)
692                 return;
693
694         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
695
696         weston_view_set_output(view, woutput);
697
698         ivi_compute_popup_position(woutput, view,
699                                    surface->popup.x, surface->popup.y, &new_x, &new_y);
700         weston_view_set_position(view, new_x, new_y);
701         weston_view_update_transform(view);
702
703         /* only clip the pop-up dialog window if we have a valid
704          * width and height being passed on. Users might not want to have one
705          * set-up so only enfore it is really passed on. */
706         if (surface->popup.bb.width > 0 && surface->popup.bb.height > 0)
707                 weston_view_set_mask(view, surface->popup.bb.x, surface->popup.bb.y,
708                                      surface->popup.bb.width, surface->popup.bb.height);
709
710         weston_layer_entry_insert(&ivi->popup.view_list, &view->layer_link);
711
712         weston_view_geometry_dirty(view);
713         weston_surface_damage(view->surface);
714
715         if (ivi_seat)
716                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
717
718         wsurface->is_mapped = true;
719         surface->view->is_mapped = true;
720
721         shell_advertise_app_state(ivi, app_id,
722                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
723
724         weston_log("Activation completed for app_id %s, role %s, output %s\n",
725                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
726 }
727
728 static void
729 ivi_layout_popup_re_add(struct ivi_surface *surface)
730 {
731         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
732         struct weston_view *view = surface->view;
733
734         if (weston_view_is_mapped(view)) {
735                 struct weston_desktop_surface *dsurface = surface->dsurface;
736                 struct weston_surface *wsurface =
737                         weston_desktop_surface_get_surface(dsurface);
738
739                 weston_layer_entry_remove(&view->layer_link);
740
741                 wsurface->is_mapped = false;
742                 view->is_mapped = false;
743         }
744
745         /* reset the activate by default in order to (still) allow the surface
746          * to be activaved using the request */
747         if (!surface->mapped)
748                 surface->mapped = true;
749
750         surface->state = NORMAL;
751         ivi_layout_popup_committed(surface);
752 }
753
754 static bool
755 ivi_layout_surface_is_split_or_fullscreen(struct ivi_surface *surf)
756 {
757         struct ivi_compositor *ivi = surf->ivi;
758         struct ivi_surface *is;
759
760         if (surf->role != IVI_SURFACE_ROLE_SPLIT_H &&
761             surf->role != IVI_SURFACE_ROLE_SPLIT_V &&
762             surf->role != IVI_SURFACE_ROLE_FULLSCREEN)
763                 return false;
764
765         /* reset the activate by default in order to (still) allow the surface
766          * to be activaved using the request */
767         if (!surf->mapped)
768                 surf->mapped = true;
769
770         wl_list_for_each(is, &ivi->surfaces, link)
771                 if (is == surf)
772                         return true;
773
774         return false;
775 }
776
777 void
778 ivi_layout_activate_by_surf(struct ivi_output *output, struct ivi_surface *surf)
779 {
780         struct ivi_compositor *ivi = output->ivi;
781         struct weston_desktop_surface *dsurf;
782         struct weston_geometry geom;
783         struct ivi_policy *policy = output->ivi->policy;
784
785         dsurf = surf->dsurface;
786
787         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
788
789         if (!surf)
790                 return;
791
792         if (policy && policy->api.surface_activate &&
793             !policy->api.surface_activate(surf, surf->ivi)) {
794                 return;
795         }
796
797 #ifdef AGL_COMP_DEBUG
798         weston_log("Activating app_id %s, type %s\n", app_id,
799                         ivi_layout_get_surface_role_name(surf));
800 #endif
801
802         if (surf->role == IVI_SURFACE_ROLE_POPUP) {
803                 ivi_layout_popup_re_add(surf);
804                 return;
805         }
806
807         /* do not 're'-activate surfaces that are split or active */
808         if (surf == output->active ||
809             ivi_layout_surface_is_split_or_fullscreen(surf))
810                 return;
811
812         if (surf->role == IVI_SURFACE_ROLE_REMOTE) {
813                 struct ivi_output *remote_output =
814                         ivi_layout_find_with_app_id(app_id, ivi);
815
816                 /* if already active on a remote output do not
817                  * attempt to activate it again */
818                 if (remote_output && remote_output->active == surf)
819                         return;
820         }
821
822
823         geom = weston_desktop_surface_get_geometry(dsurf);
824
825         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
826                 surf->desktop.pending_output = output;
827         if (weston_desktop_surface_get_maximized(dsurf) &&
828             geom.width == output->area.width &&
829             geom.height == output->area.height) {
830                 ivi_layout_activate_complete(output, surf);
831                 return;
832         }
833
834         ivi_layout_add_to_hidden_layer(surf, output);
835 }
836
837 void
838 ivi_layout_activate(struct ivi_output *output, const char *app_id)
839 {
840         struct ivi_surface *surf;
841         struct ivi_compositor *ivi = output->ivi;
842
843         if (!app_id)
844                 return;
845
846         surf = ivi_find_app(ivi, app_id);
847         if (!surf)
848                 return;
849
850         ivi_layout_activate_by_surf(output, surf);
851 }
852
853 struct ivi_output *
854 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
855 {
856         struct ivi_output *ivi_output = NULL;
857
858         switch (surf->role) {
859         case IVI_SURFACE_ROLE_DESKTOP:
860                 if (surf->desktop.pending_output)
861                         ivi_output = surf->desktop.pending_output;
862                 else
863                         ivi_output = surf->desktop.last_output;
864                 break;
865         case IVI_SURFACE_ROLE_POPUP:
866                 ivi_output = surf->popup.output;
867                 break;
868         case IVI_SURFACE_ROLE_BACKGROUND:
869                 ivi_output = surf->bg.output;
870                 break;
871         case IVI_SURFACE_ROLE_PANEL:
872                 ivi_output = surf->panel.output;
873                 break;
874         case IVI_SURFACE_ROLE_FULLSCREEN:
875                 ivi_output = surf->fullscreen.output;
876                 break;
877         case IVI_SURFACE_ROLE_SPLIT_H:
878         case IVI_SURFACE_ROLE_SPLIT_V:
879                 ivi_output = surf->split.output;
880                 break;
881         case IVI_SURFACE_ROLE_REMOTE:
882                 ivi_output = surf->remote.output;
883                 break;
884         case IVI_SURFACE_ROLE_NONE:
885         default:
886                 break;
887         }
888
889         return ivi_output;
890 }
891
892 void
893 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
894 {
895         struct ivi_surface *surf;
896         struct ivi_output *ivi_output;
897         struct ivi_policy *policy = ivi->policy;
898
899         if (!app_id)
900                 return;
901
902         surf = ivi_find_app(ivi, app_id);
903         if (!surf)
904                 return;
905
906         if (policy && policy->api.surface_deactivate &&
907             !policy->api.surface_deactivate(surf, surf->ivi)) {
908                 return;
909         }
910
911         ivi_output = ivi_layout_get_output_from_surface(surf);
912         weston_log("Deactiving %s, role %s\n", app_id,
913                         ivi_layout_get_surface_role_name(surf));
914
915         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
916                 struct ivi_surface *previous_active;
917
918                 previous_active = ivi_output->previous_active;
919                 if (!previous_active) {
920                         /* we don't have a previous active it means we should
921                          * display the bg */
922                         if (ivi_output->active) {
923                                 struct weston_view *view;
924
925                                 view = ivi_output->active->view;
926                                 view->is_mapped = false;
927                                 view->surface->is_mapped = false;
928
929                                 weston_layer_entry_remove(&view->layer_link);
930                                 weston_view_geometry_dirty(view);
931                                 weston_surface_damage(view->surface);
932                                 ivi_output->active = NULL;
933                         }
934                 } else {
935                         struct weston_desktop_surface *dsurface;
936                         const char *previous_active_app_id;
937
938                         dsurface = previous_active->dsurface;
939                         previous_active_app_id =
940                                 weston_desktop_surface_get_app_id(dsurface);
941                         ivi_layout_activate(ivi_output, previous_active_app_id);
942                 }
943         } else if (surf->role == IVI_SURFACE_ROLE_POPUP) {
944                 struct weston_view *view  = surf->view;
945
946                 weston_view_unmap(view);
947                 surf->state = HIDDEN;
948
949                 weston_layer_entry_remove(&view->layer_link);
950                 weston_view_geometry_dirty(view);
951                 weston_surface_damage(view->surface);
952         }
953 }