cleanup specfile for packaging
[profile/ivi/cogl.git] / cogl / cogl-xlib-renderer.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2008,2009,2010 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  * Authors:
24  *   Robert Bragg <robert@linux.intel.com>
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "cogl-xlib-renderer.h"
32 #include "cogl-util.h"
33 #include "cogl-internal.h"
34 #include "cogl-object.h"
35
36 #include "cogl-renderer-private.h"
37 #include "cogl-xlib-renderer-private.h"
38 #include "cogl-x11-renderer-private.h"
39 #include "cogl-winsys-private.h"
40
41 #include <X11/Xlib.h>
42 #include <X11/extensions/Xdamage.h>
43
44 #include <stdlib.h>
45
46 static char *_cogl_x11_display_name = NULL;
47 static GList *_cogl_xlib_renderers = NULL;
48
49 static void
50 destroy_xlib_renderer_data (void *user_data)
51 {
52   g_slice_free (CoglXlibRenderer, user_data);
53 }
54
55 CoglXlibRenderer *
56 _cogl_xlib_renderer_get_data (CoglRenderer *renderer)
57 {
58   static CoglUserDataKey key;
59   CoglXlibRenderer *data;
60
61   /* Constructs a CoglXlibRenderer struct on demand and attaches it to
62      the object using user data. It's done this way instead of using a
63      subclassing hierarchy in the winsys data because all EGL winsys's
64      need the EGL winsys data but only one of them wants the Xlib
65      data. */
66
67   data = cogl_object_get_user_data (COGL_OBJECT (renderer), &key);
68
69   if (data == NULL)
70     {
71       data = g_slice_new0 (CoglXlibRenderer);
72
73       cogl_object_set_user_data (COGL_OBJECT (renderer),
74                                  &key,
75                                  data,
76                                  destroy_xlib_renderer_data);
77     }
78
79   return data;
80 }
81
82 static void
83 register_xlib_renderer (CoglRenderer *renderer)
84 {
85   GList *l;
86
87   for (l = _cogl_xlib_renderers; l; l = l->next)
88     if (l->data == renderer)
89       return;
90
91   _cogl_xlib_renderers = g_list_prepend (_cogl_xlib_renderers, renderer);
92 }
93
94 static void
95 unregister_xlib_renderer (CoglRenderer *renderer)
96 {
97   _cogl_xlib_renderers = g_list_remove (_cogl_xlib_renderers, renderer);
98 }
99
100 static CoglRenderer *
101 get_renderer_for_xdisplay (Display *xdpy)
102 {
103   GList *l;
104
105   for (l = _cogl_xlib_renderers; l; l = l->next)
106     {
107       CoglRenderer *renderer = l->data;
108       CoglXlibRenderer *xlib_renderer =
109         _cogl_xlib_renderer_get_data (renderer);
110
111       if (xlib_renderer->xdpy == xdpy)
112         return renderer;
113     }
114
115   return NULL;
116 }
117
118 static int
119 error_handler (Display *xdpy,
120                XErrorEvent *error)
121 {
122   CoglRenderer *renderer;
123   CoglXlibRenderer *xlib_renderer;
124
125   renderer = get_renderer_for_xdisplay (xdpy);
126
127   xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
128   g_assert (xlib_renderer->trap_state);
129
130   xlib_renderer->trap_state->trapped_error_code = error->error_code;
131
132   return 0;
133 }
134
135 void
136 _cogl_xlib_renderer_trap_errors (CoglRenderer *renderer,
137                                  CoglXlibTrapState *state)
138 {
139   CoglXlibRenderer *xlib_renderer;
140
141   xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
142
143   state->trapped_error_code = 0;
144   state->old_error_handler = XSetErrorHandler (error_handler);
145
146   state->old_state = xlib_renderer->trap_state;
147   xlib_renderer->trap_state = state;
148 }
149
150 int
151 _cogl_xlib_renderer_untrap_errors (CoglRenderer *renderer,
152                                    CoglXlibTrapState *state)
153 {
154   CoglXlibRenderer *xlib_renderer;
155
156   xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
157   g_assert (state == xlib_renderer->trap_state);
158
159   XSetErrorHandler (state->old_error_handler);
160
161   xlib_renderer->trap_state = state->old_state;
162
163   return state->trapped_error_code;
164 }
165
166 static Display *
167 assert_xlib_display (CoglRenderer *renderer, GError **error)
168 {
169   Display *xdpy = cogl_xlib_renderer_get_foreign_display (renderer);
170   CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
171
172   /* A foreign display may have already been set... */
173   if (xdpy)
174     {
175       xlib_renderer->xdpy = xdpy;
176       return xdpy;
177     }
178
179   xdpy = XOpenDisplay (_cogl_x11_display_name);
180   if (xdpy == NULL)
181     {
182       g_set_error (error,
183                    COGL_RENDERER_ERROR,
184                    COGL_RENDERER_ERROR_XLIB_DISPLAY_OPEN,
185                    "Failed to open X Display %s", _cogl_x11_display_name);
186       return NULL;
187     }
188
189   xlib_renderer->xdpy = xdpy;
190   return xdpy;
191 }
192
193 gboolean
194 _cogl_xlib_renderer_connect (CoglRenderer *renderer, GError **error)
195 {
196   CoglXlibRenderer *xlib_renderer =
197     _cogl_xlib_renderer_get_data (renderer);
198   CoglX11Renderer *x11_renderer =
199     (CoglX11Renderer *) xlib_renderer;
200   int damage_error;
201
202   if (!assert_xlib_display (renderer, error))
203     return FALSE;
204
205   if (getenv ("COGL_X11_SYNC"))
206     XSynchronize (xlib_renderer->xdpy, TRUE);
207
208   /* Check whether damage events are supported on this display */
209   if (!XDamageQueryExtension (xlib_renderer->xdpy,
210                               &x11_renderer->damage_base,
211                               &damage_error))
212     x11_renderer->damage_base = -1;
213
214   xlib_renderer->trap_state = NULL;
215
216   xlib_renderer->poll_fd.fd = ConnectionNumber (xlib_renderer->xdpy);
217   xlib_renderer->poll_fd.events = COGL_POLL_FD_EVENT_IN;
218
219   register_xlib_renderer (renderer);
220
221   return TRUE;
222 }
223
224 void
225 _cogl_xlib_renderer_disconnect (CoglRenderer *renderer)
226 {
227   CoglXlibRenderer *xlib_renderer =
228     _cogl_xlib_renderer_get_data (renderer);
229
230   if (!renderer->foreign_xdpy && xlib_renderer->xdpy)
231     XCloseDisplay (xlib_renderer->xdpy);
232
233   unregister_xlib_renderer (renderer);
234 }
235
236 Display *
237 cogl_xlib_renderer_get_display (CoglRenderer *renderer)
238 {
239   CoglXlibRenderer *xlib_renderer;
240
241   _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL);
242
243   xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
244
245   return xlib_renderer->xdpy;
246 }
247
248 CoglFilterReturn
249 cogl_xlib_renderer_handle_event (CoglRenderer *renderer,
250                                  XEvent *event)
251 {
252   return _cogl_renderer_handle_native_event (renderer, event);
253 }
254
255 void
256 cogl_xlib_renderer_add_filter (CoglRenderer *renderer,
257                                CoglXlibFilterFunc func,
258                                void *data)
259 {
260   _cogl_renderer_add_native_filter (renderer,
261                                     (CoglNativeFilterFunc)func, data);
262 }
263
264 void
265 cogl_xlib_renderer_remove_filter (CoglRenderer *renderer,
266                                   CoglXlibFilterFunc func,
267                                   void *data)
268 {
269   _cogl_renderer_remove_native_filter (renderer,
270                                        (CoglNativeFilterFunc)func, data);
271 }
272
273 void
274 _cogl_xlib_renderer_poll_get_info (CoglRenderer *renderer,
275                                    CoglPollFD **poll_fds,
276                                    int *n_poll_fds,
277                                    gint64 *timeout)
278 {
279   CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
280
281   if (renderer->xlib_enable_event_retrieval)
282     {
283       *n_poll_fds = 1;
284       *poll_fds = &xlib_renderer->poll_fd;
285       if (XPending (xlib_renderer->xdpy))
286         *timeout = 0;
287       else
288         *timeout = -1;
289     }
290   else
291     {
292       *n_poll_fds = 0;
293       *poll_fds = NULL;
294       *timeout = -1;
295     }
296 }
297
298 void
299 _cogl_xlib_renderer_poll_dispatch (CoglRenderer *renderer,
300                                    const CoglPollFD *poll_fds,
301                                    int n_poll_fds)
302 {
303   CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
304
305   if (renderer->xlib_enable_event_retrieval)
306     while (XPending (xlib_renderer->xdpy))
307       {
308         XEvent xevent;
309
310         XNextEvent (xlib_renderer->xdpy, &xevent);
311
312         cogl_xlib_renderer_handle_event (renderer, &xevent);
313       }
314 }