1 /*****************************************************************************
2 * This file is part of gfxprim library. *
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. *
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. *
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 *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
26 #include "../../config.h"
28 #include "core/GP_Debug.h"
29 #include "core/GP_Common.h"
34 #include <X11/Xutil.h>
35 #include <X11/Xatom.h>
41 #include <X11/extensions/XShm.h>
42 #endif /* HAVE_X_SHM */
44 #include "input/GP_InputDriverX11.h"
48 /* Connection details */
60 XShmSegmentInfo shminfo
;
62 #endif /* HAVE_X_SHM */
67 /* used to store width and height from ConfigureNotify event */
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
);
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
);
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");
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");
121 XLockDisplay(x11
->dpy
);
125 XShmPutImage(x11
->dpy
, x11
->win
, DefaultGC(x11
->dpy
, x11
->scr
),
126 x11
->img
, 0, 0, 0, 0, w
, h
, False
);
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
);
134 XUnlockDisplay(x11
->dpy
);
137 static void x11_ev(GP_Backend
*self
, XEvent
*ev
)
139 struct x11_priv
*x11
= GP_BACKEND_PRIV(self
);
143 GP_DEBUG(4, "Expose %ix%i-%ix%i %i",
144 ev
->xexpose
.x
, ev
->xexpose
.y
,
145 ev
->xexpose
.width
, ev
->xexpose
.height
,
148 if (x11
->resized_flag
)
152 if (ev
->xexpose
.x
+ ev
->xexpose
.width
> (int)self
->context
->w
) {
153 GP_WARN("Expose x + w > context->w");
157 if (ev
->xexpose
.y
+ ev
->xexpose
.height
> (int)self
->context
->h
) {
158 GP_WARN("Expose y + h > context->h");
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);
167 case ConfigureNotify
:
168 if (ev
->xconfigure
.width
== (int)self
->context
->w
&&
169 ev
->xconfigure
.height
== (int)self
->context
->h
)
172 if (ev
->xconfigure
.width
== (int)x11
->new_w
&&
173 ev
->xconfigure
.height
== (int)x11
->new_h
)
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;
184 GP_InputDriverX11EventPut(ev
);
189 static void x11_poll(GP_Backend
*self
)
191 struct x11_priv
*x11
= GP_BACKEND_PRIV(self
);
194 XLockDisplay(x11
->dpy
);
196 while (XPending(x11
->dpy
)) {
197 XNextEvent(x11
->dpy
, &ev
);
201 XUnlockDisplay(x11
->dpy
);
204 static void x11_wait(GP_Backend
*self
)
206 struct x11_priv
*x11
= GP_BACKEND_PRIV(self
);
209 XLockDisplay(x11
->dpy
);
211 XNextEvent(x11
->dpy
, &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
);
222 if (resize_shm_ximage(self
, w
, h
))
225 if (resize_ximage(self
, w
, h
))
232 static int x11_set_attributes(struct GP_Backend
*self
,
233 uint32_t w
, uint32_t h
,
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
);
253 XUnlockDisplay(x11
->dpy
);
258 static int x11_resize_ack(struct GP_Backend
*self
)
260 struct x11_priv
*x11
= GP_BACKEND_PRIV(self
);
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;
273 XUnlockDisplay(x11
->dpy
);
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
,
292 if (*pixel_type
!= GP_PIXEL_UNKNOWN
)
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");
309 if (self
->context
== NULL
)
310 GP_DEBUG(1, "Using MIT SHM Extension");
312 enum GP_PixelType pixel_type
;
315 if (self
->context
== NULL
)
316 match_pixel_type(x11
, &pixel_type
, &depth
);
318 pixel_type
= self
->context
->pixel_type
;
320 if (pixel_type
== GP_PIXEL_UNKNOWN
) {
321 GP_DEBUG(1, "Unknown pixel type");
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");
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
));
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
));
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",
356 x11
->shminfo
.readOnly
= False
;
358 if (XShmAttach(x11
->dpy
, &x11
->shminfo
) == False
) {
359 GP_WARN("XShmAttach failed");
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
;
370 //FIXME: Proper synchronization
371 XSync(x11
->dpy
, True
);
375 shmdt(x11
->shminfo
.shmaddr
);
377 shmctl(x11
->shminfo
.shmid
, IPC_RMID
, 0);
379 XDestroyImage(x11
->img
);
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
);
391 shmdt(x11
->shminfo
.shmaddr
);
392 XDestroyImage(x11
->img
);
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
);
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
);
418 static int create_shm_ximage(GP_Backend
GP_UNUSED(*self
),
419 GP_Size
GP_UNUSED(w
), GP_Size
GP_UNUSED(h
))
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
;
443 match_pixel_type(x11
, &pixel_type
, &depth
);
445 if (pixel_type
== GP_PIXEL_UNKNOWN
) {
446 GP_DEBUG(1, "Unknown pixel type");
450 self
->context
= GP_ContextAlloc(w
, h
, pixel_type
);
452 if (self
->context
== NULL
)
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
);
466 x11
->img
->data
= (char*)self
->context
->pixels
;
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
);
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);
490 GP_DEBUG(2, "XCreateImage failed");
495 if (GP_ContextResize(self
->context
, w
, h
)) {
501 x11
->img
->data
= NULL
;
502 XDestroyImage(x11
->img
);
504 /* Swap the pointers */
505 img
->data
= (char*)self
->context
->pixels
;
511 static void window_close(GP_Backend
*self
)
513 struct x11_priv
*x11
= GP_BACKEND_PRIV(self
);
515 XLockDisplay(x11
->dpy
);
518 destroy_shm_ximage(self
);
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
);
535 /* I wonder if this is right sequence... */
536 //XUnlockDisplay(x11->dpy);
537 XCloseDisplay(x11
->dpy
);
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;
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
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",
566 XChangeWindowAttributes(x11
->dpy
, x11
->win
, attr_mask
, &attrs
);
572 * For some reason reading mouse button clicks on root win are not
575 attrs
.event_mask
|= ButtonPressMask
| ButtonReleaseMask
;
578 * Create undecoreated root window on background
580 if (flags
& GP_X11_CREATE_ROOT_WIN
) {
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",
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
);
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
);
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
);
625 GP_DEBUG(2, "Setting Atom _WIN_LAYER to 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
);
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);
645 xa
= XInternAtom(x11
->dpy
, "_NET_WM_DESKTOP", False
);
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
);
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);
668 xa
= XInternAtom(x11
->dpy
, "_NET_WM_STATE", False
);
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);
680 xa
= XInternAtom(x11
->dpy
, "_NET_WM_STATE", False
);
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
);
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);
704 XMapWindow(x11
->dpy
, x11
->win
);
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
);
723 GP_DEBUG(2, "Setting WM_DELETE_WINDOW Atom to True");
725 XSetWMProtocols(x11
->dpy
, x11
->win
, &xa
, 1);
727 GP_DEBUG(2, "Failed to set WM_DELETE_WINDOW Atom to True");
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
);
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");
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");
785 GP_Backend
*GP_BackendX11Init(const char *display
, int x
, int y
,
786 unsigned int w
, unsigned int h
,
788 enum GP_BackendX11Flags flags
)
791 struct x11_priv
*x11
;
793 GP_DEBUG(1, "Initalizing X11 display '%s'", display
);
795 if (!XInitThreads()) {
796 GP_DEBUG(2, "XInitThreads failed");
800 backend
= malloc(sizeof(GP_Backend
) +
801 sizeof(struct x11_priv
));
806 x11
= GP_BACKEND_PRIV(backend
);
808 x11
->dpy
= XOpenDisplay(display
);
810 if (x11
->dpy
== NULL
)
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");
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
))
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
);
855 XCloseDisplay(x11
->dpy
);
861 void GP_BackendX11RequestFullscreen(GP_Backend
*self
, int mode
)
863 request_fullscreen(self
, mode
);
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");
880 void GP_BackendX11RequestFullscreen(GP_Backend
*GP_UNUSED(self
),
885 #endif /* HAVE_LIBX11 */
887 int GP_BackendIsX11(GP_Backend
*self
)
889 return !strcmp(self
->name
, "X11");