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