]> git.sur5r.net Git - i3/i3/blob - src/mainx.c
Implement autostart using "exec" in config
[i3/i3] / src / mainx.c
1 /*
2  * vim:ts=8:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  *
6  * © 2009 Michael Stapelberg and contributors
7  *
8  * See file LICENSE for license information.
9  *
10  */
11 #include <stdio.h>
12 #include <assert.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 #include <stdbool.h>
18 #include <assert.h>
19 #include <limits.h>
20 #include <locale.h>
21
22 #include <X11/XKBlib.h>
23 #include <X11/extensions/XKB.h>
24
25 #include <xcb/xcb.h>
26 #include <xcb/xcb_atom.h>
27 #include <xcb/xcb_aux.h>
28 #include <xcb/xcb_event.h>
29 #include <xcb/xcb_property.h>
30 #include <xcb/xcb_keysyms.h>
31 #include <xcb/xcb_icccm.h>
32 #include <xcb/xinerama.h>
33
34 #include "config.h"
35 #include "data.h"
36 #include "debug.h"
37 #include "handlers.h"
38 #include "i3.h"
39 #include "layout.h"
40 #include "queue.h"
41 #include "table.h"
42 #include "util.h"
43 #include "xcb.h"
44 #include "xinerama.h"
45
46 /* This is the path to i3, copied from argv[0] when starting up */
47 char **start_argv;
48
49 /* This is our connection to X11 for use with XKB */
50 Display *xkbdpy;
51
52 /* The list of key bindings */
53 struct bindings_head bindings = TAILQ_HEAD_INITIALIZER(bindings);
54
55 /* The list of exec-lines */
56 struct autostarts_head autostarts = TAILQ_HEAD_INITIALIZER(autostarts);
57
58 /* This is a list of Stack_Windows, global, for easier/faster access on expose events */
59 struct stack_wins_head stack_wins = SLIST_HEAD_INITIALIZER(stack_wins);
60
61 /* The event handlers need to be global because they are accessed by our custom event handler
62    in handle_button_press(), needed for graphical resizing */
63 xcb_event_handlers_t evenths;
64 xcb_atom_t atoms[NUM_ATOMS];
65
66 int num_screens = 0;
67
68 /*
69  * Do some sanity checks and then reparent the window.
70  *
71  */
72 void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn, xcb_window_t window, window_attributes_t wa) {
73         LOG("managing window.\n");
74         xcb_drawable_t d = { window };
75         xcb_get_geometry_cookie_t geomc;
76         xcb_get_geometry_reply_t *geom;
77         xcb_get_window_attributes_reply_t *attr = 0;
78
79         if (wa.tag == TAG_COOKIE) {
80                 /* Check if the window is mapped (it could be not mapped when intializing and
81                    calling manage_window() for every window) */
82                 if ((attr = xcb_get_window_attributes_reply(conn, wa.u.cookie, 0)) == NULL)
83                         return;
84
85                 if (attr->map_state != XCB_MAP_STATE_VIEWABLE)
86                         goto out;
87
88                 wa.tag = TAG_VALUE;
89                 wa.u.override_redirect = attr->override_redirect;
90         }
91
92         /* Don’t manage clients with the override_redirect flag */
93         if (wa.u.override_redirect)
94                 goto out;
95
96         /* Check if the window is already managed */
97         if (table_get(&by_child, window))
98                 goto out;
99
100         /* Get the initial geometry (position, size, …) */
101         geomc = xcb_get_geometry(conn, d);
102         if (!attr) {
103                 wa.tag = TAG_COOKIE;
104                 wa.u.cookie = xcb_get_window_attributes(conn, window);
105                 attr = xcb_get_window_attributes_reply(conn, wa.u.cookie, 0);
106         }
107         geom = xcb_get_geometry_reply(conn, geomc, 0);
108         if (attr && geom) {
109                 reparent_window(conn, window, attr->visual, geom->root, geom->depth,
110                                 geom->x, geom->y, geom->width, geom->height);
111                 xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_CLASS);
112                 xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
113                 xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
114                 xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
115         }
116
117         free(geom);
118 out:
119         free(attr);
120         return;
121 }
122
123 /*
124  * reparent_window() gets called when a new window was opened and becomes a child of the root
125  * window, or it gets called by us when we manage the already existing windows at startup.
126  *
127  * Essentially, this is the point where we take over control.
128  *
129  */
130 void reparent_window(xcb_connection_t *conn, xcb_window_t child,
131                      xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
132                      int16_t x, int16_t y, uint16_t width, uint16_t height) {
133
134         xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie;
135         uint32_t mask = 0;
136         uint32_t values[3];
137
138         /* We are interested in property changes */
139         mask = XCB_CW_EVENT_MASK;
140         values[0] = CHILD_EVENT_MASK;
141         xcb_change_window_attributes(conn, child, mask, values);
142
143         /* Map the window first to avoid flickering */
144         xcb_map_window(conn, child);
145
146         /* Place requests for properties ASAP */
147         wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
148         strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
149         state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
150
151         Client *new = table_get(&by_child, child);
152
153         /* Events for already managed windows should already be filtered in manage_window() */
154         assert(new == NULL);
155
156         LOG("reparenting new client\n");
157         new = calloc(sizeof(Client), 1);
158         new->force_reconfigure = true;
159
160         /* Update the data structures */
161         Client *old_focused = CUR_CELL->currently_focused;
162
163         new->container = CUR_CELL;
164         new->workspace = new->container->workspace;
165
166         new->frame = xcb_generate_id(conn);
167         new->child = child;
168         new->rect.width = width;
169         new->rect.height = height;
170
171         mask = 0;
172
173         /* Don’t generate events for our new window, it should *not* be managed */
174         mask |= XCB_CW_OVERRIDE_REDIRECT;
175         values[0] = 1;
176
177         /* We want to know when… */
178         mask |= XCB_CW_EVENT_MASK;
179         values[1] = FRAME_EVENT_MASK;
180
181         LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
182
183         i3Font *font = load_font(conn, config.font);
184         width = min(width, c_ws->rect.x + c_ws->rect.width);
185         height = min(height, c_ws->rect.y + c_ws->rect.height);
186
187         Rect framerect = {x, y,
188                           width + 2 + 2,                  /* 2 px border at each side */
189                           height + 2 + 2 + font->height}; /* 2 px border plus font’s height */
190
191         /* Yo dawg, I heard you like windows, so I create a window around your window… */
192         new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_CURSOR_LEFT_PTR, mask, values);
193
194         long data[] = { XCB_WM_STATE_NORMAL, XCB_NONE };
195         xcb_change_property(conn, XCB_PROP_MODE_REPLACE, new->child, atoms[WM_STATE], atoms[WM_STATE], 32, 2, data);
196
197         /* Put the client inside the save set. Upon termination (whether killed or normal exit
198            does not matter) of the window manager, these clients will be correctly reparented
199            to their most closest living ancestor (= cleanup) */
200         xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
201
202         /* Generate a graphics context for the titlebar */
203         new->titlegc = xcb_generate_id(conn);
204         xcb_create_gc(conn, new->titlegc, new->frame, 0, 0);
205
206         /* Moves the original window into the new frame we've created for it */
207         new->awaiting_useless_unmap = true;
208         xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
209         if (xcb_request_check(conn, cookie) != NULL) {
210                 LOG("Could not reparent the window, aborting\n");
211                 xcb_destroy_window(conn, new->frame);
212                 free(new);
213                 return;
214         }
215
216         /* Put our data structure (Client) into the table */
217         table_put(&by_parent, new->frame, new);
218         table_put(&by_child, child, new);
219
220         /* We need to grab the mouse buttons for click to focus */
221         xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
222                         XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
223                         1 /* left mouse button */,
224                         XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
225
226         /* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
227         xcb_atom_t *atom;
228         xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
229         if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
230                 for (int i = 0; i < xcb_get_property_value_length(preply); i++)
231                         if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
232                                 LOG("Window is a dock.\n");
233                                 new->dock = true;
234                                 new->titlebar_position = TITLEBAR_OFF;
235                                 new->force_reconfigure = true;
236                                 new->container = NULL;
237                                 SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
238                         }
239         }
240
241         if (new->dock) {
242                 /* Get _NET_WM_STRUT_PARTIAL to determine the client’s requested height */
243                 uint32_t *strut;
244                 preply = xcb_get_property_reply(conn, strut_cookie, NULL);
245                 if (preply != NULL && preply->value_len > 0 && (strut = xcb_get_property_value(preply))) {
246                         /* We only use a subset of the provided values, namely the reserved space at the top/bottom
247                            of the screen. This is because the only possibility for bars is at to be at the top/bottom
248                            with maximum horizontal size.
249                            TODO: bars at the top */
250                         new->desired_height = strut[3];
251                         if (new->desired_height == 0) {
252                                 LOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", height);
253                                 new->desired_height = height;
254                         }
255                         LOG("the client wants to be %d pixels high\n", new->desired_height);
256                 } else {
257                         LOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", height);
258                         new->desired_height = height;
259                 }
260         }
261
262         /* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
263         if (CUR_CELL->workspace->fullscreen_client == NULL) {
264                 if (!new->dock) {
265                         CUR_CELL->currently_focused = new;
266                         xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
267                 }
268         } else {
269                 /* If we are in fullscreen, we should lower the window to not be annoying */
270                 uint32_t values[] = { XCB_STACK_MODE_BELOW };
271                 xcb_configure_window(conn, new->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
272         }
273
274         /* Insert into the currently active container, if it’s not a dock window */
275         if (!new->dock) {
276                 /* Insert after the old active client, if existing. If it does not exist, the
277                    container is empty and it does not matter, where we insert it */
278                 if (old_focused != NULL && !old_focused->dock)
279                         CIRCLEQ_INSERT_AFTER(&(CUR_CELL->clients), old_focused, new, clients);
280                 else CIRCLEQ_INSERT_TAIL(&(CUR_CELL->clients), new, clients);
281
282                 SLIST_INSERT_HEAD(&(new->container->workspace->focus_stack), new, focus_clients);
283         }
284
285         /* Check if the window already got the fullscreen hint set */
286         xcb_atom_t *state;
287         if ((preply = xcb_get_property_reply(conn, state_cookie, NULL)) != NULL &&
288             (state = xcb_get_property_value(preply)) != NULL)
289                 /* Check all set _NET_WM_STATEs */
290                 for (int i = 0; i < xcb_get_property_value_length(preply); i++)
291                         if (state[i] == atoms[_NET_WM_STATE_FULLSCREEN]) {
292                                 /* If the window got the fullscreen state, we just toggle fullscreen
293                                    and don’t event bother to redraw the layout – that would not change
294                                    anything anyways */
295                                 toggle_fullscreen(conn, new);
296                                 return;
297                         }
298
299         render_layout(conn);
300 }
301
302 /*
303  * Go through all existing windows (if the window manager is restarted) and manage them
304  *
305  */
306 void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *prophs, xcb_window_t root) {
307         xcb_query_tree_reply_t *reply;
308         int i, len;
309         xcb_window_t *children;
310         xcb_get_window_attributes_cookie_t *cookies;
311
312         /* Get the tree of windows whose parent is the root window (= all) */
313         if ((reply = xcb_query_tree_reply(conn, xcb_query_tree(conn, root), 0)) == NULL)
314                 return;
315
316         len = xcb_query_tree_children_length(reply);
317         cookies = smalloc(len * sizeof(*cookies));
318
319         /* Request the window attributes for every window */
320         children = xcb_query_tree_children(reply);
321         for(i = 0; i < len; ++i)
322                 cookies[i] = xcb_get_window_attributes(conn, children[i]);
323
324         /* Call manage_window with the attributes for every window */
325         for(i = 0; i < len; ++i) {
326                 window_attributes_t wa = { TAG_COOKIE, { cookies[i] } };
327                 manage_window(prophs, conn, children[i], wa);
328         }
329
330         free(reply);
331         free(cookies);
332 }
333
334 int main(int argc, char *argv[], char *env[]) {
335         int i, screens, opt;
336         char *override_configpath = NULL;
337         xcb_connection_t *conn;
338         xcb_property_handlers_t prophs;
339         xcb_window_t root;
340         xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
341
342         setlocale(LC_ALL, "");
343
344         /* Disable output buffering to make redirects in .xsession actually useful for debugging */
345         if (!isatty(fileno(stdout)))
346                 setbuf(stdout, NULL);
347
348         start_argv = argv;
349
350         while ((opt = getopt(argc, argv, "c:v")) != -1) {
351                 switch (opt) {
352                         case 'c':
353                                 override_configpath = sstrdup(optarg);
354                                 break;
355                         case 'v':
356                                 printf("i3 version " I3_VERSION " © 2009 Michael Stapelberg and contributors\n");
357                                 exit(EXIT_SUCCESS);
358                         default:
359                                 fprintf(stderr, "Usage: %s [-c configfile]\n", argv[0]);
360                                 exit(EXIT_FAILURE);
361                 }
362         }
363
364         LOG("i3 version " I3_VERSION " starting\n");
365
366         /* Initialize the table data structures for each workspace */
367         init_table();
368
369         memset(&evenths, 0, sizeof(xcb_event_handlers_t));
370         memset(&prophs, 0, sizeof(xcb_property_handlers_t));
371
372         load_configuration(override_configpath);
373
374         conn = xcb_connect(NULL, &screens);
375
376         /* Place requests for the atoms we need as soon as possible */
377         #define REQUEST_ATOM(name) atom_cookies[name] = xcb_intern_atom(conn, 0, strlen(#name), #name);
378
379         REQUEST_ATOM(_NET_SUPPORTED);
380         REQUEST_ATOM(_NET_WM_STATE_FULLSCREEN);
381         REQUEST_ATOM(_NET_SUPPORTING_WM_CHECK);
382         REQUEST_ATOM(_NET_WM_NAME);
383         REQUEST_ATOM(_NET_WM_STATE);
384         REQUEST_ATOM(_NET_WM_WINDOW_TYPE);
385         REQUEST_ATOM(_NET_WM_DESKTOP);
386         REQUEST_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
387         REQUEST_ATOM(_NET_WM_STRUT_PARTIAL);
388         REQUEST_ATOM(WM_PROTOCOLS);
389         REQUEST_ATOM(WM_DELETE_WINDOW);
390         REQUEST_ATOM(UTF8_STRING);
391         REQUEST_ATOM(WM_STATE);
392
393         /* TODO: this has to be more beautiful somewhen */
394         int major, minor, error;
395
396         major = XkbMajorVersion;
397         minor = XkbMinorVersion;
398
399         int evBase, errBase;
400
401         if ((xkbdpy = XkbOpenDisplay(getenv("DISPLAY"), &evBase, &errBase, &major, &minor, &error)) == NULL) {
402                 fprintf(stderr, "XkbOpenDisplay() failed\n");
403                 return 1;
404         }
405
406         int i1;
407         if (!XkbQueryExtension(xkbdpy,&i1,&evBase,&errBase,&major,&minor)) {
408                 fprintf(stderr, "XKB not supported by X-server\n");
409                 return 1;
410         }
411         /* end of ugliness */
412
413         xcb_event_handlers_init(conn, &evenths);
414
415         /* DEBUG: Trap all events and print them */
416         for (i = 2; i < 128; ++i)
417                 xcb_event_set_handler(&evenths, i, handle_event, 0);
418
419         for (i = 0; i < 256; ++i)
420                 xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t)handle_event, 0);
421
422         /* Expose = an Application should redraw itself, in this case it’s our titlebars. */
423         xcb_event_set_expose_handler(&evenths, handle_expose_event, NULL);
424
425         /* Key presses/releases are pretty obvious, I think */
426         xcb_event_set_key_press_handler(&evenths, handle_key_press, NULL);
427         xcb_event_set_key_release_handler(&evenths, handle_key_release, NULL);
428
429         /* Enter window = user moved his mouse over the window */
430         xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, NULL);
431
432         /* Button press = user pushed a mouse button over one of our windows */
433         xcb_event_set_button_press_handler(&evenths, handle_button_press, NULL);
434
435         /* Map notify = there is a new window */
436         xcb_event_set_map_request_handler(&evenths, handle_map_request, &prophs);
437
438         /* Unmap notify = window disappeared. When sent from a client, we don’t manage
439            it any longer. Usually, the client destroys the window shortly afterwards. */
440         xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, NULL);
441
442         /* Configure notify = window’s configuration (geometry, stacking, …). We only need
443            it to set up ignore the following enter_notify events */
444         xcb_event_set_configure_notify_handler(&evenths, handle_configure_event, NULL);
445
446         /* Configure request = window tried to change size on its own */
447         xcb_event_set_configure_request_handler(&evenths, handle_configure_request, NULL);
448
449         /* Client message are sent to the root window. The only interesting client message
450            for us is _NET_WM_STATE, we honour _NET_WM_STATE_FULLSCREEN */
451         xcb_event_set_client_message_handler(&evenths, handle_client_message, NULL);
452
453         /* Initialize the property handlers */
454         xcb_property_handlers_init(&prophs, &evenths);
455
456         /* Watch size hints (to obey correct aspect ratio) */
457         xcb_property_set_handler(&prophs, WM_NORMAL_HINTS, UINT_MAX, handle_normal_hints, NULL);
458
459         /* Get the root window and set the event mask */
460         root = xcb_aux_get_screen(conn, screens)->root;
461
462         uint32_t mask = XCB_CW_EVENT_MASK;
463         uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
464                               XCB_EVENT_MASK_STRUCTURE_NOTIFY |         /* when the user adds a screen (e.g. video
465                                                                            projector), the root window gets a
466                                                                            ConfigureNotify */
467                               XCB_EVENT_MASK_PROPERTY_CHANGE |
468                               XCB_EVENT_MASK_ENTER_WINDOW };
469         xcb_change_window_attributes(conn, root, mask, values);
470
471         /* Setup NetWM atoms */
472         #define GET_ATOM(name) { \
473                 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, atom_cookies[name], NULL); \
474                 if (!reply) { \
475                         LOG("Could not get atom " #name "\n"); \
476                         exit(-1); \
477                 } \
478                 atoms[name] = reply->atom; \
479                 free(reply); \
480         }
481
482         GET_ATOM(_NET_SUPPORTED);
483         GET_ATOM(_NET_WM_STATE_FULLSCREEN);
484         GET_ATOM(_NET_SUPPORTING_WM_CHECK);
485         GET_ATOM(_NET_WM_NAME);
486         GET_ATOM(_NET_WM_STATE);
487         GET_ATOM(_NET_WM_WINDOW_TYPE);
488         GET_ATOM(_NET_WM_DESKTOP);
489         GET_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
490         GET_ATOM(_NET_WM_STRUT_PARTIAL);
491         GET_ATOM(WM_PROTOCOLS);
492         GET_ATOM(WM_DELETE_WINDOW);
493         GET_ATOM(UTF8_STRING);
494         GET_ATOM(WM_STATE);
495
496         xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, handle_window_type, NULL);
497         /* TODO: In order to comply with EWMH, we have to watch _NET_WM_STRUT_PARTIAL */
498
499         /* Watch _NET_WM_NAME (= title of the window in UTF-8) property */
500         xcb_property_set_handler(&prophs, atoms[_NET_WM_NAME], 128, handle_windowname_change, NULL);
501
502         /* Watch WM_NAME (= title of the window in compound text) property for legacy applications */
503         xcb_watch_wm_name(&prophs, 128, handle_windowname_change_legacy, NULL);
504
505         /* Watch WM_CLASS (= class of the window) */
506         xcb_property_set_handler(&prophs, WM_CLASS, 128, handle_windowclass_change, NULL);
507
508         /* Set up the atoms we support */
509         check_error(conn, xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED],
510                        ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");
511         /* Set up the window manager’s name */
512         xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTING_WM_CHECK], WINDOW, 32, 1, &root);
513         xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, strlen("i3"), "i3");
514
515         xcb_get_numlock_mask(conn);
516
517         /* Grab the bound keys */
518         Binding *bind;
519         TAILQ_FOREACH(bind, &bindings, bindings) {
520                 LOG("Grabbing %d\n", bind->keycode);
521                 if (bind->mods & BIND_MODE_SWITCH)
522                         xcb_grab_key(conn, 0, root, 0, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
523                 else {
524                         /* Grab the key in all combinations */
525                         #define GRAB_KEY(modifier) xcb_grab_key(conn, 0, root, modifier, bind->keycode, \
526                                                                 XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC)
527                         GRAB_KEY(bind->mods);
528                         GRAB_KEY(bind->mods | xcb_numlock_mask);
529                         GRAB_KEY(bind->mods | xcb_numlock_mask | XCB_MOD_MASK_LOCK);
530                 }
531         }
532
533         /* Autostarting exec-lines */
534         Autostart *exec;
535         TAILQ_FOREACH(exec, &autostarts, autostarts) {
536                 LOG("auto-starting %s\n", exec->command);
537                 start_application(exec->command);
538         }
539
540         /* check for Xinerama */
541         LOG("Checking for Xinerama...\n");
542         initialize_xinerama(conn);
543
544         xcb_flush(conn);
545
546         manage_existing_windows(conn, &prophs, root);
547
548         /* Get pointer position to see on which screen we’re starting */
549         xcb_query_pointer_reply_t *reply;
550         if ((reply = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, root), NULL)) == NULL) {
551                 LOG("Could not get pointer position\n");
552                 return 1;
553         }
554
555         i3Screen *screen = get_screen_containing(reply->root_x, reply->root_y);
556         if (screen == NULL) {
557                 LOG("ERROR: No screen at %d x %d\n", reply->root_x, reply->root_y);
558                 return 0;
559         }
560         if (screen->current_workspace != 0) {
561                 LOG("Ok, I need to go to the other workspace\n");
562                 c_ws = &workspaces[screen->current_workspace];
563         }
564
565         /* Enter xcb’s event handler */
566         xcb_event_wait_for_event_loop(&evenths);
567
568         /* not reached */
569         return 0;
570 }