filters: Fix the laplace filter (it's not separable, gah)
[gfxprim.git] / libs / backends / GP_X11.c
blobd95e2dec45ca3ce11f414df6efb438e3ed27328e
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 #include "core/GP_Debug.h"
26 #include "core/GP_Common.h"
28 #ifdef HAVE_LIBX11
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/Xatom.h>
33 #include <X11/Xmd.h>
35 #include "input/GP_InputDriverX11.h"
36 #include "GP_X11.h"
38 struct x11_priv {
39 Display *dpy;
40 int scr;
41 Screen *scr_ptr;
42 int scr_depth;
43 Window win;
44 Visual *vis;
46 XImage *img;
48 int resized_flag;
51 static void destroy_ximage(GP_Backend *self);
53 static int resize_ximage(GP_Backend *self, int w, int h);
55 static void x11_exit(GP_Backend *self)
57 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
59 XLockDisplay(x11->dpy);
61 destroy_ximage(self);
63 XDestroyWindow(x11->dpy, x11->win);
64 /* I wonder if this is right sequence... */
65 XUnlockDisplay(x11->dpy);
66 XCloseDisplay(x11->dpy);
68 free(self);
71 static void x11_update_rect(GP_Backend *self, GP_Coord x0, GP_Coord y0,
72 GP_Coord x1, GP_Coord y1)
74 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
76 GP_DEBUG(4, "Updating rect %ix%i-%ix%i", x0, y0, x1, y1);
78 XLockDisplay(x11->dpy);
80 XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
81 x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1);
82 XFlush(x11->dpy);
84 x11->resized_flag = 0;
86 XUnlockDisplay(x11->dpy);
89 static void x11_flip(GP_Backend *self)
91 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
92 unsigned int w = self->context->w;
93 unsigned int h = self->context->h;
95 GP_DEBUG(4, "Flipping context");
97 XLockDisplay(x11->dpy);
99 XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
100 x11->img, 0, 0, 0, 0, w, h);
101 XFlush(x11->dpy);
103 x11->resized_flag = 0;
105 XUnlockDisplay(x11->dpy);
108 static void x11_ev(GP_Backend *self, XEvent *ev)
110 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
112 switch (ev->type) {
113 case Expose:
114 GP_DEBUG(4, "Expose %ix%i-%ix%i %i",
115 ev->xexpose.x, ev->xexpose.y,
116 ev->xexpose.width, ev->xexpose.height,
117 ev->xexpose.count);
119 if (x11->resized_flag)
120 break;
122 x11_update_rect(self, ev->xexpose.x, ev->xexpose.y,
123 ev->xexpose.x + ev->xexpose.width - 1,
124 ev->xexpose.y + ev->xexpose.height - 1);
125 break;
126 case ConfigureNotify:
127 if (ev->xconfigure.width == (int)self->context->w &&
128 ev->xconfigure.height == (int)self->context->h)
129 break;
130 default:
131 GP_InputDriverX11EventPut(ev);
132 break;
136 static void x11_poll(GP_Backend *self)
138 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
139 XEvent ev;
141 XLockDisplay(x11->dpy);
143 while (XPending(x11->dpy)) {
144 XNextEvent(x11->dpy, &ev);
145 x11_ev(self, &ev);
148 XUnlockDisplay(x11->dpy);
151 static void x11_wait(GP_Backend *self)
153 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
154 XEvent ev;
156 XLockDisplay(x11->dpy);
158 XNextEvent(x11->dpy, &ev);
159 x11_ev(self, &ev);
161 XUnlockDisplay(x11->dpy);
164 static int x11_set_attributes(struct GP_Backend *self,
165 uint32_t w, uint32_t h,
166 const char *caption)
168 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
170 XLockDisplay(x11->dpy);
172 if (caption != NULL) {
173 GP_DEBUG(3, "Setting window caption to '%s'", caption);
174 XmbSetWMProperties(x11->dpy, x11->win, caption, caption,
175 NULL, 0, NULL, NULL, NULL);
178 if (w != 0 && h != 0) {
179 GP_DEBUG(3, "Setting window size to %ux%u", w, h);
181 if (resize_ximage(self, w, h))
182 return 1;
184 /* Resize X11 window */
185 // XResizeWindow(x11->dpy, x11->win, w, h);
186 XFlush(x11->dpy);
188 x11->resized_flag = 1;
191 XUnlockDisplay(x11->dpy);
193 return 0;
196 static int create_ximage(GP_Backend *self, GP_Size w, GP_Size h)
198 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
199 int depth;
200 enum GP_PixelType pixel_type;
203 * Eh, the XImage supports either 8, 16 or 32 bit pixels
205 * Do best effor on selecting appropriate pixel type
207 for (depth = 8; depth <= 32; depth<<=1) {
208 pixel_type = GP_PixelRGBMatch(x11->vis->red_mask,
209 x11->vis->green_mask,
210 x11->vis->blue_mask,
211 0x0, depth);
213 if (pixel_type != GP_PIXEL_UNKNOWN)
214 break;
217 if (pixel_type == GP_PIXEL_UNKNOWN) {
218 GP_DEBUG(1, "Unknown pixel type");
219 return 1;
222 self->context = GP_ContextAlloc(w, h, pixel_type);
224 if (self->context == NULL)
225 return 1;
227 x11->img = XCreateImage(x11->dpy, x11->vis, x11->scr_depth, ZPixmap, 0,
228 NULL, w, h, depth, 0);
230 if (x11->img == NULL) {
231 GP_DEBUG(1, "Failed to create XImage");
232 GP_ContextFree(self->context);
233 return 1;
236 x11->img->data = (char*)self->context->pixels;
237 return 0;
240 static void destroy_ximage(GP_Backend *self)
242 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
244 GP_ContextFree(self->context);
245 x11->img->data = NULL;
246 XDestroyImage(x11->img);
249 static int resize_ximage(GP_Backend *self, int w, int h)
251 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
252 XImage *img;
254 /* Create new X image */
255 img = XCreateImage(x11->dpy, x11->vis, x11->scr_depth, ZPixmap, 0, NULL,
256 w, h, x11->img->bitmap_pad, 0);
258 if (img == NULL) {
259 GP_DEBUG(2, "XCreateImage failed");
260 return 1;
263 /* Resize context */
264 if (GP_ContextResize(self->context, w, h)) {
265 XDestroyImage(img);
266 return 1;
269 /* Free old image */
270 x11->img->data = NULL;
271 XDestroyImage(x11->img);
273 /* Swap the pointers */
274 img->data = (char*)self->context->pixels;
275 x11->img = img;
277 return 0;
280 void create_window(struct x11_priv *x11, int x, int y,
281 unsigned int *w, unsigned int *h,
282 const char *caption, enum GP_BackendX11Flags flags)
284 XSetWindowAttributes attrs;
285 unsigned long attr_mask = 0;
287 /* Set event mask */
288 attrs.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
289 KeyReleaseMask | PointerMotionMask;
290 attr_mask |= CWEventMask;
293 * If root window was selected, resize w and h and set x11->win to root
294 * window.
296 if (flags & GP_X11_USE_ROOT_WIN) {
297 x11->win = DefaultRootWindow(x11->dpy);
298 *w = DisplayWidth(x11->dpy, x11->scr);
299 *h = DisplayHeight(x11->dpy, x11->scr);
301 GP_DEBUG(2, "Using root window, owerriding size to %ux%u",
302 *w, *h);
304 XChangeWindowAttributes(x11->dpy, x11->win, attr_mask, &attrs);
306 return;
310 * For some reason reading mouse button clicks on root win are not
311 * allowed...
313 attrs.event_mask |= ButtonPressMask | ButtonReleaseMask;
316 * Create undecoreated root window on background
318 if (flags & GP_X11_CREATE_ROOT_WIN) {
319 Atom xa;
321 *w = DisplayWidth(x11->dpy, x11->scr);
322 *h = DisplayHeight(x11->dpy, x11->scr);
324 GP_DEBUG(2, "Creating a window above root, owerriding size to %ux%u",
325 *w, *h);
327 x11->win = XCreateWindow(x11->dpy, DefaultRootWindow(x11->dpy),
328 0, 0, *w, *h, 0, CopyFromParent,
329 InputOutput, CopyFromParent, attr_mask, &attrs);
331 /* Set empty WM_PROTOCOLS */
332 GP_DEBUG(2, "Setting empty MW_PROTOCOLS");
333 XSetWMProtocols(x11->dpy, x11->win, NULL, 0);
335 /* Set window type to desktop */
336 xa = XInternAtom(x11->dpy, "_NET_WM_WINDOW_TYPE", False);
338 if (xa != None) {
339 GP_DEBUG(2, "Setting Atom _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_DESKTOP");
341 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
343 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
344 PropModeReplace, (unsigned char *) &xa_prop, 1);
347 /* Turn off window decoration */
348 xa = XInternAtom(x11->dpy, "_MOTIF_WM_HINTS", False);
350 if (xa != None) {
351 GP_DEBUG(2, "Setting Atom _MOTIF_WM_HINTS to 2, 0, 0, 0, 0");
353 long prop[5] = {2, 0, 0, 0, 0};
355 XChangeProperty(x11->dpy, x11->win, xa, xa, 32,
356 PropModeReplace, (unsigned char *) prop, 5);
359 /* Set below other windows */
360 xa = XInternAtom(x11->dpy, "_WIN_LAYER", False);
362 if (xa != None) {
363 GP_DEBUG(2, "Setting Atom _WIN_LAYER to 6");
365 long prop = 6;
367 XChangeProperty(x11->dpy, x11->win, xa, XA_CARDINAL, 32,
368 PropModeAppend, (unsigned char *) &prop, 1);
371 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
373 if (xa != None) {
374 GP_DEBUG(2, "Setting Atom _NET_WM_STATE to _NET_WM_STATE_BELOW");
376 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_BELOW", False);
378 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
379 PropModeAppend, (unsigned char *) &xa_prop, 1);
382 /* Set sticky */
383 xa = XInternAtom(x11->dpy, "_NET_WM_DESKTOP", False);
385 if (xa != None) {
386 GP_DEBUG(2, "Setting Atom _NET_WM_DESKTOP to 0xffffffff");
388 CARD32 xa_prop = 0xffffffff;
390 XChangeProperty(x11->dpy, x11->win, xa, XA_CARDINAL, 32,
391 PropModeAppend, (unsigned char *) &xa_prop, 1);
394 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
396 if (xa != None) {
397 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_WM_STATE_STICKY");
399 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_STICKY", False);
401 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
402 PropModeAppend, (unsigned char *) &xa_prop, 1);
405 /* Skip taskbar */
406 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
408 if (xa != None) {
409 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_STATE_SKIP_TASKBAR");
411 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_SKIP_TASKBAR", False);
413 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
414 PropModeAppend, (unsigned char *) &xa_prop, 1);
417 /* Skip pager */
418 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
420 if (xa != None) {
421 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_STATE_SKIP_PAGER");
423 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_SKIP_PAGER", False);
425 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
426 PropModeAppend, (unsigned char *) &xa_prop, 1);
429 /* Set 100% opacity */
430 xa = XInternAtom(x11->dpy, "_NET_WM_WINDOW_OPACITY", False);
432 if (xa != None) {
433 GP_DEBUG(2, "Setting Atom _NET_WM_WINDOW_OPACITY to 0xffffffff");
435 long prop = 0xffffffff;
437 XChangeProperty(x11->dpy, x11->win, xa, XA_CARDINAL, 32,
438 PropModeAppend, (unsigned char *) &prop, 1);
441 /* Show window */
442 XMapWindow(x11->dpy, x11->win);
443 return;
446 GP_DEBUG(2, "Opening window '%s' %ix%i-%ux%u",
447 caption, x, y, *w, *h);
449 x11->win = XCreateWindow(x11->dpy, DefaultRootWindow(x11->dpy),
450 x, y, *w, *h, 0, CopyFromParent,
451 InputOutput, CopyFromParent, attr_mask, &attrs);
453 /* Set window caption */
454 XmbSetWMProperties(x11->dpy, x11->win, caption, caption,
455 NULL, 0, NULL, NULL, NULL);
457 /* Show window */
458 XMapWindow(x11->dpy, x11->win);
461 GP_Backend *GP_BackendX11Init(const char *display, int x, int y,
462 unsigned int w, unsigned int h,
463 const char *caption,
464 enum GP_BackendX11Flags flags)
466 GP_Backend *backend;
467 struct x11_priv *x11;
469 GP_DEBUG(1, "Initalizing X11 display '%s'", display);
471 if (!XInitThreads()) {
472 GP_DEBUG(2, "XInitThreads failed");
473 return NULL;
476 backend = malloc(sizeof(GP_Backend) +
477 sizeof(struct x11_priv));
479 if (backend == NULL)
480 return NULL;
482 x11 = GP_BACKEND_PRIV(backend);
484 x11->dpy = XOpenDisplay(display);
486 if (x11->dpy == NULL)
487 goto err0;
489 x11->scr = DefaultScreen(x11->dpy);
490 x11->vis = DefaultVisual(x11->dpy, x11->scr);
491 x11->scr_ptr = DefaultScreenOfDisplay(x11->dpy);
492 x11->scr_depth = DefaultDepthOfScreen(x11->scr_ptr);
494 GP_DEBUG(2, "Have Visual id %i, depth %u", (int)x11->vis->visualid, x11->scr_depth);
496 create_window(x11, x, y, &w, &h, caption, flags);
498 if (x11->win == None) {
499 //TODO: Error message?
500 GP_DEBUG(1, "Failed to create window");
501 goto err1;
504 if (create_ximage(backend, w, h))
505 goto err1;
508 XFlush(x11->dpy);
510 x11->resized_flag = 0;
512 backend->name = "X11";
513 backend->Flip = x11_flip;
514 backend->UpdateRect = x11_update_rect;
515 backend->Exit = x11_exit;
516 backend->Poll = x11_poll;
517 backend->Wait = x11_wait;
518 backend->SetAttributes = x11_set_attributes;
519 backend->fd = XConnectionNumber(x11->dpy);
521 return backend;
522 err1:
523 XCloseDisplay(x11->dpy);
524 err0:
525 free(backend);
526 return NULL;
529 #else
531 #include "GP_Backend.h"
533 GP_Backend *GP_BackendX11Init(const char *GP_UNUSED(display),
534 int GP_UNUSED(x), int GP_UNUSED(y),
535 unsigned int GP_UNUSED(w),
536 unsigned int GP_UNUSED(h),
537 const char *GP_UNUSED(caption))
539 GP_DEBUG(0, "FATAL: X11 support not compiled in");
540 return NULL;
543 #endif /* HAVE_LIBX11 */