backends: X11: Flush the connection after set_attributes().
[gfxprim.git] / libs / backends / GP_X11.c
blob63d8162a11d6858e282b4d9e37886afdaf5d398a
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 <string.h>
24 #include <errno.h>
26 #include "../../config.h"
28 #include "core/GP_Debug.h"
29 #include "core/GP_Common.h"
31 #ifdef HAVE_LIBX11
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/Xatom.h>
36 #include <X11/Xmd.h>
38 #ifdef HAVE_X_SHM
39 #include <sys/ipc.h>
40 #include <sys/shm.h>
41 #include <X11/extensions/XShm.h>
42 #endif /* HAVE_X_SHM */
44 #include "input/GP_InputDriverX11.h"
45 #include "GP_X11.h"
47 struct x11_priv {
48 /* Connection details */
49 Display *dpy;
50 int scr;
51 Screen *scr_ptr;
52 int scr_depth;
53 Window win;
54 Visual *vis;
56 /* Image details */
57 XImage *img;
59 #ifdef HAVE_X_SHM
60 XShmSegmentInfo shminfo;
61 GP_Context context;
62 #endif /* HAVE_X_SHM */
64 int resized_flag:1;
65 int shm_flag:1;
67 /* used to store width and height from ConfigureNotify event */
68 unsigned int new_w;
69 unsigned int new_h;
72 static int resize_ximage(GP_Backend *self, int w, int h);
73 static int resize_shm_ximage(GP_Backend *self, int w, int h);
75 static void putimage(struct GP_Backend *self, int x0, int y0, int x1, int y1)
77 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
79 #ifdef HAVE_X_SHM
80 if (x11->shm_flag)
81 XShmPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
82 x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1, False);
83 else
84 #endif /* HAVE_X_SHM */
85 XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
86 x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1);
89 static void x11_update_rect(GP_Backend *self, GP_Coord x0, GP_Coord y0,
90 GP_Coord x1, GP_Coord y1)
92 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
94 GP_DEBUG(4, "Updating rect %ix%i-%ix%i", x0, y0, x1, y1);
96 if (x11->resized_flag) {
97 GP_DEBUG(4, "Ignoring update rect, waiting for resize ack");
98 return;
101 XLockDisplay(x11->dpy);
103 putimage(self, x0, y0, x1, y1);
105 XUnlockDisplay(x11->dpy);
108 static void x11_flip(GP_Backend *self)
110 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
111 unsigned int w = self->context->w;
112 unsigned int h = self->context->h;
114 GP_DEBUG(4, "Flipping context");
116 if (x11->resized_flag) {
117 GP_DEBUG(4, "Ignoring flip, waiting for resize ack");
118 return;
121 XLockDisplay(x11->dpy);
123 #ifdef HAVE_X_SHM
124 if (x11->shm_flag)
125 XShmPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
126 x11->img, 0, 0, 0, 0, w, h, False);
127 else
128 #endif /* HAVE_X_SHM */
129 XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr),
130 x11->img, 0, 0, 0, 0, w, h);
132 XFlush(x11->dpy);
134 XUnlockDisplay(x11->dpy);
137 static void x11_ev(GP_Backend *self, XEvent *ev)
139 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
141 switch (ev->type) {
142 case Expose:
143 GP_DEBUG(4, "Expose %ix%i-%ix%i %i",
144 ev->xexpose.x, ev->xexpose.y,
145 ev->xexpose.width, ev->xexpose.height,
146 ev->xexpose.count);
148 if (x11->resized_flag)
149 break;
151 /* Safety measure */
152 if (ev->xexpose.x + ev->xexpose.width > (int)self->context->w) {
153 GP_WARN("Expose x + w > context->w");
154 break;
157 if (ev->xexpose.y + ev->xexpose.height > (int)self->context->h) {
158 GP_WARN("Expose y + h > context->h");
159 break;
162 /* Update the rectangle */
163 x11_update_rect(self, ev->xexpose.x, ev->xexpose.y,
164 ev->xexpose.x + ev->xexpose.width - 1,
165 ev->xexpose.y + ev->xexpose.height - 1);
166 break;
167 case ConfigureNotify:
168 if (ev->xconfigure.width == (int)self->context->w &&
169 ev->xconfigure.height == (int)self->context->h)
170 break;
172 if (ev->xconfigure.width == (int)x11->new_w &&
173 ev->xconfigure.height == (int)x11->new_h)
174 break;
176 x11->new_w = ev->xconfigure.width;
177 x11->new_h = ev->xconfigure.height;
179 GP_DEBUG(4, "Configure Notify %ux%u", x11->new_w, x11->new_h);
181 /* Window has been resized, set flag. */
182 x11->resized_flag = 1;
183 default:
184 GP_InputDriverX11EventPut(ev);
185 break;
189 static void x11_poll(GP_Backend *self)
191 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
192 XEvent ev;
194 XLockDisplay(x11->dpy);
196 while (XPending(x11->dpy)) {
197 XNextEvent(x11->dpy, &ev);
198 x11_ev(self, &ev);
201 XUnlockDisplay(x11->dpy);
204 static void x11_wait(GP_Backend *self)
206 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
207 XEvent ev;
209 XLockDisplay(x11->dpy);
211 XNextEvent(x11->dpy, &ev);
212 x11_ev(self, &ev);
214 XUnlockDisplay(x11->dpy);
217 static int resize_buffer(struct GP_Backend *self, uint32_t w, uint32_t h)
219 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
221 if (x11->shm_flag) {
222 if (resize_shm_ximage(self, w, h))
223 return 1;
224 } else {
225 if (resize_ximage(self, w, h))
226 return 1;
229 return 0;
232 static int x11_set_attributes(struct GP_Backend *self,
233 uint32_t w, uint32_t h,
234 const char *caption)
236 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
238 XLockDisplay(x11->dpy);
240 if (caption != NULL) {
241 GP_DEBUG(3, "Setting window caption to '%s'", caption);
242 XmbSetWMProperties(x11->dpy, x11->win, caption, caption,
243 NULL, 0, NULL, NULL, NULL);
246 if (w != 0 && h != 0) {
247 GP_DEBUG(3, "Setting window size to %ux%u", w, h);
248 XResizeWindow(x11->dpy, x11->win, w, h);
251 XFlush(x11->dpy);
253 XUnlockDisplay(x11->dpy);
255 return 0;
258 static int x11_resize_ack(struct GP_Backend *self)
260 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
261 int ret;
263 XLockDisplay(x11->dpy);
265 GP_DEBUG(3, "Setting buffer size to %ux%u", x11->new_w, x11->new_h);
267 ret = resize_buffer(self, x11->new_w, x11->new_h);
269 x11->resized_flag = 0;
271 GP_DEBUG(3, "Done");
273 XUnlockDisplay(x11->dpy);
275 return ret;
278 static void match_pixel_type(struct x11_priv *x11,
279 enum GP_PixelType *pixel_type, int *depth)
282 * Eh, the XImage supports either 8, 16 or 32 bit pixels
284 * Do best effor on selecting appropriate pixel type
286 for (*depth = 8; *depth <= 32; *depth<<=1) {
287 *pixel_type = GP_PixelRGBMatch(x11->vis->red_mask,
288 x11->vis->green_mask,
289 x11->vis->blue_mask,
290 0x0, *depth);
292 if (*pixel_type != GP_PIXEL_UNKNOWN)
293 break;
297 #ifdef HAVE_X_SHM
299 static int create_shm_ximage(GP_Backend *self, GP_Size w, GP_Size h)
301 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
303 if (XShmQueryExtension(x11->dpy) == False) {
304 GP_DEBUG(1, "MIT SHM Extension not supported, "
305 "falling back to XImage");
306 return 1;
309 if (self->context == NULL)
310 GP_DEBUG(1, "Using MIT SHM Extension");
312 enum GP_PixelType pixel_type;
313 int depth;
315 if (self->context == NULL)
316 match_pixel_type(x11, &pixel_type, &depth);
317 else
318 pixel_type = self->context->pixel_type;
320 if (pixel_type == GP_PIXEL_UNKNOWN) {
321 GP_DEBUG(1, "Unknown pixel type");
322 return 1;
325 x11->img = XShmCreateImage(x11->dpy, x11->vis, x11->scr_depth,
326 ZPixmap, NULL, &x11->shminfo, w, h);
328 if (x11->img == NULL) {
329 GP_WARN("Failed to create SHM XImage");
330 return 1;
333 size_t size = x11->img->bytes_per_line * x11->img->height;
335 x11->shminfo.shmid = shmget(IPC_PRIVATE, size, 0600);
337 if (x11->shminfo.shmid == -1) {
338 GP_WARN("Calling shmget() failed: %s", strerror(errno));
339 goto err0;
342 x11->shminfo.shmaddr = x11->img->data = shmat(x11->shminfo.shmid, 0, 0);
344 if (x11->shminfo.shmaddr == (void *)-1) {
345 GP_WARN("Calling shmat() failed: %s", strerror(errno));
346 goto err1;
349 /* Mark SHM for deletion after detach */
350 if (shmctl(x11->shminfo.shmid, IPC_RMID, 0)) {
351 GP_WARN("Calling shmctl(..., IPC_RMID), 0) failed: %s",
352 strerror(errno));
353 goto err2;
356 x11->shminfo.readOnly = False;
358 if (XShmAttach(x11->dpy, &x11->shminfo) == False) {
359 GP_WARN("XShmAttach failed");
360 goto err2;
363 GP_ContextInit(&x11->context, w, h, pixel_type, x11->shminfo.shmaddr);
364 x11->context.bytes_per_row = x11->img->bytes_per_line;
366 self->context = &x11->context;
368 x11->shm_flag = 1;
370 //FIXME: Proper synchronization
371 XSync(x11->dpy, True);
373 return 0;
374 err2:
375 shmdt(x11->shminfo.shmaddr);
376 err1:
377 shmctl(x11->shminfo.shmid, IPC_RMID, 0);
378 err0:
379 XDestroyImage(x11->img);
380 return 1;
383 static void destroy_shm_ximage(GP_Backend *self)
385 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
387 XLockDisplay(x11->dpy);
389 XShmDetach(x11->dpy, &x11->shminfo);
390 XFlush(x11->dpy);
391 shmdt(x11->shminfo.shmaddr);
392 XDestroyImage(x11->img);
393 XFlush(x11->dpy);
395 XUnlockDisplay(x11->dpy);
398 static int resize_shm_ximage(GP_Backend *self, int w, int h)
400 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
401 int ret;
403 GP_DEBUG(4, "Resizing XShmImage %ux%u -> %ux%u",
404 self->context->w, self->context->h, w, h);
406 XLockDisplay(x11->dpy);
408 destroy_shm_ximage(self);
409 ret = create_shm_ximage(self, w, h);
411 XUnlockDisplay(x11->dpy);
413 return ret;
416 #else
418 static int create_shm_ximage(GP_Backend GP_UNUSED(*self),
419 GP_Size GP_UNUSED(w), GP_Size GP_UNUSED(h))
421 return 1;
424 static void destroy_shm_ximage(GP_Backend GP_UNUSED(*self))
426 GP_WARN("Stub called");
429 static int resize_shm_ximage(GP_Backend GP_UNUSED(*self),
430 int GP_UNUSED(w), int GP_UNUSED(h))
432 GP_WARN("Stub called");
435 #endif /* HAVE_X_SHM */
437 static int create_ximage(GP_Backend *self, GP_Size w, GP_Size h)
439 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
440 enum GP_PixelType pixel_type;
441 int depth;
443 match_pixel_type(x11, &pixel_type, &depth);
445 if (pixel_type == GP_PIXEL_UNKNOWN) {
446 GP_DEBUG(1, "Unknown pixel type");
447 return 1;
450 self->context = GP_ContextAlloc(w, h, pixel_type);
452 if (self->context == NULL)
453 return 1;
455 x11->img = XCreateImage(x11->dpy, x11->vis, x11->scr_depth, ZPixmap, 0,
456 NULL, w, h, depth, 0);
458 if (x11->img == NULL) {
459 GP_DEBUG(1, "Failed to create XImage");
460 GP_ContextFree(self->context);
461 return 1;
464 x11->shm_flag = 0;
466 x11->img->data = (char*)self->context->pixels;
468 return 0;
471 static void destroy_ximage(GP_Backend *self)
473 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
475 GP_ContextFree(self->context);
476 x11->img->data = NULL;
477 XDestroyImage(x11->img);
480 static int resize_ximage(GP_Backend *self, int w, int h)
482 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
483 XImage *img;
485 /* Create new X image */
486 img = XCreateImage(x11->dpy, x11->vis, x11->scr_depth, ZPixmap, 0, NULL,
487 w, h, x11->img->bitmap_pad, 0);
489 if (img == NULL) {
490 GP_DEBUG(2, "XCreateImage failed");
491 return 1;
494 /* Resize context */
495 if (GP_ContextResize(self->context, w, h)) {
496 XDestroyImage(img);
497 return 1;
500 /* Free old image */
501 x11->img->data = NULL;
502 XDestroyImage(x11->img);
504 /* Swap the pointers */
505 img->data = (char*)self->context->pixels;
506 x11->img = img;
508 return 0;
511 static void window_close(GP_Backend *self)
513 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
515 XLockDisplay(x11->dpy);
517 if (x11->shm_flag)
518 destroy_shm_ximage(self);
519 else
520 destroy_ximage(self);
522 XDestroyWindow(x11->dpy, x11->win);
524 XUnlockDisplay(x11->dpy);
527 static void x11_exit(GP_Backend *self)
529 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
531 XLockDisplay(x11->dpy);
533 window_close(self);
535 /* I wonder if this is right sequence... */
536 //XUnlockDisplay(x11->dpy);
537 XCloseDisplay(x11->dpy);
539 free(self);
542 static void create_window(struct x11_priv *x11, int x, int y,
543 unsigned int *w, unsigned int *h,
544 const char *caption, enum GP_BackendX11Flags flags)
546 XSetWindowAttributes attrs;
547 unsigned long attr_mask = 0;
549 /* Set event mask */
550 attrs.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
551 KeyReleaseMask | PointerMotionMask;
552 attr_mask |= CWEventMask;
555 * If root window was selected, resize w and h and set x11->win to root
556 * window.
558 if (flags & GP_X11_USE_ROOT_WIN) {
559 x11->win = DefaultRootWindow(x11->dpy);
560 *w = DisplayWidth(x11->dpy, x11->scr);
561 *h = DisplayHeight(x11->dpy, x11->scr);
563 GP_DEBUG(2, "Using root window, owerriding size to %ux%u",
564 *w, *h);
566 XChangeWindowAttributes(x11->dpy, x11->win, attr_mask, &attrs);
568 return;
572 * For some reason reading mouse button clicks on root win are not
573 * allowed...
575 attrs.event_mask |= ButtonPressMask | ButtonReleaseMask;
578 * Create undecoreated root window on background
580 if (flags & GP_X11_CREATE_ROOT_WIN) {
581 Atom xa;
583 *w = DisplayWidth(x11->dpy, x11->scr);
584 *h = DisplayHeight(x11->dpy, x11->scr);
586 GP_DEBUG(2, "Creating a window above root, owerriding size to %ux%u",
587 *w, *h);
589 x11->win = XCreateWindow(x11->dpy, DefaultRootWindow(x11->dpy),
590 0, 0, *w, *h, 0, CopyFromParent,
591 InputOutput, CopyFromParent, attr_mask, &attrs);
593 /* Set empty WM_PROTOCOLS */
594 GP_DEBUG(2, "Setting empty MW_PROTOCOLS");
595 XSetWMProtocols(x11->dpy, x11->win, NULL, 0);
597 /* Set window type to desktop */
598 xa = XInternAtom(x11->dpy, "_NET_WM_WINDOW_TYPE", False);
600 if (xa != None) {
601 GP_DEBUG(2, "Setting Atom _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_DESKTOP");
603 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
605 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
606 PropModeReplace, (unsigned char *) &xa_prop, 1);
609 /* Turn off window decoration */
610 xa = XInternAtom(x11->dpy, "_MOTIF_WM_HINTS", False);
612 if (xa != None) {
613 GP_DEBUG(2, "Setting Atom _MOTIF_WM_HINTS to 2, 0, 0, 0, 0");
615 long prop[5] = {2, 0, 0, 0, 0};
617 XChangeProperty(x11->dpy, x11->win, xa, xa, 32,
618 PropModeReplace, (unsigned char *) prop, 5);
621 /* Set below other windows */
622 xa = XInternAtom(x11->dpy, "_WIN_LAYER", False);
624 if (xa != None) {
625 GP_DEBUG(2, "Setting Atom _WIN_LAYER to 6");
627 long prop = 6;
629 XChangeProperty(x11->dpy, x11->win, xa, XA_CARDINAL, 32,
630 PropModeAppend, (unsigned char *) &prop, 1);
633 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
635 if (xa != None) {
636 GP_DEBUG(2, "Setting Atom _NET_WM_STATE to _NET_WM_STATE_BELOW");
638 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_BELOW", False);
640 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
641 PropModeAppend, (unsigned char *) &xa_prop, 1);
644 /* Set sticky */
645 xa = XInternAtom(x11->dpy, "_NET_WM_DESKTOP", False);
647 if (xa != None) {
648 GP_DEBUG(2, "Setting Atom _NET_WM_DESKTOP to 0xffffffff");
650 CARD32 xa_prop = 0xffffffff;
652 XChangeProperty(x11->dpy, x11->win, xa, XA_CARDINAL, 32,
653 PropModeAppend, (unsigned char *) &xa_prop, 1);
656 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
658 if (xa != None) {
659 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_WM_STATE_STICKY");
661 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_STICKY", False);
663 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
664 PropModeAppend, (unsigned char *) &xa_prop, 1);
667 /* Skip taskbar */
668 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
670 if (xa != None) {
671 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_STATE_SKIP_TASKBAR");
673 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_SKIP_TASKBAR", False);
675 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
676 PropModeAppend, (unsigned char *) &xa_prop, 1);
679 /* Skip pager */
680 xa = XInternAtom(x11->dpy, "_NET_WM_STATE", False);
682 if (xa != None) {
683 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_STATE_SKIP_PAGER");
685 Atom xa_prop = XInternAtom(x11->dpy, "_NET_WM_STATE_SKIP_PAGER", False);
687 XChangeProperty(x11->dpy, x11->win, xa, XA_ATOM, 32,
688 PropModeAppend, (unsigned char *) &xa_prop, 1);
691 /* Set 100% opacity */
692 xa = XInternAtom(x11->dpy, "_NET_WM_WINDOW_OPACITY", False);
694 if (xa != None) {
695 GP_DEBUG(2, "Setting Atom _NET_WM_WINDOW_OPACITY to 0xffffffff");
697 long prop = 0xffffffff;
699 XChangeProperty(x11->dpy, x11->win, xa, XA_CARDINAL, 32,
700 PropModeAppend, (unsigned char *) &prop, 1);
703 /* Show window */
704 XMapWindow(x11->dpy, x11->win);
705 return;
708 GP_DEBUG(2, "Opening window '%s' %ix%i-%ux%u",
709 caption, x, y, *w, *h);
711 x11->win = XCreateWindow(x11->dpy, DefaultRootWindow(x11->dpy),
712 x, y, *w, *h, 0, CopyFromParent,
713 InputOutput, CopyFromParent, attr_mask, &attrs);
715 /* Set window caption */
716 XmbSetWMProperties(x11->dpy, x11->win, caption, caption,
717 NULL, 0, NULL, NULL, NULL);
719 /* Make the window close button send event */
720 Atom xa = XInternAtom(x11->dpy, "WM_DELETE_WINDOW", True);
722 if (xa != None) {
723 GP_DEBUG(2, "Setting WM_DELETE_WINDOW Atom to True");
725 XSetWMProtocols(x11->dpy, x11->win, &xa, 1);
726 } else {
727 GP_DEBUG(2, "Failed to set WM_DELETE_WINDOW Atom to True");
730 /* Show window */
731 XMapWindow(x11->dpy, x11->win);
734 #ifndef _NET_WM_STATE_ADD
735 # define _NET_WM_STATE_ADD 1
736 #endif /* _NET_WM_STATE_ADD */
738 #ifndef _NET_WM_STATE_REMOVE
739 # define _NET_WM_STATE_REMOVE 0
740 #endif /* _NET_WM_STATE_REMOVE */
742 /* Send NETWM message, most modern Window Managers should understand */
743 static void request_fullscreen(struct GP_Backend *self, int mode)
745 struct x11_priv *x11 = GP_BACKEND_PRIV(self);
747 if (mode < 0 || mode > 2) {
748 GP_WARN("Invalid fullscreen mode = %u", mode);
749 return;
752 GP_DEBUG(2, "Requesting fullscreen mode = %u", mode);
754 Atom wm_state, fullscreen;
756 wm_state = XInternAtom(x11->dpy, "_NET_WM_STATE", True);
757 fullscreen = XInternAtom(x11->dpy, "_NET_WM_STATE_FULLSCREEN", True);
759 if (wm_state == None || fullscreen == None) {
760 GP_WARN("Failed to create _NET_WM_* atoms");
761 return;
764 XEvent ev;
766 memset(&ev, 0, sizeof(ev));
768 ev.type = ClientMessage;
769 ev.xclient.window = x11->win;
770 ev.xclient.message_type = wm_state;
771 ev.xclient.format = 32;
772 ev.xclient.data.l[0] = mode;
773 ev.xclient.data.l[1] = fullscreen;
774 ev.xclient.data.l[2] = 0;
775 ev.xclient.data.l[3] = 1;
777 if (!XSendEvent(x11->dpy, XDefaultRootWindow(x11->dpy), False, SubstructureNotifyMask, &ev)) {
778 GP_WARN("Failed to send _NET_WM_STATE_FULLSCREEN event");
779 return;
782 XFlush(x11->dpy);
785 GP_Backend *GP_BackendX11Init(const char *display, int x, int y,
786 unsigned int w, unsigned int h,
787 const char *caption,
788 enum GP_BackendX11Flags flags)
790 GP_Backend *backend;
791 struct x11_priv *x11;
793 GP_DEBUG(1, "Initalizing X11 display '%s'", display);
795 if (!XInitThreads()) {
796 GP_DEBUG(2, "XInitThreads failed");
797 return NULL;
800 backend = malloc(sizeof(GP_Backend) +
801 sizeof(struct x11_priv));
803 if (backend == NULL)
804 return NULL;
806 x11 = GP_BACKEND_PRIV(backend);
808 x11->dpy = XOpenDisplay(display);
810 if (x11->dpy == NULL)
811 goto err0;
813 //XSynchronize(x11->dpy, True);
815 x11->scr = DefaultScreen(x11->dpy);
816 x11->vis = DefaultVisual(x11->dpy, x11->scr);
817 x11->scr_ptr = DefaultScreenOfDisplay(x11->dpy);
818 x11->scr_depth = DefaultDepthOfScreen(x11->scr_ptr);
820 GP_DEBUG(2, "Have Visual id %i, depth %u", (int)x11->vis->visualid, x11->scr_depth);
822 create_window(x11, x, y, &w, &h, caption, flags);
824 if (x11->win == None) {
825 //TODO: Error message?
826 GP_DEBUG(1, "Failed to create window");
827 goto err1;
830 if (flags & GP_X11_FULLSCREEN)
831 request_fullscreen(backend, 1);
833 backend->context = NULL;
835 if ((flags & GP_X11_DISABLE_SHM) || create_shm_ximage(backend, w, h))
836 if (create_ximage(backend, w, h))
837 goto err1;
839 XFlush(x11->dpy);
841 x11->resized_flag = 0;
843 backend->name = "X11";
844 backend->Flip = x11_flip;
845 backend->UpdateRect = x11_update_rect;
846 backend->Exit = x11_exit;
847 backend->Poll = x11_poll;
848 backend->Wait = x11_wait;
849 backend->SetAttributes = x11_set_attributes;
850 backend->ResizeAck = x11_resize_ack;
851 backend->fd = XConnectionNumber(x11->dpy);
853 return backend;
854 err1:
855 XCloseDisplay(x11->dpy);
856 err0:
857 free(backend);
858 return NULL;
861 void GP_BackendX11RequestFullscreen(GP_Backend *self, int mode)
863 request_fullscreen(self, mode);
866 #else
868 #include "GP_Backend.h"
870 GP_Backend *GP_BackendX11Init(const char *GP_UNUSED(display),
871 int GP_UNUSED(x), int GP_UNUSED(y),
872 unsigned int GP_UNUSED(w),
873 unsigned int GP_UNUSED(h),
874 const char *GP_UNUSED(caption))
876 GP_WARN("FATAL: X11 support not compiled in");
877 return NULL;
880 void GP_BackendX11RequestFullscreen(GP_Backend *GP_UNUSED(self),
881 int GP_UNUSED(mode))
885 #endif /* HAVE_LIBX11 */
887 int GP_BackendIsX11(GP_Backend *self)
889 return !strcmp(self->name, "X11");