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