layout: Detect when an application should be migrated to other outputs
[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         /*
289          * If the view isn't mapped, we put it onto the hidden layer so it will
290          * start receiving frame events, and will be able to act on our
291          * configure event.
292          */
293         if (!weston_view_is_mapped(ev)) {
294                 ev->is_mapped = true;
295                 ev->surface->is_mapped = true;
296
297                 weston_desktop_surface_set_maximized(dsurf, true);
298                 weston_desktop_surface_set_size(dsurf,
299                                                 ivi_output->area.width,
300                                                 ivi_output->area.height);
301
302                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
303                                 app_id, ivi_layout_get_surface_role_name(surf),
304                                 ivi_output->area.width, ivi_output->area.height);
305
306                 surf->hidden_layer_output = ivi_output;
307                 weston_view_set_output(ev, ivi_output->output);
308                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
309                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
310                                 app_id, ivi_layout_get_surface_role_name(surf),
311                                 ivi_output->output->name);
312
313                 weston_compositor_schedule_repaint(ivi->compositor);
314                 return;
315         }
316
317         /* we might have another output to activate */
318         if (surf->hidden_layer_output &&
319             surf->hidden_layer_output != ivi_output) {
320                 weston_layer_entry_remove(&ev->layer_link);
321
322                 if (ivi_output->area.width != surf->hidden_layer_output->area.width &&
323                     ivi_output->area.height != surf->hidden_layer_output->area.height) {
324                         weston_desktop_surface_set_maximized(dsurf, true);
325                         weston_desktop_surface_set_size(dsurf,
326                                                         ivi_output->area.width,
327                                                         ivi_output->area.height);
328                 }
329
330                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
331                                 app_id, ivi_layout_get_surface_role_name(surf),
332                                 ivi_output->area.width, ivi_output->area.height);
333
334                 surf->hidden_layer_output = ivi_output;
335                 weston_view_set_output(ev, ivi_output->output);
336                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
337                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
338                                 app_id, ivi_layout_get_surface_role_name(surf),
339                                 ivi_output->output->name);
340         }
341
342         weston_compositor_schedule_repaint(ivi->compositor);
343 }
344
345 void
346 ivi_layout_desktop_committed(struct ivi_surface *surf)
347 {
348         struct weston_desktop_surface *dsurf = surf->dsurface;
349         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
350         struct ivi_policy *policy = surf->ivi->policy;
351         struct ivi_output *output;
352         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
353
354         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP ||
355                surf->role == IVI_SURFACE_ROLE_REMOTE);
356
357         /*
358          * we can't make use here of the ivi_layout_get_output_from_surface()
359          * due to the fact that we'll always land here when a surface performs
360          * a commit and pending_output will not bet set. This works in tandem
361          * with 'mapped' at this point to avoid tripping over
362          * to a surface that continuously updates its content
363          */
364         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
365                 output = surf->desktop.pending_output;
366         else
367                 output = surf->remote.output;
368
369         if (surf->role == IVI_SURFACE_ROLE_DESKTOP && !output) {
370                 struct ivi_output *r_output;
371
372                 if (policy && policy->api.surface_activate_by_default &&
373                     !policy->api.surface_activate_by_default(surf, surf->ivi))
374                         return;
375
376                 /* we can only activate it again by using the protocol */
377                 if (surf->mapped)
378                         return;
379
380                 /* check first if there aren't any outputs being set */
381                 r_output = ivi_layout_find_with_app_id(app_id, surf->ivi);
382
383                 if (r_output) {
384                         struct weston_view *view = r_output->fullscreen_view.fs->view;
385                         if (view->is_mapped || view->surface->is_mapped)
386                                 remove_black_surface(r_output);
387                 }
388
389
390                 /* try finding an output with a background and use that */
391                 if (!r_output)
392                         r_output = ivi_layout_find_bg_output(surf->ivi);
393
394                 /* if we couldn't still find an output by this point, there's
395                  * something wrong so we abort with a protocol error */
396                 if (!r_output) {
397                         wl_resource_post_error(surf->ivi->shell_client.resource,
398                                                AGL_SHELL_ERROR_INVALID_ARGUMENT,
399                                                "No valid output found to activate surface by default");
400                         return;
401                 }
402
403                 if (!surf->ivi->activate_by_default) {
404                         weston_log("Refusing to activate surface role %d, app_id %s\n",
405                                         surf->role, app_id);
406
407                         if (!weston_desktop_surface_get_maximized(dsurf) ||
408                             geom.width != r_output->area.width ||
409                             geom.height != r_output->area.height)
410                                 ivi_layout_add_to_hidden_layer(surf, r_output);
411
412                         return;
413                 }
414
415                 /* use the output of the bg to activate the app on start-up by
416                  * default */
417                 if (surf->view && r_output) {
418                         if (app_id && r_output) {
419                                 weston_log("Surface with app_id %s, role %s activating by default\n",
420                                         weston_desktop_surface_get_app_id(surf->dsurface),
421                                         ivi_layout_get_surface_role_name(surf));
422                                 ivi_layout_activate(r_output, app_id);
423                         } else if (!app_id) {
424                                 /*
425                                  * applications not setting an app_id, or
426                                  * setting an app_id but at a later point in
427                                  * time, might fall-back here so give them a
428                                  * chance to receive the configure event and
429                                  * act upon it
430                                  */
431                                 weston_log("Surface no app_id, role %s activating by default\n",
432                                         ivi_layout_get_surface_role_name(surf));
433                                 ivi_layout_activate_by_surf(r_output, surf);
434                         }
435                 }
436
437                 return;
438         }
439
440         if (surf->role == IVI_SURFACE_ROLE_REMOTE && output) {
441                 if (policy && policy->api.surface_activate_by_default &&
442                     !policy->api.surface_activate_by_default(surf, surf->ivi))
443                         return;
444
445                 /* we can only activate it again by using the protocol, but
446                  * additionally the output is not reset when
447                  * ivi_layout_activate_complete() terminates so we use the
448                  * current active surface to avoid hitting this again and again
449                  * */
450                 if (surf->mapped && output->active == surf)
451                         return;
452
453                 if (app_id) {
454                         weston_log("Surface with app_id %s, role %s activating "
455                                    "by default on output %s\n",
456                                    weston_desktop_surface_get_app_id(surf->dsurface),
457                                    ivi_layout_get_surface_role_name(surf),
458                                    output->output->name);
459                         ivi_layout_activate(output, app_id);
460                 }
461                 return;
462         }
463
464         if (!weston_desktop_surface_get_maximized(dsurf) ||
465             geom.width != output->area.width ||
466             geom.height != output->area.height)
467                 return;
468
469         ivi_layout_activate_complete(output, surf);
470 }
471
472 void
473 ivi_layout_fullscreen_committed(struct ivi_surface *surface)
474 {
475         struct ivi_compositor *ivi = surface->ivi;
476         struct ivi_policy *policy = ivi->policy;
477
478         struct weston_desktop_surface *dsurface = surface->dsurface;
479         struct weston_surface *wsurface =
480                 weston_desktop_surface_get_surface(dsurface);
481         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
482
483         struct ivi_output *output = surface->split.output;
484         struct weston_output *woutput = output->output;
485         struct ivi_output *bg_output = ivi_layout_find_bg_output(ivi);
486
487         struct weston_view *view = surface->view;
488         struct weston_geometry geom =
489                 weston_desktop_surface_get_geometry(dsurface);
490
491         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
492         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
493
494         bool is_fullscreen = weston_desktop_surface_get_fullscreen(dsurface);
495         bool is_dim_same =
496                 geom.width == bg_output->output->width &&
497                 geom.height == bg_output->output->height;
498
499         if (policy && policy->api.surface_activate_by_default &&
500             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
501             !surface->mapped)
502                 return;
503
504         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
505
506         if (weston_view_is_mapped(view))
507                 return;
508
509         /* if we still get here but we haven't resized so far, send configure
510          * events to do so */
511         if (surface->state != RESIZING && (!is_fullscreen || !is_dim_same)) {
512                 struct ivi_output *bg_output =
513                         ivi_layout_find_bg_output(surface->ivi);
514
515                 weston_log("Placing fullscreen app_id %s, type %s in hidden layer\n",
516                                 app_id, ivi_layout_get_surface_role_name(surface));
517                 weston_desktop_surface_set_fullscreen(dsurface, true);
518                 weston_desktop_surface_set_size(dsurface,
519                                                 bg_output->output->width,
520                                                 bg_output->output->height);
521
522                 surface->state = RESIZING;
523                 weston_view_set_output(view, output->output);
524                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
525                 return;
526         }
527
528         /* eventually, we would set the surface fullscreen, but the client
529          * hasn't resized correctly by this point, so terminate connection */
530         if (surface->state == RESIZING && is_fullscreen && !is_dim_same) {
531                 struct weston_desktop_client *desktop_client =
532                         weston_desktop_surface_get_client(dsurface);
533                 struct wl_client *client =
534                         weston_desktop_client_get_client(desktop_client);
535                 wl_client_post_implementation_error(client,
536                                 "can not display surface due to invalid geometry."
537                                 " Client should perform a geometry resize!");
538                 return;
539         }
540
541         /* this implies we resized correctly */
542         if (!weston_view_is_mapped(view)) {
543                 weston_layer_entry_remove(&view->layer_link);
544
545                 weston_view_set_output(view, woutput);
546                 weston_view_set_position(view, woutput->x, woutput->y);
547                 weston_layer_entry_insert(&ivi->fullscreen.view_list, &view->layer_link);
548
549                 wsurface->is_mapped = true;
550                 surface->view->is_mapped = true;
551                 surface->state = FULLSCREEN;
552
553                 weston_view_geometry_dirty(view);
554                 weston_surface_damage(view->surface);
555
556                 if (ivi_seat)
557                         ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
558
559                 shell_advertise_app_state(ivi, app_id,
560                                 NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
561
562                 weston_log("Activation completed for app_id %s, role %s, "
563                            "output %s\n", app_id,
564                            ivi_layout_get_surface_role_name(surface),
565                            output->name);
566
567         }
568 }
569
570 void
571 ivi_layout_desktop_resize(struct ivi_surface *surface,
572                           struct weston_geometry area)
573 {
574         struct weston_desktop_surface *dsurf = surface->dsurface;
575         struct weston_view *view = surface->view;
576
577         int x = area.x;
578         int y = area.y;
579         int width = area.width;
580         int height = area.height;
581
582         weston_desktop_surface_set_size(dsurf,
583                                         width, height);
584
585         weston_view_set_position(view, x, y);
586
587         weston_view_geometry_dirty(view);
588         weston_surface_damage(view->surface);
589 }
590
591 void
592 ivi_layout_split_committed(struct ivi_surface *surface)
593 {
594         struct ivi_compositor *ivi = surface->ivi;
595         struct ivi_policy *policy = ivi->policy;
596
597         struct weston_desktop_surface *dsurface = surface->dsurface;
598         struct weston_surface *wsurface =
599                 weston_desktop_surface_get_surface(dsurface);
600         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
601
602         struct ivi_output *output = surface->split.output;
603         struct weston_output *woutput = output->output;
604
605         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
606         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
607
608         struct weston_view *view = surface->view;
609         struct weston_geometry geom;
610
611         int x, y;
612         int width, height;
613
614         x = woutput->x;
615         y = woutput->y;
616
617         if (policy && policy->api.surface_activate_by_default &&
618             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
619             !surface->mapped)
620                 return;
621
622         if (surface->view->is_mapped)
623                 return;
624
625         geom = weston_desktop_surface_get_geometry(dsurface);
626
627         assert(surface->role == IVI_SURFACE_ROLE_SPLIT_H ||
628                surface->role == IVI_SURFACE_ROLE_SPLIT_V);
629
630         /* save the previous area in order to recover it back when if this kind
631          * of surface is being destroyed/removed */
632         output->area_saved = output->area;
633
634         switch (surface->role) {
635         case IVI_SURFACE_ROLE_SPLIT_V:
636                 geom.width = (output->area.width / 2);
637
638                 x += woutput->width - geom.width;
639                 output->area.width -= geom.width;
640
641                 width = woutput->width - x;
642                 height = output->area.height;
643                 y = output->area.y;
644
645                 break;
646         case IVI_SURFACE_ROLE_SPLIT_H:
647                 geom.height = (output->area.height / 2);
648
649                 y = output->area.y;
650                 output->area.y += geom.height;
651                 output->area.height -= geom.height;
652
653                 width = output->area.width;
654                 height = output->area.height;
655
656                 x = output->area.x;
657
658                 break;
659         default:
660                 assert(!"Invalid split orientation\n");
661         }
662
663         weston_desktop_surface_set_size(dsurface,
664                                         width, height);
665
666         /* resize the active surface first, output->area already contains
667          * correct area to resize to */
668         if (output->active)
669                 ivi_layout_desktop_resize(output->active, output->area);
670
671         weston_view_set_output(view, woutput);
672         weston_view_set_position(view, x, y);
673         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
674
675         weston_view_geometry_dirty(view);
676         weston_surface_damage(view->surface);
677
678         if (ivi_seat)
679                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
680
681         wsurface->is_mapped = true;
682         surface->view->is_mapped = true;
683
684         shell_advertise_app_state(ivi, app_id,
685                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
686
687         weston_log("Activation completed for app_id %s, role %s, output %s\n",
688                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
689 }
690
691 static void
692 ivi_compute_popup_position(const struct weston_output *output, struct weston_view *view,
693                            int initial_x, int initial_y, int *new_x, int *new_y)
694 {
695         *new_x = output->x + initial_x;
696         *new_y = output->y + initial_y;
697 }
698
699
700 void
701 ivi_layout_popup_committed(struct ivi_surface *surface)
702 {
703         struct ivi_compositor *ivi = surface->ivi;
704         struct ivi_policy *policy = ivi->policy;
705
706         struct weston_desktop_surface *dsurface = surface->dsurface;
707         struct weston_surface *wsurface =
708                 weston_desktop_surface_get_surface(dsurface);
709         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
710
711         int new_x, new_y;
712
713         struct ivi_output *output = surface->popup.output;
714         struct weston_output *woutput = output->output;
715
716         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
717         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
718
719         struct weston_view *view = surface->view;
720
721         if (policy && policy->api.surface_activate_by_default &&
722             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
723             !surface->mapped)
724                 return;
725
726         if (surface->view->is_mapped || surface->state == HIDDEN)
727                 return;
728
729         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
730
731         weston_view_set_output(view, woutput);
732
733         ivi_compute_popup_position(woutput, view,
734                                    surface->popup.x, surface->popup.y, &new_x, &new_y);
735         weston_view_set_position(view, new_x, new_y);
736         weston_view_update_transform(view);
737
738         /* only clip the pop-up dialog window if we have a valid
739          * width and height being passed on. Users might not want to have one
740          * set-up so only enfore it is really passed on. */
741         if (surface->popup.bb.width > 0 && surface->popup.bb.height > 0)
742                 weston_view_set_mask(view, surface->popup.bb.x, surface->popup.bb.y,
743                                      surface->popup.bb.width, surface->popup.bb.height);
744
745         weston_layer_entry_insert(&ivi->popup.view_list, &view->layer_link);
746
747         weston_view_geometry_dirty(view);
748         weston_surface_damage(view->surface);
749
750         if (ivi_seat)
751                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
752
753         wsurface->is_mapped = true;
754         surface->view->is_mapped = true;
755
756         shell_advertise_app_state(ivi, app_id,
757                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
758
759         weston_log("Activation completed for app_id %s, role %s, output %s\n",
760                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
761 }
762
763 static void
764 ivi_layout_popup_re_add(struct ivi_surface *surface)
765 {
766         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
767         struct weston_view *view = surface->view;
768
769         if (weston_view_is_mapped(view)) {
770                 struct weston_desktop_surface *dsurface = surface->dsurface;
771                 struct weston_surface *wsurface =
772                         weston_desktop_surface_get_surface(dsurface);
773
774                 weston_layer_entry_remove(&view->layer_link);
775
776                 wsurface->is_mapped = false;
777                 view->is_mapped = false;
778         }
779
780         /* reset the activate by default in order to (still) allow the surface
781          * to be activaved using the request */
782         if (!surface->mapped)
783                 surface->mapped = true;
784
785         surface->state = NORMAL;
786         ivi_layout_popup_committed(surface);
787 }
788
789 static bool
790 ivi_layout_surface_is_split_or_fullscreen(struct ivi_surface *surf)
791 {
792         struct ivi_compositor *ivi = surf->ivi;
793         struct ivi_surface *is;
794
795         if (surf->role != IVI_SURFACE_ROLE_SPLIT_H &&
796             surf->role != IVI_SURFACE_ROLE_SPLIT_V &&
797             surf->role != IVI_SURFACE_ROLE_FULLSCREEN)
798                 return false;
799
800         /* reset the activate by default in order to (still) allow the surface
801          * to be activaved using the request */
802         if (!surf->mapped)
803                 surf->mapped = true;
804
805         wl_list_for_each(is, &ivi->surfaces, link)
806                 if (is == surf)
807                         return true;
808
809         return false;
810 }
811
812 void
813 ivi_layout_activate_by_surf(struct ivi_output *output, struct ivi_surface *surf)
814 {
815         struct ivi_compositor *ivi = output->ivi;
816         struct weston_desktop_surface *dsurf;
817         struct weston_geometry geom;
818         struct ivi_policy *policy = output->ivi->policy;
819
820         dsurf = surf->dsurface;
821
822         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
823
824         if (!surf)
825                 return;
826
827         if (policy && policy->api.surface_activate &&
828             !policy->api.surface_activate(surf, surf->ivi)) {
829                 return;
830         }
831
832 #ifdef AGL_COMP_DEBUG
833         weston_log("Activating app_id %s, type %s, on output %s\n", app_id,
834                         ivi_layout_get_surface_role_name(surf), output->output->name);
835 #endif
836
837         if (surf->role == IVI_SURFACE_ROLE_POPUP) {
838                 ivi_layout_popup_re_add(surf);
839                 return;
840         }
841
842         /* do not 're'-activate surfaces that are split or active */
843         if (surf == output->active ||
844             ivi_layout_surface_is_split_or_fullscreen(surf))
845                 return;
846
847         if (surf->role == IVI_SURFACE_ROLE_REMOTE) {
848                 struct ivi_output *remote_output =
849                         ivi_layout_find_with_app_id(app_id, ivi);
850
851                 /* if already active on a remote output do not
852                  * attempt to activate it again */
853                 if (remote_output && remote_output->active == surf)
854                         return;
855         }
856
857
858         geom = weston_desktop_surface_get_geometry(dsurf);
859
860         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
861                 surf->desktop.pending_output = output;
862         if (weston_desktop_surface_get_maximized(dsurf) &&
863             geom.width == output->area.width &&
864             geom.height == output->area.height) {
865                 ivi_layout_activate_complete(output, surf);
866                 return;
867         }
868
869         ivi_layout_add_to_hidden_layer(surf, output);
870 }
871
872 void
873 ivi_layout_activate(struct ivi_output *output, const char *app_id)
874 {
875         struct ivi_surface *surf;
876         struct ivi_compositor *ivi = output->ivi;
877
878         if (!app_id)
879                 return;
880
881         surf = ivi_find_app(ivi, app_id);
882         if (!surf)
883                 return;
884
885         ivi_layout_activate_by_surf(output, surf);
886 }
887
888 struct ivi_output *
889 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
890 {
891         struct ivi_output *ivi_output = NULL;
892
893         switch (surf->role) {
894         case IVI_SURFACE_ROLE_DESKTOP:
895                 if (surf->desktop.pending_output)
896                         ivi_output = surf->desktop.pending_output;
897                 else
898                         ivi_output = surf->desktop.last_output;
899                 break;
900         case IVI_SURFACE_ROLE_POPUP:
901                 ivi_output = surf->popup.output;
902                 break;
903         case IVI_SURFACE_ROLE_BACKGROUND:
904                 ivi_output = surf->bg.output;
905                 break;
906         case IVI_SURFACE_ROLE_PANEL:
907                 ivi_output = surf->panel.output;
908                 break;
909         case IVI_SURFACE_ROLE_FULLSCREEN:
910                 ivi_output = surf->fullscreen.output;
911                 break;
912         case IVI_SURFACE_ROLE_SPLIT_H:
913         case IVI_SURFACE_ROLE_SPLIT_V:
914                 ivi_output = surf->split.output;
915                 break;
916         case IVI_SURFACE_ROLE_REMOTE:
917                 ivi_output = surf->remote.output;
918                 break;
919         case IVI_SURFACE_ROLE_NONE:
920         default:
921                 break;
922         }
923
924         return ivi_output;
925 }
926
927 void
928 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
929 {
930         struct ivi_surface *surf;
931         struct ivi_output *ivi_output;
932         struct ivi_policy *policy = ivi->policy;
933
934         if (!app_id)
935                 return;
936
937         surf = ivi_find_app(ivi, app_id);
938         if (!surf)
939                 return;
940
941         if (policy && policy->api.surface_deactivate &&
942             !policy->api.surface_deactivate(surf, surf->ivi)) {
943                 return;
944         }
945
946         ivi_output = ivi_layout_get_output_from_surface(surf);
947         weston_log("Deactiving %s, role %s\n", app_id,
948                         ivi_layout_get_surface_role_name(surf));
949
950         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
951                 struct ivi_surface *previous_active;
952
953                 previous_active = ivi_output->previous_active;
954                 if (!previous_active) {
955                         /* we don't have a previous active it means we should
956                          * display the bg */
957                         if (ivi_output->active) {
958                                 struct weston_view *view;
959
960                                 view = ivi_output->active->view;
961                                 view->is_mapped = false;
962                                 view->surface->is_mapped = false;
963
964                                 weston_layer_entry_remove(&view->layer_link);
965                                 weston_view_geometry_dirty(view);
966                                 weston_surface_damage(view->surface);
967                                 ivi_output->active = NULL;
968                         }
969                 } else {
970                         struct weston_desktop_surface *dsurface;
971                         const char *previous_active_app_id;
972
973                         dsurface = previous_active->dsurface;
974                         previous_active_app_id =
975                                 weston_desktop_surface_get_app_id(dsurface);
976                         ivi_layout_activate(ivi_output, previous_active_app_id);
977                 }
978         } else if (surf->role == IVI_SURFACE_ROLE_POPUP) {
979                 struct weston_view *view  = surf->view;
980
981                 weston_view_unmap(view);
982                 surf->state = HIDDEN;
983
984                 weston_layer_entry_remove(&view->layer_link);
985                 weston_view_geometry_dirty(view);
986                 weston_surface_damage(view->surface);
987         }
988 }