2 * Copyright (c) 2015 Andy Spencer <andy753421@gmail.com>
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.
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
30 static int border = 2;
31 static int stack = 25;
32 static int no_capture = 0;
34 /* Internal structures */
37 int override; // normal vs override redirect
38 int managed; // window is currently managed by wm
42 static xcb_connection_t *conn;
43 static xcb_window_t root;
44 static list_t *screens;
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",
75 static int win_cmp(const void *_a, const void *_b)
79 if (a->sys->xcb < b->sys->xcb) return -1;
80 if (a->sys->xcb > b->sys->xcb) return 1;
84 static win_t *win_get(xcb_window_t xcb)
86 win_sys_t sys = { .xcb = xcb };
87 win_t key = { .sys = &sys };
89 win_t **win = tfind(&key, &cache, win_cmp);
92 printf("Warning: no window for %u\n", xcb);
99 /**********************
100 * X11 Event Handlers *
101 **********************/
103 /* Specific events */
104 static void on_create_notify(xcb_create_notify_event_t *event)
106 win_t *win = new0(win_t);
107 win_sys_t *sys = new0(win_sys_t);
109 printf("on_create_notify: xcb=%u -> win=%p\n",
114 win->w = event->width;
115 win->h = event->height;
118 sys->xcb = event->window;
119 sys->override = event->override_redirect;
121 tsearch(win, &cache, win_cmp);
124 static void on_destroy_notify(win_t *win, xcb_destroy_notify_event_t *event)
126 printf("on_destroy_notify: xcb=%u -> win=%p\n",
129 tdelete(win, &cache, win_cmp);
135 static void on_map_request(win_t *win, xcb_map_request_event_t *event)
137 printf("on_map_request: xcb=%u -> win=%p\n",
140 if (!win->sys->managed) {
142 win->sys->managed = 1;
145 xcb_map_window(conn, win->sys->xcb);
146 sys_move(win, win->x, win->y, win->w, win->h);
149 static void on_configure_request(win_t *win, xcb_configure_request_event_t *event)
151 printf("on_configure_request: xcb=%u -> win=%p -- %dx%d @ %d,%d\n",
153 event->width, event->height,
158 win->w = event->width;
159 win->h = event->height;
161 xcb_configure_notify_event_t resp = {
162 .response_type = XCB_CONFIGURE_NOTIFY,
163 .event = win->sys->xcb,
164 .window = win->sys->xcb,
169 .border_width = border,
172 xcb_send_event(conn, 0, win->sys->xcb,
173 XCB_EVENT_MASK_STRUCTURE_NOTIFY,
174 (const char *)&resp);
178 static void on_event(xcb_generic_event_t *event)
181 switch (event->response_type) {
182 case XCB_CREATE_NOTIFY:
183 on_create_notify((xcb_create_notify_event_t *)event);
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);
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);
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);
198 printf("on_%s\n", event_names[event->response_type] ?: "unknown_event");
203 /********************
205 ********************/
207 void sys_move(win_t *win, int x, int y, int w, int h)
209 printf("sys_move: %p - %dx%d @ %d,%d\n",
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};
223 xcb_configure_window(conn, win->sys->xcb, mask, list);
226 void sys_raise(win_t *win)
228 printf("sys_raise: %p\n", win);
231 void sys_focus(win_t *win)
233 printf("sys_focus: %p\n", win);
236 void sys_show(win_t *win, state_t state)
238 printf("sys_show: %p - %d\n", win, state);
241 void sys_watch(win_t *win, event_t ev, mod_t mod)
243 printf("sys_watch: %p - 0x%X,0x%X\n", win, ev, mod2int(mod));
246 void sys_unwatch(win_t *win, event_t ev, mod_t mod)
248 printf("sys_unwatch: %p - 0x%X,0x%X\n", win, ev, mod2int(mod));
251 list_t *sys_info(void)
253 printf("sys_info\n");
255 if (screens == NULL) {
256 win_t *screen = new0(win_t);
261 screens = list_insert(NULL, screen);
269 printf("sys_init\n");
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);
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");
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;
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");
305 xcb_generic_event_t *event;
306 if (!(event = xcb_wait_for_event(conn)))
310 if (!(status = xcb_flush(conn)))
317 printf("sys_exit\n");
319 xcb_disconnect(conn);
325 printf("sys_free\n");
327 xcb_disconnect(conn);