2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
35 #include <murphy/common.h>
37 #include <murphy-db/mqi.h>
39 #include <murphy/resource/config-api.h>
40 #include <murphy/resource/manager-api.h>
41 #include <murphy/resource/client-api.h>
45 #include "wayland/area.h"
46 #include "wayland/output.h"
47 #include "application/application.h"
49 #define ANY_OUTPUT (~((uint32_t)0))
50 #define ANY_AREA (~((uint32_t)0))
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)))
66 #define PRIORITY_BITS 8
67 #define CLASSPRI_BITS 8
68 #define ZORDER_BITS 16
70 #define PRIORITY_POSITION 0
71 #define CLASSPRI_POSITION (PRIORITY_POSITION + PRIORITY_BITS)
72 #define ZORDER_POSITION (CLASSPRI_POSITION + CLASSPRI_BITS)
74 #define PRIORITY_MASK MASK(PRIORITY_BITS)
75 #define CLASSPRI_MASK MASK(CLASSPRI_BITS)
76 #define ZORDER_MASK MASK(ZORDER_BITS)
78 #define PRIORITY_MAX MAX(PRIORITY_BITS)
79 #define CLASSPRI_MAX MAX(CLASSPRI_BITS)
80 #define ZORDER_MAX MAX(ZORDER_BITS)
83 #define ATTRIBUTE(n,t,v) {n, MRP_RESOURCE_RW, mqi_##t, {.t=v}}
84 #define ATTR_END {NULL, 0, 0, {.string=NULL}}
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;
92 struct screen_resource_s {
94 mrp_resmgr_screen_t *screen;
103 mrp_application_requisite_t requisite;
104 mrp_resmgr_disable_t disable;
107 struct disable_iterator_s {
111 mrp_resmgr_disable_t type;
115 mrp_application_requisite_t req;
122 struct output_iterator_s {
124 mrp_wayland_output_t *out;
127 struct area_iterator_s {
128 mrp_resmgr_t *resmgr;
129 const char *fullname;
132 mrp_resmgr_screen_area_t *area;
135 const char *names[MRP_ZONE_MAX + 1];
140 static int hash_compare(const void *, const void *);
141 static uint32_t hash_function(const void *);
143 static void overlap_add(mrp_resmgr_screen_area_t *, size_t);
144 static void overlap_remove(mrp_resmgr_screen_area_t *, size_t);
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 *);
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 *,
163 static screen_resource_t *screen_resource_lookup(mrp_resmgr_screen_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 *);
173 static uint32_t zorder_new_top_value(mrp_resmgr_screen_area_t *);
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 *);
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 *);
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 *);
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
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 ),
204 static mrp_resource_mgr_ftbl_t screen_ftbl = {
213 mrp_resmgr_screen_t *mrp_resmgr_screen_create(mrp_resmgr_t *resmgr)
215 mrp_resmgr_screen_t *screen;
216 mrp_htbl_config_t cfg;
220 if ((screen = mrp_allocz(sizeof(mrp_resmgr_screen_t)))) {
221 resid = mrp_resource_definition_create(MRP_SYSCTL_SCREEN_RESOURCE,
223 &screen_ftbl,screen);
224 mrp_lua_resclass_create_from_c(resid);
226 cfg.nentry = MRP_RESMGR_RESOURCE_MAX;
227 cfg.comp = hash_compare;
228 cfg.hash = hash_function;
230 cfg.nbucket = MRP_RESMGR_RESOURCE_BUCKETS;
232 screen->resmgr = resmgr;
233 screen->resid = resid;
234 screen->resources = mrp_htbl_create(&cfg);
236 for (i = 0; i < MRP_ZONE_MAX; i++)
237 mrp_list_init(screen->zones + i);
244 void mrp_resmgr_screen_destroy(mrp_resmgr_screen_t *screen)
247 mrp_htbl_destroy(screen->resources, false);
252 static int screen_disable_cb(void *key, void *object, void *user_data)
254 screen_resource_t *sr = (screen_resource_t *)object;
255 disable_iterator_t *it = (disable_iterator_t *)user_data;
261 MRP_ASSERT(sr && it, "invalid argument");
263 if ((it->outputid == ANY_OUTPUT || sr->outputid == it->outputid) &&
264 (it->areaid == ANY_AREA || sr->areaid == it->areaid ) )
268 case MRP_RESMGR_DISABLE_REQUISITE:
269 if (it->req && (it->req & sr->requisite) == it->req)
273 case MRP_RESMGR_DISABLE_APPID:
275 if (!strcmp(it->appid, "*"))
277 appid = get_appid_for_resource(sr->res);
278 if (appid && !strcmp(it->appid, appid))
283 case MRP_RESMGR_DISABLE_SURFACEID:
287 disable = sr->disable & it->mask;
291 sr->disable |= it->mask;
296 sr->disable &= ~it->mask;
299 it->zones |= (((uint32_t)1) << sr->zoneid);
303 return MRP_HTBL_ITER_STOP;
307 return MRP_HTBL_ITER_MORE;
310 static int output_find_cb(void *key, void *object, void *user_data)
312 mrp_wayland_output_t *out = (mrp_wayland_output_t *)object;
313 output_iterator_t *it = (output_iterator_t *)user_data;
317 MRP_ASSERT(out && it, "invalid argument");
319 if (out->name && !strcmp(it->name, out->outputname)) {
321 return MRP_HTBL_ITER_STOP;
324 return MRP_HTBL_ITER_MORE;
327 int mrp_resmgr_screen_disable(mrp_resmgr_screen_t *screen,
328 const char *output_name,
329 const char *area_name,
331 mrp_resmgr_disable_t type,
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;
349 MRP_ASSERT(screen && data, "invalid argument");
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",
357 if (output_name && strcmp(output_name, "*")) {
358 memset(&oit, 0, sizeof(oit));
359 oit.name = output_name;
361 mrp_wayland_foreach(w, i) {
362 mrp_htbl_foreach(w->outputs.by_index, output_find_cb, &oit);
366 output_id = o->outputid;
370 if (output_id == ANY_OUTPUT) {
371 mrp_log_error("system-controller: failed to disable screen: "
372 "can't find output '%s'", output_name);
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)))
382 mrp_log_error("system-controller: failed to disable screen: "
383 "can't find area '%s'", area_name);
388 memset(&dit, 0, sizeof(dit));
389 dit.outputid = output_id;
390 dit.areaid = area_id;
391 dit.disable = disable;
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);
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);
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);
419 screen_disable_cb(hk, obj, &dit);
423 mrp_log_error("system-controller: invalid type %d of "
424 "screen disable", type);
429 for (z = 0; dit.zones && z < MRP_ZONE_MAX; z++) {
430 mask = (((uint32_t)1) << z);
432 if ((mask & dit.zones)) {
434 mrp_resource_owner_recalc(z);
443 int mrp_resmgr_screen_print(mrp_resmgr_screen_t *screen,
449 p += snprintf(p, e-p, __VA_ARGS__); \
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;
463 char requisite[1024];
465 MRP_ASSERT(screen && buf && len > 0, "invalid argument");
470 if (zoneid < MRP_ZONE_MAX) {
471 areas = screen->zones + zoneid;
472 grantid = screen->grantids[zoneid];
479 PRINT(" Resource '%s' - grantid:%u\n",
480 MRP_SYSCTL_SCREEN_RESOURCE, grantid);
482 if (!areas || mrp_list_empty(areas))
483 PRINT(" No resources\n");
485 mrp_list_foreach_back(areas, aentry, an) {
486 area = mrp_list_entry(aentry, mrp_resmgr_screen_area_t, link);
487 resources = &area->resources;
489 PRINT(" Area '%s':\n", area->name);
491 mrp_list_foreach_back(resources, rentry, rn) {
492 sr = mrp_list_entry(rentry, screen_resource_t, link);
494 mrp_resmgr_disable_print(sr->disable, disable,
496 mrp_application_requisite_print(sr->requisite, requisite,
500 "key:0x%08x %s grantid:%u requisite:%s disable:%s",
502 sr->acquire ? "acquire":"release",
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);
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;
522 } /* mrp_list_foreach_back - resources */
523 } /* mrp_list_foreach_back - areas */
529 static int area_resolution_cb(void *key, void *object, void *user_data)
532 screen_resource_t *sr = (screen_resource_t *)object;
533 area_iterator_t *ait = (area_iterator_t *)user_data;
534 const char *areaname;
536 const char *zonename;
542 MRP_ASSERT(sr && sr->res && ait, "confused with data structures");
544 if (sr->areaid == ANY_AREA && sr->zoneid < MRP_ZONE_MAX) {
545 areaname = get_areaname_for_resource(sr->res);
547 if (areaname && !strcmp(areaname, ait->fullname)) {
548 appid = get_appid_for_resource(sr->res);
549 surfaceid = get_surfaceid_for_resource(sr->res);
552 mrp_debug(" resolving screen resource for '%s'",
553 appid ? appid : "<unknown appid>");
555 sr->areaid = ait->areaid;
556 sr->outputid = ait->outputid;
558 area_insert_resource(ait->area, sr);
561 ait->zone.mask |= (((uint32_t)1) << sr->zoneid);
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,
569 mrp_resmgr_notifier_flush_screen_events(ait->resmgr,
575 return MRP_HTBL_ITER_MORE;
578 void mrp_resmgr_screen_area_create(mrp_resmgr_screen_t *screen,
579 mrp_wayland_area_t *wlarea,
580 const char *zonename)
582 mrp_resmgr_screen_area_t *rmarea, *a;
588 int32_t x, x0, x1, y, y0, y1;
593 MRP_ASSERT(screen && wlarea && wlarea->output && zonename,
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);
603 areaid = wlarea->areaid;
604 name = wlarea->name ? wlarea->name : "<unknown>";
605 outputid = wlarea->output->outputid;
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);
613 if (areaid >= screen->narea) {
614 screen->areas = mrp_reallocz(screen->areas, screen->narea, areaid + 1);
616 MRP_ASSERT(screen->areas, "can't allocate memory for screen areas");
618 screen->narea = areaid + 1;
621 if (screen->areas[areaid]) {
622 mrp_log_error("system-controller: attempt to redefine "
623 "resource manager area %d", areaid);
627 screen->areas[areaid] = rmarea = mrp_allocz(sizeof(*rmarea));
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);
638 x1 = (x0 = rmarea->x) + rmarea->width;
639 y1 = (y0 = rmarea->y) + rmarea->height;
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) ) )
649 overlap_add(a, areaid);
650 overlap_add(rmarea, i);
655 mrp_debug("resolving resources in '%s' area", wlarea->fullname);
657 memset(&ait, 0, sizeof(ait));
658 ait.resmgr = screen->resmgr;
659 ait.fullname = wlarea->fullname;
661 ait.outputid = outputid;
663 mrp_zone_get_all_names(MRP_ZONE_MAX + 1, ait.zone.names);
665 mrp_htbl_foreach(screen->resources, area_resolution_cb, &ait);
668 mrp_debug("recalculating owners ...");
670 for (z = 0; ait.zone.mask && z < MRP_ZONE_MAX; z++) {
671 mask = (((uint32_t)1) << z);
673 if ((mask & ait.zone.mask)) {
674 ait.zone.mask &= ~mask;
675 mrp_resource_owner_recalc(z);
680 mrp_log_info("system-controller: resource manager registered screen area "
681 "%d - '%s'", areaid, name);
684 void mrp_screen_area_destroy(mrp_resmgr_screen_t *screen, int32_t areaid)
686 mrp_resmgr_screen_area_t *area;
689 MRP_ASSERT(screen && areaid >= 0 && areaid < MRP_WAYLAND_AREA_MAX,
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);
697 screen->areas[areaid] = NULL;
699 for (i = 0; i < area->noverlap; i++)
700 overlap_remove(screen->areas[area->overlaps[i]], areaid);
702 mrp_free((void *)area->name);
703 mrp_free((void *)area->overlaps);
708 void mrp_screen_resource_raise(mrp_resmgr_screen_t *screen,
712 mrp_resmgr_screen_area_t *area;
713 mrp_list_hook_t *resources, *entry, *n;
714 screen_resource_t *sr;
719 bool zones[MRP_ZONE_MAX];
721 MRP_ASSERT(screen && screen->resources && appid, "invalid argument");
723 if (surfaceid == 0) {
726 zmin = MRP_ZONE_MAX-1;
728 for (i = cnt = 0; i < screen->narea; i++) {
729 if (!(area = screen->areas[i]))
732 resources = &area->resources;
734 mrp_list_foreach(resources, entry, n) {
735 sr = mrp_list_entry(entry, screen_resource_t, link);
738 if ((id = get_appid_for_resource(res)) && !strcmp(id, appid)) {
739 mrp_debug("raise surface %d to top", surfaceid);
741 if (!screen_resource_is_on_top(screen, sr)) {
742 screen_resource_raise_to_top(screen, sr);
745 zones[sr->zoneid] = true;
746 if (zmax < sr->zoneid) zmax = sr->zoneid;
747 if (zmin > sr->zoneid) zmin = sr->zoneid;
755 mrp_debug("nothing to be raised");
757 for (i = zmin; i <= zmax; i++) {
759 mrp_resource_owner_recalc(i);
764 if ((sr = mrp_htbl_lookup(screen->resources, NULL + surfaceid))) {
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);
773 if (screen_resource_is_on_top(screen, sr)) {
774 mrp_debug("nothing to be raised: surface %d "
775 "is already on top", surfaceid);
778 mrp_debug("raise surface %d to top", surfaceid);
779 screen_resource_raise_to_top(screen, sr);
780 mrp_resource_owner_recalc(sr->zoneid);
787 void mrp_screen_resource_lower(mrp_resmgr_screen_t *screen,
791 mrp_resmgr_screen_area_t *area;
792 mrp_list_hook_t *resources, *entry, *n;
793 screen_resource_t *sr;
798 bool zones[MRP_ZONE_MAX];
800 MRP_ASSERT(screen && screen->resources && appid, "invalid argument");
802 if (surfaceid == 0) {
805 zmin = MRP_ZONE_MAX-1;
807 for (i = cnt = 0; i < screen->narea; i++) {
808 if (!(area = screen->areas[i]))
811 resources = &area->resources;
813 mrp_list_foreach_back(resources, entry, n) {
814 sr = mrp_list_entry(entry, screen_resource_t, link);
817 if ((id = get_appid_for_resource(res)) && !strcmp(id, appid)) {
818 mrp_debug("lower surface %d to bottom", surfaceid);
820 screen_resource_lower_to_bottom(screen, sr);
823 zones[sr->zoneid] = true;
824 if (zmax < sr->zoneid) zmax = sr->zoneid;
825 if (zmin > sr->zoneid) zmin = sr->zoneid;
831 mrp_debug("nothing to be lowered");
833 for (i = zmin; i <= zmax; i++) {
835 mrp_resource_owner_recalc(i);
840 if ((sr = mrp_htbl_lookup(screen->resources, NULL + surfaceid))) {
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);
849 mrp_debug("lower surface %d to bottom", surfaceid);
850 screen_resource_lower_to_bottom(screen, sr);
851 mrp_resource_owner_recalc(sr->zoneid);
857 static int hash_compare(const void *key1, const void *key2)
866 static uint32_t hash_function(const void *key)
868 return (uint32_t)(key - (const void *)0);
871 static void overlap_add(mrp_resmgr_screen_area_t *area, size_t overlapid)
875 for (i = 0; i < area->noverlap; i++) {
876 if (area->overlaps[i] == overlapid)
880 area->overlaps = mrp_realloc(area->overlaps, sizeof(size_t *) * (i + 1));
882 MRP_ASSERT(area->overlaps, "can't allocate memory for overalapping "
883 "resource manager areas");
885 area->overlaps[i] = overlapid;
889 static void overlap_remove(mrp_resmgr_screen_area_t *area, size_t overlapid)
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];
902 mrp_log_error("system-controller: attempt to remove unregistered "
906 static const char *get_appid_for_resource(mrp_resource_t *res)
911 if (!mrp_resource_read_attribute(res, APPID_ATTRIDX, &attr) ||
912 attr.type != mqi_string || !(appid = attr.value.string) )
918 static int32_t get_surfaceid_for_resource(mrp_resource_t *res)
922 if (mrp_resource_read_attribute(res, SURFACE_ATTRIDX, &attr)) {
923 if (attr.type == mqi_integer)
924 return attr.value.integer;
930 static int32_t get_layerid_for_resource(mrp_resource_t *res)
937 static const char *get_areaname_for_resource(mrp_resource_t *res)
941 if (mrp_resource_read_attribute(res, AREA_ATTRIDX, &attr)) {
942 if (attr.type == mqi_string)
943 return attr.value.string;
949 static mrp_application_t *get_application_for_resource(mrp_resource_t *res)
951 const char *appid = get_appid_for_resource(res);
952 mrp_application_t *app = NULL;
954 if (!appid || !(app = mrp_application_find(appid)))
955 app = mrp_application_find(MRP_SYSCTL_APPID_DEFAULT);
960 static int32_t get_area_for_resource(mrp_resource_t *res)
963 mrp_wayland_area_t *a;
964 const char *areaname;
967 if ((areaname = get_areaname_for_resource(res))) {
968 mrp_wayland_foreach(wl, it) {
969 if ((a = mrp_wayland_area_find(wl, areaname)))
978 static uint32_t get_priority_for_resource(mrp_resource_t *res)
981 uint32_t priority = 0;
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;
991 static uint32_t get_class_priority_for_resource(mrp_resource_t *res,
992 mrp_application_class_t *ac)
997 priority = mrp_application_class_get_priority(ac);
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;
1007 static int32_t get_zone_id(const char *name)
1009 const char *zones[MRP_ZONE_MAX + 1];
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))
1025 static screen_resource_t *screen_resource_create(mrp_resmgr_screen_t *screen,
1027 mrp_resource_t *res,
1028 mrp_application_class_t *ac)
1030 mrp_resmgr_t *resmgr;
1031 const char *zonename;
1033 mrp_application_t *app;
1034 mrp_resmgr_screen_area_t *area;
1040 screen_resource_t *sr;
1043 MRP_ASSERT(screen && screen->resources && zone && res && ac,
1044 "invalid argument");
1045 MRP_ASSERT(screen->resmgr, "confused with data structures");
1047 resmgr = screen->resmgr;
1050 zonename = mrp_zone_get_name(zone);
1051 appid = get_appid_for_resource(res);
1053 if (!(app = get_application_for_resource(res))) {
1054 mrp_log_error("system-controller: failed to create screen resource: "
1059 layerid = get_layerid_for_resource(sr->res);
1061 if ((id = get_area_for_resource(res)) >= 0 &&
1062 (size_t)id < screen->narea &&
1063 (area = screen->areas[id]) )
1066 outputid = area->outputid;
1069 mrp_debug("delayed area resolution");
1072 outputid = ANY_OUTPUT;
1075 if (!(surfaceid = get_surfaceid_for_resource(res))) {
1076 mrp_log_error("system-controller: failed to create screen resource: "
1077 "invalid surface attribute");
1081 if (!(sr = mrp_allocz(sizeof(*sr)))) {
1082 mrp_log_error("system-controller: failed to create screen resource: "
1083 "can't allocate memory");
1087 mrp_list_init(&sr->link);
1088 sr->screen = screen;
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;
1097 area_insert_resource(area, sr);
1099 mrp_debug("inserting resource to hash table: key=%p value=%p", res, sr);
1100 mrp_resmgr_insert_resource(resmgr, zone, res, sr);
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);
1107 mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1108 sr->zoneid,zonename,
1109 MRP_RESMGR_EVENTID_CREATE,
1110 appid, surfaceid, layerid,
1112 mrp_resmgr_notifier_flush_screen_events(screen->resmgr, sr->zoneid);
1119 static void screen_resource_destroy(mrp_resmgr_screen_t *screen,
1121 mrp_resource_t *res)
1123 screen_resource_t *sr;
1124 const char *zonename;
1128 const char *areaname;
1130 MRP_ASSERT(res && screen && screen->resources, "invalid argument");
1131 MRP_ASSERT(screen->resmgr, "confused with data structures");
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);
1140 mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1141 sr->zoneid, zonename,
1142 MRP_RESMGR_EVENTID_DESTROY,
1143 appid, surfaceid, layerid,
1146 mrp_htbl_remove(screen->resources, NULL + surfaceid, false);
1148 mrp_list_delete(&sr->link);
1151 mrp_resmgr_notifier_flush_screen_events(screen->resmgr, sr->zoneid);
1156 static screen_resource_t *screen_resource_lookup(mrp_resmgr_screen_t *screen,
1157 mrp_resource_t *res)
1159 screen_resource_t *sr;
1161 MRP_ASSERT(res && screen, "invalid argument");
1162 MRP_ASSERT(screen->resmgr, "confused with data structures");
1164 sr = mrp_resmgr_lookup_resource(screen->resmgr, res);
1169 static bool screen_resource_is_on_top(mrp_resmgr_screen_t *screen,
1170 screen_resource_t *sr)
1172 mrp_resmgr_screen_area_t *area;
1175 if (sr->areaid >= screen->narea || !(area = screen->areas[sr->areaid]))
1178 on_top = (area->resources.prev == &sr->link);
1183 static void screen_resource_raise_to_top(mrp_resmgr_screen_t *screen,
1184 screen_resource_t *sr)
1186 mrp_resmgr_screen_area_t *area;
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");
1193 sr->key &= ~(ZORDER_MASK << ZORDER_POSITION);
1194 sr->key |= zorder_new_top_value(area);
1196 area_insert_resource(area, sr);
1203 static void screen_resource_lower_to_bottom(mrp_resmgr_screen_t *screen,
1204 screen_resource_t *sr)
1206 mrp_resmgr_screen_area_t *area;
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");
1213 sr->key &= ~(ZORDER_MASK << ZORDER_POSITION);
1215 area_insert_resource(area, sr);
1218 sr->acquire = false;
1222 static uint32_t zorder_new_top_value(mrp_resmgr_screen_area_t *area)
1224 mrp_list_hook_t *resources, *entry, *n;
1225 screen_resource_t *sr;
1226 uint32_t new_top, min, max, z;
1228 if ((new_top = ++(area->zorder)) >= ZORDER_MAX) {
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.
1235 resources = &area->resources;
1237 if (mrp_list_empty(resources))
1238 new_top = area->zorder = 1;
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);
1247 if (z < min) min = z;
1248 if (z > max) max = z;
1251 /* assert if the range moving would not help */
1252 MRP_ASSERT(min < ZORDER_MAX-1, "Z-order overflow");
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;
1258 sr->key &= ~(ZORDER_MASK << ZORDER_POSITION);
1259 sr->key |= (z << ZORDER_POSITION);
1262 new_top = area->zorder = (max - min) + 1;
1266 return (new_top << ZORDER_POSITION);
1270 static void screen_grant_resources(mrp_resmgr_screen_t *screen,
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;
1284 zoneid = mrp_zone_get_id(zone);
1285 zonename = mrp_zone_get_name(zone);
1286 areas = screen->zones + zoneid;
1287 grantid = ++(screen->grantids[zoneid]);
1290 zonename = "<unknown>";
1292 mrp_list_foreach(areas, aentry, an) {
1293 area = mrp_list_entry(aentry, mrp_resmgr_screen_area_t, link);
1294 resources = &area->resources;
1296 mrp_list_foreach_back(resources, rentry, rn) {
1297 sr = mrp_list_entry(rentry, screen_resource_t, link);
1299 MRP_ASSERT(sr->res, "confused with data structures");
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);
1307 appid = "<unknown>";
1309 mrp_debug("preallocate screen resource in '%s' area for '%s' "
1310 "in zone '%s'", area->name, appid, zonename);
1312 sr->grantid = grantid;
1314 mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1316 MRP_RESMGR_EVENTID_PREALLOCATE,
1317 appid, surfaceid, layerid,
1325 static void screen_queue_events(mrp_resmgr_screen_t *screen, mrp_zone_t *zone)
1328 const char *zonename;
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;
1335 mrp_resmgr_eventid_t eventid;
1336 const char *appid, *areaname;
1337 int32_t surfaceid, layerid;
1339 zoneid = mrp_zone_get_id(zone);
1340 zonename = mrp_zone_get_name(zone);
1341 areas = screen->zones + zoneid;
1342 grantid = screen->grantids[zoneid];
1344 mrp_list_foreach(areas, aentry, an) {
1345 area = mrp_list_entry(aentry, mrp_resmgr_screen_area_t, link);
1346 resources = &area->resources;
1349 mrp_list_foreach_back(resources, rentry, rn) {
1350 sr = mrp_list_entry(rentry, screen_resource_t, link);
1351 grant = (grantid == sr->grantid);
1353 if ((grant && !sr->grant) || (!grant && sr->grant)) {
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);
1362 mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1375 static void area_insert_resource(mrp_resmgr_screen_area_t *area,
1376 screen_resource_t *resource)
1378 mrp_list_hook_t *resources, *insert_after, *n;
1379 screen_resource_t *sr;
1382 mrp_list_delete(&resource->link);
1384 resources = &area->resources;
1385 key = resource->key;
1386 insert_after = resources; /* keep the compiler happy: foreach below
1387 will do it anyways */
1389 mrp_list_foreach_back(resources, insert_after, n) {
1390 sr = mrp_list_entry(insert_after, screen_resource_t, link);
1395 mrp_list_insert_after(insert_after, &resource->link);
1398 static uint32_t resource_key(mrp_resource_t *res, mrp_application_class_t *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) ;
1414 static void screen_notify(mrp_resource_event_t event,
1416 mrp_application_class_t *ac,
1417 mrp_resource_t *res,
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;
1424 MRP_ASSERT(zone && ac && res && screen, "invalid argument");
1428 case MRP_RESOURCE_EVENT_CREATED:
1429 mrp_debug("screen resource in zone '%s' created", zonename);
1430 screen_resource_create(screen, zone, res, ac);
1433 case MRP_RESOURCE_EVENT_DESTROYED:
1434 mrp_debug("screen resource in zone '%s' destroyed", zonename);
1435 screen_resource_destroy(screen, zone, res);
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;
1443 screen_resource_raise_to_top(screen, sr);
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;
1451 screen_resource_lower_to_bottom(screen, sr);
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);
1461 mrp_log_error("system-controller: invalid event %d at screen "
1462 "notification (zone '%s')", event, zonename);
1467 static void screen_init(mrp_zone_t *zone, void *userdata)
1469 mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1471 const char *zonename;
1473 MRP_ASSERT(zone && screen, "invalid argument");
1475 zoneid = mrp_zone_get_id(zone);
1476 zonename = mrp_zone_get_name(zone);
1479 zonename = "<unknown>";
1481 mrp_debug("screen init in zone '%s'", zonename);
1483 mrp_resmgr_notifier_queue_screen_event(screen->resmgr,
1485 MRP_RESMGR_EVENTID_INIT,
1486 "<unknown>", -1, -1, "<unknown>");
1487 screen_grant_resources(screen, zone);
1489 mrp_resmgr_notifier_flush_screen_events(screen->resmgr, zoneid);
1492 static bool screen_allocate(mrp_zone_t *zone,
1493 mrp_resource_t *res,
1496 mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1498 const char *zonename;
1499 const char *appid = get_appid_for_resource(res);
1500 screen_resource_t *sr;
1504 MRP_ASSERT(zone && res && screen && screen->resmgr, "invalid argument");
1506 zoneid = mrp_zone_get_id(zone);
1507 grantid = screen->grantids[zoneid];
1509 if (!(zonename = mrp_zone_get_name(zone)))
1510 zonename = "<unknown>";
1511 if (!(appid = get_appid_for_resource(res)))
1512 appid = "<unknown>";
1514 if ((sr = screen_resource_lookup(screen, res))) {
1515 allocated = (sr->grantid == grantid);
1517 mrp_debug("screen allocation for '%s' in zone '%s' %s",
1518 zonename, appid, allocated ? "succeeded":"failed");
1523 mrp_log_error("system-controller: attempt to allocate untracked "
1524 "resource '%s' in zone '%s'", appid, zonename);
1529 static void screen_free(mrp_zone_t *zone, mrp_resource_t *res, void *userdata)
1531 mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1532 const char *zonename;
1534 screen_resource_t *sr;
1536 MRP_ASSERT(zone && res && screen, "invalid argument");
1538 if (!(zonename = mrp_zone_get_name(zone)))
1539 zonename = "<unknown>";
1540 if (!(appid = get_appid_for_resource(res)))
1541 appid = "<unknown>";
1543 mrp_debug("free screen of '%s' in zone '%s'", appid, zonename);
1545 if ((sr = screen_resource_lookup(screen, res)))
1549 static bool screen_advice(mrp_zone_t *zone,mrp_resource_t *res,void *userdata)
1551 mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1552 const char *zonename;
1555 MRP_ASSERT(zone && res && screen, "invalid argument");
1557 if (!(zonename = mrp_zone_get_name(zone)))
1558 zonename = "<unknown>";
1559 if (!(appid = get_appid_for_resource(res)))
1560 appid = "<unknown>";
1562 mrp_debug("screen advice for '%s' in zone '%s'", appid, zonename);
1567 static void screen_commit(mrp_zone_t *zone, void *userdata)
1569 mrp_resmgr_screen_t *screen = (mrp_resmgr_screen_t *)userdata;
1570 const char *zonename;
1573 MRP_ASSERT(zone && screen && screen->resmgr, "invalid argument");
1575 zoneid = mrp_zone_get_id(zone);
1577 if (!(zonename = mrp_zone_get_name(zone)))
1578 zonename = "<unknown>";
1580 mrp_debug("screen commit in zone '%s'", zonename);
1582 screen_queue_events(screen, zone);
1583 mrp_resmgr_notifier_flush_screen_events(screen->resmgr, zoneid);