scaler: Fix missing free for allocated resources
[platform/core/uifw/libds-tizen.git] / src / scaler / scaler.c
1 #include <stdlib.h>
2
3 #include <wayland-server.h>
4 #include <scaler-server-protocol.h>
5
6 #include <libds/log.h>
7 #include <libds/surface.h>
8
9 #define SCALER_VERSION 2
10
11 struct ds_tizen_scaler
12 {
13     struct wl_global *global;
14
15     struct wl_listener display_destroy;
16 };
17
18 struct viewport
19 {
20     struct wl_resource *resource;
21     struct ds_surface_viewport *surface_viewport;
22
23     struct wl_listener surface_destroy;
24     struct wl_listener surface_commit;
25 };
26
27 static void scaler_bind(struct wl_client *client, void *data, uint32_t version,
28         uint32_t id);
29 static void scaler_handle_display_destroy(struct wl_listener *listener,
30         void *data);
31 static void viewport_set_source(struct viewport *viewport,
32         wl_fixed_t x_fixed, wl_fixed_t y_fixed,
33         wl_fixed_t width_fixed, wl_fixed_t height_fixed);
34 static void viewport_set_destination(struct viewport *viewport,
35         int32_t width, int32_t height);
36
37 struct ds_tizen_scaler *
38 ds_tizen_scaler_create(struct wl_display *display)
39 {
40     struct ds_tizen_scaler *scaler;
41
42     scaler = calloc(1, sizeof *scaler);
43     if (!scaler)
44         return NULL;
45
46     scaler->global = wl_global_create(display, &wl_scaler_interface,
47             SCALER_VERSION, NULL, scaler_bind);
48     if (!scaler->global) {
49         free(scaler);
50         return NULL;
51     }
52
53     scaler->display_destroy.notify = scaler_handle_display_destroy;
54     wl_display_add_destroy_listener(display, &scaler->display_destroy);
55
56     return scaler;
57 }
58
59 static void
60 viewport_destroy(struct viewport *viewport)
61 {
62     ds_surface_viewport_release(viewport->surface_viewport);
63
64     wl_resource_set_user_data(viewport->resource, NULL);
65     wl_list_remove(&viewport->surface_commit.link);
66     wl_list_remove(&viewport->surface_destroy.link);
67     free(viewport);
68 }
69
70 static void
71 viewport_handle_destroy(struct wl_client *client, struct wl_resource *resource)
72 {
73     wl_resource_destroy(resource);
74 }
75
76 static void
77 viewport_handle_set(struct wl_client *client, struct wl_resource *resource,
78         wl_fixed_t src_x, wl_fixed_t src_y,
79         wl_fixed_t src_width, wl_fixed_t src_height,
80         int32_t dst_width, int32_t dst_height)
81 {
82     struct viewport *viewport;
83
84     viewport = wl_resource_get_user_data(resource);
85     if (!viewport) {
86         ds_err("wl_viewport@%d.set sent after wl_surface has been destroyed",
87                 wl_resource_get_id(resource));
88         return;
89     }
90
91     viewport_set_source(viewport, src_x, src_y, src_width, src_height);
92     viewport_set_destination(viewport, dst_width, dst_height);
93 }
94
95 static void
96 viewport_handle_set_source(struct wl_client *client,
97         struct wl_resource *resource, wl_fixed_t x, wl_fixed_t y,
98         wl_fixed_t width, wl_fixed_t height)
99 {
100     struct viewport *viewport;
101
102     viewport = wl_resource_get_user_data(resource);
103     if (!viewport) {
104         ds_err("wl_viewport@%d.set_source sent after wl_surface has been "
105                 "destroyed", wl_resource_get_id(resource));
106         return;
107     }
108
109     viewport_set_source(viewport, x, y, width, height);
110 }
111
112 static void
113 viewport_handle_set_destination(struct wl_client *client,
114         struct wl_resource *resource, int32_t width, int32_t height)
115 {
116     struct viewport *viewport;
117
118     viewport = wl_resource_get_user_data(resource);
119     if (!viewport) {
120         ds_err("wl_viewport@%d.set_destination sent after wl_surface has been "
121                 "destroyed", wl_resource_get_id(resource));
122         return;
123     }
124
125     viewport_set_destination(viewport, width, height);
126 }
127
128 static const struct wl_viewport_interface viewport_iface = {
129     .destroy = viewport_handle_destroy,
130     .set = viewport_handle_set,
131     .set_source = viewport_handle_set_source,
132     .set_destination = viewport_handle_set_destination,
133 };
134
135 static void
136 viewport_handle_surface_destroy(struct wl_listener *listener, void *data)
137 {
138     struct viewport *viewport;
139
140     viewport = wl_container_of(listener, viewport, surface_destroy);
141     viewport_destroy(viewport);
142 }
143
144 static void
145 viewport_handle_resource_destroy(struct wl_resource *resource)
146 {
147     struct viewport *viewport;
148
149     viewport = wl_resource_get_user_data(resource);
150     if (viewport)
151         viewport_destroy(viewport);
152 }
153
154 static void
155 viewport_handle_surface_commit(struct wl_listener *listener, void *data)
156 {
157     struct viewport *viewport;
158
159     viewport = wl_container_of(listener, viewport, surface_commit);
160
161     // TODO
162 }
163
164 static void
165 scaler_handle_destroy(struct wl_client *client, struct wl_resource *resource)
166 {
167     wl_resource_destroy(resource);
168 }
169
170 static void
171 scaler_handle_get_viewport(struct wl_client *client,
172         struct wl_resource *resource, uint32_t id,
173         struct wl_resource *surface_resource)
174 {
175     struct viewport *viewport;
176     struct ds_surface *surface;
177     struct ds_surface_viewport *surface_viewport;
178
179     surface = ds_surface_from_resource(surface_resource);
180     surface_viewport = ds_surface_take_viewport(surface);
181     if (!surface_viewport) {
182         wl_resource_post_error(resource, WL_SCALER_ERROR_VIEWPORT_EXISTS,
183                 "a viewport for that surface already exists");
184         return;
185     }
186
187     viewport = calloc(1, sizeof *viewport);
188     if (!viewport)
189         goto err_alloc;
190
191     viewport->resource = wl_resource_create(client, &wl_viewport_interface,
192             wl_resource_get_version(resource), id);
193     if (!viewport->resource)
194         goto err_resource;
195
196     wl_resource_set_implementation(viewport->resource, &viewport_iface,
197             viewport, viewport_handle_resource_destroy);
198
199     viewport->surface_viewport = surface_viewport;
200
201     viewport->surface_destroy.notify = viewport_handle_surface_destroy;
202     ds_surface_add_destroy_listener(surface, &viewport->surface_destroy);
203
204     viewport->surface_commit.notify = viewport_handle_surface_commit;
205     ds_surface_add_commit_listener(surface, &viewport->surface_commit);
206
207     return;
208 err_resource:
209     wl_resource_post_no_memory(resource);
210     free(viewport);
211 err_alloc:
212     ds_surface_viewport_release(surface_viewport);
213 }
214
215 static const struct wl_scaler_interface scaler_iface = {
216     .destroy = scaler_handle_destroy,
217     .get_viewport = scaler_handle_get_viewport,
218 };
219
220 static void
221 scaler_bind(struct wl_client *client, void *data, uint32_t version,
222         uint32_t id)
223 {
224     struct wl_resource *resource;
225     uint32_t bind_version;
226
227     bind_version = version < SCALER_VERSION ? version : SCALER_VERSION;
228     resource = wl_resource_create(client, &wl_scaler_interface, bind_version,
229             id);
230     if (!resource) {
231         wl_client_post_no_memory(client);
232         return;
233     }
234     wl_resource_set_implementation(resource, &scaler_iface, NULL, NULL);
235 }
236
237 static void
238 scaler_handle_display_destroy(struct wl_listener *listener, void *data)
239 {
240     struct ds_tizen_scaler *scaler;
241
242     scaler = wl_container_of(listener, scaler, display_destroy);
243     wl_list_remove(&scaler->display_destroy.link);
244     wl_global_destroy(scaler->global);
245     free(scaler);
246 }
247
248 static void
249 viewport_set_source(struct viewport *viewport,
250         wl_fixed_t x_fixed, wl_fixed_t y_fixed,
251         wl_fixed_t width_fixed, wl_fixed_t height_fixed)
252 {
253     double x, y, width, height;
254
255     x = wl_fixed_to_double(x_fixed);
256     y = wl_fixed_to_double(y_fixed);
257     width = wl_fixed_to_double(width_fixed);
258     height = wl_fixed_to_double(height_fixed);
259
260     if (width == -1.0 && height == -1.0) {
261         ds_surface_viewport_unset_source(viewport->surface_viewport);
262     }
263     else if (x < 0 || y < 0 || width <= 0 || height <= 0) {
264         ds_inf("wl_viewport.set_source sent with invalid values (%f %f %fx%f)",
265                 x, y, width, height);
266         if (width <= 0 || height <= 0) {
267             wl_resource_post_error(viewport->resource,
268                     WL_VIEWPORT_ERROR_BAD_VALUE,
269                     "wl_viewport.set_source sent with invalid values");
270         }
271     }
272     else {
273         ds_surface_viewport_set_source(viewport->surface_viewport,
274                 x, y, width, height);
275     }
276 }
277
278 static void
279 viewport_set_destination(struct viewport *viewport,
280         int32_t width, int32_t height)
281 {
282     if (width == -1 && height == -1) {
283         ds_surface_viewport_unset_destination(viewport->surface_viewport);
284     }
285     else if (width <= 0 || height <= 0) {
286         wl_resource_post_error(viewport->resource, WL_VIEWPORT_ERROR_BAD_VALUE,
287                 "destination size must be positive (%dx%d)",
288                 width, height);
289     }
290     else {
291         ds_surface_viewport_set_destination(viewport->surface_viewport,
292                 width, height);
293     }
294 }