Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore / ecore_glib.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7
8 #include "Ecore.h"
9 #include "ecore_private.h"
10
11 #ifdef HAVE_GLIB
12 #include <glib.h>
13
14 static Eina_Bool _ecore_glib_active = EINA_FALSE;
15 static Ecore_Select_Function _ecore_glib_select_original;
16 static GCond *_ecore_glib_cond = NULL;
17 static GPollFD *_ecore_glib_fds = NULL;
18 static size_t _ecore_glib_fds_size = 0;
19 static const size_t ECORE_GLIB_FDS_INITIAL = 128;
20 static const size_t ECORE_GLIB_FDS_STEP = 8;
21 static const size_t ECORE_GLIB_FDS_MAX_FREE = 256;
22
23 static Eina_Bool
24 _ecore_glib_fds_resize(size_t size)
25 {
26    void *tmp = realloc(_ecore_glib_fds, sizeof(GPollFD) * size);
27
28    if (!tmp)
29      {
30         ERR("Could not realloc from %zu to %zu buckets.",
31             _ecore_glib_fds_size, size);
32         return EINA_FALSE;
33      }
34
35    _ecore_glib_fds = tmp;
36    _ecore_glib_fds_size = size;
37    return EINA_TRUE;
38 }
39
40 static int
41 _ecore_glib_context_query(GMainContext *ctx,
42                           int           priority,
43                           int          *p_timer)
44 {
45    int reqfds;
46
47    if (_ecore_glib_fds_size == 0)
48      {
49         if (!_ecore_glib_fds_resize(ECORE_GLIB_FDS_INITIAL)) return -1;
50      }
51
52    while (1)
53      {
54         size_t size;
55
56         reqfds = g_main_context_query
57             (ctx, priority, p_timer, _ecore_glib_fds, _ecore_glib_fds_size);
58         if (reqfds <= (int)_ecore_glib_fds_size) break;
59
60         size = (1 + reqfds / ECORE_GLIB_FDS_STEP) * ECORE_GLIB_FDS_STEP;
61         if (!_ecore_glib_fds_resize(size)) return -1;
62      }
63
64    if (reqfds + ECORE_GLIB_FDS_MAX_FREE < _ecore_glib_fds_size)
65      {
66         size_t size;
67
68         size = (1 + reqfds / ECORE_GLIB_FDS_MAX_FREE) * ECORE_GLIB_FDS_MAX_FREE;
69         _ecore_glib_fds_resize(size);
70      }
71
72    return reqfds;
73 }
74
75 static int
76 _ecore_glib_context_poll_from(const GPollFD *pfds,
77                               int            count,
78                               fd_set        *rfds,
79                               fd_set        *wfds,
80                               fd_set        *efds)
81 {
82    const GPollFD *itr = pfds, *itr_end = pfds + count;
83    int glib_fds = -1;
84
85    for (; itr < itr_end; itr++)
86      {
87         if (glib_fds < itr->fd)
88           glib_fds = itr->fd;
89
90         if (itr->events & G_IO_IN)
91           FD_SET(itr->fd, rfds);
92         if (itr->events & G_IO_OUT)
93           FD_SET(itr->fd, wfds);
94         if (itr->events & (G_IO_HUP | G_IO_ERR))
95           FD_SET(itr->fd, efds);
96      }
97
98    return glib_fds + 1;
99 }
100
101 static int
102 _ecore_glib_context_poll_to(GPollFD      *pfds,
103                             int           count,
104                             const fd_set *rfds,
105                             const fd_set *wfds,
106                             const fd_set *efds,
107                             int           ready)
108 {
109    GPollFD *itr = pfds, *itr_end = pfds + count;
110
111    for (; (itr < itr_end) && (ready > 0); itr++)
112      {
113         itr->revents = 0;
114         if (FD_ISSET(itr->fd, rfds) && (itr->events & G_IO_IN))
115           {
116              itr->revents |= G_IO_IN;
117              ready--;
118           }
119         if (FD_ISSET(itr->fd, wfds) && (itr->events & G_IO_OUT))
120           {
121              itr->revents |= G_IO_OUT;
122              ready--;
123           }
124         if (FD_ISSET(itr->fd, efds) && (itr->events & (G_IO_HUP | G_IO_ERR)))
125           {
126              itr->revents |= G_IO_ERR;
127              ready--;
128           }
129      }
130    return ready;
131 }
132
133 static int
134 _ecore_glib_select__locked(GMainContext   *ctx,
135                            int             ecore_fds,
136                            fd_set         *rfds,
137                            fd_set         *wfds,
138                            fd_set         *efds,
139                            struct timeval *ecore_timeout)
140 {
141    int priority, maxfds, glib_fds, reqfds, reqtimeout, ret;
142    struct timeval *timeout, glib_timeout;
143
144    g_main_context_prepare(ctx, &priority);
145    reqfds = _ecore_glib_context_query(ctx, priority, &reqtimeout);
146    if (reqfds < 0) goto error;
147
148    glib_fds = _ecore_glib_context_poll_from
149        (_ecore_glib_fds, reqfds, rfds, wfds, efds);
150
151    if (reqtimeout == -1)
152      timeout = ecore_timeout;
153    else
154      {
155         glib_timeout.tv_sec = reqtimeout / 1000;
156         glib_timeout.tv_usec = (reqtimeout % 1000) * 1000;
157
158         if (!ecore_timeout || timercmp(ecore_timeout, &glib_timeout, >))
159           timeout = &glib_timeout;
160         else
161           timeout = ecore_timeout;
162      }
163
164    maxfds = (ecore_fds >= glib_fds) ? ecore_fds : glib_fds;
165    ret = _ecore_glib_select_original(maxfds, rfds, wfds, efds, timeout);
166
167    ret = _ecore_glib_context_poll_to
168        (_ecore_glib_fds, reqfds, rfds, wfds, efds, ret);
169
170    if (g_main_context_check(ctx, priority, _ecore_glib_fds, reqfds))
171      g_main_context_dispatch(ctx);
172
173    return ret;
174
175 error:
176    return _ecore_glib_select_original
177             (ecore_fds, rfds, wfds, efds, ecore_timeout);
178 }
179
180 static int
181 _ecore_glib_select(int             ecore_fds,
182                    fd_set         *rfds,
183                    fd_set         *wfds,
184                    fd_set         *efds,
185                    struct timeval *ecore_timeout)
186 {
187    GStaticMutex lock = G_STATIC_MUTEX_INIT;
188    GMutex *mutex = g_static_mutex_get_mutex(&lock);
189    GMainContext *ctx = g_main_context_default();
190    int ret;
191
192    if (g_main_context_acquire(ctx))
193      {
194         if (mutex) g_mutex_lock(mutex);
195      }
196    else
197      {
198         if (!_ecore_glib_cond)
199           _ecore_glib_cond = g_cond_new();
200
201         while (!g_main_context_wait(ctx, _ecore_glib_cond, mutex))
202           g_thread_yield();
203      }
204
205    ret = _ecore_glib_select__locked
206        (ctx, ecore_fds, rfds, wfds, efds, ecore_timeout);
207
208    if (mutex) g_mutex_unlock(mutex);
209    g_main_context_release(ctx);
210    g_static_mutex_free(&lock);
211
212    return ret;
213 }
214
215 #endif
216
217 void
218 _ecore_glib_init(void)
219 {
220 }
221
222 void
223 _ecore_glib_shutdown(void)
224 {
225 #ifdef HAVE_GLIB
226    if (!_ecore_glib_active) return;
227    _ecore_glib_active = EINA_FALSE;
228
229    if (ecore_main_loop_select_func_get() == _ecore_glib_select)
230      ecore_main_loop_select_func_set(_ecore_glib_select_original);
231
232    if (_ecore_glib_fds)
233      {
234         free(_ecore_glib_fds);
235         _ecore_glib_fds = NULL;
236      }
237    _ecore_glib_fds_size = 0;
238
239    if (_ecore_glib_cond)
240      {
241         g_cond_free(_ecore_glib_cond);
242         _ecore_glib_cond = NULL;
243      }
244 #endif
245 }
246
247 /**
248  * @addtogroup Ecore_Main_Loop_Group
249  *
250  * @}
251  */
252
253 /**
254  * Request ecore to integrate GLib's main loop.
255  *
256  * This will add a small overhead during every main loop interaction
257  * by checking glib's default main context (used by its main loop). If
258  * it have events to be checked (timers, file descriptors or idlers),
259  * then these will be polled alongside with Ecore's own events, then
260  * dispatched before Ecore's. This is done by calling
261  * ecore_main_loop_select_func_set().
262  *
263  * This will cooperate with previously set
264  * ecore_main_loop_select_func_set() by calling the old
265  * function. Similarly, if you want to override
266  * ecore_main_loop_select_func_set() after main loop is integrated,
267  * call the new select function set by this call (get it by calling
268  * ecore_main_loop_select_func_get() right after
269  * ecore_main_loop_glib_integrate()).
270  *
271  * This is useful to use GMainLoop libraries, like GTK, GUPnP,
272  * LibSoup, GConf and more. Adobe Flash plugin and other plugins
273  * systems depend on this as well.
274  *
275  * Once initialized/integrated, it will be valid until Ecore is
276  * completely shut down.
277  *
278  * Example of use:
279  * @code
280  *
281  * int main(void)
282  * {
283  *    ecore_init();
284  *    ecore_main_loop_glib_integrate();
285  *
286  *    // some code here
287  *
288  *    ecore_main_loop_begin();
289  *
290  *    ecore_shutdown();
291  *
292  *    return 0;
293  * }
294  *
295  * @endcode
296  *
297  * @note This is only available if Ecore was compiled with GLib support.
298  * @note You don't need to call this function if Ecore was compiled with
299  * --enable-glib-integration-always.
300  *
301  * @return @c EINA_TRUE on success of @c EINA_FALSE if it failed,
302  *         likely no GLib support in Ecore.
303  */
304 EAPI Eina_Bool
305 ecore_main_loop_glib_integrate(void)
306 {
307 #ifdef HAVE_GLIB
308    void *func;
309
310    if (_ecore_glib_active) return EINA_TRUE;
311    func = ecore_main_loop_select_func_get();
312    if (func == _ecore_glib_select) return EINA_TRUE;
313    _ecore_glib_select_original = func;
314    ecore_main_loop_select_func_set(_ecore_glib_select);
315    _ecore_glib_active = EINA_TRUE;
316    return EINA_TRUE;
317 #else
318    fputs("ERROR: no glib support in ecore.\n", stderr);
319    return EINA_FALSE;
320 #endif
321 }
322
323 Eina_Bool _ecore_glib_always_integrate = 1;
324
325 /**
326  * Disable always integrating glib
327  *
328  * If ecore is compiled with --enable-glib-integration-always (to always
329  * call ecore_main_loop_glib_integrate() when ecore_init() is called), then
330  * calling this before calling ecore_init() will disable the integration.
331  * This is for apps that explicitly do not want this to happen for whatever
332  * reasons they may have.
333  */
334 EAPI void
335 ecore_main_loop_glib_always_integrate_disable(void)
336 {
337    _ecore_glib_always_integrate = 0;
338 }
339
340 /**
341  * @}
342  */