Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_wayland / ecore_wl.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <fcntl.h>
6 #include "ecore_wl_private.h"
7
8 /* local function prototypes */
9 static Eina_Bool _ecore_wl_shutdown(Eina_Bool close);
10 static int _ecore_wl_cb_event_mask_update(unsigned int mask, void *data);
11 static Eina_Bool _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl __UNUSED__);
12 static void _ecore_wl_cb_handle_global(struct wl_display *disp, unsigned int id, const char *interface, unsigned int version __UNUSED__, void *data);
13 static Eina_Bool _ecore_wl_xkb_init(Ecore_Wl_Display *ewd);
14 static Eina_Bool _ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd);
15
16 /* local variables */
17 static int _ecore_wl_init_count = 0;
18
19 /* external variables */
20 int _ecore_wl_log_dom = -1;
21 Ecore_Wl_Display *_ecore_wl_disp = NULL;
22
23 EAPI int ECORE_WL_EVENT_MOUSE_IN = 0;
24 EAPI int ECORE_WL_EVENT_MOUSE_OUT = 0;
25 EAPI int ECORE_WL_EVENT_FOCUS_IN = 0;
26 EAPI int ECORE_WL_EVENT_FOCUS_OUT = 0;
27 EAPI int ECORE_WL_EVENT_WINDOW_CONFIGURE = 0;
28 EAPI int ECORE_WL_EVENT_DND_ENTER = 0;
29 EAPI int ECORE_WL_EVENT_DND_POSITION = 0;
30 EAPI int ECORE_WL_EVENT_DND_LEAVE = 0;
31 EAPI int ECORE_WL_EVENT_DND_DROP = 0;
32 EAPI int ECORE_WL_EVENT_DATA_SOURCE_TARGET = 0;
33 EAPI int ECORE_WL_EVENT_DATA_SOURCE_SEND = 0;
34 EAPI int ECORE_WL_EVENT_SELECTION_DATA_READY = 0;
35 EAPI int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = 0;
36 EAPI int ECORE_WL_EVENT_INTERFACES_BOUND = 0;
37
38 /**
39  * @defgroup Ecore_Wl_Init_Group Wayland Library Init and Shutdown Functions
40  * 
41  * Functions that start and shutdown the Ecore Wayland Library.
42  */
43
44 /**
45  * Initialize the Wayland display connection to the given display.
46  * 
47  * @param   name Display target name. if @c NULL, the default display is 
48  *          assumed.
49  * @return  The number of times the library has been initialized without being 
50  *          shut down. 0 is returned if an error occurs.
51  * 
52  * @ingroup Ecore_Wl_Init_Group
53  */
54 EAPI int 
55 ecore_wl_init(const char *name)
56 {
57    LOGFN(__FILE__, __LINE__, __FUNCTION__);
58
59    if (++_ecore_wl_init_count != 1) return _ecore_wl_init_count;
60
61    if (!eina_init()) return --_ecore_wl_init_count;
62
63    _ecore_wl_log_dom = 
64      eina_log_domain_register("ecore_wl", ECORE_WL_DEFAULT_LOG_COLOR);
65    if (_ecore_wl_log_dom < 0)
66      {
67         EINA_LOG_ERR("Cannot create a log domain for Ecore Wayland");
68         eina_shutdown();
69         return --_ecore_wl_init_count;
70      }
71
72    if (!ecore_init())
73      {
74         ERR("Could not initialize ecore");
75         eina_log_domain_unregister(_ecore_wl_log_dom);
76         _ecore_wl_log_dom = -1;
77         eina_shutdown();
78         return --_ecore_wl_init_count;
79      }
80
81    if (!ecore_event_init())
82      {
83         ERR("Could not initialize ecore_event");
84         eina_log_domain_unregister(_ecore_wl_log_dom);
85         _ecore_wl_log_dom = -1;
86         ecore_shutdown();
87         eina_shutdown();
88         return --_ecore_wl_init_count;
89      }
90
91    if (!ECORE_WL_EVENT_MOUSE_IN)
92      {
93         ECORE_WL_EVENT_MOUSE_IN = ecore_event_type_new();
94         ECORE_WL_EVENT_MOUSE_OUT = ecore_event_type_new();
95         ECORE_WL_EVENT_FOCUS_IN = ecore_event_type_new();
96         ECORE_WL_EVENT_FOCUS_OUT = ecore_event_type_new();
97         ECORE_WL_EVENT_WINDOW_CONFIGURE = ecore_event_type_new();
98         ECORE_WL_EVENT_DND_ENTER = ecore_event_type_new();
99         ECORE_WL_EVENT_DND_POSITION = ecore_event_type_new();
100         ECORE_WL_EVENT_DND_LEAVE = ecore_event_type_new();
101         ECORE_WL_EVENT_DND_DROP = ecore_event_type_new();
102         ECORE_WL_EVENT_DATA_SOURCE_TARGET = ecore_event_type_new();
103         ECORE_WL_EVENT_DATA_SOURCE_SEND = ecore_event_type_new();
104         ECORE_WL_EVENT_SELECTION_DATA_READY = ecore_event_type_new();
105         ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = ecore_event_type_new();
106         ECORE_WL_EVENT_INTERFACES_BOUND = ecore_event_type_new();
107      }
108
109    if (!(_ecore_wl_disp = malloc(sizeof(Ecore_Wl_Display))))
110      {
111         ERR("Could not allocate memory for Ecore_Wl_Display structure");
112         eina_log_domain_unregister(_ecore_wl_log_dom);
113         _ecore_wl_log_dom = -1;
114         ecore_event_shutdown();
115         ecore_shutdown();
116         eina_shutdown();
117         return --_ecore_wl_init_count;
118      }
119
120    memset(_ecore_wl_disp, 0, sizeof(Ecore_Wl_Display));
121
122    if (!(_ecore_wl_disp->wl.display = wl_display_connect(name)))
123      {
124         ERR("Could not connect to Wayland display");
125         eina_log_domain_unregister(_ecore_wl_log_dom);
126         _ecore_wl_log_dom = -1;
127         ecore_event_shutdown();
128         ecore_shutdown();
129         eina_shutdown();
130         return --_ecore_wl_init_count;
131      }
132
133    _ecore_wl_disp->fd = 
134      wl_display_get_fd(_ecore_wl_disp->wl.display, 
135                        _ecore_wl_cb_event_mask_update, _ecore_wl_disp);
136
137    _ecore_wl_disp->fd_hdl = 
138      ecore_main_fd_handler_add(_ecore_wl_disp->fd, ECORE_FD_READ, 
139                                _ecore_wl_cb_handle_data, _ecore_wl_disp, 
140                                NULL, NULL);
141
142    wl_list_init(&_ecore_wl_disp->inputs);
143    wl_list_init(&_ecore_wl_disp->outputs);
144
145    wl_display_add_global_listener(_ecore_wl_disp->wl.display, 
146                                   _ecore_wl_cb_handle_global, _ecore_wl_disp);
147
148    /* Init egl */
149
150    /* FIXME: Process connection events ?? */
151    /* wl_display_iterate(_ecore_wl_disp->wl.display, WL_DISPLAY_READABLE); */
152
153    /* TODO: create pointer surfaces */
154
155    if (!_ecore_wl_xkb_init(_ecore_wl_disp))
156      {
157         ERR("Could not initialize XKB");
158         free(_ecore_wl_disp);
159         eina_log_domain_unregister(_ecore_wl_log_dom);
160         _ecore_wl_log_dom = -1;
161         ecore_event_shutdown();
162         ecore_shutdown();
163         eina_shutdown();
164         return --_ecore_wl_init_count;
165      }
166
167    _ecore_wl_window_init();
168
169    return _ecore_wl_init_count;
170 }
171
172 /**
173  * Shuts down the Ecore Wayland Library
174  * 
175  * In shutting down the library, the Wayland display connection is terminated 
176  * and any event handlers for it are removed.
177  * 
178  * @return  The number of times the library has been initialized without 
179  *          being shut down.
180  * 
181  * @ingroup Ecore_Wl_Init_Group
182  */
183 EAPI int 
184 ecore_wl_shutdown(void)
185 {
186    LOGFN(__FILE__, __LINE__, __FUNCTION__);
187
188    return _ecore_wl_shutdown(EINA_TRUE);
189 }
190
191 /**
192  * @defgroup Ecore_Wl_Flush_Group Wayland Synchronization Functions
193  * 
194  * Functions that ensure that all commands which have been issued by the 
195  * Ecore Wayland library have been sent to the server.
196  */
197
198 /**
199  * Sends all Wayland commands to the Wayland Display.
200  * 
201  * @ingroup Ecore_Wl_Flush_Group
202  * @since 1.2
203  */
204 EAPI void 
205 ecore_wl_flush(void)
206 {
207 //   LOGFN(__FILE__, __LINE__, __FUNCTION__);
208
209    while (_ecore_wl_disp->mask & WL_DISPLAY_WRITABLE)
210      wl_display_iterate(_ecore_wl_disp->wl.display, WL_DISPLAY_WRITABLE);
211 }
212
213 /**
214  * Flushes the command buffer and waits until all requests have been 
215  * processed by the server.
216  * 
217  * @ingroup Ecore_Wl_Flush_Group
218  * @since 1.2
219  */
220 EAPI void 
221 ecore_wl_sync(void)
222 {
223 //   LOGFN(__FILE__, __LINE__, __FUNCTION__);
224
225    wl_display_sync(_ecore_wl_disp->wl.display);
226 }
227
228 /**
229  * @defgroup Ecore_Wl_Display_Group Wayland Display Functions
230  * 
231  * Functions that set and retrieve various information about the Wayland Display.
232  */
233
234 /**
235  * Retrieves the Wayland Shm Interface used for the current Wayland connection.
236  * 
237  * @return The current wayland shm interface
238  * 
239  * @ingroup Ecore_Wl_Display_Group
240  * @since 1.2
241  */
242 EAPI struct wl_shm *
243 ecore_wl_shm_get(void)
244 {
245    return _ecore_wl_disp->wl.shm;
246 }
247
248 /**
249  * Retrieves the Wayland Display Interface used for the current Wayland connection.
250  * 
251  * @return The current wayland display interface
252  * 
253  * @ingroup Ecore_Wl_Display_Group
254  * @since 1.2
255  */
256 EAPI struct wl_display *
257 ecore_wl_display_get(void)
258 {
259    return _ecore_wl_disp->wl.display;
260 }
261
262 /**
263  * Retrieves the size of the current screen.
264  * 
265  * @param w where to return the width. May be NULL. Returns 0 on error.
266  * @param h where to return the height. May be NULL. Returns 0 on error.
267  * 
268  * @ingroup Ecore_Wl_Display_Group
269  * @since 1.2
270  */
271 EAPI void 
272 ecore_wl_screen_size_get(int *w, int *h)
273 {
274    LOGFN(__FILE__, __LINE__, __FUNCTION__);
275
276    if (w) *w = 0;
277    if (h) *h = 0;
278
279    if (!_ecore_wl_disp->output) return;
280
281    if (w) *w = _ecore_wl_disp->output->allocation.w;
282    if (h) *h = _ecore_wl_disp->output->allocation.h;
283 }
284
285 /* @since 1.2 */
286 EAPI void 
287 ecore_wl_pointer_xy_get(int *x, int *y)
288 {
289    LOGFN(__FILE__, __LINE__, __FUNCTION__);
290
291    _ecore_wl_input_pointer_xy_get(x, y);
292 }
293
294 /**
295  * Return the screen DPI
296  *
297  * This is a simplistic call to get DPI. It does not account for differing
298  * DPI in the x and y axes nor does it account for multihead or xinerama and
299  * xrandr where different parts of the screen may have different DPI etc.
300  *
301  * @return the general screen DPI (dots/pixels per inch).
302  * 
303  * @since 1.2
304  */
305 EAPI int 
306 ecore_wl_dpi_get(void)
307 {
308    int w, mw;
309
310    LOGFN(__FILE__, __LINE__, __FUNCTION__);
311
312    if (!_ecore_wl_disp->output) return 75;
313
314    mw = _ecore_wl_disp->output->mw;
315    if (mw <= 0) return 75;
316
317    w = _ecore_wl_disp->output->allocation.w;
318    /* FIXME: NB: Hrrrmmm, need to verify this. xorg code is using a different 
319     * formula to calc this */
320    return (((w * 254) / mw) + 5) / 10;
321 }
322
323 EAPI void 
324 ecore_wl_display_iterate(void)
325 {
326    wl_display_iterate(_ecore_wl_disp->wl.display, WL_DISPLAY_READABLE);
327 }
328
329 /**
330  * Retrieves the requested cursor from the cursor theme
331  * 
332  * @param cursor_name The desired cursor name to be looked up in the theme
333  * @return the cursor or NULL if the cursor cannot be found
334  *
335  * @since 1.2
336  */
337 EAPI struct wl_cursor *
338 ecore_wl_cursor_get(const char *cursor_name)
339 {
340    if ((!_ecore_wl_disp) || (!_ecore_wl_disp->cursor_theme)) 
341      return NULL;
342
343    return wl_cursor_theme_get_cursor(_ecore_wl_disp->cursor_theme,
344                                      cursor_name);
345 }
346
347 /* local functions */
348 static Eina_Bool 
349 _ecore_wl_shutdown(Eina_Bool close)
350 {
351    LOGFN(__FILE__, __LINE__, __FUNCTION__);
352
353    if (--_ecore_wl_init_count != 0) return _ecore_wl_init_count;
354    if (!_ecore_wl_disp) return _ecore_wl_init_count;
355
356    _ecore_wl_window_shutdown();
357
358    if (_ecore_wl_disp->fd_hdl) 
359      ecore_main_fd_handler_del(_ecore_wl_disp->fd_hdl);
360
361    if (close) 
362      {
363         Ecore_Wl_Output *out, *tout;
364         Ecore_Wl_Input *in, *tin;
365
366         wl_list_for_each_safe(out, tout, &_ecore_wl_disp->outputs, link)
367           _ecore_wl_output_del(out);
368
369         wl_list_for_each_safe(in, tin, &_ecore_wl_disp->inputs, link)
370           _ecore_wl_input_del(in);
371
372         _ecore_wl_xkb_shutdown(_ecore_wl_disp);
373
374         if (_ecore_wl_disp->wl.shell) 
375           wl_shell_destroy(_ecore_wl_disp->wl.shell);
376         if (_ecore_wl_disp->wl.shm) wl_shm_destroy(_ecore_wl_disp->wl.shm);
377         if (_ecore_wl_disp->wl.data_device_manager)
378           wl_data_device_manager_destroy(_ecore_wl_disp->wl.data_device_manager);
379         if (_ecore_wl_disp->wl.compositor)
380           wl_compositor_destroy(_ecore_wl_disp->wl.compositor);
381         if (_ecore_wl_disp->wl.display)
382           {
383              wl_display_flush(_ecore_wl_disp->wl.display);
384              wl_display_disconnect(_ecore_wl_disp->wl.display);
385           }
386         free(_ecore_wl_disp);
387      }
388
389    ecore_event_shutdown();
390    ecore_shutdown();
391
392    eina_log_domain_unregister(_ecore_wl_log_dom);
393    _ecore_wl_log_dom = -1;
394    eina_shutdown();
395
396    return _ecore_wl_init_count;
397 }
398
399 static int 
400 _ecore_wl_cb_event_mask_update(unsigned int mask, void *data)
401 {
402    Ecore_Wl_Display *ewd;
403
404 //   LOGFN(__FILE__, __LINE__, __FUNCTION__);
405
406    ewd = data;
407    ewd->mask = mask;
408    return 0;
409 }
410
411 static Eina_Bool 
412 _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl __UNUSED__)
413 {
414    Ecore_Wl_Display *ewd;
415
416    /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */
417
418    if (!(ewd = data)) return ECORE_CALLBACK_RENEW;
419    wl_display_iterate(ewd->wl.display, ewd->mask);
420    return ECORE_CALLBACK_RENEW;
421 }
422
423 static void 
424 _ecore_wl_cb_handle_global(struct wl_display *disp, unsigned int id, const char *interface, unsigned int version __UNUSED__, void *data)
425 {
426    Ecore_Wl_Display *ewd;
427
428 //   LOGFN(__FILE__, __LINE__, __FUNCTION__);
429
430    ewd = data;
431
432    /* TODO: Add listener for wl_display so we can catch fatal errors !! */
433
434    if (!strcmp(interface, "wl_compositor"))
435      ewd->wl.compositor = wl_display_bind(disp, id, &wl_compositor_interface);
436    else if (!strcmp(interface, "wl_output"))
437      _ecore_wl_output_add(ewd, id);
438    else if (!strcmp(interface, "wl_seat"))
439      _ecore_wl_input_add(ewd, id);
440    else if (!strcmp(interface, "wl_shell"))
441      ewd->wl.shell = wl_display_bind(disp, id, &wl_shell_interface);
442    /* else if (!strcmp(interface, "desktop_shell")) */
443    /*   ewd->wl.desktop_shell = wl_display_bind(disp, id, &wl_shell_interface); */
444    else if (!strcmp(interface, "wl_shm"))
445      {
446         ewd->wl.shm = wl_display_bind(disp, id, &wl_shm_interface);
447
448         /* FIXME: We should not hard-code a cursor size here, and we should 
449          * also import the theme name from a config or env variable */
450         ewd->cursor_theme = wl_cursor_theme_load(NULL, 32, ewd->wl.shm);
451      }
452    else if (!strcmp(interface, "wl_data_device_manager"))
453      {
454         ewd->wl.data_device_manager = 
455           wl_display_bind(disp, id, &wl_data_device_manager_interface);
456      }
457
458    if ((ewd->wl.compositor) && (ewd->wl.shm) && (ewd->wl.shell))
459      {
460         Ecore_Wl_Event_Interfaces_Bound *ev;
461
462         if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Interfaces_Bound))))
463           return;
464
465         ev->compositor = (ewd->wl.compositor != NULL);
466         ev->shm = (ewd->wl.shm != NULL);
467         ev->shell = (ewd->wl.shell != NULL);
468
469         ecore_event_add(ECORE_WL_EVENT_INTERFACES_BOUND, ev, NULL, NULL);
470      }
471 }
472
473 static Eina_Bool 
474 _ecore_wl_xkb_init(Ecore_Wl_Display *ewd)
475 {
476    LOGFN(__FILE__, __LINE__, __FUNCTION__);
477
478    if (!(ewd->xkb.context = xkb_context_new(0)))
479      return EINA_FALSE;
480
481    return EINA_TRUE;
482 }
483
484 static Eina_Bool 
485 _ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd)
486 {
487    LOGFN(__FILE__, __LINE__, __FUNCTION__);
488
489    xkb_context_unref(ewd->xkb.context);
490
491    return EINA_TRUE;
492 }
493
494 struct wl_data_source *
495 _ecore_wl_create_data_source(Ecore_Wl_Display *ewd)
496 {
497    return wl_data_device_manager_create_data_source(ewd->wl.data_device_manager);
498 }