028ff4a58737243028784d296d7e7d8fd20445bb
[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
413                 if (ivi_output->area.width != surf->hidden_layer_output->area.width &&
414                     ivi_output->area.height != surf->hidden_layer_output->area.height) {
415                         weston_desktop_surface_set_maximized(dsurf, true);
416                         weston_desktop_surface_set_size(dsurf,
417                                                         ivi_output->area.width,
418                                                         ivi_output->area.height);
419                 }
420
421                 weston_log("Setting app_id %s, role %s, set to maximized (%dx%d)\n",
422                                 app_id, ivi_layout_get_surface_role_name(surf),
423                                 ivi_output->area.width, ivi_output->area.height);
424
425                 surf->hidden_layer_output = ivi_output;
426                 weston_view_set_output(ev, ivi_output->output);
427                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
428                 weston_log("Placed app_id %s, type %s in hidden layer on output %s\n",
429                                 app_id, ivi_layout_get_surface_role_name(surf),
430                                 ivi_output->output->name);
431         }
432
433         weston_compositor_schedule_repaint(ivi->compositor);
434 }
435
436 void
437 ivi_layout_desktop_committed(struct ivi_surface *surf)
438 {
439         struct weston_desktop_surface *dsurf = surf->dsurface;
440         struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf);
441         struct ivi_policy *policy = surf->ivi->policy;
442         struct ivi_output *output;
443         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
444
445         assert(surf->role == IVI_SURFACE_ROLE_DESKTOP ||
446                surf->role == IVI_SURFACE_ROLE_REMOTE);
447
448         /*
449          * we can't make use here of the ivi_layout_get_output_from_surface()
450          * due to the fact that we'll always land here when a surface performs
451          * a commit and pending_output will not bet set. This works in tandem
452          * with 'mapped' at this point to avoid tripping over
453          * to a surface that continuously updates its content
454          */
455         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
456                 output = surf->desktop.pending_output;
457         else
458                 output = surf->remote.output;
459
460         if (surf->role == IVI_SURFACE_ROLE_DESKTOP && !output) {
461                 struct ivi_output *r_output;
462
463                 if (policy && policy->api.surface_activate_by_default &&
464                     !policy->api.surface_activate_by_default(surf, surf->ivi))
465                         return;
466
467                 /* we can only activate it again by using the protocol */
468                 if (surf->mapped)
469                         return;
470
471                 /* check first if there aren't any outputs being set */
472                 r_output = ivi_layout_find_with_app_id(app_id, surf->ivi);
473
474                 if (r_output) {
475                         struct weston_view *view = r_output->fullscreen_view.fs->view;
476                         if (view->is_mapped || view->surface->is_mapped)
477                                 remove_black_curtain(r_output);
478                 }
479
480
481                 /* try finding an output with a background and use that */
482                 if (!r_output)
483                         r_output = ivi_layout_find_bg_output(surf->ivi);
484
485                 /* if we couldn't still find an output by this point, there's
486                  * something wrong so we abort with a protocol error */
487                 if (!r_output) {
488                         wl_resource_post_error(surf->ivi->shell_client.resource,
489                                                AGL_SHELL_ERROR_INVALID_ARGUMENT,
490                                                "No valid output found to activate surface by default");
491                         return;
492                 }
493
494                 if (!surf->ivi->activate_by_default) {
495                         weston_log("Refusing to activate surface role %d, app_id %s\n",
496                                         surf->role, app_id);
497
498                         if (!weston_desktop_surface_get_maximized(dsurf) ||
499                             geom.width != r_output->area.width ||
500                             geom.height != r_output->area.height)
501                                 ivi_layout_add_to_hidden_layer(surf, r_output);
502
503                         return;
504                 }
505
506                 /* use the output of the bg to activate the app on start-up by
507                  * default */
508                 if (surf->view && r_output) {
509                         if (app_id && r_output) {
510                                 weston_log("Surface with app_id %s, role %s activating by default\n",
511                                         weston_desktop_surface_get_app_id(surf->dsurface),
512                                         ivi_layout_get_surface_role_name(surf));
513                                 ivi_layout_activate(r_output, app_id);
514                         } else if (!app_id) {
515                                 /*
516                                  * applications not setting an app_id, or
517                                  * setting an app_id but at a later point in
518                                  * time, might fall-back here so give them a
519                                  * chance to receive the configure event and
520                                  * act upon it
521                                  */
522                                 weston_log("Surface no app_id, role %s activating by default\n",
523                                         ivi_layout_get_surface_role_name(surf));
524                                 ivi_layout_activate_by_surf(r_output, surf);
525                         }
526                 }
527
528                 return;
529         }
530
531         if (surf->role == IVI_SURFACE_ROLE_REMOTE && output) {
532                 if (policy && policy->api.surface_activate_by_default &&
533                     !policy->api.surface_activate_by_default(surf, surf->ivi))
534                         return;
535
536                 /* we can only activate it again by using the protocol, but
537                  * additionally the output is not reset when
538                  * ivi_layout_activate_complete() terminates so we use the
539                  * current active surface to avoid hitting this again and again
540                  * */
541                 if (surf->mapped && output->active == surf)
542                         return;
543
544                 if (app_id) {
545                         weston_log("Surface with app_id %s, role %s activating "
546                                    "by default on output %s\n",
547                                    weston_desktop_surface_get_app_id(surf->dsurface),
548                                    ivi_layout_get_surface_role_name(surf),
549                                    output->output->name);
550                         ivi_layout_activate(output, app_id);
551                 }
552                 return;
553         }
554
555         if (!weston_desktop_surface_get_maximized(dsurf) ||
556             geom.width != output->area.width ||
557             geom.height != output->area.height)
558                 return;
559
560         ivi_layout_activate_complete(output, surf);
561 }
562
563 void
564 ivi_layout_fullscreen_committed(struct ivi_surface *surface)
565 {
566         struct ivi_compositor *ivi = surface->ivi;
567         struct ivi_policy *policy = ivi->policy;
568
569         struct weston_desktop_surface *dsurface = surface->dsurface;
570         struct weston_surface *wsurface =
571                 weston_desktop_surface_get_surface(dsurface);
572         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
573
574         struct ivi_output *output = surface->split.output;
575         struct weston_output *woutput = output->output;
576         struct ivi_output *bg_output = ivi_layout_find_bg_output(ivi);
577
578         struct weston_view *view = surface->view;
579         struct weston_geometry geom =
580                 weston_desktop_surface_get_geometry(dsurface);
581
582         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
583         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
584
585         bool is_fullscreen = weston_desktop_surface_get_fullscreen(dsurface);
586         bool is_dim_same =
587                 geom.width == bg_output->output->width &&
588                 geom.height == bg_output->output->height;
589
590         if (policy && policy->api.surface_activate_by_default &&
591             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
592             !surface->mapped)
593                 return;
594
595         assert(surface->role == IVI_SURFACE_ROLE_FULLSCREEN);
596
597         if (weston_view_is_mapped(view))
598                 return;
599
600         /* if we still get here but we haven't resized so far, send configure
601          * events to do so */
602         if (surface->state != RESIZING && (!is_fullscreen || !is_dim_same)) {
603                 struct ivi_output *bg_output =
604                         ivi_layout_find_bg_output(surface->ivi);
605
606                 weston_log("Placing fullscreen app_id %s, type %s in hidden layer\n",
607                                 app_id, ivi_layout_get_surface_role_name(surface));
608                 weston_desktop_surface_set_fullscreen(dsurface, true);
609                 weston_desktop_surface_set_size(dsurface,
610                                                 bg_output->output->width,
611                                                 bg_output->output->height);
612
613                 surface->state = RESIZING;
614                 weston_view_set_output(view, output->output);
615                 weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link);
616                 return;
617         }
618
619         /* eventually, we would set the surface fullscreen, but the client
620          * hasn't resized correctly by this point, so terminate connection */
621         if (surface->state == RESIZING && is_fullscreen && !is_dim_same) {
622                 struct weston_desktop_client *desktop_client =
623                         weston_desktop_surface_get_client(dsurface);
624                 struct wl_client *client =
625                         weston_desktop_client_get_client(desktop_client);
626                 wl_client_post_implementation_error(client,
627                                 "can not display surface due to invalid geometry."
628                                 " Client should perform a geometry resize!");
629                 return;
630         }
631
632         /* this implies we resized correctly */
633         if (!weston_view_is_mapped(view)) {
634                 weston_layer_entry_remove(&view->layer_link);
635
636                 weston_view_set_output(view, woutput);
637                 weston_view_set_position(view, woutput->x, woutput->y);
638                 weston_layer_entry_insert(&ivi->fullscreen.view_list, &view->layer_link);
639
640                 wsurface->is_mapped = true;
641                 surface->view->is_mapped = true;
642                 surface->state = FULLSCREEN;
643
644                 weston_view_geometry_dirty(view);
645                 weston_surface_damage(view->surface);
646
647                 if (ivi_seat)
648                         ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
649
650                 shell_advertise_app_state(ivi, app_id,
651                                 NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
652
653                 weston_log("Activation completed for app_id %s, role %s, "
654                            "output %s\n", app_id,
655                            ivi_layout_get_surface_role_name(surface),
656                            output->name);
657
658         }
659 }
660
661 void
662 ivi_layout_desktop_resize(struct ivi_surface *surface,
663                           struct weston_geometry area)
664 {
665         struct weston_desktop_surface *dsurf = surface->dsurface;
666         struct weston_view *view = surface->view;
667
668         int x = area.x;
669         int y = area.y;
670         int width = area.width;
671         int height = area.height;
672
673         weston_desktop_surface_set_size(dsurf,
674                                         width, height);
675
676         weston_view_set_position(view, x, y);
677
678         weston_view_geometry_dirty(view);
679         weston_surface_damage(view->surface);
680 }
681
682 void
683 ivi_layout_split_committed(struct ivi_surface *surface)
684 {
685         struct ivi_compositor *ivi = surface->ivi;
686         struct ivi_policy *policy = ivi->policy;
687
688         struct weston_desktop_surface *dsurface = surface->dsurface;
689         struct weston_surface *wsurface =
690                 weston_desktop_surface_get_surface(dsurface);
691         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
692
693         struct ivi_output *output = surface->split.output;
694         struct weston_output *woutput = output->output;
695
696         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
697         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
698
699         struct weston_view *view = surface->view;
700         struct weston_geometry geom;
701
702         int x, y;
703         int width, height;
704
705         x = woutput->x;
706         y = woutput->y;
707
708         if (policy && policy->api.surface_activate_by_default &&
709             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
710             !surface->mapped)
711                 return;
712
713         if (surface->view->is_mapped)
714                 return;
715
716         geom = weston_desktop_surface_get_geometry(dsurface);
717
718         assert(surface->role == IVI_SURFACE_ROLE_SPLIT_H ||
719                surface->role == IVI_SURFACE_ROLE_SPLIT_V);
720
721         /* save the previous area in order to recover it back when if this kind
722          * of surface is being destroyed/removed */
723         output->area_saved = output->area;
724
725         switch (surface->role) {
726         case IVI_SURFACE_ROLE_SPLIT_V:
727                 geom.width = (output->area.width / 2);
728
729                 x += woutput->width - geom.width;
730                 output->area.width -= geom.width;
731
732                 width = woutput->width - x;
733                 height = output->area.height;
734                 y = output->area.y;
735
736                 break;
737         case IVI_SURFACE_ROLE_SPLIT_H:
738                 geom.height = (output->area.height / 2);
739
740                 y = output->area.y;
741                 output->area.y += geom.height;
742                 output->area.height -= geom.height;
743
744                 width = output->area.width;
745                 height = output->area.height;
746
747                 x = output->area.x;
748
749                 break;
750         default:
751                 assert(!"Invalid split orientation\n");
752         }
753
754         weston_desktop_surface_set_size(dsurface,
755                                         width, height);
756
757         /* resize the active surface first, output->area already contains
758          * correct area to resize to */
759         if (output->active)
760                 ivi_layout_desktop_resize(output->active, output->area);
761
762         weston_view_set_output(view, woutput);
763         weston_view_set_position(view, x, y);
764         weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link);
765
766         weston_view_geometry_dirty(view);
767         weston_surface_damage(view->surface);
768
769         if (ivi_seat)
770                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
771
772         wsurface->is_mapped = true;
773         surface->view->is_mapped = true;
774
775         shell_advertise_app_state(ivi, app_id,
776                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
777
778         weston_log("Activation completed for app_id %s, role %s, output %s\n",
779                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
780 }
781
782 static void
783 ivi_compute_popup_position(const struct weston_output *output, struct weston_view *view,
784                            int initial_x, int initial_y, int *new_x, int *new_y)
785 {
786         *new_x = output->x + initial_x;
787         *new_y = output->y + initial_y;
788 }
789
790
791 void
792 ivi_layout_popup_committed(struct ivi_surface *surface)
793 {
794         struct ivi_compositor *ivi = surface->ivi;
795         struct ivi_policy *policy = ivi->policy;
796
797         struct weston_desktop_surface *dsurface = surface->dsurface;
798         struct weston_surface *wsurface =
799                 weston_desktop_surface_get_surface(dsurface);
800         const char *app_id = weston_desktop_surface_get_app_id(dsurface);
801
802         int new_x, new_y;
803
804         struct ivi_output *output = surface->popup.output;
805         struct weston_output *woutput = output->output;
806
807         struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
808         struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat);
809
810         struct weston_view *view = surface->view;
811
812         if (policy && policy->api.surface_activate_by_default &&
813             !policy->api.surface_activate_by_default(surface, surface->ivi) &&
814             !surface->mapped)
815                 return;
816
817         if (surface->view->is_mapped || surface->state == HIDDEN)
818                 return;
819
820         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
821
822         weston_view_set_output(view, woutput);
823
824         ivi_compute_popup_position(woutput, view,
825                                    surface->popup.x, surface->popup.y, &new_x, &new_y);
826         weston_view_set_position(view, new_x, new_y);
827         weston_view_update_transform(view);
828
829         /* only clip the pop-up dialog window if we have a valid
830          * width and height being passed on. Users might not want to have one
831          * set-up so only enfore it is really passed on. */
832         if (surface->popup.bb.width > 0 && surface->popup.bb.height > 0)
833                 weston_view_set_mask(view, surface->popup.bb.x, surface->popup.bb.y,
834                                      surface->popup.bb.width, surface->popup.bb.height);
835
836         weston_layer_entry_insert(&ivi->popup.view_list, &view->layer_link);
837
838         weston_view_geometry_dirty(view);
839         weston_surface_damage(view->surface);
840
841         if (ivi_seat)
842                 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
843
844         wsurface->is_mapped = true;
845         surface->view->is_mapped = true;
846
847         shell_advertise_app_state(ivi, app_id,
848                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
849
850         weston_log("Activation completed for app_id %s, role %s, output %s\n",
851                         app_id, ivi_layout_get_surface_role_name(surface), output->name);
852 }
853
854 static void
855 ivi_layout_popup_re_add(struct ivi_surface *surface)
856 {
857         assert(surface->role == IVI_SURFACE_ROLE_POPUP);
858         struct weston_view *view = surface->view;
859
860         if (weston_view_is_mapped(view)) {
861                 struct weston_desktop_surface *dsurface = surface->dsurface;
862                 struct weston_surface *wsurface =
863                         weston_desktop_surface_get_surface(dsurface);
864
865                 weston_layer_entry_remove(&view->layer_link);
866
867                 wsurface->is_mapped = false;
868                 view->is_mapped = false;
869         }
870
871         /* reset the activate by default in order to (still) allow the surface
872          * to be activaved using the request */
873         if (!surface->mapped)
874                 surface->mapped = true;
875
876         surface->state = NORMAL;
877         ivi_layout_popup_committed(surface);
878 }
879
880 static bool
881 ivi_layout_surface_is_split_or_fullscreen(struct ivi_surface *surf)
882 {
883         struct ivi_compositor *ivi = surf->ivi;
884         struct ivi_surface *is;
885
886         if (surf->role != IVI_SURFACE_ROLE_SPLIT_H &&
887             surf->role != IVI_SURFACE_ROLE_SPLIT_V &&
888             surf->role != IVI_SURFACE_ROLE_FULLSCREEN)
889                 return false;
890
891         /* reset the activate by default in order to (still) allow the surface
892          * to be activaved using the request */
893         if (!surf->mapped)
894                 surf->mapped = true;
895
896         wl_list_for_each(is, &ivi->surfaces, link)
897                 if (is == surf)
898                         return true;
899
900         return false;
901 }
902
903 void
904 ivi_layout_activate_by_surf(struct ivi_output *output, struct ivi_surface *surf)
905 {
906         struct ivi_compositor *ivi = output->ivi;
907         struct weston_desktop_surface *dsurf;
908         struct weston_geometry geom;
909         struct ivi_policy *policy = output->ivi->policy;
910
911         dsurf = surf->dsurface;
912
913         const char *app_id = weston_desktop_surface_get_app_id(dsurf);
914
915         if (!surf)
916                 return;
917
918         if (policy && policy->api.surface_activate &&
919             !policy->api.surface_activate(surf, surf->ivi)) {
920                 return;
921         }
922
923 #ifdef AGL_COMP_DEBUG
924         weston_log("Activating app_id %s, type %s, on output %s\n", app_id,
925                         ivi_layout_get_surface_role_name(surf), output->output->name);
926 #endif
927
928         if (surf->role == IVI_SURFACE_ROLE_POPUP) {
929                 ivi_layout_popup_re_add(surf);
930                 return;
931         }
932
933         /* do not 're'-activate surfaces that are split or active */
934         if (surf == output->active ||
935             ivi_layout_surface_is_split_or_fullscreen(surf)) {
936                 weston_log("Application %s is already active on output %s\n",
937                                 app_id, output->output->name);
938                 return;
939         }
940
941         if (surf->role == IVI_SURFACE_ROLE_REMOTE) {
942                 struct ivi_output *remote_output =
943                         ivi_layout_find_with_app_id(app_id, ivi);
944
945                 weston_log("Changed activation for app_id %s, type %s, on output %s\n", app_id,
946                                 ivi_layout_get_surface_role_name(surf), output->output->name);
947
948                 /* if already active on a remote output do not
949                  * attempt to activate it again */
950                 if (remote_output && remote_output->active == surf)
951                         return;
952         }
953
954
955         geom = weston_desktop_surface_get_geometry(dsurf);
956
957         if (surf->role == IVI_SURFACE_ROLE_DESKTOP)
958                 surf->desktop.pending_output = output;
959         if (weston_desktop_surface_get_maximized(dsurf) &&
960             geom.width == output->area.width &&
961             geom.height == output->area.height) {
962                 ivi_layout_activate_complete(output, surf);
963                 return;
964         }
965
966         /* the background surface is already "maximized" so we don't need to
967          * add to the hidden layer */
968         if (surf->role == IVI_SURFACE_ROLE_BACKGROUND) {
969                 ivi_layout_activate_complete(output, surf);
970                 return;
971         }
972
973         ivi_layout_add_to_hidden_layer(surf, output);
974 }
975
976 void
977 ivi_layout_activate(struct ivi_output *output, const char *app_id)
978 {
979         struct ivi_surface *surf;
980         struct ivi_compositor *ivi = output->ivi;
981
982         if (!app_id)
983                 return;
984
985         surf = ivi_find_app(ivi, app_id);
986         if (!surf)
987                 return;
988
989         ivi_layout_activate_by_surf(output, surf);
990 }
991
992 struct ivi_output *
993 ivi_layout_get_output_from_surface(struct ivi_surface *surf)
994 {
995         struct ivi_output *ivi_output = NULL;
996
997         switch (surf->role) {
998         case IVI_SURFACE_ROLE_DESKTOP:
999                 if (surf->desktop.pending_output)
1000                         ivi_output = surf->desktop.pending_output;
1001                 else
1002                         ivi_output = surf->desktop.last_output;
1003                 break;
1004         case IVI_SURFACE_ROLE_POPUP:
1005                 ivi_output = surf->popup.output;
1006                 break;
1007         case IVI_SURFACE_ROLE_BACKGROUND:
1008                 ivi_output = surf->bg.output;
1009                 break;
1010         case IVI_SURFACE_ROLE_PANEL:
1011                 ivi_output = surf->panel.output;
1012                 break;
1013         case IVI_SURFACE_ROLE_FULLSCREEN:
1014                 ivi_output = surf->fullscreen.output;
1015                 break;
1016         case IVI_SURFACE_ROLE_SPLIT_H:
1017         case IVI_SURFACE_ROLE_SPLIT_V:
1018                 ivi_output = surf->split.output;
1019                 break;
1020         case IVI_SURFACE_ROLE_REMOTE:
1021                 ivi_output = surf->remote.output;
1022                 break;
1023         case IVI_SURFACE_ROLE_NONE:
1024         default:
1025                 break;
1026         }
1027
1028         return ivi_output;
1029 }
1030
1031 void
1032 ivi_layout_deactivate(struct ivi_compositor *ivi, const char *app_id)
1033 {
1034         struct ivi_surface *surf;
1035         struct ivi_output *ivi_output;
1036         struct ivi_policy *policy = ivi->policy;
1037
1038         if (!app_id)
1039                 return;
1040
1041         surf = ivi_find_app(ivi, app_id);
1042         if (!surf)
1043                 return;
1044
1045         if (policy && policy->api.surface_deactivate &&
1046             !policy->api.surface_deactivate(surf, surf->ivi)) {
1047                 return;
1048         }
1049
1050         ivi_output = ivi_layout_get_output_from_surface(surf);
1051         weston_log("Deactiving %s, role %s\n", app_id,
1052                         ivi_layout_get_surface_role_name(surf));
1053
1054         if (surf->role == IVI_SURFACE_ROLE_DESKTOP) {
1055                 struct ivi_surface *previous_active;
1056
1057                 previous_active = ivi_output->previous_active;
1058                 if (!previous_active) {
1059                         /* we don't have a previous active it means we should
1060                          * display the bg */
1061                         if (ivi_output->active) {
1062                                 struct weston_view *view;
1063
1064                                 view = ivi_output->active->view;
1065                                 view->is_mapped = false;
1066                                 view->surface->is_mapped = false;
1067
1068                                 weston_layer_entry_remove(&view->layer_link);
1069                                 weston_view_geometry_dirty(view);
1070                                 weston_surface_damage(view->surface);
1071                                 ivi_output->active = NULL;
1072                         }
1073                 } else {
1074                         struct weston_desktop_surface *dsurface;
1075                         const char *previous_active_app_id;
1076
1077                         dsurface = previous_active->dsurface;
1078                         previous_active_app_id =
1079                                 weston_desktop_surface_get_app_id(dsurface);
1080                         ivi_layout_activate(ivi_output, previous_active_app_id);
1081                 }
1082         } else if (surf->role == IVI_SURFACE_ROLE_POPUP) {
1083                 struct weston_view *view  = surf->view;
1084
1085                 weston_view_unmap(view);
1086                 surf->state = HIDDEN;
1087
1088                 weston_layer_entry_remove(&view->layer_link);
1089                 weston_view_geometry_dirty(view);
1090                 weston_surface_damage(view->surface);
1091         }
1092
1093       shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_DEACTIVATED);
1094 }