examples: Move simple c examples into c_simple directory.
[gfxprim.git] / libs / backends / GP_X11.c
blobaf98a67ca3f8bc3e16b275a615b1da591300f4c1
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include "../../config.h"
25 #ifdef HAVE_LIBX11
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
30 #include "core/GP_Debug.h"
31 #include "input/GP_InputDriverX11.h"
32 #include "GP_X11.h"
34 struct x11_priv {
35 Display *dpy;
36 int scr;
37 Window win;
38 Visual *vis;
39 XImage *img;
41 int resized_flag;
44 static void x11_exit(GP_Backend *self)
46 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
48 XLockDisplay(x11->dpy);
50 GP_ContextFree(self->context);
52 x11->img->data = NULL;
53 XDestroyImage(x11->img);
54 XDestroyWindow(x11->dpy, x11->win);
55 /* I wonder if this is right sequence... */
56 XUnlockDisplay(x11->dpy);
57 XCloseDisplay(x11->dpy);
59 free(self);
62 static void x11_update_rect(GP_Backend *self, GP_Coord x0, GP_Coord y0,
63 GP_Coord x1, GP_Coord y1)
65 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
67 GP_DEBUG(4, "Updating rect %ix%i-%ix%i", x0, y0, x1, y1);
69 XLockDisplay(x11->dpy);
71 XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
72 x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1);
73 XFlush(x11->dpy);
75 x11->resized_flag = 0;
77 XUnlockDisplay(x11->dpy);
80 static void x11_flip(GP_Backend *self)
82 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
83 unsigned int w = self->context->w;
84 unsigned int h = self->context->h;
86 GP_DEBUG(4, "Flipping context");
88 XLockDisplay(x11->dpy);
90 XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
91 x11->img, 0, 0, 0, 0, w, h);
92 XFlush(x11->dpy);
94 x11->resized_flag = 0;
96 XUnlockDisplay(x11->dpy);
99 static void x11_poll(GP_Backend *self)
101 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
102 XEvent ev;
104 XLockDisplay(x11->dpy);
106 while (XPending(x11->dpy)) {
107 XNextEvent(x11->dpy, &ev);
109 switch (ev.type) {
110 case Expose:
111 GP_DEBUG(4, "Expose %ix%i-%ix%i %i",
112 ev.xexpose.x, ev.xexpose.y,
113 ev.xexpose.width, ev.xexpose.height,
114 ev.xexpose.count);
116 if (x11->resized_flag)
117 break;
119 x11_update_rect(self, ev.xexpose.x, ev.xexpose.y,
120 ev.xexpose.x + ev.xexpose.width - 1,
121 ev.xexpose.y + ev.xexpose.height - 1);
122 break;
123 case ConfigureNotify:
124 if (ev.xconfigure.width == (int)self->context->w &&
125 ev.xconfigure.height == (int)self->context->h)
126 break;
127 default:
128 GP_InputDriverX11EventPut(&ev);
129 break;
133 XUnlockDisplay(x11->dpy);
136 static int x11_set_attributes(struct GP_Backend *self,
137 uint32_t w, uint32_t h,
138 const char *caption)
140 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
142 XLockDisplay(x11->dpy);
144 if (caption != NULL) {
145 GP_DEBUG(3, "Setting window caption to '%s'", caption);
146 XmbSetWMProperties(x11->dpy, x11->win, caption, caption,
147 NULL, 0, NULL, NULL, NULL);
150 if (w != 0 || h != 0) {
151 XImage *img;
153 if (w == 0)
154 w = self->context->w;
156 if (h == 0)
157 h = self->context->h;
159 GP_DEBUG(3, "Setting window size to %ux%u", w, h);
161 /* Create new X image */
162 img = XCreateImage(x11->dpy, x11->vis, 24, ZPixmap, 0, NULL,
163 w, h, 32, 0);
165 /* Allocate new context */
167 if (GP_ContextResize(self->context, w, h)) {
168 XDestroyImage(img);
169 return 1;
172 /* Free old image */
173 x11->img->data = NULL;
174 XDestroyImage(x11->img);
176 /* Swap the pointers */
177 img->data = (char*)self->context->pixels;
178 x11->img = img;
180 /* Resize X11 window */
181 XResizeWindow(x11->dpy, x11->win, w, h);
182 XFlush(x11->dpy);
184 x11->resized_flag = 1;
187 XUnlockDisplay(x11->dpy);
189 return 0;
192 GP_Backend *GP_BackendX11Init(const char *display, int x, int y,
193 unsigned int w, unsigned int h,
194 const char *caption)
196 GP_Backend *backend;
197 struct x11_priv *x11;
199 GP_DEBUG(1, "Initalizing X11 display '%s'", display);
201 backend = malloc(sizeof(GP_Backend) +
202 sizeof(struct x11_priv));
204 if (backend == NULL)
205 return NULL;
207 x11 = GP_BACKEND_PRIV(backend);
209 backend->context = GP_ContextAlloc(w, h, GP_PIXEL_xRGB8888);
211 if (backend->context == NULL)
212 goto err0;
214 //TODO: Error checking
215 XInitThreads();
217 x11->dpy = XOpenDisplay(display);
219 if (x11->dpy == NULL)
220 goto err1;
222 x11->scr = DefaultScreen(x11->dpy);
223 x11->vis = DefaultVisual(x11->dpy, x11->scr);
225 GP_DEBUG(2, "Opening window '%s' %ix%i-%ux%u",
226 caption, x, y, w, h);
228 x11->img = XCreateImage(x11->dpy, x11->vis, 24, ZPixmap, 0, NULL,
229 w, h, 32, 0);
231 x11->img->data = (char*)backend->context->pixels;
233 x11->win = XCreateWindow(x11->dpy, DefaultRootWindow(x11->dpy),
234 x, y, w, h, 0, CopyFromParent,
235 InputOutput, CopyFromParent, 0, NULL);
237 if (x11->win == None) {
238 //TODO: Error message?
239 GP_DEBUG(1, "Failed to create window");
240 goto err2;
243 /* Select events */
244 XSelectInput(x11->dpy, x11->win, ExposureMask | StructureNotifyMask |
245 KeyPressMask | KeyReleaseMask |
246 ButtonPressMask | ButtonReleaseMask |
247 PointerMotionMask);
249 /* Set window caption */
250 XmbSetWMProperties(x11->dpy, x11->win, caption, caption,
251 NULL, 0, NULL, NULL, NULL);
253 /* Show window */
254 XMapWindow(x11->dpy, x11->win);
255 XFlush(x11->dpy);
257 x11->resized_flag = 0;
261 enum GP_PixelType pixel_type;
262 pixel_type = GP_PixelRGBLookup(vscri.red.length, vscri.red.offset,
263 vscri.green.length, vscri.green.offset,
264 vscri.blue.length, vscri.blue.offset,
265 vscri.transp.length, vscri.transp.offset,
266 vscri.bits_per_pixel);
268 if (pixel_type == GP_PIXEL_UNKNOWN) {
269 GP_DEBUG(1, "Unknown pixel type\n");
270 goto err3;
276 backend->name = "X11";
277 backend->Flip = x11_flip;
278 backend->UpdateRect = x11_update_rect;
279 backend->Exit = x11_exit;
280 backend->fd_list = NULL;
281 backend->Poll = x11_poll;
282 backend->SetAttributes = x11_set_attributes;
285 return backend;
286 //err3:
287 // XDestroyWindow(x11->dpy, x11->win);
288 err2:
289 XCloseDisplay(x11->dpy);
290 err1:
291 GP_ContextFree(backend->context);
292 err0:
293 free(backend);
294 return NULL;
297 #else
299 #include "GP_Backend.h"
301 GP_Backend *GP_BackendX11Init(const char *display, int x, int y,
302 unsigned int w, unsigned int h,
303 const char *caption)
305 return NULL;
308 #endif /* HAVE_LIBX11 */