9981ebbf8024031a3a5b0a4bad2e2835b2930ca8
[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         bool use_default_area = true;
155
156         ivi_background_init(ivi, output);
157
158         if (output->area_activation.width ||
159             output->area_activation.height ||
160             output->area_activation.x ||
161             output->area_activation.y) {
162                 /* Sanity check target area is within output bounds */
163                 if ((output->area_activation.x + output->area_activation.width) < output->output->width ||
164                     (output->area_activation.y + output->area_activation.height) < output->output->height) {
165                         weston_log("Using specified area for output %s, ignoring panels\n",
166                                    output->name);
167                         output->area.x = output->area_activation.x;
168                         output->area.y = output->area_activation.y;
169                         output->area.width = output->area_activation.width;
170                         output->area.height = output->area_activation.height;
171                         use_default_area = false;
172                 } else {
173                         weston_log("Invalid activation-area position for output %s, ignoring\n",
174                                    output->name);
175                 }
176         }
177         if (use_default_area) {
178                 output->area.x = 0;
179                 output->area.y = 0;
180                 output->area.width = output->output->width;
181                 output->area.height = output->output->height;
182
183                 ivi_panel_init(ivi, output, output->top);
184                 ivi_panel_init(ivi, output, output->bottom);
185                 ivi_panel_init(ivi, output, output->left);
186                 ivi_panel_init(ivi, output, output->right);
187         }
188
189         weston_compositor_schedule_repaint(ivi->compositor);
190
191         weston_log("Usable area: %dx%d+%d,%d\n",
192                    output->area.width, output->area.height,
193                    output->area.x, output->area.y);
194 }
195
196 struct ivi_surface *
197 ivi_find_app(struct ivi_compositor *ivi, const char *app_id)
198 {
199         struct ivi_surface *surf;
200         const char *id;
201
202         wl_list_for_each(surf, &ivi->surfaces, link) {
203                 id = weston_desktop_surface_get_app_id(surf->dsurface);
204                 if (id && strcmp(app_id, id) == 0)
205                         return surf;
206         }
207
208         return NULL;
209 }
210
211 static void
212 ivi_layout_activate_complete(struct ivi_output *output,
213                              struct ivi_surface *surf)
214 {
215         struct ivi_compositor *ivi = output->ivi;
216         struct weston_output *woutput = output->output;
217         struct weston_view *view = surf->view;
218         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
219         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
220         const char *app_id = weston_desktop_surface_get_app_id(surf->dsurface);
221         bool update_previous = true;
222
223         if (weston_view_is_mapped(view)) {
224                 weston_layer_entry_remove(&view->layer_link);
225         } else {
226                 weston_view_update_transform(view);
227         }
228
229         if (output_has_black_curtain(output)) {
230                 if (!output->background) {
231                         weston_log("Found that we have no background surface "
232                                     "for output %s. Using black curtain as background\n",
233                                     output->output->name);
234
235                         struct weston_view *ev =
236                                 output->fullscreen_view.fs->view;
237
238                         /* use the black curtain as background when we have
239                          * none added by the shell client. */
240                         weston_layer_entry_remove(&ev->layer_link);
241                         weston_layer_entry_insert(&ivi->normal.view_list,
242                                                   &ev->layer_link);
243                         weston_view_geometry_dirty(ev);
244                         weston_surface_damage(ev->surface);
245                 } else {
246                         remove_black_curtain(output);
247                 }
248         }
249
250
251         weston_view_set_output(view, woutput);
252         /* drop any previous masks set on this view */
253         weston_view_set_mask_infinite(view);
254
255         if (surf->role != IVI_SURFACE_ROLE_BACKGROUND)
256                 weston_view_set_position(view,
257                                          woutput->x + output->area.x,
258                                          woutput->y + output->area.y);
259
260         view->is_mapped = true;
261         surf->mapped = true;
262         view->surface->is_mapped = true;
263
264         /* handle a movement from one output to another */
265         if (surf->current_completed_output &&
266             surf->current_completed_output != output) {
267
268                 /* we're migrating the same surface but to another output */
269                 if (surf->current_completed_output->active == surf) {
270                         struct weston_view *ev =
271                                 surf->current_completed_output->active->view;
272
273                         weston_layer_entry_remove(&ev->layer_link);
274                         surf->current_completed_output->previous_active =
275                                 surf->current_completed_output->active;
276                         surf->current_completed_output->active = NULL;
277
278                         /* damage all possible outputs to avoid stale views */
279                         weston_compositor_damage_all(ivi->compositor);
280                 }
281         }
282
283         if (output->active) {
284                 /* keep the background surface mapped at all times */
285                 if (output->active->role != IVI_SURFACE_ROLE_BACKGROUND) {
286                         output->active->view->is_mapped = false;
287                         output->active->view->surface->is_mapped = false;
288
289                         weston_layer_entry_remove(&output->active->view->layer_link);
290                 }
291         }
292
293         if (output->previous_active && output->active) {
294                 const char *c_app_id =
295                         weston_desktop_surface_get_app_id(output->active->dsurface);
296
297                 /* if the currently activated app_id is the same as the one
298                  * we're trying to complete activation with means we're
299                  * operating on the same app_id so do update previous_active as
300                  * it will overwrite it with the same value */
301                 if (!strcmp(c_app_id, app_id)) {
302                         update_previous = false;
303                 }
304         }
305
306         if (update_previous)
307                 output->previous_active = output->active;
308         output->active = surf;
309         surf->current_completed_output = output;
310
311         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
312         weston_view_geometry_dirty(view);
313         weston_surface_damage(view->surface);
314
315         if (ivi_seat)
316                 ivi_shell_activate_surface(surf, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
317
318         /*
319          * the 'remote' role now makes use of this part so make sure we don't
320          * trip the enum such that we might end up with a modified output for
321          * 'remote' role
322          */
323         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
324                 if (surf->desktop.pending_output)
325                         surf->desktop.last_output = surf->desktop.pending_output;
326                 surf->desktop.pending_output = NULL;
327         }
328
329         weston_log("Activation completed for app_id %s, role %s, output %s\n",
330                         app_id,
331                         ivi_layout_get_surface_role_name(surf), output->name);
332
333         shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_ACTIVATED);
334 }
335
336 static bool
337 ivi_layout_find_output_with_app_id(const char *app_id, struct ivi_output *output)
338 {
339         char *cur;
340         size_t app_id_len;
341
342         cur = output->app_ids;
343         app_id_len = strlen(app_id);
344
345         while ((cur = strstr(cur, app_id))) {
346                 if ((cur[app_id_len] == ',' || cur[app_id_len] == '\0') &&
347                     (cur == output->app_ids || cur[-1] == ','))
348                         return true;
349                 cur++;
350         }
351
352         return false;
353 }
354
355 struct ivi_output *
356 ivi_layout_find_with_app_id(const char *app_id, struct ivi_compositor *ivi)
357 {
358         struct ivi_output *out;
359
360         if (!app_id)
361                 return NULL;
362
363         wl_list_for_each(out, &ivi->outputs, link) {
364                 if (!out->app_ids)
365                         continue;
366
367                 if (ivi_layout_find_output_with_app_id(app_id, out))
368                         return out;
369         }
370         return NULL;
371 }
372
373 struct ivi_output *
374 ivi_layout_find_bg_output(struct ivi_compositor *ivi)
375 {
376         struct ivi_output *out;
377
378         wl_list_for_each(out, &ivi->outputs, link) {
379                 if (out->background &&
380                     out->background->role == IVI_SURFACE_ROLE_BACKGROUND)
381                         return out;
382         }
383
384         return NULL;
385 }
386
387
388 static void
389 ivi_layout_add_to_hidden_layer(struct ivi_surface *surf,
390                                struct ivi_output *ivi_output)
391 {
392         struct weston_desktop_surface *dsurf = surf->dsurface;
393         struct weston_view *ev = surf->view;
394         struct ivi_compositor *ivi = surf->ivi;
395         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
396
397         /*
398          * If the view isn't mapped, we put it onto the hidden layer so it will
399          * start receiving frame events, and will be able to act on our
400          * configure event.
401          */
402         if (!weston_view_is_mapped(ev)) {
403                 ev->is_mapped = true;
404                 ev->surface->is_mapped = true;
405
406                 weston_desktop_surface_set_maximized(dsurf, true);
407                 weston_desktop_surface_set_size(dsurf,
408                                                 ivi_output->area.width,
409                                                 ivi_output->area.height);
410
411                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
412                            app_id, ivi_layout_get_surface_role_name(surf),
413                            ivi_output->area.width, ivi_output->area.height);
414
415                 surf->hidden_layer_output = ivi_output;
416                 weston_view_set_output(ev, ivi_output->output);
417                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
418                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
419                                 app_id, ivi_layout_get_surface_role_name(surf),
420                                 ivi_output->output->name);
421
422                 weston_compositor_schedule_repaint(ivi->compositor);
423                 return;
424         }
425
426         /* we might have another output to activate */
427         if (surf->hidden_layer_output &&
428             surf->hidden_layer_output != ivi_output) {
429                 weston_layer_entry_remove(&ev->layer_link);
430
431                 if (ivi_output->area.width != surf->hidden_layer_output->area.width &&
432                     ivi_output->area.height != surf->hidden_layer_output->area.height) {
433                         weston_desktop_surface_set_maximized(dsurf, true);
434                         weston_desktop_surface_set_size(dsurf,
435                                                         ivi_output->area.width,
436                                                         ivi_output->area.height);
437                 }
438
439                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
440                                 app_id, ivi_layout_get_surface_role_name(surf),
441                                 ivi_output->area.width, ivi_output->area.height);
442
443                 surf->hidden_layer_output = ivi_output;
444                 weston_view_set_output(ev, ivi_output->output);
445                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
446                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
447                                 app_id, ivi_layout_get_surface_role_name(surf),
448                                 ivi_output->output->name);
449         }
450
451         weston_compositor_schedule_repaint(ivi->compositor);
452 }
453
454 void
455 ivi_layout_desktop_committed(struct ivi_surface *surf)
456 {
457         struct weston_desktop_surface *dsurf = surf->dsurface;
458         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
459         struct ivi_policy *policy = surf->ivi->policy;
460         struct ivi_output *output;
461         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
462
463         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP ||
464                surf->role == IVI_SURFACE_ROLE_REMOTE);
465
466         /*
467          * we can't make use here of the ivi_layout_get_output_from_surface()
468          * due to the fact that we'll always land here when a surface performs
469          * a commit and pending_output will not bet set. This works in tandem
470          * with 'mapped' at this point to avoid tripping over
471          * to a surface that continuously updates its content
472          */
473         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
474                 output = surf->desktop.pending_output;
475         else
476                 output = surf->remote.output;
477
478         if (surf->role == IVI_SURFACE_ROLE_DESKTOP && !output) {
479                 struct ivi_output *r_output;
480
481                 if (policy && policy->api.surface_activate_by_default &&
482                     !policy->api.surface_activate_by_default(surf, surf->ivi))
483                         return;
484
485                 /* we can only activate it again by using the protocol */
486                 if (surf->mapped)
487                         return;
488
489                 /* check first if there aren't any outputs being set */
490                 r_output = ivi_layout_find_with_app_id(app_id, surf->ivi);
491
492                 if (r_output) {
493                         struct weston_view *view = r_output->fullscreen_view.fs->view;
494                         if (view->is_mapped || view->surface->is_mapped)
495                                 remove_black_curtain(r_output);
496                 }
497
498
499                 /* try finding an output with a background and use that */
500                 if (!r_output)
501                         r_output = ivi_layout_find_bg_output(surf->ivi);
502
503                 /* if we couldn't still find an output by this point, there's
504                  * something wrong so we abort with a protocol error */
505                 if (!r_output) {
506                         wl_resource_post_error(surf->ivi->shell_client.resource,
507                                                AGL_SHELL_ERROR_INVALID_ARGUMENT,
508                                                "No valid output found to activate surface by default");
509                         return;
510                 }
511
512                 if (!surf->ivi->activate_by_default) {
513                         weston_log("Refusing to activate surface role %d, app_id %s\n",
514                                         surf->role, app_id);
515
516                         if (!weston_desktop_surface_get_maximized(dsurf) ||
517                             geom.width != r_output->area.width ||
518                             geom.height != r_output->area.height)
519                                 ivi_layout_add_to_hidden_layer(surf, r_output);
520
521                         return;
522                 }
523
524                 /* use the output of the bg to activate the app on start-up by
525                  * default */
526                 if (surf->view && r_output) {
527                         if (app_id && r_output) {
528                                 weston_log("Surface with app_id %s, role %s activating by default\n",
529                                         weston_desktop_surface_get_app_id(surf->dsurface),
530                                         ivi_layout_get_surface_role_name(surf));
531                                 ivi_layout_activate(r_output, app_id);
532                         } else if (!app_id) {
533                                 /*
534                                  * applications not setting an app_id, or
535                                  * setting an app_id but at a later point in
536                                  * time, might fall-back here so give them a
537                                  * chance to receive the configure event and
538                                  * act upon it
539                                  */
540                                 weston_log("Surface no app_id, role %s activating by default\n",
541                                         ivi_layout_get_surface_role_name(surf));
542                                 ivi_layout_activate_by_surf(r_output, surf);
543                         }
544                 }
545
546                 return;
547         }
548
549         if (surf->role == IVI_SURFACE_ROLE_REMOTE && output) {
550                 if (policy && policy->api.surface_activate_by_default &&
551                     !policy->api.surface_activate_by_default(surf, surf->ivi))
552                         return;
553
554                 /* we can only activate it again by using the protocol, but
555                  * additionally the output is not reset when
556                  * ivi_layout_activate_complete() terminates so we use the
557                  * current active surface to avoid hitting this again and again
558                  * */
559                 if (surf->mapped && output->active == surf)
560                         return;
561
562                 if (app_id) {
563                         weston_log("Surface with app_id %s, role %s activating "
564                                    "by default on output %s\n",
565                                    weston_desktop_surface_get_app_id(surf->dsurface),
566                                    ivi_layout_get_surface_role_name(surf),
567                                    output->output->name);
568                         ivi_layout_activate(output, app_id);
569                 }
570                 return;
571         }
572
573         if (!weston_desktop_surface_get_maximized(dsurf) ||
574             geom.width != output->area.width ||
575             geom.height != output->area.height)
576                 return;
577
578         ivi_layout_activate_complete(output, surf);
579 }
580
581 void
582 ivi_layout_fullscreen_committed(struct ivi_surface *surface)
583 {
584         struct ivi_compositor *ivi = surface->ivi;
585         struct ivi_policy *policy = ivi->policy;
586
587         struct weston_desktop_surface *dsurface = surface->dsurface;
588         struct weston_surface *wsurface =
589                 weston_desktop_surface_get_surface(dsurface);
590         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
591
592         struct ivi_output *output = surface->split.output;
593         struct weston_output *woutput = output->output;
594         struct ivi_output *bg_output = ivi_layout_find_bg_output(ivi);
595
596         struct weston_view *view = surface->view;
597         struct weston_geometry geom =
598                 weston_desktop_surface_get_geometry(dsurface);
599
600         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
601         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
602
603         bool is_fullscreen = weston_desktop_surface_get_fullscreen(dsurface);
604         bool is_dim_same =
605                 geom.width == bg_output->output->width &&
606                 geom.height == bg_output->output->height;
607
608         if (policy && policy->api.surface_activate_by_default &&
609             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
610             !surface->mapped)
611                 return;
612
613         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
614
615
616         if (surface->state == FULLSCREEN && weston_view_is_mapped(view))
617                 return;
618
619         /* if we still get here but we haven't resized so far, send configure
620          * events to do so */
621         if (surface->state != RESIZING && (!is_fullscreen || !is_dim_same)) {
622                 struct ivi_output *bg_output =
623                         ivi_layout_find_bg_output(surface->ivi);
624
625                 weston_log("Placing fullscreen app_id %s, type %s in hidden layer\n",
626                                 app_id, ivi_layout_get_surface_role_name(surface));
627                 weston_desktop_surface_set_fullscreen(dsurface, true);
628                 weston_desktop_surface_set_size(dsurface,
629                                                 bg_output->output->width,
630                                                 bg_output->output->height);
631
632                 surface->state = RESIZING;
633                 weston_view_set_output(view, output->output);
634                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
635                 return;
636         }
637
638         /* eventually, we would set the surface fullscreen, but the client
639          * hasn't resized correctly by this point, so terminate connection */
640         if (surface->state == RESIZING && is_fullscreen && !is_dim_same) {
641                 struct weston_desktop_client *desktop_client =
642                         weston_desktop_surface_get_client(dsurface);
643                 struct wl_client *client =
644                         weston_desktop_client_get_client(desktop_client);
645                 wl_client_post_implementation_error(client,
646                                 "can not display surface due to invalid geometry."
647                                 " Client should perform a geometry resize!");
648                 return;
649         }
650
651         /* this implies we resized correctly */
652         if (!weston_view_is_mapped(view) || surface->state != FULLSCREEN) {
653                 weston_layer_entry_remove(&view->layer_link);
654
655                 weston_view_set_output(view, woutput);
656                 weston_view_set_position(view, woutput->x, woutput->y);
657                 weston_layer_entry_insert(&ivi->fullscreen.view_list, &view->layer_link);
658
659                 wsurface->is_mapped = true;
660                 surface->view->is_mapped = true;
661                 surface->state = FULLSCREEN;
662
663                 weston_view_geometry_dirty(view);
664                 weston_surface_damage(view->surface);
665
666                 if (ivi_seat)
667                         ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
668
669                 shell_advertise_app_state(ivi, app_id,
670                                 NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
671
672                 weston_log("Activation completed for app_id %s, role %s, "
673                            "output %s\n", app_id,
674                            ivi_layout_get_surface_role_name(surface),
675                            output->name);
676
677         }
678 }
679
680 void
681 ivi_layout_desktop_resize(struct ivi_surface *surface,
682                           struct weston_geometry area)
683 {
684         struct weston_desktop_surface *dsurf = surface->dsurface;
685         struct weston_view *view = surface->view;
686
687         int x = area.x;
688         int y = area.y;
689         int width = area.width;
690         int height = area.height;
691
692         weston_desktop_surface_set_size(dsurf,
693                                         width, height);
694
695         weston_view_set_position(view, x, y);
696
697         weston_view_geometry_dirty(view);
698         weston_surface_damage(view->surface);
699 }
700
701 void
702 ivi_layout_split_committed(struct ivi_surface *surface)
703 {
704         struct ivi_compositor *ivi = surface->ivi;
705         struct ivi_policy *policy = ivi->policy;
706
707         struct weston_desktop_surface *dsurface = surface->dsurface;
708         struct weston_surface *wsurface =
709                 weston_desktop_surface_get_surface(dsurface);
710         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
711
712         struct ivi_output *output = surface->split.output;
713         struct weston_output *woutput = output->output;
714
715         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
716         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
717
718         struct weston_view *view = surface->view;
719         struct weston_geometry geom;
720
721         int x, y;
722         int width, height;
723
724         x = woutput->x;
725         y = woutput->y;
726
727         if (policy && policy->api.surface_activate_by_default &&
728             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
729             !surface->mapped)
730                 return;
731
732         if (surface->view->is_mapped)
733                 return;
734
735         geom = weston_desktop_surface_get_geometry(dsurface);
736
737         assert(surface->role == IVI_SURFACE_ROLE_SPLIT_H ||
738                surface->role == IVI_SURFACE_ROLE_SPLIT_V);
739
740         /* save the previous area in order to recover it back when if this kind
741          * of surface is being destroyed/removed */
742         output->area_saved = output->area;
743
744         switch (surface->role) {
745         case IVI_SURFACE_ROLE_SPLIT_V:
746                 geom.width = (output->area.width / 2);
747
748                 x += woutput->width - geom.width;
749                 output->area.width -= geom.width;
750
751                 width = woutput->width - x;
752                 height = output->area.height;
753                 y = output->area.y;
754
755                 break;
756         case IVI_SURFACE_ROLE_SPLIT_H:
757                 geom.height = (output->area.height / 2);
758
759                 y = output->area.y;
760                 output->area.y += geom.height;
761                 output->area.height -= geom.height;
762
763                 width = output->area.width;
764                 height = output->area.height;
765
766                 x = output->area.x;
767
768                 break;
769         default:
770                 assert(!"Invalid split orientation\n");
771         }
772
773         weston_desktop_surface_set_size(dsurface,
774                                         width, height);
775
776         /* resize the active surface first, output->area already contains
777          * correct area to resize to */
778         if (output->active)
779                 ivi_layout_desktop_resize(output->active, output->area);
780
781         weston_view_set_output(view, woutput);
782         weston_view_set_position(view, x, y);
783         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
784
785         weston_view_geometry_dirty(view);
786         weston_surface_damage(view->surface);
787
788         if (ivi_seat)
789                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
790
791         wsurface->is_mapped = true;
792         surface->view->is_mapped = true;
793
794         shell_advertise_app_state(ivi, app_id,
795                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
796
797         weston_log("Activation completed for app_id %s, role %s, output %s\n",
798                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
799 }
800
801 static void
802 ivi_compute_popup_position(const struct weston_output *output, struct weston_view *view,
803                            int initial_x, int initial_y, int *new_x, int *new_y)
804 {
805         *new_x = output->x + initial_x;
806         *new_y = output->y + initial_y;
807 }
808
809
810 static bool
811 ivi_surf_in_hidden_layer(struct ivi_compositor *ivi, struct ivi_surface *surface)
812 {
813         struct weston_view *ev;
814
815         wl_list_for_each(ev, &ivi->hidden.view_list.link, layer_link.link) {
816                 if (ev == surface->view)
817                         return true;
818         }
819
820         wl_list_for_each(ev, &ivi->fullscreen.view_list.link, layer_link.link) {
821                 if (ev == surface->view)
822                         return true;
823         }
824
825         return false;
826 }
827
828 void
829 ivi_layout_popup_committed(struct ivi_surface *surface)
830 {
831         struct ivi_compositor *ivi = surface->ivi;
832         struct ivi_policy *policy = ivi->policy;
833
834         struct weston_desktop_surface *dsurface = surface->dsurface;
835         struct weston_surface *wsurface =
836                 weston_desktop_surface_get_surface(dsurface);
837         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
838
839         int new_x, new_y;
840
841         struct ivi_output *output = surface->popup.output;
842         struct weston_output *woutput = output->output;
843
844         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
845         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
846
847         struct weston_view *view = surface->view;
848
849         if (policy && policy->api.surface_activate_by_default &&
850             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
851             !surface->mapped)
852                 return;
853
854         if (surface->view->is_mapped || surface->state == HIDDEN)
855                 return;
856
857         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
858
859         /* remove it from hidden layer if present */
860         if (ivi_surf_in_hidden_layer(ivi, surface))
861                 weston_layer_entry_remove(&view->layer_link);
862
863         weston_view_set_output(view, woutput);
864
865         ivi_compute_popup_position(woutput, view,
866                                    surface->popup.x, surface->popup.y, &new_x, &new_y);
867         weston_view_set_position(view, new_x, new_y);
868         weston_view_update_transform(view);
869
870         /* only clip the pop-up dialog window if we have a valid
871          * width and height being passed on. Users might not want to have one
872          * set-up so only enfore it is really passed on. */
873         if (surface->popup.bb.width > 0 && surface->popup.bb.height > 0)
874                 weston_view_set_mask(view, surface->popup.bb.x, surface->popup.bb.y,
875                                      surface->popup.bb.width, surface->popup.bb.height);
876
877         weston_layer_entry_insert(&ivi->popup.view_list, &view->layer_link);
878
879         weston_view_geometry_dirty(view);
880         weston_surface_damage(view->surface);
881
882         if (ivi_seat)
883                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
884
885         wsurface->is_mapped = true;
886         surface->view->is_mapped = true;
887
888         shell_advertise_app_state(ivi, app_id,
889                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
890
891         weston_log("Activation completed for app_id %s, role %s, output %s\n",
892                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
893 }
894
895 static void
896 ivi_layout_popup_re_add(struct ivi_surface *surface)
897 {
898         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
899         struct weston_view *view = surface->view;
900
901         if (weston_view_is_mapped(view)) {
902                 struct weston_desktop_surface *dsurface = surface->dsurface;
903                 struct weston_surface *wsurface =
904                         weston_desktop_surface_get_surface(dsurface);
905
906                 weston_layer_entry_remove(&view->layer_link);
907
908                 wsurface->is_mapped = false;
909                 view->is_mapped = false;
910         }
911
912         /* reset the activate by default in order to (still) allow the surface
913          * to be activaved using the request */
914         if (!surface->mapped)
915                 surface->mapped = true;
916
917         surface->state = NORMAL;
918         ivi_layout_popup_committed(surface);
919 }
920
921 static bool
922 ivi_layout_surface_is_split_or_fullscreen(struct ivi_surface *surf)
923 {
924         struct ivi_compositor *ivi = surf->ivi;
925         struct ivi_surface *is;
926
927         if (surf->role != IVI_SURFACE_ROLE_SPLIT_H &&
928             surf->role != IVI_SURFACE_ROLE_SPLIT_V &&
929             surf->role != IVI_SURFACE_ROLE_FULLSCREEN)
930                 return false;
931
932         /* reset the activate by default in order to (still) allow the surface
933          * to be activaved using the request */
934         if (!surf->mapped)
935                 surf->mapped = true;
936
937         wl_list_for_each(is, &ivi->surfaces, link)
938                 if (is == surf)
939                         return true;
940
941         return false;
942 }
943
944 void
945 ivi_layout_activate_by_surf(struct ivi_output *output, struct ivi_surface *surf)
946 {
947         struct ivi_compositor *ivi = output->ivi;
948         struct weston_desktop_surface *dsurf;
949         struct weston_geometry geom;
950         struct ivi_policy *policy = output->ivi->policy;
951
952         dsurf = surf->dsurface;
953
954         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
955
956         if (!surf)
957                 return;
958
959         if (policy && policy->api.surface_activate &&
960             !policy->api.surface_activate(surf, surf->ivi)) {
961                 return;
962         }
963
964 #ifdef AGL_COMP_DEBUG
965         weston_log("Activating app_id %s, type %s, on output %s\n", app_id,
966                         ivi_layout_get_surface_role_name(surf), output->output->name);
967 #endif
968
969         if (surf->role == IVI_SURFACE_ROLE_POPUP) {
970                 ivi_layout_popup_re_add(surf);
971                 return;
972         }
973
974         /* do not 're'-activate surfaces that are split or active */
975         if (surf == output->active ||
976             ivi_layout_surface_is_split_or_fullscreen(surf)) {
977                 weston_log("Application %s is already active on output %s\n",
978                                 app_id, output->output->name);
979                 return;
980         }
981
982         if (surf->role == IVI_SURFACE_ROLE_REMOTE) {
983                 struct ivi_output *remote_output =
984                         ivi_layout_find_with_app_id(app_id, ivi);
985
986                 weston_log("Changed activation for app_id %s, type %s, on output %s\n", app_id,
987                                 ivi_layout_get_surface_role_name(surf), output->output->name);
988
989                 /* if already active on a remote output do not
990                  * attempt to activate it again */
991                 if (remote_output && remote_output->active == surf)
992                         return;
993         }
994
995
996         geom = weston_desktop_surface_get_geometry(dsurf);
997
998         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
999                 surf->desktop.pending_output = output;
1000         if (weston_desktop_surface_get_maximized(dsurf) &&
1001             geom.width == output->area.width &&
1002             geom.height == output->area.height) {
1003                 ivi_layout_activate_complete(output, surf);
1004                 return;
1005         }
1006
1007         /* the background surface is already "maximized" so we don't need to
1008          * add to the hidden layer */
1009         if (surf->role == IVI_SURFACE_ROLE_BACKGROUND) {
1010                 ivi_layout_activate_complete(output, surf);
1011                 return;
1012         }
1013
1014         ivi_layout_add_to_hidden_layer(surf, output);
1015 }
1016
1017 void
1018 ivi_layout_activate(struct ivi_output *output, const char *app_id)
1019 {
1020         struct ivi_surface *surf;
1021         struct ivi_compositor *ivi = output->ivi;
1022
1023         if (!app_id)
1024                 return;
1025
1026         surf = ivi_find_app(ivi, app_id);
1027         if (!surf)
1028                 return;
1029
1030         ivi_layout_activate_by_surf(output, surf);
1031 }
1032
1033 struct ivi_output *
1034 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
1035 {
1036         struct ivi_output *ivi_output = NULL;
1037
1038         switch (surf->role) {
1039         case IVI_SURFACE_ROLE_DESKTOP:
1040                 if (surf->desktop.pending_output)
1041                         ivi_output = surf->desktop.pending_output;
1042                 else
1043                         ivi_output = surf->desktop.last_output;
1044                 break;
1045         case IVI_SURFACE_ROLE_POPUP:
1046                 ivi_output = surf->popup.output;
1047                 break;
1048         case IVI_SURFACE_ROLE_BACKGROUND:
1049                 ivi_output = surf->bg.output;
1050                 break;
1051         case IVI_SURFACE_ROLE_PANEL:
1052                 ivi_output = surf->panel.output;
1053                 break;
1054         case IVI_SURFACE_ROLE_FULLSCREEN:
1055                 ivi_output = surf->fullscreen.output;
1056                 break;
1057         case IVI_SURFACE_ROLE_SPLIT_H:
1058         case IVI_SURFACE_ROLE_SPLIT_V:
1059                 ivi_output = surf->split.output;
1060                 break;
1061         case IVI_SURFACE_ROLE_REMOTE:
1062                 ivi_output = surf->remote.output;
1063                 break;
1064         case IVI_SURFACE_ROLE_NONE:
1065         default:
1066                 break;
1067         }
1068
1069         return ivi_output;
1070 }
1071
1072 void
1073 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
1074 {
1075         struct ivi_surface *surf;
1076         struct ivi_output *ivi_output;
1077         struct ivi_policy *policy = ivi->policy;
1078
1079         if (!app_id)
1080                 return;
1081
1082         surf = ivi_find_app(ivi, app_id);
1083         if (!surf)
1084                 return;
1085
1086         if (policy && policy->api.surface_deactivate &&
1087             !policy->api.surface_deactivate(surf, surf->ivi)) {
1088                 return;
1089         }
1090
1091         ivi_output = ivi_layout_get_output_from_surface(surf);
1092         weston_log("Deactiving %s, role %s\n", app_id,
1093                         ivi_layout_get_surface_role_name(surf));
1094
1095         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
1096                 struct ivi_surface *previous_active;
1097
1098                 previous_active = ivi_output->previous_active;
1099                 if (!previous_active) {
1100                         /* we don't have a previous active it means we should
1101                          * display the bg */
1102                         if (ivi_output->active) {
1103                                 struct weston_view *view;
1104
1105                                 view = ivi_output->active->view;
1106                                 view->is_mapped = false;
1107                                 view->surface->is_mapped = false;
1108
1109                                 weston_layer_entry_remove(&view->layer_link);
1110                                 weston_view_geometry_dirty(view);
1111                                 weston_surface_damage(view->surface);
1112                                 ivi_output->active = NULL;
1113                         }
1114                 } else {
1115                         struct weston_desktop_surface *dsurface;
1116                         const char *previous_active_app_id;
1117
1118                         dsurface = previous_active->dsurface;
1119                         previous_active_app_id =
1120                                 weston_desktop_surface_get_app_id(dsurface);
1121                         ivi_layout_activate(ivi_output, previous_active_app_id);
1122                 }
1123         } else if (surf->role == IVI_SURFACE_ROLE_POPUP) {
1124                 struct weston_view *view  = surf->view;
1125
1126                 weston_view_unmap(view);
1127                 surf->state = HIDDEN;
1128
1129                 weston_layer_entry_remove(&view->layer_link);
1130                 weston_view_geometry_dirty(view);
1131                 weston_surface_damage(view->surface);
1132         }
1133
1134       shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_DEACTIVATED);
1135 }