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