]> Pileus Git - wmpus/blob - sys-xcb.c
Add XCB window mapping
[wmpus] / sys-xcb.c
1 /*
2  * Copyright (c) 2015 Andy Spencer <andy753421@gmail.com>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  */
15
16 #define _GNU_SOURCE
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <search.h>
20
21 #include <xcb/xcb.h>
22
23 #include "util.h"
24 #include "conf.h"
25 #include "types.h"
26 #include "sys.h"
27 #include "wm.h"
28
29 /* Configuration */
30 static int border     = 2;
31 static int stack      = 25;
32 static int no_capture = 0;
33
34 /* Internal structures */
35 struct win_sys {
36         xcb_window_t xcb;
37         int override; // normal vs override redirect
38         int managed;  // window is currently managed by wm
39 };
40
41 /* Global data */
42 static xcb_connection_t *conn;
43 static xcb_window_t      root;
44 static list_t           *screens;
45 static void             *cache;
46
47 /*****************
48  * Constant data *
49  *****************/
50
51 const char *event_names[] = {
52         [XCB_KEY_PRESS        ] "key_press",         [XCB_KEY_RELEASE      ] "key_release",
53         [XCB_BUTTON_PRESS     ] "button_press",      [XCB_BUTTON_RELEASE   ] "button_release",
54         [XCB_MOTION_NOTIFY    ] "motion_notify",     [XCB_ENTER_NOTIFY     ] "enter_notify",
55         [XCB_LEAVE_NOTIFY     ] "leave_notify",      [XCB_FOCUS_IN         ] "focus_in",
56         [XCB_FOCUS_OUT        ] "focus_out",         [XCB_KEYMAP_NOTIFY    ] "keymap_notify",
57         [XCB_EXPOSE           ] "expose",            [XCB_GRAPHICS_EXPOSURE] "graphics_exposure",
58         [XCB_NO_EXPOSURE      ] "no_exposure",       [XCB_VISIBILITY_NOTIFY] "visibility_notify",
59         [XCB_CREATE_NOTIFY    ] "create_notify",     [XCB_DESTROY_NOTIFY   ] "destroy_notify",
60         [XCB_UNMAP_NOTIFY     ] "unmap_notify",      [XCB_MAP_NOTIFY       ] "map_notify",
61         [XCB_MAP_REQUEST      ] "map_request",       [XCB_REPARENT_NOTIFY  ] "reparent_notify",
62         [XCB_CONFIGURE_NOTIFY ] "configure_notify",  [XCB_CONFIGURE_REQUEST] "configure_request",
63         [XCB_GRAVITY_NOTIFY   ] "gravity_notify",    [XCB_RESIZE_REQUEST   ] "resize_request",
64         [XCB_CIRCULATE_NOTIFY ] "circulate_notify",  [XCB_CIRCULATE_REQUEST] "circulate_request",
65         [XCB_PROPERTY_NOTIFY  ] "property_notify",   [XCB_SELECTION_CLEAR  ] "selection_clear",
66         [XCB_SELECTION_REQUEST] "selection_request", [XCB_SELECTION_NOTIFY ] "selection_notify",
67         [XCB_COLORMAP_NOTIFY  ] "colormap_notify",   [XCB_CLIENT_MESSAGE   ] "client_message",
68         [XCB_MAPPING_NOTIFY   ] "mapping_notify",    [XCB_GE_GENERIC       ] "ge_generic",
69 };
70
71 /********************
72  * Window functions *
73  ********************/
74
75 static int win_cmp(const void *_a, const void *_b)
76 {
77         const win_t *a = _a;
78         const win_t *b = _b;
79         if (a->sys->xcb < b->sys->xcb) return -1;
80         if (a->sys->xcb > b->sys->xcb) return  1;
81         return 0;
82 }
83
84 static win_t *win_get(xcb_window_t xcb)
85 {
86         win_sys_t sys = { .xcb =  xcb };
87         win_t     key = { .sys = &sys };
88
89         win_t   **win = tfind(&key, &cache, win_cmp);
90
91         if (!win) {
92                 printf("Warning: no window for %u\n", xcb);
93                 return NULL;
94         }
95
96         return *win;
97 }
98
99 /**********************
100  * X11 Event Handlers *
101  **********************/
102
103 /* Specific events */
104 static void on_create_notify(xcb_create_notify_event_t *event)
105 {
106         win_t     *win = new0(win_t);
107         win_sys_t *sys = new0(win_sys_t);
108
109         printf("on_create_notify:     xcb=%u -> win=%p\n",
110                         event->window, win);
111
112         win->x        = event->x;
113         win->y        = event->y;
114         win->w        = event->width;
115         win->h        = event->height;
116         win->sys      = sys;
117
118         sys->xcb      = event->window;
119         sys->override = event->override_redirect;
120
121         tsearch(win, &cache, win_cmp);
122 }
123
124 static void on_destroy_notify(win_t *win, xcb_destroy_notify_event_t *event)
125 {
126         printf("on_destroy_notify:    xcb=%u -> win=%p\n",
127                         event->window, win);
128
129         tdelete(win, &cache, win_cmp);
130
131         free(win->sys);
132         free(win);
133 }
134
135 static void on_map_request(win_t *win, xcb_map_request_event_t *event)
136 {
137         printf("on_map_request:       xcb=%u -> win=%p\n",
138                         event->window, win);
139
140         if (!win->sys->managed) {
141                 wm_insert(win);
142                 win->sys->managed = 1;
143         }
144
145         xcb_map_window(conn, win->sys->xcb);
146         sys_move(win, win->x, win->y, win->w, win->h);
147 }
148
149 static void on_configure_request(win_t *win, xcb_configure_request_event_t *event)
150 {
151         printf("on_configure_request: xcb=%u -> win=%p -- %dx%d @ %d,%d\n",
152                         event->window, win,
153                         event->width, event->height,
154                         event->x, event->y);
155
156         win->x = event->x;
157         win->y = event->y;
158         win->w = event->width;
159         win->h = event->height;
160
161         xcb_configure_notify_event_t resp = {
162                 .response_type = XCB_CONFIGURE_NOTIFY,
163                 .event         = win->sys->xcb,
164                 .window        = win->sys->xcb,
165                 .x             = win->x,
166                 .y             = win->y,
167                 .width         = win->w,
168                 .height        = win->h,
169                 .border_width  = border,
170         };
171
172         xcb_send_event(conn, 0, win->sys->xcb,
173                         XCB_EVENT_MASK_STRUCTURE_NOTIFY,
174                         (const char *)&resp);
175 }
176
177 /* Generic Event */
178 static void on_event(xcb_generic_event_t *event)
179 {
180         win_t *win = NULL;
181         switch (event->response_type) {
182                 case XCB_CREATE_NOTIFY:
183                         on_create_notify((xcb_create_notify_event_t *)event);
184                         break;
185                 case XCB_DESTROY_NOTIFY:
186                         if ((win = win_get(((xcb_destroy_notify_event_t *)event)->window)))
187                                 on_destroy_notify(win, (xcb_destroy_notify_event_t *)event);
188                         break;
189                 case XCB_MAP_REQUEST:
190                         if ((win = win_get(((xcb_map_request_event_t *)event)->window)))
191                                 on_map_request(win, (xcb_map_request_event_t *)event);
192                         break;
193                 case XCB_CONFIGURE_REQUEST:
194                         if ((win = win_get(((xcb_configure_request_event_t *)event)->window)))
195                                 on_configure_request(win, (xcb_configure_request_event_t *)event);
196                         break;
197                 default:
198                         printf("on_%s\n", event_names[event->response_type] ?: "unknown_event");
199                         break;
200         }
201 }
202
203 /********************
204  * System functions *
205  ********************/
206
207 void sys_move(win_t *win, int x, int y, int w, int h)
208 {
209         printf("sys_move: %p - %dx%d @ %d,%d\n",
210                         win, w, h, x, y);
211
212         win->x = x;
213         win->y = y;
214         win->w = w;
215         win->h = h;
216
217         uint16_t mask   = XCB_CONFIG_WINDOW_X
218                         | XCB_CONFIG_WINDOW_Y
219                         | XCB_CONFIG_WINDOW_WIDTH
220                         | XCB_CONFIG_WINDOW_HEIGHT;
221         uint32_t list[] = {x, y, w, h};
222
223         xcb_configure_window(conn, win->sys->xcb, mask, list);
224 }
225
226 void sys_raise(win_t *win)
227 {
228         printf("sys_raise: %p\n", win);
229 }
230
231 void sys_focus(win_t *win)
232 {
233         printf("sys_focus: %p\n", win);
234 }
235
236 void sys_show(win_t *win, state_t state)
237 {
238         printf("sys_show: %p - %d\n", win, state);
239 }
240
241 void sys_watch(win_t *win, event_t ev, mod_t mod)
242 {
243         printf("sys_watch: %p - 0x%X,0x%X\n", win, ev, mod2int(mod));
244 }
245
246 void sys_unwatch(win_t *win, event_t ev, mod_t mod)
247 {
248         printf("sys_unwatch: %p - 0x%X,0x%X\n", win, ev, mod2int(mod));
249 }
250
251 list_t *sys_info(void)
252 {
253         printf("sys_info\n");
254
255         if (screens == NULL) {
256                 win_t *screen = new0(win_t);
257                 screen->x = 0;
258                 screen->y = 0;
259                 screen->w = 800;
260                 screen->h = 600;
261                 screens = list_insert(NULL, screen);
262         }
263
264         return screens;
265 }
266
267 void sys_init(void)
268 {
269         printf("sys_init\n");
270
271         /* Load configuration */
272         stack      = conf_get_int("main.stack",      stack);
273         border     = conf_get_int("main.border",     border);
274         no_capture = conf_get_int("main.no-capture", no_capture);
275
276         /* Connect to display */
277         if (!(conn = xcb_connect(NULL, NULL)))
278                 error("xcb connect failed");
279         if (xcb_connection_has_error(conn))
280                 error("xcb connection has errors");
281
282         /* Get root window */
283         const xcb_setup_t     *setup = xcb_get_setup(conn);
284         xcb_screen_iterator_t  iter  = xcb_setup_roots_iterator(setup);
285         root = iter.data->root;
286
287         /* Request substructure redirect */
288         xcb_event_mask_t     mask;
289         xcb_void_cookie_t    cookie;
290         xcb_generic_error_t *err;
291         mask   = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
292                  XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
293         cookie = xcb_change_window_attributes_checked(conn, root,
294                         XCB_CW_EVENT_MASK, &mask);
295         if ((err = xcb_request_check(conn, cookie)))
296                 error("Another window manager is already running");
297 }
298
299 void sys_run(void)
300 {
301         printf("sys_run\n");
302         while (1)
303         {
304                 int status;
305                 xcb_generic_event_t *event;
306                 if (!(event = xcb_wait_for_event(conn)))
307                         break;
308                 on_event(event);
309                 free(event);
310                 if (!(status = xcb_flush(conn)))
311                         break;
312         }
313 }
314
315 void sys_exit(void)
316 {
317         printf("sys_exit\n");
318         if (conn)
319                 xcb_disconnect(conn);
320         conn = NULL;
321 }
322
323 void sys_free(void)
324 {
325         printf("sys_free\n");
326         if (conn)
327                 xcb_disconnect(conn);
328         conn = NULL;
329 }