20414e6db5a828459601fb64670d8f469c7def9f
[profile/ivi/murphy.git] / src / plugins / system-controller / resource-manager / screen.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *  * Neither the name of Intel Corporation nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include <murphy/common.h>
36
37 #include <murphy-db/mqi.h>
38
39 #include <murphy/resource/config-api.h>
40 #include <murphy/resource/manager-api.h>
41 #include <murphy/resource/client-api.h>
42
43 #include "screen.h"
44 #include "notifier.h"
45 #include "wayland/area.h"
46 #include "wayland/output.h"
47 #include "application/application.h"
48
49 #define ANY_OUTPUT  (~((uint32_t)0))
50 #define ANY_AREA    (~((uint32_t)0))
51
52 #ifdef BIT
53 #undef BIT
54 #endif
55 #ifdef MASK
56 #undef MASK
57 #endif
58 #ifdef MAX
59 #undef MAX
60 #endif
61
62 #define BIT(i)                ((uint32_t)1 << (i))
63 #define MASK(w)               (((uint32_t)1 << (w)) - 1)
64 #define MAX(w)                (((uint32_t)1 << (w)))
65
66 #define PRIORITY_BITS         8
67 #define CLASSPRI_BITS         8
68 #define ZORDER_BITS           16
69
70 #define PRIORITY_POSITION     0
71 #define CLASSPRI_POSITION     (PRIORITY_POSITION + PRIORITY_BITS)
72 #define ZORDER_POSITION       (CLASSPRI_POSITION + CLASSPRI_BITS)
73
74 #define PRIORITY_MASK         MASK(PRIORITY_BITS)
75 #define CLASSPRI_MASK         MASK(CLASSPRI_BITS)
76 #define ZORDER_MASK           MASK(ZORDER_BITS)
77
78 #define PRIORITY_MAX          MAX(PRIORITY_BITS)
79 #define CLASSPRI_MAX          MAX(CLASSPRI_BITS)
80 #define ZORDER_MAX            MAX(ZORDER_BITS)
81
82
83 #define ATTRIBUTE(n,t,v)    {n, MRP_RESOURCE_RW, mqi_##t, {.t=v}}
84 #define ATTR_END            {NULL, 0, 0, {.string=NULL}}
85
86 typedef struct screen_resource_s   screen_resource_t;
87 typedef struct disable_iterator_s  disable_iterator_t;
88 typedef struct output_iterator_s   output_iterator_t;
89 typedef struct area_iterator_s     area_iterator_t;
90
91
92 struct screen_resource_s {
93     mrp_list_hook_t link;
94     mrp_resmgr_screen_t *screen;
95     mrp_resource_t *res;
96     uint32_t zoneid;
97     size_t outputid;
98     size_t areaid;
99     uint32_t key;
100     bool acquire;
101     bool grant;
102     uint32_t grantid;
103     mrp_application_requisite_t requisite;
104     mrp_resmgr_disable_t disable;
105 };
106
107 struct disable_iterator_s {
108     uint32_t outputid;
109     uint32_t areaid;
110     bool disable;
111     mrp_resmgr_disable_t type;
112     uint32_t mask;
113     union {
114         const char *appid;
115         mrp_application_requisite_t req;
116         uint32_t surfaceid;
117     };
118     uint32_t zones;
119     int counter;
120 };
121
122 struct output_iterator_s {
123     const char *name;
124     mrp_wayland_output_t *out;
125 };
126
127 struct area_iterator_s {
128     mrp_resmgr_t *resmgr;
129     const char *fullname;
130     size_t areaid;
131     size_t outputid;
132     mrp_resmgr_screen_area_t *area;
133     struct {
134         uint32_t mask;
135         const char *names[MRP_ZONE_MAX + 1];
136     } zone;
137     int counter;
138 };
139
140 static int hash_compare(const void *, const void *);
141 static uint32_t hash_function(const void *);
142
143 static void overlap_add(mrp_resmgr_screen_area_t *, size_t);
144 static void overlap_remove(mrp_resmgr_screen_area_t *, size_t);
145
146 static const char *get_appid_for_resource(mrp_resource_t *);
147 static int32_t get_surfaceid_for_resource(mrp_resource_t *);
148 static int32_t get_layerid_for_resource(mrp_resource_t *);
149 static const char *get_areaname_for_resource(mrp_resource_t *);
150 static mrp_application_t *get_application_for_resource(mrp_resource_t *);
151 static int32_t get_area_for_resource(mrp_resource_t *);
152 static uint32_t get_priority_for_resource(mrp_resource_t *);
153 static uint32_t get_class_priority_for_resource(mrp_resource_t *,
154                                                 mrp_application_class_t *);
155 static int32_t get_zone_id(const char *);
156
157
158 static screen_resource_t *screen_resource_create(mrp_resmgr_screen_t *,
159                                                  mrp_zone_t *,mrp_resource_t *,
160                                                  mrp_application_class_t *);
161 static void screen_resource_destroy(mrp_resmgr_screen_t *,  mrp_zone_t *,
162                                     mrp_resource_t *);
163 static screen_resource_t *screen_resource_lookup(mrp_resmgr_screen_t *,
164                                                  mrp_resource_t *);
165 static bool screen_resource_is_on_top(mrp_resmgr_screen_t *,
166                                       screen_resource_t *);
167 static void screen_resource_raise_to_top(mrp_resmgr_screen_t *,
168                                          screen_resource_t *);
169 static void screen_resource_lower_to_bottom(mrp_resmgr_screen_t *,
170                                             screen_resource_t *);
171
172
173 static uint32_t zorder_new_top_value(mrp_resmgr_screen_area_t *);
174
175 static void screen_grant_resources(mrp_resmgr_screen_t *, mrp_zone_t *);
176 static void screen_queue_events(mrp_resmgr_screen_t *, mrp_zone_t *);
177
178 static void area_insert_resource(mrp_resmgr_screen_area_t*,screen_resource_t*);
179 static uint32_t resource_key(mrp_resource_t *, mrp_application_class_t *);
180
181 static void screen_notify(mrp_resource_event_t, mrp_zone_t *,
182                           mrp_application_class_t *, mrp_resource_t *, void *);
183 static void screen_init(mrp_zone_t *, void *);
184 static bool screen_allocate(mrp_zone_t *, mrp_resource_t *, void *);
185 static void screen_free(mrp_zone_t *, mrp_resource_t *, void *);
186 static bool screen_advice(mrp_zone_t *, mrp_resource_t *, void *);
187 static void screen_commit(mrp_zone_t *, void *);
188
189 #define PRIORITY_ATTRIDX  0
190 #define CLASSPRI_ATTRIDX  1
191 #define AREA_ATTRIDX      2
192 #define APPID_ATTRIDX     3
193 #define SURFACE_ATTRIDX   4
194
195 static mrp_attr_def_t screen_attrs[] = {
196     ATTRIBUTE("priority" , integer,       0      ),
197     ATTRIBUTE("classpri" , integer,      -1      ),
198     ATTRIBUTE("area"     , string , "<undefined>"),
199     ATTRIBUTE("appid"    , string , "<undefined>"),
200     ATTRIBUTE("surface"  , integer,       0      ),
201     ATTR_END
202 };
203
204 static mrp_resource_mgr_ftbl_t screen_ftbl = {
205     screen_notify,
206     screen_init,
207     screen_allocate,
208     screen_free,
209     screen_advice,
210     screen_commit
211 };
212
213 mrp_resmgr_screen_t *mrp_resmgr_screen_create(mrp_resmgr_t *resmgr)
214 {
215     mrp_resmgr_screen_t *screen;
216     mrp_htbl_config_t cfg;
217     uint32_t resid;
218     size_t i;
219
220     if ((screen = mrp_allocz(sizeof(mrp_resmgr_screen_t)))) {
221         resid = mrp_resource_definition_create(MRP_SYSCTL_SCREEN_RESOURCE,
222                                                true,screen_attrs,
223                                                &screen_ftbl,screen);
224         mrp_lua_resclass_create_from_c(resid);
225
226         cfg.nentry = MRP_RESMGR_RESOURCE_MAX;
227         cfg.comp = hash_compare;
228         cfg.hash = hash_function;
229         cfg.free = NULL;
230         cfg.nbucket = MRP_RESMGR_RESOURCE_BUCKETS;
231
232         screen->resmgr = resmgr;
233         screen->resid = resid;
234         screen->resources = mrp_htbl_create(&cfg);
235
236         for (i = 0;  i < MRP_ZONE_MAX;  i++)
237             mrp_list_init(screen->zones + i);
238     }
239
240     return screen;
241 }
242
243
244 void mrp_resmgr_screen_destroy(mrp_resmgr_screen_t *screen)
245 {
246     if (screen) {
247         mrp_htbl_destroy(screen->resources, false);
248         mrp_free(screen);
249     }
250 }
251
252 static int screen_disable_cb(void *key, void *object, void *user_data)
253 {
254     screen_resource_t *sr = (screen_resource_t *)object;
255     disable_iterator_t *it = (disable_iterator_t *)user_data;
256     const char *appid;
257     uint32_t disable;
258
259     MRP_UNUSED(key);
260
261     MRP_ASSERT(sr && it, "invalid argument");
262
263     if ((it->outputid == ANY_OUTPUT || sr->outputid == it->outputid) &&
264         (it->areaid   == ANY_AREA   || sr->areaid   == it->areaid   )  )
265     {
266         switch (it->type) {
267
268         case MRP_RESMGR_DISABLE_REQUISITE:
269             if (it->req && (it->req & sr->requisite) == it->req)
270                 goto disable;
271             break;
272
273         case MRP_RESMGR_DISABLE_APPID:
274             if (it->appid) {
275                 if (!strcmp(it->appid, "*"))
276                     goto disable;
277                 appid = get_appid_for_resource(sr->res);
278                 if (appid && !strcmp(it->appid, appid))
279                     goto disable;
280             }
281             break;
282
283         case MRP_RESMGR_DISABLE_SURFACEID:
284             goto disable;
285
286         disable:
287             disable = sr->disable & it->mask;
288             if (it->disable) {
289                 if (disable)
290                     break;
291                 sr->disable |= it->mask;
292             }
293             else {
294                 if (!disable)
295                     break;
296                 sr->disable &= ~it->mask;
297             }
298             it->counter++;
299             it->zones |= (((uint32_t)1) << sr->zoneid);
300             break;
301
302         default:
303             return MRP_HTBL_ITER_STOP;
304         }
305     }
306
307     return MRP_HTBL_ITER_MORE;
308 }
309
310 static int output_find_cb(void *key, void *object, void *user_data)
311 {
312     mrp_wayland_output_t *out = (mrp_wayland_output_t *)object;
313     output_iterator_t *it = (output_iterator_t *)user_data;
314
315     MRP_UNUSED(key);
316
317     MRP_ASSERT(out && it, "invalid argument");
318
319     if (out->name && !strcmp(it->name, out->outputname)) {
320         it->out = out;
321         return MRP_HTBL_ITER_STOP;
322     }
323
324     return MRP_HTBL_ITER_MORE;
325 }
326
327 int mrp_resmgr_screen_disable(mrp_resmgr_screen_t *screen,
328                               const char *output_name,
329                               const char *area_name,
330                               bool disable,
331                               mrp_resmgr_disable_t type,
332                               void *data,
333                               bool recalc_owner)
334 {
335     mrp_wayland_t *w;
336     disable_iterator_t dit;
337     output_iterator_t oit;
338     mrp_wayland_output_t *o;
339     mrp_wayland_area_t *a;
340     mrp_wayland_t *wl = NULL;
341     uint32_t output_id = ANY_OUTPUT;
342     uint32_t area_id = ANY_AREA;
343     void *i;
344     char fullname[1024];
345     uint32_t mask;
346     uint32_t z;
347     void *hk, *obj;
348
349     MRP_ASSERT(screen && data, "invalid argument");
350
351     mrp_debug("output_name='%s' area_name='%s' %s, type=0x%02x data=%p",
352               output_name ? output_name : "<any output>",
353               area_name ? area_name : "<any area>",
354               disable ? "disable" : "enable",
355               type, data);
356
357     if (output_name && strcmp(output_name, "*")) {
358         memset(&oit, 0, sizeof(oit));
359         oit.name = output_name;
360
361         mrp_wayland_foreach(w, i) {
362             mrp_htbl_foreach(w->outputs.by_index, output_find_cb, &oit);
363
364             if ((o = oit.out)) {
365                 wl = w;
366                 output_id = o->outputid;
367                 break;
368             }
369         }
370         if (output_id == ANY_OUTPUT) {
371             mrp_log_error("system-controller: failed to disable screen: "
372                           "can't find output '%s'", output_name);
373             return -1;
374         }
375     }
376
377     if (wl && area_name && strcmp(area_name, "*")) {
378         snprintf(fullname, sizeof(fullname), "%s.%s", output_name, area_name);
379         if ((a = mrp_wayland_area_find(wl, fullname)))
380             area_id = a->areaid;
381         else {
382             mrp_log_error("system-controller: failed to disable screen: "
383                           "can't find area '%s'", area_name);
384             return -1;
385         }
386     }
387
388     memset(&dit, 0, sizeof(dit));
389     dit.outputid = output_id;
390     dit.areaid = area_id;
391     dit.disable = disable;
392     dit.type = type;
393     dit.zones = 0;
394     dit.counter = 0;
395
396     switch (type) {
397
398     case MRP_RESMGR_DISABLE_REQUISITE:
399         dit.mask = BIT(MRP_RESMGR_DISABLE_REQUISITE - 1);
400         dit.req = *(mrp_application_requisite_t *)data;
401         mrp_htbl_foreach(screen->resources, screen_disable_cb, &dit);
402         break;
403
404     case MRP_RESMGR_DISABLE_APPID:
405         dit.mask = BIT(MRP_RESMGR_DISABLE_APPID - 1);
406         dit.appid = (const char *)data;
407         mrp_htbl_foreach(screen->resources, screen_disable_cb, &dit);
408         break;
409
410     case MRP_RESMGR_DISABLE_SURFACEID:
411         dit.mask = BIT(MRP_RESMGR_DISABLE_APPID - 1);
412         dit.surfaceid = *(uint32_t *)data;
413         hk = NULL + dit.surfaceid;
414         if (!(obj = mrp_htbl_lookup(screen->resources, hk))) {
415             mrp_log_error("system-controller: failed to disable screen: "
416                           "can't find surface %u", dit.surfaceid);
417             return -1;
418         }
419         screen_disable_cb(hk, obj, &dit);
420         break;
421
422     default:
423         mrp_log_error("system-controller: invalid type %d of "
424                       "screen disable", type);
425         return -1;
426     }
427
428     if (recalc_owner) {
429         for (z = 0;   dit.zones && z < MRP_ZONE_MAX;   z++) {
430             mask = (((uint32_t)1) << z);
431
432             if ((mask & dit.zones)) {
433                 dit.zones &= ~mask;
434                 mrp_resource_owner_recalc(z);
435             }
436         }
437     }
438
439     return dit.counter;
440 }
441
442
443 int mrp_resmgr_screen_print(mrp_resmgr_screen_t *screen,
444                             uint32_t zoneid,
445                             char *buf, int len)
446 {
447 #define PRINT(...)                              \
448     do {                                        \
449         p += snprintf(p, e-p, __VA_ARGS__);     \
450         if (p >= e)                             \
451             return p - buf;                     \
452     } while (0)
453
454     char *p, *e;
455     uint32_t grantid;
456     mrp_resmgr_screen_area_t *area;
457     mrp_list_hook_t *areas, *aentry, *an;
458     mrp_list_hook_t *resources, *rentry, *rn;
459     screen_resource_t *sr;
460     mrp_attr_t a;
461     size_t i;
462     char disable[256];
463     char requisite[1024];
464
465     MRP_ASSERT(screen && buf && len > 0, "invalid argument");
466
467     e = (p = buf) + len;
468     *p = 0;
469
470     if (zoneid < MRP_ZONE_MAX) {
471         areas = screen->zones + zoneid;
472         grantid = screen->grantids[zoneid];
473     }
474     else {
475         areas = NULL;
476         grantid = 0;
477     }
478
479     PRINT("      Resource '%s' - grantid:%u\n",
480           MRP_SYSCTL_SCREEN_RESOURCE, grantid);
481
482     if (!areas || mrp_list_empty(areas))
483         PRINT("         No resources\n");
484     else {
485         mrp_list_foreach_back(areas, aentry, an) {
486             area = mrp_list_entry(aentry, mrp_resmgr_screen_area_t, link);
487             resources = &area->resources;
488
489             PRINT("         Area '%s':\n", area->name);
490
491             mrp_list_foreach_back(resources, rentry, rn) {
492                 sr = mrp_list_entry(rentry, screen_resource_t, link);
493
494                 mrp_resmgr_disable_print(sr->disable, disable,
495                                          sizeof(disable));
496                 mrp_application_requisite_print(sr->requisite, requisite,
497                                                 sizeof(requisite));
498
499                 PRINT("            "
500                       "key:0x%08x %s grantid:%u requisite:%s disable:%s",
501                       sr->key,
502                       sr->acquire ? "acquire":"release",
503                       sr->grantid,
504                       requisite,
505                       disable);
506
507                 for (i = 0;  i < MRP_ARRAY_SIZE(screen_attrs) - 1;  i++) {
508                     if ((mrp_resource_read_attribute(sr->res, i, &a))) {
509                         PRINT(" %s:", a.name);
510
511                         switch (a.type) {
512                         case mqi_string:   PRINT("'%s'",a.value.string); break;
513                         case mqi_integer:  PRINT("%d",a.value.integer);  break;
514                         case mqi_unsignd:  PRINT("%u",a.value.unsignd);  break;
515                         case mqi_floating: PRINT("%lf",a.value.floating);break;
516                         default:           PRINT("<unsupported type>");  break;
517                         }
518                     }
519                 }
520
521                 PRINT("\n");
522             } /* mrp_list_foreach_back - resources */
523         }  /* mrp_list_foreach_back - areas */
524     }
525
526     return p - buf;
527 }
528
529 static int area_resolution_cb(void *key, void *object, void *user_data)
530 {
531
532     screen_resource_t  *sr = (screen_resource_t *)object;
533     area_iterator_t *ait = (area_iterator_t *)user_data;
534     const char *areaname;
535     const char *appid;
536     const char *zonename;
537     int32_t surfaceid;
538     int32_t layerid;
539
540     MRP_UNUSED(key);
541
542     MRP_ASSERT(sr && sr->res && ait, "confused with data structures");
543
544     if (sr->areaid == ANY_AREA && sr->zoneid < MRP_ZONE_MAX) {
545         areaname = get_areaname_for_resource(sr->res);
546
547         if (areaname && !strcmp(areaname, ait->fullname)) {
548             appid = get_appid_for_resource(sr->res);
549             surfaceid = get_surfaceid_for_resource(sr->res);
550             layerid = -1;
551
552             mrp_debug("  resolving screen resource for '%s'",
553                       appid ? appid : "<unknown appid>");
554
555             sr->areaid = ait->areaid;
556             sr->outputid = ait->outputid;
557
558             area_insert_resource(ait->area, sr);
559
560             ait->counter++;
561             ait->zone.mask |= (((uint32_t)1) << sr->zoneid);
562
563             if ((zonename = ait->zone.names[sr->zoneid])) {
564                 mrp_resmgr_notifier_queue_screen_event(ait->resmgr,
565                                                     sr->zoneid, zonename,
566                                                     MRP_RESMGR_EVENTID_CREATE,
567                                                     appid, surfaceid, layerid,
568                                                     ait->area->name);
569                 mrp_resmgr_notifier_flush_screen_events(ait->resmgr,
570                                                     sr->zoneid);
571             }
572         }
573     }
574
575     return MRP_HTBL_ITER_MORE;
576 }
577
578 void mrp_resmgr_screen_area_create(mrp_resmgr_screen_t *screen,
579                                    mrp_wayland_area_t *wlarea,
580                                    const char *zonename)
581 {
582     mrp_resmgr_screen_area_t *rmarea, *a;
583     int32_t zoneid;
584     size_t areaid;
585     const char *name;
586     int32_t outputid;
587     size_t i;
588     int32_t x, x0, x1, y, y0, y1;
589     area_iterator_t ait;
590     uint32_t mask;
591     uint32_t z;
592
593     MRP_ASSERT(screen && wlarea && wlarea->output && zonename,
594                "invalid argument");
595
596     if (wlarea->areaid < 0 || wlarea->areaid >= MRP_WAYLAND_AREA_MAX) {
597         mrp_log_error("system-controller: refuse to create screen area '%s': "
598                       "id %d is out of range (0 - %d)",
599                       wlarea->name, wlarea->areaid, MRP_WAYLAND_AREA_MAX - 1);
600         return;
601     }
602
603     areaid   = wlarea->areaid;
604     name     = wlarea->name ? wlarea->name : "<unknown>";
605     outputid = wlarea->output->outputid;
606
607     if ((zoneid = get_zone_id(zonename))) {
608         mrp_log_error("system-controller: can't create resource manager area "
609                       "%d: can't find zone '%s' for it", areaid, zonename);
610         return;
611     }
612
613     if (areaid >= screen->narea) {
614         screen->areas = mrp_reallocz(screen->areas, screen->narea, areaid + 1);
615
616         MRP_ASSERT(screen->areas, "can't allocate memory for screen areas");
617
618         screen->narea = areaid + 1;
619     }
620
621     if (screen->areas[areaid]) {
622         mrp_log_error("system-controller: attempt to redefine "
623                       "resource manager area %d", areaid);
624         return;
625     }
626
627     screen->areas[areaid] = rmarea = mrp_allocz(sizeof(*rmarea));
628
629     mrp_list_append(screen->zones + zoneid, &rmarea->link);
630     rmarea->name = mrp_strdup(name);
631     rmarea->outputid = outputid;
632     rmarea->x = wlarea->x;
633     rmarea->y = wlarea->y;
634     rmarea->width = wlarea->width;
635     rmarea->height = wlarea->height;
636     mrp_list_init(&rmarea->resources);
637
638     x1 = (x0 = rmarea->x) + rmarea->width;
639     y1 = (y0 = rmarea->y) + rmarea->height;
640
641     for (i = 0;  i < screen->narea; i++) {
642         if ((a = screen->areas[i]) && i != areaid) {
643             if ((      a->outputid == outputid        ) &&
644                 (((x  = a->x     ) >= x0 && x < x1) ||
645                  ((x += a->width ) >= x0 && x < x1) ||
646                  ((y  = a->y     ) >= y0 && y < y1) ||
647                  ((y += a->height) >= y0 && y < y1)   )   )
648             {
649                 overlap_add(a, areaid);
650                 overlap_add(rmarea, i);
651             }
652         }
653     }
654
655     mrp_debug("resolving resources in '%s' area", wlarea->fullname);
656
657     memset(&ait, 0, sizeof(ait));
658     ait.resmgr   = screen->resmgr;
659     ait.fullname = wlarea->fullname;
660     ait.areaid   = areaid;
661     ait.outputid = outputid;
662     ait.area     = rmarea;
663     mrp_zone_get_all_names(MRP_ZONE_MAX + 1, ait.zone.names);
664
665     mrp_htbl_foreach(screen->resources, area_resolution_cb, &ait);
666
667     if (ait.zone.mask) {
668         mrp_debug("recalculating owners ...");
669
670         for (z = 0;   ait.zone.mask && z < MRP_ZONE_MAX;   z++) {
671             mask = (((uint32_t)1) << z);
672
673             if ((mask & ait.zone.mask)) {
674                 ait.zone.mask &= ~mask;
675                 mrp_resource_owner_recalc(z);
676             }
677         }
678     }
679
680     mrp_log_info("system-controller: resource manager registered screen area "
681                  "%d - '%s'", areaid, name);
682 }
683
684 void mrp_screen_area_destroy(mrp_resmgr_screen_t *screen, int32_t areaid)
685 {
686     mrp_resmgr_screen_area_t *area;
687     size_t i;
688
689     MRP_ASSERT(screen && areaid >= 0 && areaid < MRP_WAYLAND_AREA_MAX,
690                "invalid argument");
691
692     if (areaid >= (int32_t)screen->narea || !(area = screen->areas[areaid])) {
693         mrp_log_error("system-controller: attempt to destroy non-existent "
694                       "resource manager area %d", areaid);
695     }
696     else {
697         screen->areas[areaid] = NULL;
698
699         for (i = 0;  i < area->noverlap;  i++)
700             overlap_remove(screen->areas[area->overlaps[i]], areaid);
701
702         mrp_free((void *)area->name);
703         mrp_free((void *)area->overlaps);
704         mrp_free(area);
705     }
706 }
707
708 void mrp_screen_resource_raise(mrp_resmgr_screen_t *screen,
709                                const char *appid,
710                                int32_t surfaceid)
711 {
712     mrp_resmgr_screen_area_t *area;
713     mrp_list_hook_t *resources, *entry, *n;
714     screen_resource_t *sr;
715     mrp_resource_t *res;
716     const char *id;
717     size_t i, cnt;
718     size_t zmax, zmin;
719     bool zones[MRP_ZONE_MAX];
720
721     MRP_ASSERT(screen && screen->resources && appid, "invalid argument");
722
723     if (surfaceid == 0) {
724         cnt = 0;
725         zmax = 0;
726         zmin = MRP_ZONE_MAX-1;
727
728         for (i = cnt = 0;  i < screen->narea;  i++) {
729             if (!(area = screen->areas[i]))
730                 continue;
731
732             resources = &area->resources;
733
734             mrp_list_foreach(resources, entry, n) {
735                 sr = mrp_list_entry(entry, screen_resource_t, link);
736                 res = sr->res;
737
738                 if ((id = get_appid_for_resource(res)) && !strcmp(id, appid)) {
739                     mrp_debug("raise surface %d to top", surfaceid);
740
741                     if (!screen_resource_is_on_top(screen, sr)) {
742                         screen_resource_raise_to_top(screen, sr);
743
744                         cnt++;
745                         zones[sr->zoneid] = true;
746                         if (zmax < sr->zoneid)  zmax = sr->zoneid;
747                         if (zmin > sr->zoneid)  zmin = sr->zoneid;
748                     }
749                     break;
750                 }
751             }
752         }
753
754         if (!cnt)
755             mrp_debug("nothing to be raised");
756         else {
757             for (i = zmin;  i <= zmax;  i++) {
758                 if (zones[i])
759                     mrp_resource_owner_recalc(i);
760             }
761         }
762     }
763     else {
764         if ((sr = mrp_htbl_lookup(screen->resources, NULL + surfaceid))) {
765             res = sr->res;
766
767             if (!(id = get_appid_for_resource(res)) || strcmp(id, appid)) {
768                 mrp_log_error("system-controller: can't raise window %u: "
769                               "appid mismatch ('%s' vs. '%s')",
770                               surfaceid, id, appid);
771             }
772             else {
773                 if (screen_resource_is_on_top(screen, sr)) {
774                     mrp_debug("nothing to be raised: surface %d "
775                               "is already on top", surfaceid);
776                 }
777                 else {
778                     mrp_debug("raise surface %d to top", surfaceid);
779                     screen_resource_raise_to_top(screen, sr);
780                     mrp_resource_owner_recalc(sr->zoneid);
781                 }
782             }
783         }
784     }
785 }
786
787 void mrp_screen_resource_lower(mrp_resmgr_screen_t *screen,
788                                const char *appid,
789                                int32_t surfaceid)
790 {
791     mrp_resmgr_screen_area_t *area;
792     mrp_list_hook_t *resources, *entry, *n;
793     screen_resource_t *sr;
794     mrp_resource_t *res;
795     const char *id;
796     size_t i, cnt;
797     size_t zmax, zmin;
798     bool zones[MRP_ZONE_MAX];
799
800     MRP_ASSERT(screen && screen->resources && appid, "invalid argument");
801
802     if (surfaceid == 0) {
803         cnt = 0;
804         zmax = 0;
805         zmin = MRP_ZONE_MAX-1;
806
807         for (i = cnt = 0;  i < screen->narea;  i++) {
808             if (!(area = screen->areas[i]))
809                 continue;
810
811             resources = &area->resources;
812
813             mrp_list_foreach_back(resources, entry, n) {
814                 sr = mrp_list_entry(entry, screen_resource_t, link);
815                 res = sr->res;
816
817                 if ((id = get_appid_for_resource(res)) && !strcmp(id, appid)) {
818                     mrp_debug("lower surface %d to bottom", surfaceid);
819
820                     screen_resource_lower_to_bottom(screen, sr);
821
822                     cnt++;
823                     zones[sr->zoneid] = true;
824                     if (zmax < sr->zoneid)  zmax = sr->zoneid;
825                     if (zmin > sr->zoneid)  zmin = sr->zoneid;
826                 }
827             }
828         }
829
830         if (!cnt)
831             mrp_debug("nothing to be lowered");
832         else {
833             for (i = zmin;  i <= zmax;  i++) {
834                 if (zones[i])
835                     mrp_resource_owner_recalc(i);
836             }
837         }
838     }
839     else {
840         if ((sr = mrp_htbl_lookup(screen->resources, NULL + surfaceid))) {
841             res = sr->res;
842
843             if (!(id = get_appid_for_resource(res)) || strcmp(id, appid)) {
844                 mrp_log_error("system-controller: can't lower window %u: "
845                               "appid mismatch ('%s' vs. '%s')",
846                               surfaceid, id, appid);
847             }
848             else {
849                 mrp_debug("lower surface %d to bottom", surfaceid);
850                 screen_resource_lower_to_bottom(screen, sr);
851                 mrp_resource_owner_recalc(sr->zoneid);
852             }
853         }
854     }
855 }
856
857 static int hash_compare(const void *key1, const void *key2)
858 {
859     if (key1 < key2)
860         return -1;
861     if (key1 > key2)
862         return 1;
863     return 0;
864 }
865
866 static uint32_t hash_function(const void *key)
867 {
868     return (uint32_t)(key - (const void *)0);
869 }
870
871 static void overlap_add(mrp_resmgr_screen_area_t *area, size_t overlapid)
872 {
873     size_t i;
874
875     for (i = 0;  i < area->noverlap;  i++) {
876         if (area->overlaps[i] == overlapid)
877             return;
878     }
879
880     area->overlaps = mrp_realloc(area->overlaps, sizeof(size_t *) * (i + 1));
881
882     MRP_ASSERT(area->overlaps, "can't allocate memory for overalapping "
883                "resource manager areas");
884
885     area->overlaps[i] = overlapid;
886     area->noverlap++;
887 }
888
889 static void overlap_remove(mrp_resmgr_screen_area_t *area, size_t overlapid)
890 {
891     size_t i;
892
893     for (i = 0;  i < area->noverlap;  i++) {
894         if (area->overlaps[i] == overlapid) {
895             for (i++; i < area->noverlap; i++)
896                 area->overlaps[i-1] = area->overlaps[i];
897             area->noverlap--;
898             return;
899         }
900     }
901
902     mrp_log_error("system-controller: attempt to remove unregistered "
903                   "overlapping area");
904 }
905
906 static const char *get_appid_for_resource(mrp_resource_t *res)
907 {
908     mrp_attr_t attr;
909     const char *appid;
910
911     if (!mrp_resource_read_attribute(res, APPID_ATTRIDX, &attr) ||
912         attr.type != mqi_string || !(appid = attr.value.string)  )
913         appid = NULL;
914
915     return appid;
916 }
917
918 static int32_t get_surfaceid_for_resource(mrp_resource_t *res)
919 {
920     mrp_attr_t attr;
921
922     if (mrp_resource_read_attribute(res, SURFACE_ATTRIDX, &attr)) {
923         if (attr.type == mqi_integer)
924             return attr.value.integer;
925     }
926
927     return 0;
928 }
929
930 static int32_t get_layerid_for_resource(mrp_resource_t *res)
931 {
932     MRP_UNUSED(res);
933
934     return -1;
935 }
936
937 static const char *get_areaname_for_resource(mrp_resource_t *res)
938 {
939     mrp_attr_t attr;
940
941     if (mrp_resource_read_attribute(res, AREA_ATTRIDX, &attr)) {
942         if (attr.type == mqi_string)
943             return attr.value.string;
944     }
945
946     return NULL;
947 }
948
949 static mrp_application_t *get_application_for_resource(mrp_resource_t *res)
950 {
951     const char        *appid = get_appid_for_resource(res);
952     mrp_application_t *app   = NULL;
953
954     if (!appid || !(app = mrp_application_find(appid)))
955         app = mrp_application_find(MRP_SYSCTL_APPID_DEFAULT);
956
957     return app;
958 }
959
960 static int32_t get_area_for_resource(mrp_resource_t *res)
961 {
962     mrp_wayland_t *wl;
963     mrp_wayland_area_t *a;
964     const char *areaname;
965     void *it;
966
967     if ((areaname = get_areaname_for_resource(res))) {
968         mrp_wayland_foreach(wl, it) {
969             if ((a = mrp_wayland_area_find(wl, areaname)))
970                 return a->areaid;
971         }
972     }
973
974     return -1;
975 }
976
977
978 static uint32_t get_priority_for_resource(mrp_resource_t *res)
979 {
980     mrp_attr_t attr;
981     uint32_t priority = 0;
982
983     if (mrp_resource_read_attribute(res, PRIORITY_ATTRIDX, &attr)) {
984         if (attr.type == mqi_integer && attr.value.integer >= 0)
985             priority = attr.value.integer;
986     }
987
988     return priority;
989 }
990
991 static uint32_t get_class_priority_for_resource(mrp_resource_t *res,
992                                                 mrp_application_class_t *ac)
993 {
994     mrp_attr_t attr;
995     uint32_t priority;
996
997     priority = mrp_application_class_get_priority(ac);
998
999     if (mrp_resource_read_attribute(res, CLASSPRI_ATTRIDX, &attr)) {
1000         if (attr.type == mqi_integer && attr.value.integer >= 0)
1001             priority = attr.value.integer;
1002     }
1003
1004     return priority;
1005 }
1006
1007 static int32_t get_zone_id(const char *name)
1008 {
1009     const char *zones[MRP_ZONE_MAX + 1];
1010     const char *zone;
1011     int32_t id;
1012
1013     if (mrp_zone_get_all_names(MRP_ZONE_MAX + 1, zones)) {
1014         for (id = 0;   (zone = zones[id]);  id++) {
1015             if (!strcmp(name, zone))
1016                 return id;
1017         }
1018     }
1019
1020     return -1;
1021 }
1022
1023
1024
1025 static screen_resource_t *screen_resource_create(mrp_resmgr_screen_t *screen,
1026                                                  mrp_zone_t *zone,
1027                                                  mrp_resource_t *res,
1028                                                  mrp_application_class_t *ac)
1029 {
1030     mrp_resmgr_t *resmgr;
1031     const char *zonename;
1032     const char *appid;
1033     mrp_application_t *app;
1034     mrp_resmgr_screen_area_t *area;
1035     int32_t id;
1036     size_t layerid;
1037     size_t areaid;
1038     int32_t outputid;
1039     int32_t surfaceid;
1040     screen_resource_t *sr;
1041     void *hk;
1042
1043     MRP_ASSERT(screen && screen->resources && zone && res && ac,
1044                "invalid argument");
1045     MRP_ASSERT(screen->resmgr, "confused with data structures");
1046
1047     resmgr = screen->resmgr;
1048     sr = NULL;
1049
1050     zonename = mrp_zone_get_name(zone);
1051     appid = get_appid_for_resource(res);
1052
1053     if (!(app = get_application_for_resource(res))) {
1054         mrp_log_error("system-controller: failed to create screen resource: "
1055                       "can't find app");
1056         return NULL;
1057     }
1058
1059     layerid = get_layerid_for_resource(sr->res);
1060
1061     if ((id = get_area_for_resource(res)) >= 0 &&
1062         (size_t)id < screen->narea             &&
1063         (area = screen->areas[id])              )
1064     {
1065         areaid = id;
1066         outputid = area->outputid;
1067     }
1068     else {
1069         mrp_debug("delayed area resolution");
1070         area = NULL;
1071         areaid = ANY_AREA;
1072         outputid = ANY_OUTPUT;
1073     }
1074
1075     if (!(surfaceid = get_surfaceid_for_resource(res))) {
1076         mrp_log_error("system-controller: failed to create screen resource: "
1077                       "invalid surface attribute");
1078         return NULL;
1079     }
1080
1081     if (!(sr = mrp_allocz(sizeof(*sr)))) {
1082         mrp_log_error("system-controller: failed to create screen resource: "
1083                       "can't allocate memory");
1084         return NULL;
1085     }
1086
1087     mrp_list_init(&sr->link);
1088     sr->screen    = screen;
1089     sr->res       = res;
1090     sr->zoneid    = mrp_zone_get_id(zone);
1091     sr->outputid  = outputid;
1092     sr->areaid    = areaid;
1093     sr->key       = resource_key(res, ac);
1094     sr->requisite = app->requisites.screen;
1095
1096     if (area)
1097         area_insert_resource(area, sr);
1098
1099     mrp_debug("inserting resource to hash table: key=%p value=%p", res, sr);
1100     mrp_resmgr_insert_resource(resmgr, zone, res, sr);
1101
1102     hk = NULL + surfaceid;
1103     mrp_debug("inserting surface to hash table: key=%p value=%p", hk, sr);
1104     mrp_htbl_insert(screen->resources, hk, sr);
1105
1106     if (area) {
1107         mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1108                                                sr->zoneid,zonename,
1109                                                MRP_RESMGR_EVENTID_CREATE,
1110                                                appid, surfaceid, layerid,
1111                                                area->name);
1112         mrp_resmgr_notifier_flush_screen_events(screen->resmgr, sr->zoneid);
1113     }
1114
1115     return sr;
1116 }
1117
1118
1119 static void screen_resource_destroy(mrp_resmgr_screen_t *screen,
1120                                     mrp_zone_t *zone,
1121                                     mrp_resource_t *res)
1122 {
1123     screen_resource_t *sr;
1124     const char *zonename;
1125     const char *appid;
1126     int32_t layerid;
1127     int32_t surfaceid;
1128     const char *areaname;
1129
1130     MRP_ASSERT(res && screen && screen->resources, "invalid argument");
1131     MRP_ASSERT(screen->resmgr, "confused with data structures");
1132
1133     if ((sr = mrp_resmgr_remove_resource(screen->resmgr, zone, res))) {
1134         zonename  = mrp_zone_get_name(zone);
1135         appid     = get_appid_for_resource(res);
1136         surfaceid = get_surfaceid_for_resource(res);
1137         layerid   = get_layerid_for_resource(res);
1138         areaname  = get_areaname_for_resource(res);
1139
1140         mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1141                                                sr->zoneid, zonename,
1142                                                MRP_RESMGR_EVENTID_DESTROY,
1143                                                appid, surfaceid, layerid,
1144                                                areaname);
1145         if (surfaceid)
1146             mrp_htbl_remove(screen->resources, NULL + surfaceid, false);
1147
1148         mrp_list_delete(&sr->link);
1149         mrp_free(sr);
1150
1151         mrp_resmgr_notifier_flush_screen_events(screen->resmgr, sr->zoneid);
1152     }
1153 }
1154
1155
1156 static screen_resource_t *screen_resource_lookup(mrp_resmgr_screen_t *screen,
1157                                                  mrp_resource_t *res)
1158 {
1159     screen_resource_t *sr;
1160
1161     MRP_ASSERT(res && screen, "invalid argument");
1162     MRP_ASSERT(screen->resmgr, "confused with data structures");
1163
1164     sr = mrp_resmgr_lookup_resource(screen->resmgr, res);
1165
1166     return sr;
1167 }
1168
1169 static bool screen_resource_is_on_top(mrp_resmgr_screen_t *screen,
1170                                       screen_resource_t *sr)
1171 {
1172     mrp_resmgr_screen_area_t *area;
1173     bool on_top;
1174
1175     if (sr->areaid >= screen->narea || !(area = screen->areas[sr->areaid]))
1176         on_top = false;
1177     else
1178         on_top = (area->resources.prev == &sr->link);
1179
1180     return on_top;
1181 }
1182
1183 static void screen_resource_raise_to_top(mrp_resmgr_screen_t *screen,
1184                                          screen_resource_t *sr)
1185 {
1186     mrp_resmgr_screen_area_t *area;
1187
1188     if (sr->areaid >= screen->narea || !(area = screen->areas[sr->areaid])) {
1189         mrp_log_error("system-controller: failed to raise screen resource: "
1190                       "can't find area for screen");
1191     }
1192     else {
1193         sr->key &= ~(ZORDER_MASK << ZORDER_POSITION);
1194         sr->key |= zorder_new_top_value(area);
1195
1196         area_insert_resource(area, sr);
1197     }
1198
1199     sr->acquire = true;
1200 }
1201
1202
1203 static void screen_resource_lower_to_bottom(mrp_resmgr_screen_t *screen,
1204                                             screen_resource_t *sr)
1205 {
1206     mrp_resmgr_screen_area_t *area;
1207
1208     if (sr->areaid >= screen->narea || !(area = screen->areas[sr->areaid])) {
1209         mrp_log_error("system-controller: failed to lower screen resource: "
1210                       "can't find area for screen");
1211     }
1212     else {
1213         sr->key &= ~(ZORDER_MASK << ZORDER_POSITION);
1214
1215         area_insert_resource(area, sr);
1216     }
1217
1218     sr->acquire = false;
1219 }
1220
1221
1222 static uint32_t zorder_new_top_value(mrp_resmgr_screen_area_t *area)
1223 {
1224     mrp_list_hook_t *resources, *entry, *n;
1225     screen_resource_t *sr;
1226     uint32_t new_top, min, max, z;
1227
1228     if ((new_top = ++(area->zorder)) >= ZORDER_MAX) {
1229         /*
1230          * we get here in the unlikely event of z-order value overflow
1231          * what we try to do here is to find out the range of the z values
1232          * and subtract from all the minimum value, ie. move the whole range
1233          * to start from zero.
1234          */
1235         resources = &area->resources;
1236
1237         if (mrp_list_empty(resources))
1238             new_top = area->zorder = 1;
1239         else {
1240             min = ZORDER_MAX;
1241             max = 0;
1242
1243             mrp_list_foreach(resources, entry, n) {
1244                 sr = mrp_list_entry(entry, screen_resource_t, link);
1245                 z = ((sr->key >> ZORDER_POSITION) & ZORDER_MASK);
1246
1247                 if (z < min)   min = z;
1248                 if (z > max)   max = z;
1249             }
1250
1251             /* assert if the range moving would not help */
1252             MRP_ASSERT(min < ZORDER_MAX-1, "Z-order overflow");
1253
1254             mrp_list_foreach(resources, entry, n) {
1255                 sr = mrp_list_entry(entry, screen_resource_t, link);
1256                 z = ((sr->key >> ZORDER_POSITION) & ZORDER_MASK) - min;
1257
1258                 sr->key &= ~(ZORDER_MASK << ZORDER_POSITION);
1259                 sr->key |= (z << ZORDER_POSITION);
1260             }
1261
1262             new_top = area->zorder = (max - min) + 1;
1263         }
1264     }
1265
1266     return (new_top << ZORDER_POSITION);
1267 }
1268
1269
1270 static void screen_grant_resources(mrp_resmgr_screen_t *screen,
1271                                    mrp_zone_t *zone)
1272 {
1273     uint32_t zoneid;
1274     uint32_t grantid;
1275     const char *zonename;
1276     mrp_list_hook_t *areas, *aentry, *an;
1277     mrp_list_hook_t *resources, *rentry , *rn;
1278     mrp_resmgr_screen_area_t *area;
1279     screen_resource_t *sr;
1280     const char *appid;
1281     int32_t surfaceid;
1282     int32_t layerid;
1283
1284     zoneid   = mrp_zone_get_id(zone);
1285     zonename = mrp_zone_get_name(zone);
1286     areas    = screen->zones + zoneid;
1287     grantid  = ++(screen->grantids[zoneid]);
1288
1289     if (!zonename)
1290         zonename = "<unknown>";
1291
1292     mrp_list_foreach(areas, aentry, an) {
1293         area = mrp_list_entry(aentry, mrp_resmgr_screen_area_t, link);
1294         resources = &area->resources;
1295
1296         mrp_list_foreach_back(resources, rentry, rn) {
1297             sr = mrp_list_entry(rentry, screen_resource_t, link);
1298
1299             MRP_ASSERT(sr->res, "confused with data structures");
1300
1301             if (sr->acquire && !sr->disable) {
1302                 appid     = get_appid_for_resource(sr->res);
1303                 surfaceid = get_surfaceid_for_resource(sr->res);
1304                 layerid   = get_layerid_for_resource(sr->res);
1305
1306                 if (!appid)
1307                     appid = "<unknown>";
1308
1309                 mrp_debug("preallocate screen resource in '%s' area for '%s' "
1310                           "in zone '%s'", area->name, appid, zonename);
1311
1312                 sr->grantid = grantid;
1313
1314                 mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1315                                                 zoneid, zonename,
1316                                                 MRP_RESMGR_EVENTID_PREALLOCATE,
1317                                                 appid, surfaceid, layerid,
1318                                                 area->name);
1319                 break;
1320             }
1321         }
1322     }
1323 }
1324
1325 static void screen_queue_events(mrp_resmgr_screen_t *screen, mrp_zone_t *zone)
1326 {
1327     uint32_t zoneid;
1328     const char *zonename;
1329     uint32_t grantid;
1330     mrp_list_hook_t *areas, *aentry, *an;
1331     mrp_list_hook_t *resources, *rentry, *rn;
1332     mrp_resmgr_screen_area_t *area;
1333     screen_resource_t *sr;
1334     bool grant;
1335     mrp_resmgr_eventid_t eventid;
1336     const char *appid, *areaname;
1337     int32_t surfaceid, layerid;
1338
1339     zoneid   = mrp_zone_get_id(zone);
1340     zonename = mrp_zone_get_name(zone);
1341     areas    = screen->zones + zoneid;
1342     grantid  = screen->grantids[zoneid];
1343
1344     mrp_list_foreach(areas, aentry, an) {
1345         area = mrp_list_entry(aentry, mrp_resmgr_screen_area_t, link);
1346         resources = &area->resources;
1347
1348
1349         mrp_list_foreach_back(resources, rentry, rn) {
1350             sr = mrp_list_entry(rentry, screen_resource_t, link);
1351             grant = (grantid == sr->grantid);
1352
1353             if ((grant && !sr->grant) || (!grant && sr->grant)) {
1354
1355                 eventid   = grant ? MRP_RESMGR_EVENTID_GRANT :
1356                                     MRP_RESMGR_EVENTID_REVOKE;
1357                 appid     = get_appid_for_resource(sr->res);
1358                 surfaceid = get_surfaceid_for_resource(sr->res);
1359                 layerid   = get_layerid_for_resource(sr->res);
1360                 areaname  = get_areaname_for_resource(sr->res);
1361
1362                 mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1363                                                        zoneid, zonename,
1364                                                        eventid,
1365                                                        appid, surfaceid,
1366                                                        layerid, areaname);
1367             }
1368
1369             sr->grant = grant;
1370         }
1371     }
1372 }
1373
1374
1375 static void area_insert_resource(mrp_resmgr_screen_area_t *area,
1376                                  screen_resource_t *resource)
1377 {
1378     mrp_list_hook_t *resources, *insert_after, *n;
1379     screen_resource_t *sr;
1380     uint32_t key;
1381
1382     mrp_list_delete(&resource->link);
1383
1384     resources = &area->resources;
1385     key = resource->key;
1386     insert_after = resources;   /* keep the compiler happy: foreach below
1387                                    will do it anyways */
1388
1389     mrp_list_foreach_back(resources, insert_after, n) {
1390         sr = mrp_list_entry(insert_after, screen_resource_t, link);
1391         if (key >= sr->key)
1392             break;
1393     }
1394
1395     mrp_list_insert_after(insert_after, &resource->link);
1396 }
1397
1398 static uint32_t resource_key(mrp_resource_t *res, mrp_application_class_t *ac)
1399 {
1400     uint32_t priority;
1401     uint32_t classpri;
1402     uint32_t key = 0;
1403
1404     if (res && ac) {
1405         priority = get_priority_for_resource(res);
1406         classpri = get_class_priority_for_resource(res, ac);
1407         key = ((priority & PRIORITY_MASK) << PRIORITY_POSITION) |
1408               ((classpri & CLASSPRI_MASK) << CLASSPRI_POSITION) ;
1409     }
1410
1411     return key;
1412 }
1413
1414 static void screen_notify(mrp_resource_event_t event,
1415                           mrp_zone_t *zone,
1416                           mrp_application_class_t *ac,
1417                           mrp_resource_t *res,
1418                           void *userdata)
1419 {
1420     mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1421     const char *zonename = mrp_zone_get_name(zone);
1422     screen_resource_t *sr;
1423
1424     MRP_ASSERT(zone && ac && res && screen, "invalid argument");
1425
1426     switch (event) {
1427
1428     case MRP_RESOURCE_EVENT_CREATED:
1429         mrp_debug("screen resource in zone '%s' created", zonename);
1430         screen_resource_create(screen, zone, res, ac);
1431         break;
1432
1433     case MRP_RESOURCE_EVENT_DESTROYED:
1434         mrp_debug("screen resource in zone '%s' destroyed", zonename);
1435         screen_resource_destroy(screen, zone, res);
1436         break;
1437
1438     case MRP_RESOURCE_EVENT_ACQUIRE:
1439         mrp_debug("screen resource in zone '%s' is acquiring", zonename);
1440         if (!(sr = screen_resource_lookup(screen, res)))
1441             goto no_screen_resource;
1442         else
1443             screen_resource_raise_to_top(screen, sr);
1444         break;
1445
1446     case MRP_RESOURCE_EVENT_RELEASE:
1447         mrp_debug("screen resource in zone '%s' is released", zonename);
1448         if (!(sr = screen_resource_lookup(screen, res)))
1449             goto no_screen_resource;
1450         else
1451             screen_resource_lower_to_bottom(screen, sr);
1452         break;
1453
1454     no_screen_resource:
1455         mrp_debug("resource lookup in hash table failed: key=%p", res);
1456         mrp_log_error("system-controller: can't find screen resource "
1457                       "in zone '%s'", zonename);
1458         break;
1459
1460     default:
1461         mrp_log_error("system-controller: invalid event %d at screen "
1462                       "notification (zone '%s')", event, zonename);
1463         break;
1464     }
1465 }
1466
1467 static void screen_init(mrp_zone_t *zone, void *userdata)
1468 {
1469     mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1470     uint32_t zoneid;
1471     const char *zonename;
1472
1473     MRP_ASSERT(zone && screen, "invalid argument");
1474
1475     zoneid   = mrp_zone_get_id(zone);
1476     zonename = mrp_zone_get_name(zone);
1477
1478     if (!zonename)
1479         zonename = "<unknown>";
1480
1481     mrp_debug("screen init in zone '%s'", zonename);
1482
1483     mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1484                                            zoneid,zonename,
1485                                            MRP_RESMGR_EVENTID_INIT,
1486                                            "<unknown>", -1, -1, "<unknown>");
1487     screen_grant_resources(screen, zone);
1488
1489     mrp_resmgr_notifier_flush_screen_events(screen->resmgr, zoneid);
1490 }
1491
1492 static bool screen_allocate(mrp_zone_t *zone,
1493                             mrp_resource_t *res,
1494                             void *userdata)
1495 {
1496     mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1497     uint32_t zoneid;
1498     const char *zonename;
1499     const char *appid = get_appid_for_resource(res);
1500     screen_resource_t *sr;
1501     uint32_t grantid;
1502     bool allocated;
1503
1504     MRP_ASSERT(zone && res && screen && screen->resmgr, "invalid argument");
1505
1506     zoneid  = mrp_zone_get_id(zone);
1507     grantid = screen->grantids[zoneid];
1508
1509     if (!(zonename = mrp_zone_get_name(zone)))
1510         zonename = "<unknown>";
1511     if (!(appid = get_appid_for_resource(res)))
1512         appid = "<unknown>";
1513
1514     if ((sr = screen_resource_lookup(screen, res))) {
1515         allocated = (sr->grantid == grantid);
1516
1517         mrp_debug("screen allocation for '%s' in zone '%s' %s",
1518                   zonename, appid, allocated ? "succeeded":"failed");
1519
1520         return allocated;
1521     }
1522
1523     mrp_log_error("system-controller: attempt to allocate untracked "
1524                   "resource '%s' in zone '%s'", appid, zonename);
1525
1526     return FALSE;
1527 }
1528
1529 static void screen_free(mrp_zone_t *zone, mrp_resource_t *res, void *userdata)
1530 {
1531     mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1532     const char *zonename;
1533     const char *appid;
1534     screen_resource_t *sr;
1535
1536     MRP_ASSERT(zone && res && screen, "invalid argument");
1537
1538     if (!(zonename = mrp_zone_get_name(zone)))
1539         zonename = "<unknown>";
1540     if (!(appid = get_appid_for_resource(res)))
1541         appid = "<unknown>";
1542
1543     mrp_debug("free screen of '%s' in zone '%s'", appid, zonename);
1544
1545     if ((sr = screen_resource_lookup(screen, res)))
1546         sr->grantid = 0;
1547 }
1548
1549 static bool screen_advice(mrp_zone_t *zone,mrp_resource_t *res,void *userdata)
1550 {
1551     mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1552     const char *zonename;
1553     const char *appid;
1554
1555     MRP_ASSERT(zone && res && screen, "invalid argument");
1556
1557     if (!(zonename = mrp_zone_get_name(zone)))
1558         zonename = "<unknown>";
1559     if (!(appid = get_appid_for_resource(res)))
1560         appid = "<unknown>";
1561
1562     mrp_debug("screen advice for '%s' in zone '%s'", appid, zonename);
1563
1564     return TRUE;
1565 }
1566
1567 static void screen_commit(mrp_zone_t *zone, void *userdata)
1568 {
1569     mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1570     const char *zonename;
1571     uint32_t zoneid;
1572
1573     MRP_ASSERT(zone && screen && screen->resmgr, "invalid argument");
1574
1575     zoneid  = mrp_zone_get_id(zone);
1576
1577     if (!(zonename = mrp_zone_get_name(zone)))
1578         zonename = "<unknown>";
1579
1580     mrp_debug("screen commit in zone '%s'", zonename);
1581
1582     screen_queue_events(screen, zone);
1583     mrp_resmgr_notifier_flush_screen_events(screen->resmgr, zoneid);
1584 }