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