free_region(struct surface_region * reg)1 static void free_region(struct surface_region* reg)
2 {
3 struct surface_region* last = reg;
4
5 while (last){
6 struct surface_region* next = last->next;
7 last->next = NULL;
8 free(last);
9 last = next;
10 }
11 }
12
region_destroy(struct wl_client * client,struct wl_resource * res)13 static void region_destroy(struct wl_client* client, struct wl_resource* res)
14 {
15 trace(TRACE_REGION, "region_destroy");
16 free_region(wl_resource_get_user_data(res));
17 }
18
duplicate_region(struct surface_region * reg)19 static struct surface_region* duplicate_region(struct surface_region* reg)
20 {
21 struct surface_region* res = malloc(sizeof(struct surface_region));
22 if (!res)
23 return NULL;
24
25 memcpy(res, reg, sizeof(struct surface_region));
26
27 while (reg->next){
28 res->next = malloc(sizeof(struct surface_region));
29 if (!res->next)
30 return res;
31
32 memcpy(res->next, reg->next, sizeof(struct surface_region));
33 reg = reg->next;
34 }
35
36 return res;
37 }
38
find_free_region_slot(struct surface_region * reg,size_t max_depth)39 static struct region* find_free_region_slot(
40 struct surface_region* reg, size_t max_depth)
41 {
42 for (size_t i = 0; i < max_depth; i++){
43 for (size_t j = 0; j < COUNT_OF(reg->regions); j++){
44 if (reg->regions[j].op == REGION_OP_IGNORE)
45 return ®->regions[j];
46 }
47
48 if (!reg->next && i < max_depth - 1){
49 struct surface_region* nr = malloc(sizeof(struct surface_region));
50 *nr = (struct surface_region){0};
51 reg->next = nr;
52 }
53
54 reg = reg->next;
55 }
56
57 return NULL;
58 }
59
60 /* protocol unspecified with negative width, negative height - more ambitious
61 * would be the sort/merge/split set of operations to make intersect/union/...
62 * more bearable */
coord_to_reg(struct region * reg,int32_t x,int32_t y,int32_t width,int32_t height)63 static void coord_to_reg(struct region* reg,
64 int32_t x, int32_t y, int32_t width, int32_t height)
65 {
66 size_t x1 = x;
67 size_t y1 = y;
68 size_t x2 = x + width;
69 size_t y2 = y + height;
70
71 if (width < 0){
72 x2 = x;
73 x1 = x + width;
74 }
75
76 if (height < 0){
77 y2 = y;
78 y1 = y + height;
79 }
80 reg->x1 = x1;
81 reg->x2 = x2;
82 reg->y1 = y1;
83 reg->y2 = y2;
84 }
85
region_add(struct wl_client * client,struct wl_resource * res,int32_t x,int32_t y,int32_t width,int32_t height)86 static void region_add(struct wl_client* client,
87 struct wl_resource* res, int32_t x, int32_t y, int32_t width, int32_t height)
88 {
89 trace(TRACE_REGION,
90 "region_add(%"PRId32", %"PRId32", +%"PRId32", +%"PRId32")", x, y, width, height);
91 struct surface_region* reg = wl_resource_get_user_data(res);
92 struct region* nr = find_free_region_slot(reg, 4);
93 if (!nr)
94 return;
95
96 coord_to_reg(nr, x, y, width, height);
97 nr->op = REGION_OP_ADD;
98 }
99
region_sub(struct wl_client * client,struct wl_resource * res,int32_t x,int32_t y,int32_t width,int32_t height)100 static void region_sub(struct wl_client* client,
101 struct wl_resource* res, int32_t x, int32_t y, int32_t width, int32_t height)
102 {
103 trace(TRACE_REGION,
104 "region_sub(%"PRId32", %"PRId32", +%"PRId32", +%"PRId32")", x, y, width, height);
105 struct surface_region* reg = wl_resource_get_user_data(res);
106 struct region* nr = find_free_region_slot(reg, 4);
107 if (!nr)
108 return;
109
110 coord_to_reg(nr, x, y, width, height);
111 nr->op = REGION_OP_SUB;
112 }
113