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);
492 LOG(
"CORE DUMPS: You are running a development version of i3, so coredumps were automatically enabled (ulimit -c unlimited).\n");
493 if (getcwd(cwd,
sizeof(cwd)) != NULL)
494 LOG(
"CORE DUMPS: Your current working directory is \"%s\".\n", cwd);
496 if ((patternfd = open(
"/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) {
497 memset(cwd,
'\0',
sizeof(cwd));
498 if (read(patternfd, cwd,
sizeof(cwd)) > 0)
500 LOG(
"CORE DUMPS: Your core_pattern is: %s", cwd);
505 LOG(
"i3 " I3_VERSION
" starting\n");
508 if (xcb_connection_has_error(
conn))
509 errx(EXIT_FAILURE,
"Cannot open display\n");
518 die(
"Could not initialize libev. Bad LIBEV_FLAGS?\n");
533 xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(
conn,
root);
534 xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(
conn,
root);
538 LOG(
"Done checking configuration file. Exiting.\n");
550 xcb_void_cookie_t cookie;
552 check_error(
conn, cookie,
"Another window manager seems to be running");
554 xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(
conn, gcookie, NULL);
555 if (greply == NULL) {
556 ELOG(
"Could not get geometry of the root window, exiting\n");
559 DLOG(
"root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
562 #define xmacro(atom) \
563 xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
564 #include "atoms.xmacro"
572 ELOG(
"ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n");
575 }
else if (fcntl(ConnectionNumber(
xlibdpy), F_SETFD, FD_CLOEXEC) == -1) {
576 ELOG(
"Could not set FD_CLOEXEC on xkbdpy\n");
591 major = XkbMajorVersion,
592 minor = XkbMinorVersion;
594 if (fcntl(ConnectionNumber(
xkbdpy), F_SETFD, FD_CLOEXEC) == -1) {
595 fprintf(stderr,
"Could not set FD_CLOEXEC on xkbdpy\n");
601 fprintf(stderr,
"XKB not supported by X-server\n");
607 XkbMapNotifyMask | XkbStateNotifyMask,
608 XkbMapNotifyMask | XkbStateNotifyMask)) {
609 fprintf(stderr,
"Could not set XKB event mask\n");
615 #define xmacro(name) \
617 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
619 ELOG("Could not get atom " #name "\n"); \
622 A_ ## name = reply->atom; \
625 #include "atoms.xmacro"
639 bool needs_tree_init =
true;
641 LOG(
"Trying to restore the layout from %s...", layout_path);
643 if (delete_layout_path)
656 if (fake_outputs != NULL) {
666 DLOG(
"Checking for XRandR...\n");
672 xcb_query_pointer_reply_t *pointerreply;
674 if (!(pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL))) {
675 ELOG(
"Could not query pointer position, using first screen\n");
677 DLOG(
"Pointer at %d, %d\n", pointerreply->root_x, pointerreply->root_y);
680 ELOG(
"ERROR: No screen at (%d, %d), starting on the first screen\n",
681 pointerreply->root_x, pointerreply->root_y);
692 if (ipc_socket == -1) {
693 ELOG(
"Could not create the IPC socket, IPC disabled\n");
696 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
706 ELOG(
"socket activation: Error in sd_listen_fds\n");
708 DLOG(
"socket activation: no sockets passed\n");
714 DLOG(
"socket activation: also listening on fd %d\n", fd);
719 if ((flags = fcntl(fd, F_GETFD)) < 0 ||
720 fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
721 ELOG(
"Could not disable FD_CLOEXEC on fd %d\n", fd);
724 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
734 struct ev_io *xcb_watcher =
scalloc(
sizeof(
struct ev_io));
735 struct ev_io *xkb =
scalloc(
sizeof(
struct ev_io));
736 struct ev_check *xcb_check =
scalloc(
sizeof(
struct ev_check));
737 struct ev_prepare *xcb_prepare =
scalloc(
sizeof(
struct ev_prepare));
755 ev_prepare_start(
main_loop, xcb_prepare);
772 xcb_grab_server(
conn);
775 xcb_generic_event_t *event;
776 while ((event = xcb_poll_for_event(
conn)) != NULL) {
777 if (event->response_type == 0) {
783 int type = (
event->response_type & 0x7F);
788 if (type == XCB_MAP_REQUEST)
795 xcb_ungrab_server(
conn);
797 struct sigaction action;
800 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
801 sigemptyset(&action.sa_mask);
803 if (!disable_signalhandler)
807 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
808 sigaction(SIGILL, &action, NULL) == -1 ||
809 sigaction(SIGABRT, &action, NULL) == -1 ||
810 sigaction(SIGFPE, &action, NULL) == -1 ||
811 sigaction(SIGSEGV, &action, NULL) == -1)
812 ELOG(
"Could not setup signal handler");
816 if (sigaction(SIGHUP, &action, NULL) == -1 ||
817 sigaction(SIGINT, &action, NULL) == -1 ||
818 sigaction(SIGALRM, &action, NULL) == -1 ||
819 sigaction(SIGUSR1, &action, NULL) == -1 ||
820 sigaction(SIGUSR2, &action, NULL) == -1)
821 ELOG(
"Could not setup signal handler");
825 signal(SIGPIPE, SIG_IGN);
839 LOG(
"auto-starting (always!) %s\n", exec_always->
command);
847 sasprintf(&command,
"%s --bar_id=%s --socket=\"%s\"",
850 LOG(
"Starting bar process: %s\n", command);