impelement libds-tizen-clipboard
[platform/core/uifw/libds-tizen.git] / src / clipboard / clipboard.c
1 #include <assert.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <wayland-server.h>
5 #include <tizen-extension-server-protocol.h>
6 #include <libds/log.h>
7
8 #include "util.h"
9 #include "libds-tizen/clipboard.h"
10
11 #define TIZEN_CLIPBOARD_VERSION 2
12
13 struct ds_tizen_clipboard
14 {
15     struct wl_global *global;
16
17     struct wl_list clients;
18
19     struct wl_listener destroy;
20
21     struct {
22         struct wl_signal destroy;
23         struct wl_signal show;
24         struct wl_signal hide;
25         struct wl_signal set_data_only;
26     } events;
27 };
28
29 struct ds_tizen_clipboard_client
30 {
31     struct ds_tizen_clipboard *clipboard;
32
33     struct wl_resource *resource;
34     struct wl_client *wl_client;
35
36     struct wl_list infos;
37
38     uint32_t data_only;
39
40     struct wl_list link; // ds_tizen_clipboard::clients
41 };
42
43 struct ds_tizen_clipboard_info
44 {
45     struct ds_surface *surface;
46
47     struct wl_list link; // ds_tizen_clipboard_client::infos
48 };
49
50 static void clipboard_handle_display_destroy(struct wl_listener *listener,
51         void *data);
52
53 static void clipboard_bind(struct wl_client *wl_client, void *data,
54         uint32_t version, uint32_t id);
55
56 static struct ds_tizen_clipboard_client *tizen_clipboard_find_client(
57     struct ds_tizen_clipboard *clipboard,
58     struct ds_surface *surface);
59
60 static struct ds_tizen_clipboard_info *tizen_clipboard_client_find_info(
61     struct ds_tizen_clipboard_client *client,
62     struct ds_surface *surface);
63
64 static struct ds_tizen_clipboard_info *tizen_clipboard_client_get_info(
65         struct ds_tizen_clipboard_client *client,
66         struct ds_surface *surface);
67
68 WL_EXPORT struct ds_tizen_clipboard *
69 ds_tizen_clipboard_create(struct wl_display *display)
70 {
71     struct ds_tizen_clipboard *clipboard;
72
73     clipboard = calloc(1, sizeof *clipboard);
74     if (!clipboard) {
75         ds_err("calloc() failed.");
76         return NULL;
77     }
78
79     clipboard->global = wl_global_create(display, &tizen_clipboard_interface,
80             TIZEN_CLIPBOARD_VERSION, clipboard, clipboard_bind);
81     if (!clipboard->global) {
82         ds_err("wl_global_create() failed. tizen_clipboard_interface");
83         free(clipboard);
84         return NULL;
85     }
86
87     wl_list_init(&clipboard->clients);
88
89     clipboard->destroy.notify = clipboard_handle_display_destroy;
90     wl_display_add_destroy_listener(display, &clipboard->destroy);
91
92     wl_signal_init(&clipboard->events.destroy);
93     wl_signal_init(&clipboard->events.show);
94     wl_signal_init(&clipboard->events.hide);
95     wl_signal_init(&clipboard->events.set_data_only);
96
97         ds_inf("Global created: tizen_clipboard(%p)", clipboard);
98
99     return clipboard;
100 }
101
102 WL_EXPORT void
103 ds_tizen_clipboard_add_destroy_listener(struct ds_tizen_clipboard *clipboard,
104         struct wl_listener *listener)
105 {
106     wl_signal_add(&clipboard->events.destroy, listener);
107 }
108
109 WL_EXPORT void
110 ds_tizen_clipboard_add_show_listener(
111     struct ds_tizen_clipboard *clipboard, struct wl_listener *listener)
112 {
113     wl_signal_add(&clipboard->events.show, listener);
114 }
115
116 WL_EXPORT void
117 ds_tizen_clipboard_add_hide_listener(
118     struct ds_tizen_clipboard *clipboard, struct wl_listener *listener)
119 {
120     wl_signal_add(&clipboard->events.hide, listener);
121 }
122
123 WL_EXPORT void
124 ds_tizen_clipboard_add_set_data_only_listener(
125     struct ds_tizen_clipboard *clipboard, struct wl_listener *listener)
126 {
127     wl_signal_add(&clipboard->events.set_data_only, listener);
128 }
129
130 WL_EXPORT uint32_t
131 ds_tizen_clipboard_client_get_data_only(
132         struct ds_tizen_clipboard_client *client)
133 {
134     return client->data_only;
135 }
136
137 WL_EXPORT void
138 ds_tizen_clipboard_send_data_selected(struct ds_tizen_clipboard *clipboard,
139         struct ds_surface *surface)
140 {
141     struct ds_tizen_clipboard_client *client;
142
143     client = tizen_clipboard_find_client(clipboard, surface);
144     if (client == NULL) {
145         ds_err("tizen_clipboard: tizen_clipboard_find_client() failed.");
146         return;
147     }
148
149     tizen_clipboard_send_data_selected(client->resource,
150         ds_surface_get_wl_resource(surface));
151 }
152
153 WL_EXPORT void
154 ds_tizen_clipboard_client_send_allowed_data_only(
155     struct ds_tizen_clipboard_client *client, uint32_t allowed)
156 {
157     tizen_clipboard_send_allowed_data_only(client->resource, allowed);
158 }
159
160 static struct ds_tizen_clipboard_client *
161 tizen_clipboard_find_client(struct ds_tizen_clipboard *clipboard,
162     struct ds_surface *surface)
163 {
164     struct ds_tizen_clipboard_info *info;
165     struct ds_tizen_clipboard_client *client;
166
167     wl_list_for_each(client, &clipboard->clients, link) {
168         info = tizen_clipboard_client_find_info(client, surface);
169         if (info != NULL)
170             return client;
171     }
172
173     return NULL;
174 }
175
176 static struct ds_tizen_clipboard_info *
177 tizen_clipboard_client_find_info(struct ds_tizen_clipboard_client *client,
178     struct ds_surface *surface)
179 {
180     struct ds_tizen_clipboard_info *info;
181
182     wl_list_for_each(info, &client->infos, link) {
183         if (surface == info->surface)
184             return info;
185     }
186
187     return NULL;
188 }
189
190 static struct ds_tizen_clipboard_info *
191 tizen_clipboard_client_get_info(struct ds_tizen_clipboard_client *client,
192     struct ds_surface *surface)
193 {
194     struct ds_tizen_clipboard_info *info;
195
196     info = tizen_clipboard_client_find_info(client, surface);
197     if (info)
198         return info;
199
200     info = calloc(1, sizeof *info);
201     if (info == NULL) {
202         ds_err("calloc() failed. tizen_clipboard");
203         return NULL;
204     }
205
206     info->surface = surface;
207
208     wl_list_insert(&client->infos, &info->link);
209
210     return info;
211 }
212
213 static void
214 clipboard_handle_display_destroy(struct wl_listener *listener, void *data)
215 {
216     struct ds_tizen_clipboard *clipboard;
217
218     clipboard = wl_container_of(listener, clipboard, destroy);
219
220     ds_inf("Global destroy: clipboard(%p)", clipboard);
221
222     wl_signal_emit(&clipboard->events.destroy, clipboard);
223     wl_list_remove(&clipboard->destroy.link);
224     wl_global_destroy(clipboard->global);
225     free(clipboard);
226 }
227
228 static void
229 clipboard_handle_destroy(struct wl_client *wl_client,
230     struct wl_resource *resource)
231 {
232     struct ds_tizen_clipboard_client *client;
233
234     client = wl_resource_get_user_data(resource);
235
236     if (!wl_list_empty(&client->infos)) {
237         ds_err("tizen_clipboard was destroyed before children");
238         return;
239     }
240
241     wl_resource_destroy(resource);
242 }
243
244 static void
245 clipboard_handle_show(struct wl_client *wl_client,
246     struct wl_resource *resource, struct wl_resource *surface_resource)
247 {
248     struct ds_tizen_clipboard_client *client;
249     struct ds_tizen_clipboard_info *info;
250     struct ds_surface *surface;
251
252     ds_inf("tizen_clipboard: show");
253
254     client = wl_resource_get_user_data(resource);
255     surface = ds_surface_from_resource(surface_resource);
256
257     info = tizen_clipboard_client_get_info(client, surface);
258     if (info == NULL) {
259         ds_err("tizen_clipboard_client_get_info() failed. tizen_clipboard");
260         wl_client_post_no_memory(wl_client);
261         return;
262     }
263
264     wl_signal_emit(&client->clipboard->events.show, surface);
265 }
266
267 static void
268 clipboard_handle_hide(struct wl_client *wl_client,
269     struct wl_resource *resource, struct wl_resource *surface_resource)
270 {
271     struct ds_tizen_clipboard_client *client;
272     struct ds_tizen_clipboard_info *info;
273     struct ds_surface *surface;
274
275     ds_inf("tizen_clipboard: hide");
276
277     client = wl_resource_get_user_data(resource);
278     surface = ds_surface_from_resource(surface_resource);
279
280     info = tizen_clipboard_client_get_info(client, surface);
281     if (info == NULL) {
282         ds_err("tizen_clipboard_client_get_info() failed. tizen_clipboard");
283         wl_client_post_no_memory(wl_client);
284         return;
285     }
286
287     wl_signal_emit(&client->clipboard->events.hide, surface);
288 }
289
290 static void
291 clipboard_handle_set_data_only(struct wl_client *wl_client,
292     struct wl_resource *resource, uint32_t set)
293 {
294     struct ds_tizen_clipboard_client *client;
295
296     ds_inf("tizen_clipboard: set_data_only. set(%d)", set);
297
298     client = wl_resource_get_user_data(resource);
299     client->data_only = set;
300
301     wl_signal_emit(&client->clipboard->events.set_data_only, client);
302 }
303
304 static const struct tizen_clipboard_interface clipboard_impl =
305 {
306    clipboard_handle_destroy,
307    clipboard_handle_show,
308    clipboard_handle_hide,
309    clipboard_handle_set_data_only,
310 };
311
312 static void
313 _tizen_clipboard_client_handle_destroy(struct wl_resource *resource)
314 {
315     struct ds_tizen_clipboard_client *client;
316     struct ds_tizen_clipboard_info *info, *tmp;
317
318     client = wl_resource_get_user_data(resource);
319
320     ds_inf("_tizen_clipboard_client_handle_destroy (client:%p)", client);
321
322     wl_list_for_each_safe(info, tmp, &client->infos, link) {
323         wl_list_remove(&info->link);
324         free(info);
325     }
326
327     wl_list_remove(&client->link);
328     free(client);
329 }
330
331 static void
332 clipboard_bind(struct wl_client *wl_client, void *data, uint32_t version,
333         uint32_t id)
334 {
335     struct ds_tizen_clipboard *clipboard = data;
336     struct ds_tizen_clipboard_client *client;
337
338     client = calloc(1, sizeof *client);
339     if (client == NULL) {
340         ds_err("calloc() failed. tizen_clipboard");
341         wl_client_post_no_memory(wl_client);
342         return;
343     }
344
345     ds_inf("tizen_clipboard_client binds. (client:%p)", client);
346
347     client->clipboard = clipboard;
348     client->wl_client = wl_client;
349
350     wl_list_init(&client->infos);
351
352     client->resource = wl_resource_create(wl_client, &tizen_clipboard_interface,
353             MIN(version, TIZEN_CLIPBOARD_VERSION), id);
354
355     if (client->resource == NULL) {
356         ds_err("tizen_clipboard : wl_resource_create() failed.");
357         free(client);
358         wl_client_post_no_memory(wl_client);
359         return;
360     }
361
362     wl_resource_set_implementation(client->resource, &clipboard_impl, client,
363             _tizen_clipboard_client_handle_destroy);
364
365     wl_list_insert(&clipboard->clients, &client->link);
366 }