libs: backends: X11 backend code refactoring.
[gfxprim.git] / libs / backends / GP_X11_Win.h
blob759ec73ba0ca0e58d8b1c1db2faf3a53d7f79da4
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-2013 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
24 * X11 window.
26 struct x11_win {
27 /* X11 Display */
28 Display *dpy;
29 /* X11 Screen */
30 int scr;
31 /* X11 Screen depth */
32 int scr_depth;
33 /* X11 Visual */
34 Visual *vis;
35 /* X11 Window */
36 Window win;
38 /* Image info SHM or XImage */
39 XImage *img;
41 #ifdef HAVE_X_SHM
42 XShmSegmentInfo shminfo;
43 #endif /* HAVE_X_SHM */
45 GP_Context context;
47 /* Window list pointers */
48 struct x11_win *prev;
49 struct x11_win *next;
51 /* Flags */
52 int resized_flag:1;
53 int shm_flag:1;
55 /* used to store width and height from ConfigureNotify event */
56 unsigned int new_w;
57 unsigned int new_h;
60 static struct x11_win *win_list = NULL;
62 static void win_list_add(struct x11_win *win)
64 win->next = win_list;
65 win->prev = NULL;
66 win_list = win;
69 static void win_list_rem(struct x11_win *win)
71 if (win->prev)
72 win->prev->next = win->next;
74 if (win->next)
75 win->next->prev = win->prev;
77 if (win == win_list)
78 win_list = win->next;
81 struct x11_win *win_list_lookup(Window win)
83 struct x11_win *i;
85 for (i = win_list; i != NULL; i = i->next) {
86 if (i->win == win)
87 return i;
90 return NULL;
93 #ifndef _NET_WM_STATE_ADD
94 # define _NET_WM_STATE_ADD 1
95 #endif /* _NET_WM_STATE_ADD */
97 #ifndef _NET_WM_STATE_REMOVE
98 # define _NET_WM_STATE_REMOVE 0
99 #endif /* _NET_WM_STATE_REMOVE */
101 /* Send NETWM message, most modern Window Managers should understand */
102 static void x11_win_fullscreen(struct x11_win *win, int mode)
104 if (mode < 0 || mode > 2) {
105 GP_WARN("Invalid fullscreen mode = %u", mode);
106 return;
109 GP_DEBUG(2, "Requesting fullscreen mode = %u", mode);
111 Atom wm_state, fullscreen;
113 wm_state = XInternAtom(win->dpy, "_NET_WM_STATE", True);
114 fullscreen = XInternAtom(win->dpy, "_NET_WM_STATE_FULLSCREEN", True);
116 if (wm_state == None || fullscreen == None) {
117 GP_WARN("Failed to create _NET_WM_* atoms");
118 return;
121 XEvent ev;
123 memset(&ev, 0, sizeof(ev));
125 ev.type = ClientMessage;
126 ev.xclient.window = win->win;
127 ev.xclient.message_type = wm_state;
128 ev.xclient.format = 32;
129 ev.xclient.data.l[0] = mode;
130 ev.xclient.data.l[1] = fullscreen;
131 ev.xclient.data.l[2] = 0;
132 ev.xclient.data.l[3] = 1;
134 if (!XSendEvent(win->dpy, XDefaultRootWindow(win->dpy),
135 False, SubstructureNotifyMask, &ev)) {
136 GP_WARN("Failed to send _NET_WM_STATE_FULLSCREEN event");
137 return;
140 XFlush(win->dpy);
143 /* Window request structure */
144 struct x11_wreq {
145 struct x11_win *win;
147 /* X11 display */
148 const char *display;
150 /* geometry */
151 int x;
152 int y;
153 unsigned int w;
154 unsigned int h;
156 const char *caption;
158 unsigned int flags;
161 static void x11_get_screen_size(struct x11_wreq *wreq)
163 wreq->w = DisplayWidth(wreq->win->dpy, wreq->win->scr);
164 wreq->h = DisplayHeight(wreq->win->dpy, wreq->win->scr);
167 static int x11_win_open(struct x11_wreq *wreq)
169 XSetWindowAttributes attrs;
170 unsigned long attr_mask = 0;
171 struct x11_win *win;
172 Screen *scr_ptr;
174 /* Initialize connection/increase ref count */
175 if (!x11_open(wreq->display))
176 return 1;
178 win = wreq->win;
180 /* Copy display */
181 win->dpy = x11_conn.dpy;
183 /* Get visual and screen depth */
184 win->scr = DefaultScreen(win->dpy);
185 win->vis = DefaultVisual(win->dpy, win->scr);
186 scr_ptr = DefaultScreenOfDisplay(win->dpy);
187 win->scr_depth = DefaultDepthOfScreen(scr_ptr);
189 GP_DEBUG(2, "Have Visual id %i, depth %u", (int)win->vis->visualid, win->scr_depth);
191 /* Set event mask */
192 attrs.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
193 KeyReleaseMask | PointerMotionMask;
194 attr_mask |= CWEventMask;
197 * If root window was selected, resize w and h and set win->win to root
198 * window.
200 if (wreq->flags & GP_X11_USE_ROOT_WIN) {
202 win->win = DefaultRootWindow(win->dpy);
204 x11_get_screen_size(wreq);
206 GP_DEBUG(2, "Using root window, owerriding size to %ux%u",
207 wreq->w, wreq->h);
209 win_list_add(win);
211 XChangeWindowAttributes(win->dpy, win->win, attr_mask, &attrs);
213 return 0;
217 * For some reason reading mouse button clicks on root win are not
218 * allowed...
220 attrs.event_mask |= ButtonPressMask | ButtonReleaseMask;
223 * Create undecoreated root window on background
225 if (wreq->flags & GP_X11_CREATE_ROOT_WIN) {
226 Atom xa;
228 x11_get_screen_size(wreq);
230 GP_DEBUG(2, "Creating a window above root, owerriding size to %ux%u",
231 wreq->w, wreq->h);
233 win->win = XCreateWindow(win->dpy, DefaultRootWindow(win->dpy),
234 0, 0, wreq->w, wreq->h, 0, CopyFromParent,
235 InputOutput, CopyFromParent, attr_mask, &attrs);
237 /* Set empty WM_PROTOCOLS */
238 GP_DEBUG(2, "Setting empty MW_PROTOCOLS");
239 XSetWMProtocols(win->dpy, win->win, NULL, 0);
241 /* Set window type to desktop */
242 xa = XInternAtom(win->dpy, "_NET_WM_WINDOW_TYPE", False);
244 if (xa != None) {
245 GP_DEBUG(2, "Setting Atom _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_DESKTOP");
247 Atom xa_prop = XInternAtom(win->dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
249 XChangeProperty(win->dpy, win->win, xa, XA_ATOM, 32,
250 PropModeReplace, (unsigned char *) &xa_prop, 1);
253 /* Turn off window decoration */
254 xa = XInternAtom(win->dpy, "_MOTIF_WM_HINTS", False);
256 if (xa != None) {
257 GP_DEBUG(2, "Setting Atom _MOTIF_WM_HINTS to 2, 0, 0, 0, 0");
259 long prop[5] = {2, 0, 0, 0, 0};
261 XChangeProperty(win->dpy, win->win, xa, xa, 32,
262 PropModeReplace, (unsigned char *) prop, 5);
265 /* Set below other windows */
266 xa = XInternAtom(win->dpy, "_WIN_LAYER", False);
268 if (xa != None) {
269 GP_DEBUG(2, "Setting Atom _WIN_LAYER to 6");
271 long prop = 6;
273 XChangeProperty(win->dpy, win->win, xa, XA_CARDINAL, 32,
274 PropModeAppend, (unsigned char *) &prop, 1);
277 xa = XInternAtom(win->dpy, "_NET_WM_STATE", False);
279 if (xa != None) {
280 GP_DEBUG(2, "Setting Atom _NET_WM_STATE to _NET_WM_STATE_BELOW");
282 Atom xa_prop = XInternAtom(win->dpy, "_NET_WM_STATE_BELOW", False);
284 XChangeProperty(win->dpy, win->win, xa, XA_ATOM, 32,
285 PropModeAppend, (unsigned char *) &xa_prop, 1);
288 /* Set sticky */
289 xa = XInternAtom(win->dpy, "_NET_WM_DESKTOP", False);
291 if (xa != None) {
292 GP_DEBUG(2, "Setting Atom _NET_WM_DESKTOP to 0xffffffff");
294 CARD32 xa_prop = 0xffffffff;
296 XChangeProperty(win->dpy, win->win, xa, XA_CARDINAL, 32,
297 PropModeAppend, (unsigned char *) &xa_prop, 1);
300 xa = XInternAtom(win->dpy, "_NET_WM_STATE", False);
302 if (xa != None) {
303 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_WM_STATE_STICKY");
305 Atom xa_prop = XInternAtom(win->dpy, "_NET_WM_STATE_STICKY", False);
307 XChangeProperty(win->dpy, win->win, xa, XA_ATOM, 32,
308 PropModeAppend, (unsigned char *) &xa_prop, 1);
311 /* Skip taskbar */
312 xa = XInternAtom(win->dpy, "_NET_WM_STATE", False);
314 if (xa != None) {
315 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_STATE_SKIP_TASKBAR");
317 Atom xa_prop = XInternAtom(win->dpy, "_NET_WM_STATE_SKIP_TASKBAR", False);
319 XChangeProperty(win->dpy, win->win, xa, XA_ATOM, 32,
320 PropModeAppend, (unsigned char *) &xa_prop, 1);
323 /* Skip pager */
324 xa = XInternAtom(win->dpy, "_NET_WM_STATE", False);
326 if (xa != None) {
327 GP_DEBUG(2, "Appending to Atom _NET_WM_STATE atom _NET_STATE_SKIP_PAGER");
329 Atom xa_prop = XInternAtom(win->dpy, "_NET_WM_STATE_SKIP_PAGER", False);
331 XChangeProperty(win->dpy, win->win, xa, XA_ATOM, 32,
332 PropModeAppend, (unsigned char *) &xa_prop, 1);
335 /* Set 100% opacity */
336 xa = XInternAtom(win->dpy, "_NET_WM_WINDOW_OPACITY", False);
338 if (xa != None) {
339 GP_DEBUG(2, "Setting Atom _NET_WM_WINDOW_OPACITY to 0xffffffff");
341 long prop = 0xffffffff;
343 XChangeProperty(win->dpy, win->win, xa, XA_CARDINAL, 32,
344 PropModeAppend, (unsigned char *) &prop, 1);
347 win_list_add(win);
349 /* Show window */
350 XMapWindow(win->dpy, win->win);
351 return 0;
354 GP_DEBUG(2, "Opening window '%s' %ix%i-%ux%u",
355 wreq->caption, wreq->x, wreq->y, wreq->w, wreq->h);
357 win->win = XCreateWindow(win->dpy, DefaultRootWindow(win->dpy),
358 wreq->x, wreq->y, wreq->w, wreq->h, 0,
359 CopyFromParent, InputOutput, CopyFromParent,
360 attr_mask, &attrs);
362 /* Set window caption */
363 XmbSetWMProperties(win->dpy, win->win, wreq->caption, wreq->caption,
364 NULL, 0, NULL, NULL, NULL);
366 /* Make the window close button send event */
367 Atom xa = XInternAtom(win->dpy, "WM_DELETE_WINDOW", True);
369 if (xa != None) {
370 GP_DEBUG(2, "Setting WM_DELETE_WINDOW Atom to True");
372 XSetWMProtocols(win->dpy, win->win, &xa, 1);
373 } else {
374 GP_DEBUG(2, "Failed to set WM_DELETE_WINDOW Atom to True");
377 win_list_add(win);
379 /* Show window */
380 XMapWindow(win->dpy, win->win);
382 return 0;
385 void x11_win_close(struct x11_win *win)
387 XLockDisplay(win->dpy);
389 win_list_rem(win);
392 if (x11->shm_flag)
393 destroy_shm_ximage(self);
394 else
395 destroy_ximage(self);
398 XDestroyWindow(win->dpy, win->win);
400 XUnlockDisplay(win->dpy);
402 /* Close connection/Decrease ref count */
403 x11_close();