i3
|
00001 /* 00002 * vim:ts=4:sw=4:expandtab 00003 */ 00004 #include <ev.h> 00005 #include <fcntl.h> 00006 #include <limits.h> 00007 #include "all.h" 00008 00009 static int xkb_event_base; 00010 00011 int xkb_current_group; 00012 00013 extern Con *focused; 00014 00015 char **start_argv; 00016 00017 xcb_connection_t *conn; 00018 00019 xcb_screen_t *root_screen; 00020 xcb_window_t root; 00021 uint8_t root_depth; 00022 00023 struct ev_loop *main_loop; 00024 00025 xcb_key_symbols_t *keysyms; 00026 00027 /* Those are our connections to X11 for use with libXcursor and XKB */ 00028 Display *xlibdpy, *xkbdpy; 00029 00030 /* The list of key bindings */ 00031 struct bindings_head *bindings; 00032 00033 /* The list of exec-lines */ 00034 struct autostarts_head autostarts = TAILQ_HEAD_INITIALIZER(autostarts); 00035 00036 /* The list of exec_always lines */ 00037 struct autostarts_always_head autostarts_always = TAILQ_HEAD_INITIALIZER(autostarts_always); 00038 00039 /* The list of assignments */ 00040 struct assignments_head assignments = TAILQ_HEAD_INITIALIZER(assignments); 00041 00042 /* The list of workspace assignments (which workspace should end up on which 00043 * output) */ 00044 struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignments); 00045 00046 /* We hope that those are supported and set them to true */ 00047 bool xcursor_supported = true; 00048 bool xkb_supported = true; 00049 00050 /* 00051 * This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb. 00052 * See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop 00053 * 00054 */ 00055 static void xcb_got_event(EV_P_ struct ev_io *w, int revents) { 00056 /* empty, because xcb_prepare_cb and xcb_check_cb are used */ 00057 } 00058 00059 /* 00060 * Flush before blocking (and waiting for new events) 00061 * 00062 */ 00063 static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) { 00064 xcb_flush(conn); 00065 } 00066 00067 /* 00068 * Instead of polling the X connection socket we leave this to 00069 * xcb_poll_for_event() which knows better than we can ever know. 00070 * 00071 */ 00072 static void xcb_check_cb(EV_P_ ev_check *w, int revents) { 00073 xcb_generic_event_t *event; 00074 00075 while ((event = xcb_poll_for_event(conn)) != NULL) { 00076 if (event->response_type == 0) { 00077 if (event_is_ignored(event->sequence, 0)) 00078 DLOG("Expected X11 Error received for sequence %x\n", event->sequence); 00079 else { 00080 xcb_generic_error_t *error = (xcb_generic_error_t*)event; 00081 ELOG("X11 Error received! sequence 0x%x, error_code = %d\n", 00082 error->sequence, error->error_code); 00083 } 00084 free(event); 00085 continue; 00086 } 00087 00088 /* Strip off the highest bit (set if the event is generated) */ 00089 int type = (event->response_type & 0x7F); 00090 00091 handle_event(type, event); 00092 00093 free(event); 00094 } 00095 } 00096 00097 00098 /* 00099 * When using xmodmap to change the keyboard mapping, this event 00100 * is only sent via XKB. Therefore, we need this special handler. 00101 * 00102 */ 00103 static void xkb_got_event(EV_P_ struct ev_io *w, int revents) { 00104 DLOG("Handling XKB event\n"); 00105 XkbEvent ev; 00106 00107 /* When using xmodmap, every change (!) gets an own event. 00108 * Therefore, we just read all events and only handle the 00109 * mapping_notify once. */ 00110 bool mapping_changed = false; 00111 while (XPending(xkbdpy)) { 00112 XNextEvent(xkbdpy, (XEvent*)&ev); 00113 /* While we should never receive a non-XKB event, 00114 * better do sanity checking */ 00115 if (ev.type != xkb_event_base) 00116 continue; 00117 00118 if (ev.any.xkb_type == XkbMapNotify) { 00119 mapping_changed = true; 00120 continue; 00121 } 00122 00123 if (ev.any.xkb_type != XkbStateNotify) { 00124 ELOG("Unknown XKB event received (type %d)\n", ev.any.xkb_type); 00125 continue; 00126 } 00127 00128 /* See The XKB Extension: Library Specification, section 14.1 */ 00129 /* We check if the current group (each group contains 00130 * two levels) has been changed. Mode_switch activates 00131 * group XkbGroup2Index */ 00132 if (xkb_current_group == ev.state.group) 00133 continue; 00134 00135 xkb_current_group = ev.state.group; 00136 00137 if (ev.state.group == XkbGroup2Index) { 00138 DLOG("Mode_switch enabled\n"); 00139 grab_all_keys(conn, true); 00140 } 00141 00142 if (ev.state.group == XkbGroup1Index) { 00143 DLOG("Mode_switch disabled\n"); 00144 ungrab_all_keys(conn); 00145 grab_all_keys(conn, false); 00146 } 00147 } 00148 00149 if (!mapping_changed) 00150 return; 00151 00152 DLOG("Keyboard mapping changed, updating keybindings\n"); 00153 xcb_key_symbols_free(keysyms); 00154 keysyms = xcb_key_symbols_alloc(conn); 00155 00156 xcb_get_numlock_mask(conn); 00157 00158 ungrab_all_keys(conn); 00159 DLOG("Re-grabbing...\n"); 00160 translate_keysyms(); 00161 grab_all_keys(conn, (xkb_current_group == XkbGroup2Index)); 00162 DLOG("Done\n"); 00163 } 00164 00165 int main(int argc, char *argv[]) { 00166 //parse_cmd("[ foo ] attach, attach ; focus"); 00167 int screens; 00168 char *override_configpath = NULL; 00169 bool autostart = true; 00170 char *layout_path = NULL; 00171 bool delete_layout_path = false; 00172 bool only_check_config = false; 00173 bool force_xinerama = false; 00174 bool disable_signalhandler = false; 00175 static struct option long_options[] = { 00176 {"no-autostart", no_argument, 0, 'a'}, 00177 {"config", required_argument, 0, 'c'}, 00178 {"version", no_argument, 0, 'v'}, 00179 {"help", no_argument, 0, 'h'}, 00180 {"layout", required_argument, 0, 'L'}, 00181 {"restart", required_argument, 0, 0}, 00182 {"force-xinerama", no_argument, 0, 0}, 00183 {"disable-signalhandler", no_argument, 0, 0}, 00184 {0, 0, 0, 0} 00185 }; 00186 int option_index = 0, opt; 00187 00188 setlocale(LC_ALL, ""); 00189 00190 /* Disable output buffering to make redirects in .xsession actually useful for debugging */ 00191 if (!isatty(fileno(stdout))) 00192 setbuf(stdout, NULL); 00193 00194 init_logging(); 00195 00196 start_argv = argv; 00197 00198 while ((opt = getopt_long(argc, argv, "c:CvaL:hld:V", long_options, &option_index)) != -1) { 00199 switch (opt) { 00200 case 'a': 00201 LOG("Autostart disabled using -a\n"); 00202 autostart = false; 00203 break; 00204 case 'L': 00205 FREE(layout_path); 00206 layout_path = sstrdup(optarg); 00207 delete_layout_path = false; 00208 break; 00209 case 'c': 00210 FREE(override_configpath); 00211 override_configpath = sstrdup(optarg); 00212 break; 00213 case 'C': 00214 LOG("Checking configuration file only (-C)\n"); 00215 only_check_config = true; 00216 break; 00217 case 'v': 00218 printf("i3 version " I3_VERSION " © 2009-2011 Michael Stapelberg and contributors\n"); 00219 exit(EXIT_SUCCESS); 00220 case 'V': 00221 set_verbosity(true); 00222 break; 00223 case 'd': 00224 LOG("Enabling debug loglevel %s\n", optarg); 00225 add_loglevel(optarg); 00226 break; 00227 case 'l': 00228 /* DEPRECATED, ignored for the next 3 versions (3.e, 3.f, 3.g) */ 00229 break; 00230 case 0: 00231 if (strcmp(long_options[option_index].name, "force-xinerama") == 0) { 00232 force_xinerama = true; 00233 ELOG("Using Xinerama instead of RandR. This option should be " 00234 "avoided at all cost because it does not refresh the list " 00235 "of screens, so you cannot configure displays at runtime. " 00236 "Please check if your driver really does not support RandR " 00237 "and disable this option as soon as you can.\n"); 00238 break; 00239 } else if (strcmp(long_options[option_index].name, "disable-signalhandler") == 0) { 00240 disable_signalhandler = true; 00241 break; 00242 } else if (strcmp(long_options[option_index].name, "restart") == 0) { 00243 FREE(layout_path); 00244 layout_path = sstrdup(optarg); 00245 delete_layout_path = true; 00246 break; 00247 } 00248 /* fall-through */ 00249 default: 00250 fprintf(stderr, "Usage: %s [-c configfile] [-d loglevel] [-a] [-v] [-V] [-C]\n", argv[0]); 00251 fprintf(stderr, "\n"); 00252 fprintf(stderr, "-a: disable autostart\n"); 00253 fprintf(stderr, "-L <layoutfile>: load the layout from <layoutfile>\n"); 00254 fprintf(stderr, "-v: display version and exit\n"); 00255 fprintf(stderr, "-V: enable verbose mode\n"); 00256 fprintf(stderr, "-d <loglevel>: enable debug loglevel <loglevel>\n"); 00257 fprintf(stderr, "-c <configfile>: use the provided configfile instead\n"); 00258 fprintf(stderr, "-C: check configuration file and exit\n"); 00259 fprintf(stderr, "--force-xinerama: Use Xinerama instead of RandR. This " 00260 "option should only be used if you are stuck with the " 00261 "nvidia closed source driver which does not support RandR.\n"); 00262 exit(EXIT_FAILURE); 00263 } 00264 } 00265 00266 LOG("i3 (tree) version " I3_VERSION " starting\n"); 00267 00268 conn = xcb_connect(NULL, &screens); 00269 if (xcb_connection_has_error(conn)) 00270 errx(EXIT_FAILURE, "Cannot open display\n"); 00271 00272 /* Initialize the libev event loop. This needs to be done before loading 00273 * the config file because the parser will install an ev_child watcher 00274 * for the nagbar when config errors are found. */ 00275 main_loop = EV_DEFAULT; 00276 if (main_loop == NULL) 00277 die("Could not initialize libev. Bad LIBEV_FLAGS?\n"); 00278 00279 root_screen = xcb_aux_get_screen(conn, screens); 00280 root = root_screen->root; 00281 root_depth = root_screen->root_depth; 00282 xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root); 00283 00284 load_configuration(conn, override_configpath, false); 00285 if (only_check_config) { 00286 LOG("Done checking configuration file. Exiting.\n"); 00287 exit(0); 00288 } 00289 00290 if (config.ipc_socket_path == NULL) { 00291 /* Fall back to a file name in /tmp/ based on the PID */ 00292 if ((config.ipc_socket_path = getenv("I3SOCK")) == NULL) 00293 config.ipc_socket_path = get_process_filename("ipc-socket"); 00294 else 00295 config.ipc_socket_path = sstrdup(config.ipc_socket_path); 00296 } 00297 00298 uint32_t mask = XCB_CW_EVENT_MASK; 00299 uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | 00300 XCB_EVENT_MASK_STRUCTURE_NOTIFY | /* when the user adds a screen (e.g. video 00301 projector), the root window gets a 00302 ConfigureNotify */ 00303 XCB_EVENT_MASK_POINTER_MOTION | 00304 XCB_EVENT_MASK_PROPERTY_CHANGE | 00305 XCB_EVENT_MASK_ENTER_WINDOW }; 00306 xcb_void_cookie_t cookie; 00307 cookie = xcb_change_window_attributes_checked(conn, root, mask, values); 00308 check_error(conn, cookie, "Another window manager seems to be running"); 00309 00310 xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(conn, gcookie, NULL); 00311 if (greply == NULL) { 00312 ELOG("Could not get geometry of the root window, exiting\n"); 00313 return 1; 00314 } 00315 DLOG("root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height); 00316 00317 /* Place requests for the atoms we need as soon as possible */ 00318 #define xmacro(atom) \ 00319 xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom); 00320 #include "atoms.xmacro" 00321 #undef xmacro 00322 00323 /* Initialize the Xlib connection */ 00324 xlibdpy = xkbdpy = XOpenDisplay(NULL); 00325 00326 /* Try to load the X cursors and initialize the XKB extension */ 00327 if (xlibdpy == NULL) { 00328 ELOG("ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n"); 00329 xcursor_supported = false; 00330 xkb_supported = false; 00331 } else if (fcntl(ConnectionNumber(xlibdpy), F_SETFD, FD_CLOEXEC) == -1) { 00332 ELOG("Could not set FD_CLOEXEC on xkbdpy\n"); 00333 return 1; 00334 } else { 00335 xcursor_load_cursors(); 00336 /*init_xkb();*/ 00337 } 00338 00339 /* Set a cursor for the root window (otherwise the root window will show no 00340 cursor until the first client is launched). */ 00341 if (xcursor_supported) { 00342 xcursor_set_root_cursor(); 00343 } else { 00344 xcb_cursor_t cursor_id = xcb_generate_id(conn); 00345 i3Font cursor_font = load_font("cursor", false); 00346 int xcb_cursor = xcursor_get_xcb_cursor(XCURSOR_CURSOR_POINTER); 00347 xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id, 00348 xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535); 00349 xcb_change_window_attributes(conn, root, XCB_CW_CURSOR, &cursor_id); 00350 xcb_free_cursor(conn, cursor_id); 00351 } 00352 00353 if (xkb_supported) { 00354 int errBase, 00355 major = XkbMajorVersion, 00356 minor = XkbMinorVersion; 00357 00358 if (fcntl(ConnectionNumber(xkbdpy), F_SETFD, FD_CLOEXEC) == -1) { 00359 fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); 00360 return 1; 00361 } 00362 00363 int i1; 00364 if (!XkbQueryExtension(xkbdpy,&i1,&xkb_event_base,&errBase,&major,&minor)) { 00365 fprintf(stderr, "XKB not supported by X-server\n"); 00366 return 1; 00367 } 00368 /* end of ugliness */ 00369 00370 if (!XkbSelectEvents(xkbdpy, XkbUseCoreKbd, 00371 XkbMapNotifyMask | XkbStateNotifyMask, 00372 XkbMapNotifyMask | XkbStateNotifyMask)) { 00373 fprintf(stderr, "Could not set XKB event mask\n"); 00374 return 1; 00375 } 00376 } 00377 00378 /* Setup NetWM atoms */ 00379 #define xmacro(name) \ 00380 do { \ 00381 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \ 00382 if (!reply) { \ 00383 ELOG("Could not get atom " #name "\n"); \ 00384 exit(-1); \ 00385 } \ 00386 A_ ## name = reply->atom; \ 00387 free(reply); \ 00388 } while (0); 00389 #include "atoms.xmacro" 00390 #undef xmacro 00391 00392 property_handlers_init(); 00393 00394 /* Set up the atoms we support */ 00395 xcb_atom_t supported_atoms[] = { 00396 #define xmacro(atom) A_ ## atom, 00397 #include "atoms.xmacro" 00398 #undef xmacro 00399 }; 00400 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, A_ATOM, 32, 15, supported_atoms); 00401 /* Set up the window manager’s name */ 00402 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTING_WM_CHECK, A_WINDOW, 32, 1, &root); 00403 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3"); 00404 00405 keysyms = xcb_key_symbols_alloc(conn); 00406 00407 xcb_get_numlock_mask(conn); 00408 00409 translate_keysyms(); 00410 grab_all_keys(conn, false); 00411 00412 bool needs_tree_init = true; 00413 if (layout_path) { 00414 LOG("Trying to restore the layout from %s...", layout_path); 00415 needs_tree_init = !tree_restore(layout_path, greply); 00416 if (delete_layout_path) 00417 unlink(layout_path); 00418 free(layout_path); 00419 } 00420 if (needs_tree_init) 00421 tree_init(greply); 00422 00423 free(greply); 00424 00425 if (force_xinerama) { 00426 xinerama_init(); 00427 } else { 00428 DLOG("Checking for XRandR...\n"); 00429 randr_init(&randr_base); 00430 } 00431 00432 tree_render(); 00433 00434 /* Create the UNIX domain socket for IPC */ 00435 int ipc_socket = ipc_create_socket(config.ipc_socket_path); 00436 if (ipc_socket == -1) { 00437 ELOG("Could not create the IPC socket, IPC disabled\n"); 00438 } else { 00439 free(config.ipc_socket_path); 00440 struct ev_io *ipc_io = scalloc(sizeof(struct ev_io)); 00441 ev_io_init(ipc_io, ipc_new_client, ipc_socket, EV_READ); 00442 ev_io_start(main_loop, ipc_io); 00443 } 00444 00445 /* Set up i3 specific atoms like I3_SOCKET_PATH and I3_CONFIG_PATH */ 00446 x_set_i3_atoms(); 00447 00448 struct ev_io *xcb_watcher = scalloc(sizeof(struct ev_io)); 00449 struct ev_io *xkb = scalloc(sizeof(struct ev_io)); 00450 struct ev_check *xcb_check = scalloc(sizeof(struct ev_check)); 00451 struct ev_prepare *xcb_prepare = scalloc(sizeof(struct ev_prepare)); 00452 00453 ev_io_init(xcb_watcher, xcb_got_event, xcb_get_file_descriptor(conn), EV_READ); 00454 ev_io_start(main_loop, xcb_watcher); 00455 00456 00457 if (xkb_supported) { 00458 ev_io_init(xkb, xkb_got_event, ConnectionNumber(xkbdpy), EV_READ); 00459 ev_io_start(main_loop, xkb); 00460 00461 /* Flush the buffer so that libev can properly get new events */ 00462 XFlush(xkbdpy); 00463 } 00464 00465 ev_check_init(xcb_check, xcb_check_cb); 00466 ev_check_start(main_loop, xcb_check); 00467 00468 ev_prepare_init(xcb_prepare, xcb_prepare_cb); 00469 ev_prepare_start(main_loop, xcb_prepare); 00470 00471 xcb_flush(conn); 00472 00473 manage_existing_windows(root); 00474 00475 if (!disable_signalhandler) 00476 setup_signal_handler(); 00477 00478 /* Ignore SIGPIPE to survive errors when an IPC client disconnects 00479 * while we are sending him a message */ 00480 signal(SIGPIPE, SIG_IGN); 00481 00482 /* Autostarting exec-lines */ 00483 if (autostart) { 00484 struct Autostart *exec; 00485 TAILQ_FOREACH(exec, &autostarts, autostarts) { 00486 LOG("auto-starting %s\n", exec->command); 00487 start_application(exec->command); 00488 } 00489 } 00490 00491 /* Autostarting exec_always-lines */ 00492 struct Autostart *exec_always; 00493 TAILQ_FOREACH(exec_always, &autostarts_always, autostarts_always) { 00494 LOG("auto-starting (always!) %s\n", exec_always->command); 00495 start_application(exec_always->command); 00496 } 00497 00498 ev_loop(main_loop, 0); 00499 }