layout: Fix no-op check due to invalid checks
[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
252         if (surf->role != IVI_SURFACE_ROLE_BACKGROUND)
253                 weston_view_set_position(view,
254                                          woutput->x + output->area.x,
255                                          woutput->y + output->area.y);
256
257         view->is_mapped = true;
258         surf->mapped = true;
259         view->surface->is_mapped = true;
260
261         /* handle a movement from one output to another */
262         if (surf->current_completed_output &&
263             surf->current_completed_output != output) {
264
265                 /* we're migrating the same surface but to another output */
266                 if (surf->current_completed_output->active == surf) {
267                         struct weston_view *ev =
268                                 surf->current_completed_output->active->view;
269
270                         weston_layer_entry_remove(&ev->layer_link);
271                         surf->current_completed_output->previous_active =
272                                 surf->current_completed_output->active;
273                         surf->current_completed_output->active = NULL;
274
275                         /* damage all possible outputs to avoid stale views */
276                         weston_compositor_damage_all(ivi->compositor);
277                 }
278         }
279
280         if (output->active) {
281                 /* keep the background surface mapped at all times */
282                 if (output->active->role != IVI_SURFACE_ROLE_BACKGROUND) {
283                         output->active->view->is_mapped = false;
284                         output->active->view->surface->is_mapped = false;
285
286                         weston_layer_entry_remove(&output->active->view->layer_link);
287                 }
288         }
289         output->previous_active = output->active;
290         output->active = surf;
291         surf->current_completed_output = output;
292
293         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
294         weston_view_geometry_dirty(view);
295         weston_surface_damage(view->surface);
296
297         if (ivi_seat)
298                 ivi_shell_activate_surface(surf, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
299
300         /*
301          * the 'remote' role now makes use of this part so make sure we don't
302          * trip the enum such that we might end up with a modified output for
303          * 'remote' role
304          */
305         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
306                 if (surf->desktop.pending_output)
307                         surf->desktop.last_output = surf->desktop.pending_output;
308                 surf->desktop.pending_output = NULL;
309         }
310
311         weston_log("Activation completed for app_id %s, role %s, output %s\n",
312                         app_id,
313                         ivi_layout_get_surface_role_name(surf), output->name);
314
315         shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_ACTIVATED);
316 }
317
318 static bool
319 ivi_layout_find_output_with_app_id(const char *app_id, struct ivi_output *output)
320 {
321         char *cur;
322         size_t app_id_len;
323
324         cur = output->app_ids;
325         app_id_len = strlen(app_id);
326
327         while ((cur = strstr(cur, app_id))) {
328                 if ((cur[app_id_len] == ',' || cur[app_id_len] == '\0') &&
329                     (cur == output->app_ids || cur[-1] == ','))
330                         return true;
331                 cur++;
332         }
333
334         return false;
335 }
336
337 struct ivi_output *
338 ivi_layout_find_with_app_id(const char *app_id, struct ivi_compositor *ivi)
339 {
340         struct ivi_output *out;
341
342         if (!app_id)
343                 return NULL;
344
345         wl_list_for_each(out, &ivi->outputs, link) {
346                 if (!out->app_ids)
347                         continue;
348
349                 if (ivi_layout_find_output_with_app_id(app_id, out))
350                         return out;
351         }
352         return NULL;
353 }
354
355 struct ivi_output *
356 ivi_layout_find_bg_output(struct ivi_compositor *ivi)
357 {
358         struct ivi_output *out;
359
360         wl_list_for_each(out, &ivi->outputs, link) {
361                 if (out->background &&
362                     out->background->role == IVI_SURFACE_ROLE_BACKGROUND)
363                         return out;
364         }
365
366         return NULL;
367 }
368
369
370 static void
371 ivi_layout_add_to_hidden_layer(struct ivi_surface *surf,
372                                struct ivi_output *ivi_output)
373 {
374         struct weston_desktop_surface *dsurf = surf->dsurface;
375         struct weston_view *ev = surf->view;
376         struct ivi_compositor *ivi = surf->ivi;
377         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
378
379         /*
380          * If the view isn't mapped, we put it onto the hidden layer so it will
381          * start receiving frame events, and will be able to act on our
382          * configure event.
383          */
384         if (!weston_view_is_mapped(ev)) {
385                 ev->is_mapped = true;
386                 ev->surface->is_mapped = true;
387
388                 weston_desktop_surface_set_maximized(dsurf, true);
389                 weston_desktop_surface_set_size(dsurf,
390                                                 ivi_output->area.width,
391                                                 ivi_output->area.height);
392
393                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
394                            app_id, ivi_layout_get_surface_role_name(surf),
395                            ivi_output->area.width, ivi_output->area.height);
396
397                 surf->hidden_layer_output = ivi_output;
398                 weston_view_set_output(ev, ivi_output->output);
399                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
400                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
401                                 app_id, ivi_layout_get_surface_role_name(surf),
402                                 ivi_output->output->name);
403
404                 weston_compositor_schedule_repaint(ivi->compositor);
405                 return;
406         }
407
408         /* we might have another output to activate */
409         if (surf->hidden_layer_output &&
410             surf->hidden_layer_output != ivi_output) {
411                 weston_layer_entry_remove(&ev->layer_link);
412                 weston_view_geometry_dirty(ev);
413                 weston_surface_damage(ev->surface);
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 void
794 ivi_layout_popup_committed(struct ivi_surface *surface)
795 {
796         struct ivi_compositor *ivi = surface->ivi;
797         struct ivi_policy *policy = ivi->policy;
798
799         struct weston_desktop_surface *dsurface = surface->dsurface;
800         struct weston_surface *wsurface =
801                 weston_desktop_surface_get_surface(dsurface);
802         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
803
804         int new_x, new_y;
805
806         struct ivi_output *output = surface->popup.output;
807         struct weston_output *woutput = output->output;
808
809         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
810         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
811
812         struct weston_view *view = surface->view;
813
814         if (policy && policy->api.surface_activate_by_default &&
815             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
816             !surface->mapped)
817                 return;
818
819         if (surface->view->is_mapped || surface->state == HIDDEN)
820                 return;
821
822         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
823
824         weston_view_set_output(view, woutput);
825
826         ivi_compute_popup_position(woutput, view,
827                                    surface->popup.x, surface->popup.y, &new_x, &new_y);
828         weston_view_set_position(view, new_x, new_y);
829         weston_view_update_transform(view);
830
831         /* only clip the pop-up dialog window if we have a valid
832          * width and height being passed on. Users might not want to have one
833          * set-up so only enfore it is really passed on. */
834         if (surface->popup.bb.width > 0 && surface->popup.bb.height > 0)
835                 weston_view_set_mask(view, surface->popup.bb.x, surface->popup.bb.y,
836                                      surface->popup.bb.width, surface->popup.bb.height);
837
838         weston_layer_entry_insert(&ivi->popup.view_list, &view->layer_link);
839
840         weston_view_geometry_dirty(view);
841         weston_surface_damage(view->surface);
842
843         if (ivi_seat)
844                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
845
846         wsurface->is_mapped = true;
847         surface->view->is_mapped = true;
848
849         shell_advertise_app_state(ivi, app_id,
850                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
851
852         weston_log("Activation completed for app_id %s, role %s, output %s\n",
853                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
854 }
855
856 static void
857 ivi_layout_popup_re_add(struct ivi_surface *surface)
858 {
859         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
860         struct weston_view *view = surface->view;
861
862         if (weston_view_is_mapped(view)) {
863                 struct weston_desktop_surface *dsurface = surface->dsurface;
864                 struct weston_surface *wsurface =
865                         weston_desktop_surface_get_surface(dsurface);
866
867                 weston_layer_entry_remove(&view->layer_link);
868
869                 wsurface->is_mapped = false;
870                 view->is_mapped = false;
871         }
872
873         /* reset the activate by default in order to (still) allow the surface
874          * to be activaved using the request */
875         if (!surface->mapped)
876                 surface->mapped = true;
877
878         surface->state = NORMAL;
879         ivi_layout_popup_committed(surface);
880 }
881
882 static bool
883 ivi_layout_surface_is_split_or_fullscreen(struct ivi_surface *surf)
884 {
885         struct ivi_compositor *ivi = surf->ivi;
886         struct ivi_surface *is;
887
888         if (surf->role != IVI_SURFACE_ROLE_SPLIT_H &&
889             surf->role != IVI_SURFACE_ROLE_SPLIT_V &&
890             surf->role != IVI_SURFACE_ROLE_FULLSCREEN)
891                 return false;
892
893         /* reset the activate by default in order to (still) allow the surface
894          * to be activaved using the request */
895         if (!surf->mapped)
896                 surf->mapped = true;
897
898         wl_list_for_each(is, &ivi->surfaces, link)
899                 if (is == surf)
900                         return true;
901
902         return false;
903 }
904
905 void
906 ivi_layout_activate_by_surf(struct ivi_output *output, struct ivi_surface *surf)
907 {
908         struct ivi_compositor *ivi = output->ivi;
909         struct weston_desktop_surface *dsurf;
910         struct weston_geometry geom;
911         struct ivi_policy *policy = output->ivi->policy;
912
913         dsurf = surf->dsurface;
914
915         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
916
917         if (!surf)
918                 return;
919
920         if (policy && policy->api.surface_activate &&
921             !policy->api.surface_activate(surf, surf->ivi)) {
922                 return;
923         }
924
925 #ifdef AGL_COMP_DEBUG
926         weston_log("Activating app_id %s, type %s, on output %s\n", app_id,
927                         ivi_layout_get_surface_role_name(surf), output->output->name);
928 #endif
929
930         if (surf->role == IVI_SURFACE_ROLE_POPUP) {
931                 ivi_layout_popup_re_add(surf);
932                 return;
933         }
934
935         /* do not 're'-activate surfaces that are split or active */
936         if (surf == output->active ||
937             ivi_layout_surface_is_split_or_fullscreen(surf)) {
938                 weston_log("Application %s is already active on output %s\n",
939                                 app_id, output->output->name);
940                 return;
941         }
942
943         if (surf->role == IVI_SURFACE_ROLE_REMOTE) {
944                 struct ivi_output *remote_output =
945                         ivi_layout_find_with_app_id(app_id, ivi);
946
947                 weston_log("Changed activation for app_id %s, type %s, on output %s\n", app_id,
948                                 ivi_layout_get_surface_role_name(surf), output->output->name);
949
950                 /* if already active on a remote output do not
951                  * attempt to activate it again */
952                 if (remote_output && remote_output->active == surf)
953                         return;
954         }
955
956
957         geom = weston_desktop_surface_get_geometry(dsurf);
958
959         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
960                 surf->desktop.pending_output = output;
961         if (weston_desktop_surface_get_maximized(dsurf) &&
962             geom.width == output->area.width &&
963             geom.height == output->area.height) {
964                 ivi_layout_activate_complete(output, surf);
965                 return;
966         }
967
968         /* the background surface is already "maximized" so we don't need to
969          * add to the hidden layer */
970         if (surf->role == IVI_SURFACE_ROLE_BACKGROUND) {
971                 ivi_layout_activate_complete(output, surf);
972                 return;
973         }
974
975         ivi_layout_add_to_hidden_layer(surf, output);
976 }
977
978 void
979 ivi_layout_activate(struct ivi_output *output, const char *app_id)
980 {
981         struct ivi_surface *surf;
982         struct ivi_compositor *ivi = output->ivi;
983
984         if (!app_id)
985                 return;
986
987         surf = ivi_find_app(ivi, app_id);
988         if (!surf)
989                 return;
990
991         ivi_layout_activate_by_surf(output, surf);
992 }
993
994 struct ivi_output *
995 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
996 {
997         struct ivi_output *ivi_output = NULL;
998
999         switch (surf->role) {
1000         case IVI_SURFACE_ROLE_DESKTOP:
1001                 if (surf->desktop.pending_output)
1002                         ivi_output = surf->desktop.pending_output;
1003                 else
1004                         ivi_output = surf->desktop.last_output;
1005                 break;
1006         case IVI_SURFACE_ROLE_POPUP:
1007                 ivi_output = surf->popup.output;
1008                 break;
1009         case IVI_SURFACE_ROLE_BACKGROUND:
1010                 ivi_output = surf->bg.output;
1011                 break;
1012         case IVI_SURFACE_ROLE_PANEL:
1013                 ivi_output = surf->panel.output;
1014                 break;
1015         case IVI_SURFACE_ROLE_FULLSCREEN:
1016                 ivi_output = surf->fullscreen.output;
1017                 break;
1018         case IVI_SURFACE_ROLE_SPLIT_H:
1019         case IVI_SURFACE_ROLE_SPLIT_V:
1020                 ivi_output = surf->split.output;
1021                 break;
1022         case IVI_SURFACE_ROLE_REMOTE:
1023                 ivi_output = surf->remote.output;
1024                 break;
1025         case IVI_SURFACE_ROLE_NONE:
1026         default:
1027                 break;
1028         }
1029
1030         return ivi_output;
1031 }
1032
1033 void
1034 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
1035 {
1036         struct ivi_surface *surf;
1037         struct ivi_output *ivi_output;
1038         struct ivi_policy *policy = ivi->policy;
1039
1040         if (!app_id)
1041                 return;
1042
1043         surf = ivi_find_app(ivi, app_id);
1044         if (!surf)
1045                 return;
1046
1047         if (policy && policy->api.surface_deactivate &&
1048             !policy->api.surface_deactivate(surf, surf->ivi)) {
1049                 return;
1050         }
1051
1052         ivi_output = ivi_layout_get_output_from_surface(surf);
1053         weston_log("Deactiving %s, role %s\n", app_id,
1054                         ivi_layout_get_surface_role_name(surf));
1055
1056         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
1057                 struct ivi_surface *previous_active;
1058
1059                 previous_active = ivi_output->previous_active;
1060                 if (!previous_active) {
1061                         /* we don't have a previous active it means we should
1062                          * display the bg */
1063                         if (ivi_output->active) {
1064                                 struct weston_view *view;
1065
1066                                 view = ivi_output->active->view;
1067                                 view->is_mapped = false;
1068                                 view->surface->is_mapped = false;
1069
1070                                 weston_layer_entry_remove(&view->layer_link);
1071                                 weston_view_geometry_dirty(view);
1072                                 weston_surface_damage(view->surface);
1073                                 ivi_output->active = NULL;
1074                         }
1075                 } else {
1076                         struct weston_desktop_surface *dsurface;
1077                         const char *previous_active_app_id;
1078
1079                         dsurface = previous_active->dsurface;
1080                         previous_active_app_id =
1081                                 weston_desktop_surface_get_app_id(dsurface);
1082                         ivi_layout_activate(ivi_output, previous_active_app_id);
1083                 }
1084         } else if (surf->role == IVI_SURFACE_ROLE_POPUP) {
1085                 struct weston_view *view  = surf->view;
1086
1087                 weston_view_unmap(view);
1088                 surf->state = HIDDEN;
1089
1090                 weston_layer_entry_remove(&view->layer_link);
1091                 weston_view_geometry_dirty(view);
1092                 weston_surface_damage(view->surface);
1093         }
1094
1095       shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_DEACTIVATED);
1096 }