2 #define I3__FILE__ "main.c"
14 #include <sys/types.h>
15 #include <sys/socket.h>
18 #include <sys/resource.h>
122 xcb_generic_event_t *event;
124 while ((event = xcb_poll_for_event(
conn)) != NULL) {
125 if (event->response_type == 0) {
127 DLOG(
"Expected X11 Error received for sequence %x\n", event->sequence);
129 xcb_generic_error_t *error = (xcb_generic_error_t*)event;
130 DLOG(
"X11 Error received (probably harmless)! sequence 0x%x, error_code = %d\n",
131 error->sequence, error->error_code);
138 int type = (
event->response_type & 0x7F);
153 DLOG(
"Handling XKB event\n");
159 bool mapping_changed =
false;
160 while (XPending(
xkbdpy)) {
161 XNextEvent(
xkbdpy, (XEvent*)&ev);
167 if (ev.any.xkb_type == XkbMapNotify) {
168 mapping_changed =
true;
172 if (ev.any.xkb_type != XkbStateNotify) {
173 ELOG(
"Unknown XKB event received (type %d)\n", ev.any.xkb_type);
186 if (ev.state.group == XkbGroup2Index) {
187 DLOG(
"Mode_switch enabled\n");
191 if (ev.state.group == XkbGroup1Index) {
192 DLOG(
"Mode_switch disabled\n");
198 if (!mapping_changed)
201 DLOG(
"Keyboard mapping changed, updating keybindings\n");
208 DLOG(
"Re-grabbing...\n");
222 #if EV_VERSION_MAJOR >= 4
227 fprintf(stderr,
"Closing SHM log \"%s\"\n",
shmlogname);
246 int main(
int argc,
char *argv[]) {
249 const char *i3_version
__attribute__ ((unused)) = I3_VERSION;
250 char *override_configpath = NULL;
251 bool autostart =
true;
252 char *layout_path = NULL;
253 bool delete_layout_path =
false;
254 bool force_xinerama =
false;
255 char *fake_outputs = NULL;
256 bool disable_signalhandler =
false;
257 static struct option long_options[] = {
258 {
"no-autostart", no_argument, 0,
'a'},
259 {
"config", required_argument, 0,
'c'},
260 {
"version", no_argument, 0,
'v'},
261 {
"moreversion", no_argument, 0,
'm'},
262 {
"more-version", no_argument, 0,
'm'},
263 {
"more_version", no_argument, 0,
'm'},
264 {
"help", no_argument, 0,
'h'},
265 {
"layout", required_argument, 0,
'L'},
266 {
"restart", required_argument, 0, 0},
267 {
"force-xinerama", no_argument, 0, 0},
268 {
"force_xinerama", no_argument, 0, 0},
269 {
"disable-signalhandler", no_argument, 0, 0},
270 {
"shmlog-size", required_argument, 0, 0},
271 {
"shmlog_size", required_argument, 0, 0},
272 {
"get-socketpath", no_argument, 0, 0},
273 {
"get_socketpath", no_argument, 0, 0},
274 {
"fake_outputs", required_argument, 0, 0},
275 {
"fake-outputs", required_argument, 0, 0},
276 {
"force-old-config-parser-v4.4-only", no_argument, 0, 0},
279 int option_index = 0, opt;
281 setlocale(LC_ALL,
"");
288 if (!isatty(fileno(stdout)))
289 setbuf(stdout, NULL);
302 while ((opt = getopt_long(argc, argv,
"c:CvmaL:hld:V", long_options, &option_index)) != -1) {
305 LOG(
"Autostart disabled using -a\n");
311 delete_layout_path =
false;
314 FREE(override_configpath);
315 override_configpath =
sstrdup(optarg);
318 LOG(
"Checking configuration file only (-C)\n");
322 printf(
"i3 version " I3_VERSION
" © 2009-2013 Michael Stapelberg and contributors\n");
326 printf(
"Binary i3 version: " I3_VERSION
" © 2009-2013 Michael Stapelberg and contributors\n");
334 LOG(
"Enabling debug logging\n");
341 if (strcmp(long_options[option_index].name,
"force-xinerama") == 0 ||
342 strcmp(long_options[option_index].name,
"force_xinerama") == 0) {
343 force_xinerama =
true;
344 ELOG(
"Using Xinerama instead of RandR. This option should be "
345 "avoided at all cost because it does not refresh the list "
346 "of screens, so you cannot configure displays at runtime. "
347 "Please check if your driver really does not support RandR "
348 "and disable this option as soon as you can.\n");
350 }
else if (strcmp(long_options[option_index].name,
"disable-signalhandler") == 0) {
351 disable_signalhandler =
true;
353 }
else if (strcmp(long_options[option_index].name,
"get-socketpath") == 0 ||
354 strcmp(long_options[option_index].name,
"get_socketpath") == 0) {
357 printf(
"%s\n", socket_path);
362 }
else if (strcmp(long_options[option_index].name,
"shmlog-size") == 0 ||
363 strcmp(long_options[option_index].name,
"shmlog_size") == 0) {
370 }
else if (strcmp(long_options[option_index].name,
"restart") == 0) {
373 delete_layout_path =
true;
375 }
else if (strcmp(long_options[option_index].name,
"fake-outputs") == 0 ||
376 strcmp(long_options[option_index].name,
"fake_outputs") == 0) {
377 LOG(
"Initializing fake outputs: %s\n", optarg);
378 fake_outputs =
sstrdup(optarg);
380 }
else if (strcmp(long_options[option_index].name,
"force-old-config-parser-v4.4-only") == 0) {
381 ELOG(
"You are passing --force-old-config-parser-v4.4-only, but that flag was removed by now.\n");
386 fprintf(stderr,
"Usage: %s [-c configfile] [-d all] [-a] [-v] [-V] [-C]\n", argv[0]);
387 fprintf(stderr,
"\n");
388 fprintf(stderr,
"\t-a disable autostart ('exec' lines in config)\n");
389 fprintf(stderr,
"\t-c <file> use the provided configfile instead\n");
390 fprintf(stderr,
"\t-C validate configuration file and exit\n");
391 fprintf(stderr,
"\t-d all enable debug output\n");
392 fprintf(stderr,
"\t-L <file> path to the serialized layout during restarts\n");
393 fprintf(stderr,
"\t-v display version and exit\n");
394 fprintf(stderr,
"\t-V enable verbose mode\n");
395 fprintf(stderr,
"\n");
396 fprintf(stderr,
"\t--force-xinerama\n"
397 "\tUse Xinerama instead of RandR.\n"
398 "\tThis option should only be used if you are stuck with the\n"
399 "\told nVidia closed source driver (older than 302.17), which does\n"
400 "\tnot support RandR.\n");
401 fprintf(stderr,
"\n");
402 fprintf(stderr,
"\t--get-socketpath\n"
403 "\tRetrieve the i3 IPC socket path from X11, print it, then exit.\n");
404 fprintf(stderr,
"\n");
405 fprintf(stderr,
"\t--shmlog-size <limit>\n"
406 "\tLimits the size of the i3 SHM log to <limit> bytes. Setting this\n"
407 "\tto 0 disables SHM logging entirely.\n"
409 fprintf(stderr,
"\n");
410 fprintf(stderr,
"If you pass plain text arguments, i3 will interpret them as a command\n"
411 "to send to a currently running i3 (like i3-msg). This allows you to\n"
412 "use nice and logical commands, such as:\n"
415 "\ti3 floating toggle\n"
431 LOG(
"Additional arguments passed. Sending them as a command to i3.\n");
432 char *payload = NULL;
433 while (optind < argc) {
435 payload =
sstrdup(argv[optind]);
438 sasprintf(&both,
"%s %s", payload, argv[optind]);
444 DLOG(
"Command is: %s (%zd bytes)\n", payload, strlen(payload));
447 ELOG(
"Could not get i3 IPC socket path\n");
451 int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
453 err(EXIT_FAILURE,
"Could not create socket");
455 struct sockaddr_un addr;
456 memset(&addr, 0,
sizeof(
struct sockaddr_un));
457 addr.sun_family = AF_LOCAL;
458 strncpy(addr.sun_path, socket_path,
sizeof(addr.sun_path) - 1);
459 if (connect(sockfd, (
const struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0)
460 err(EXIT_FAILURE,
"Could not connect to i3");
463 (uint8_t*)payload) == -1)
464 err(EXIT_FAILURE,
"IPC: write()");
466 uint32_t reply_length;
470 if ((ret =
ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) {
472 err(EXIT_FAILURE,
"IPC: read()");
475 if (reply_type != I3_IPC_MESSAGE_TYPE_COMMAND)
476 errx(EXIT_FAILURE,
"IPC: received reply of type %d but expected %d (COMMAND)", reply_type, I3_IPC_MESSAGE_TYPE_COMMAND);
477 printf(
"%.*s\n", reply_length, reply);
486 struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY };
487 setrlimit(RLIMIT_CORE, &limit);
491 LOG(
"CORE DUMPS: You are running a development version of i3, so coredumps were automatically enabled (ulimit -c unlimited).\n");
492 size_t cwd_size = 1024;
495 while ((cwd_ret = getcwd(cwd, cwd_size)) == NULL && errno == ERANGE) {
496 cwd_size = cwd_size * 2;
500 LOG(
"CORE DUMPS: Your current working directory is \"%s\".\n", cwd);
502 if ((patternfd = open(
"/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) {
503 memset(cwd,
'\0', cwd_size);
504 if (read(patternfd, cwd, cwd_size) > 0)
506 LOG(
"CORE DUMPS: Your core_pattern is: %s", cwd);
512 LOG(
"i3 " I3_VERSION
" starting\n");
515 if (xcb_connection_has_error(
conn))
516 errx(EXIT_FAILURE,
"Cannot open display\n");
525 die(
"Could not initialize libev. Bad LIBEV_FLAGS?\n");
540 xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(
conn,
root);
541 xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(
conn,
root);
545 LOG(
"Done checking configuration file. Exiting.\n");
557 xcb_void_cookie_t cookie;
559 check_error(
conn, cookie,
"Another window manager seems to be running");
561 xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(
conn, gcookie, NULL);
562 if (greply == NULL) {
563 ELOG(
"Could not get geometry of the root window, exiting\n");
566 DLOG(
"root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
569 #define xmacro(atom) \
570 xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
571 #include "atoms.xmacro"
579 ELOG(
"ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n");
582 }
else if (fcntl(ConnectionNumber(
xlibdpy), F_SETFD, FD_CLOEXEC) == -1) {
583 ELOG(
"Could not set FD_CLOEXEC on xkbdpy\n");
598 major = XkbMajorVersion,
599 minor = XkbMinorVersion;
601 if (fcntl(ConnectionNumber(
xkbdpy), F_SETFD, FD_CLOEXEC) == -1) {
602 fprintf(stderr,
"Could not set FD_CLOEXEC on xkbdpy\n");
608 fprintf(stderr,
"XKB not supported by X-server\n");
614 XkbMapNotifyMask | XkbStateNotifyMask,
615 XkbMapNotifyMask | XkbStateNotifyMask)) {
616 fprintf(stderr,
"Could not set XKB event mask\n");
622 #define xmacro(name) \
624 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
626 ELOG("Could not get atom " #name "\n"); \
629 A_ ## name = reply->atom; \
632 #include "atoms.xmacro"
646 bool needs_tree_init =
true;
648 LOG(
"Trying to restore the layout from %s...", layout_path);
650 if (delete_layout_path)
663 if (fake_outputs != NULL) {
673 DLOG(
"Checking for XRandR...\n");
679 xcb_query_pointer_reply_t *pointerreply;
681 if (!(pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL))) {
682 ELOG(
"Could not query pointer position, using first screen\n");
684 DLOG(
"Pointer at %d, %d\n", pointerreply->root_x, pointerreply->root_y);
687 ELOG(
"ERROR: No screen at (%d, %d), starting on the first screen\n",
688 pointerreply->root_x, pointerreply->root_y);
699 if (ipc_socket == -1) {
700 ELOG(
"Could not create the IPC socket, IPC disabled\n");
703 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
713 ELOG(
"socket activation: Error in sd_listen_fds\n");
715 DLOG(
"socket activation: no sockets passed\n");
721 DLOG(
"socket activation: also listening on fd %d\n", fd);
726 if ((flags = fcntl(fd, F_GETFD)) < 0 ||
727 fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
728 ELOG(
"Could not disable FD_CLOEXEC on fd %d\n", fd);
731 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
741 struct ev_io *xcb_watcher =
scalloc(
sizeof(
struct ev_io));
742 struct ev_io *xkb =
scalloc(
sizeof(
struct ev_io));
743 struct ev_check *xcb_check =
scalloc(
sizeof(
struct ev_check));
744 struct ev_prepare *xcb_prepare =
scalloc(
sizeof(
struct ev_prepare));
762 ev_prepare_start(
main_loop, xcb_prepare);
779 xcb_grab_server(
conn);
782 xcb_generic_event_t *event;
783 while ((event = xcb_poll_for_event(
conn)) != NULL) {
784 if (event->response_type == 0) {
790 int type = (
event->response_type & 0x7F);
795 if (type == XCB_MAP_REQUEST)
802 xcb_ungrab_server(
conn);
805 LOG(
"This is not an in-place restart, copying root window contents to a pixmap\n");
807 uint16_t
width = root->width_in_pixels;
808 uint16_t
height = root->height_in_pixels;
810 xcb_gcontext_t gc = xcb_generate_id(
conn);
812 xcb_create_pixmap(
conn, root->root_depth, pixmap, root->root, width, height);
814 xcb_create_gc(
conn, gc, root->root,
815 XCB_GC_FUNCTION | XCB_GC_PLANE_MASK | XCB_GC_FILL_STYLE | XCB_GC_SUBWINDOW_MODE,
816 (uint32_t[]){ XCB_GX_COPY, ~0, XCB_FILL_STYLE_SOLID, XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS });
819 xcb_change_window_attributes_checked(
conn,
root->root, XCB_CW_BACK_PIXMAP, (uint32_t[]){
pixmap });
821 xcb_free_gc(
conn, gc);
825 struct sigaction action;
828 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
829 sigemptyset(&action.sa_mask);
831 if (!disable_signalhandler)
835 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
836 sigaction(SIGILL, &action, NULL) == -1 ||
837 sigaction(SIGABRT, &action, NULL) == -1 ||
838 sigaction(SIGFPE, &action, NULL) == -1 ||
839 sigaction(SIGSEGV, &action, NULL) == -1)
840 ELOG(
"Could not setup signal handler");
844 if (sigaction(SIGHUP, &action, NULL) == -1 ||
845 sigaction(SIGINT, &action, NULL) == -1 ||
846 sigaction(SIGALRM, &action, NULL) == -1 ||
847 sigaction(SIGUSR1, &action, NULL) == -1 ||
848 sigaction(SIGUSR2, &action, NULL) == -1)
849 ELOG(
"Could not setup signal handler");
853 signal(SIGPIPE, SIG_IGN);
867 LOG(
"auto-starting (always!) %s\n", exec_always->
command);
875 sasprintf(&command,
"%s --bar_id=%s --socket=\"%s\"",
878 LOG(
"Starting bar process: %s\n", command);