2 #define I3__FILE__ "main.c"
14 #include <sys/types.h>
15 #include <sys/socket.h>
18 #include <sys/resource.h>
118 xcb_generic_event_t *event;
120 while ((event = xcb_poll_for_event(
conn)) != NULL) {
121 if (event->response_type == 0) {
123 DLOG(
"Expected X11 Error received for sequence %x\n", event->sequence);
125 xcb_generic_error_t *error = (xcb_generic_error_t*)event;
126 DLOG(
"X11 Error received (probably harmless)! sequence 0x%x, error_code = %d\n",
127 error->sequence, error->error_code);
134 int type = (
event->response_type & 0x7F);
149 DLOG(
"Handling XKB event\n");
155 bool mapping_changed =
false;
156 while (XPending(
xkbdpy)) {
157 XNextEvent(
xkbdpy, (XEvent*)&ev);
163 if (ev.any.xkb_type == XkbMapNotify) {
164 mapping_changed =
true;
168 if (ev.any.xkb_type != XkbStateNotify) {
169 ELOG(
"Unknown XKB event received (type %d)\n", ev.any.xkb_type);
182 if (ev.state.group == XkbGroup2Index) {
183 DLOG(
"Mode_switch enabled\n");
187 if (ev.state.group == XkbGroup1Index) {
188 DLOG(
"Mode_switch disabled\n");
194 if (!mapping_changed)
197 DLOG(
"Keyboard mapping changed, updating keybindings\n");
204 DLOG(
"Re-grabbing...\n");
218 #if EV_VERSION_MAJOR >= 4
223 fprintf(stderr,
"Closing SHM log \"%s\"\n",
shmlogname);
242 int main(
int argc,
char *argv[]) {
245 const char *i3_version
__attribute__ ((unused)) = I3_VERSION;
246 char *override_configpath = NULL;
247 bool autostart =
true;
248 char *layout_path = NULL;
249 bool delete_layout_path =
false;
250 bool force_xinerama =
false;
251 char *fake_outputs = NULL;
252 bool disable_signalhandler =
false;
253 static struct option long_options[] = {
254 {
"no-autostart", no_argument, 0,
'a'},
255 {
"config", required_argument, 0,
'c'},
256 {
"version", no_argument, 0,
'v'},
257 {
"moreversion", no_argument, 0,
'm'},
258 {
"more-version", no_argument, 0,
'm'},
259 {
"more_version", no_argument, 0,
'm'},
260 {
"help", no_argument, 0,
'h'},
261 {
"layout", required_argument, 0,
'L'},
262 {
"restart", required_argument, 0, 0},
263 {
"force-xinerama", no_argument, 0, 0},
264 {
"force_xinerama", no_argument, 0, 0},
265 {
"disable-signalhandler", no_argument, 0, 0},
266 {
"shmlog-size", required_argument, 0, 0},
267 {
"shmlog_size", required_argument, 0, 0},
268 {
"get-socketpath", no_argument, 0, 0},
269 {
"get_socketpath", no_argument, 0, 0},
270 {
"fake_outputs", required_argument, 0, 0},
271 {
"fake-outputs", required_argument, 0, 0},
272 {
"force-old-config-parser-v4.4-only", no_argument, 0, 0},
275 int option_index = 0, opt;
277 setlocale(LC_ALL,
"");
284 if (!isatty(fileno(stdout)))
285 setbuf(stdout, NULL);
298 while ((opt = getopt_long(argc, argv,
"c:CvmaL:hld:V", long_options, &option_index)) != -1) {
301 LOG(
"Autostart disabled using -a\n");
307 delete_layout_path =
false;
310 FREE(override_configpath);
311 override_configpath =
sstrdup(optarg);
314 LOG(
"Checking configuration file only (-C)\n");
318 printf(
"i3 version " I3_VERSION
" © 2009-2012 Michael Stapelberg and contributors\n");
322 printf(
"Binary i3 version: " I3_VERSION
" © 2009-2012 Michael Stapelberg and contributors\n");
330 LOG(
"Enabling debug logging\n");
337 if (strcmp(long_options[option_index].name,
"force-xinerama") == 0 ||
338 strcmp(long_options[option_index].name,
"force_xinerama") == 0) {
339 force_xinerama =
true;
340 ELOG(
"Using Xinerama instead of RandR. This option should be "
341 "avoided at all cost because it does not refresh the list "
342 "of screens, so you cannot configure displays at runtime. "
343 "Please check if your driver really does not support RandR "
344 "and disable this option as soon as you can.\n");
346 }
else if (strcmp(long_options[option_index].name,
"disable-signalhandler") == 0) {
347 disable_signalhandler =
true;
349 }
else if (strcmp(long_options[option_index].name,
"get-socketpath") == 0 ||
350 strcmp(long_options[option_index].name,
"get_socketpath") == 0) {
353 printf(
"%s\n", socket_path);
358 }
else if (strcmp(long_options[option_index].name,
"shmlog-size") == 0 ||
359 strcmp(long_options[option_index].name,
"shmlog_size") == 0) {
366 }
else if (strcmp(long_options[option_index].name,
"restart") == 0) {
369 delete_layout_path =
true;
371 }
else if (strcmp(long_options[option_index].name,
"fake-outputs") == 0 ||
372 strcmp(long_options[option_index].name,
"fake_outputs") == 0) {
373 LOG(
"Initializing fake outputs: %s\n", optarg);
374 fake_outputs =
sstrdup(optarg);
376 }
else if (strcmp(long_options[option_index].name,
"force-old-config-parser-v4.4-only") == 0) {
377 LOG(
"FORCING OLD CONFIG PARSER!\n");
383 fprintf(stderr,
"Usage: %s [-c configfile] [-d all] [-a] [-v] [-V] [-C]\n", argv[0]);
384 fprintf(stderr,
"\n");
385 fprintf(stderr,
"\t-a disable autostart ('exec' lines in config)\n");
386 fprintf(stderr,
"\t-c <file> use the provided configfile instead\n");
387 fprintf(stderr,
"\t-C validate configuration file and exit\n");
388 fprintf(stderr,
"\t-d all enable debug output\n");
389 fprintf(stderr,
"\t-L <file> path to the serialized layout during restarts\n");
390 fprintf(stderr,
"\t-v display version and exit\n");
391 fprintf(stderr,
"\t-V enable verbose mode\n");
392 fprintf(stderr,
"\n");
393 fprintf(stderr,
"\t--force-xinerama\n"
394 "\tUse Xinerama instead of RandR.\n"
395 "\tThis option should only be used if you are stuck with the\n"
396 "\told nVidia closed source driver (older than 302.17), which does\n"
397 "\tnot support RandR.\n");
398 fprintf(stderr,
"\n");
399 fprintf(stderr,
"\t--get-socketpath\n"
400 "\tRetrieve the i3 IPC socket path from X11, print it, then exit.\n");
401 fprintf(stderr,
"\n");
402 fprintf(stderr,
"\t--shmlog-size <limit>\n"
403 "\tLimits the size of the i3 SHM log to <limit> bytes. Setting this\n"
404 "\tto 0 disables SHM logging entirely.\n"
406 fprintf(stderr,
"\n");
407 fprintf(stderr,
"If you pass plain text arguments, i3 will interpret them as a command\n"
408 "to send to a currently running i3 (like i3-msg). This allows you to\n"
409 "use nice and logical commands, such as:\n"
412 "\ti3 floating toggle\n"
428 LOG(
"Additional arguments passed. Sending them as a command to i3.\n");
429 char *payload = NULL;
430 while (optind < argc) {
432 payload =
sstrdup(argv[optind]);
435 sasprintf(&both,
"%s %s", payload, argv[optind]);
441 DLOG(
"Command is: %s (%zd bytes)\n", payload, strlen(payload));
444 ELOG(
"Could not get i3 IPC socket path\n");
448 int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
450 err(EXIT_FAILURE,
"Could not create socket");
452 struct sockaddr_un addr;
453 memset(&addr, 0,
sizeof(
struct sockaddr_un));
454 addr.sun_family = AF_LOCAL;
455 strncpy(addr.sun_path, socket_path,
sizeof(addr.sun_path) - 1);
456 if (connect(sockfd, (
const struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0)
457 err(EXIT_FAILURE,
"Could not connect to i3");
460 (uint8_t*)payload) == -1)
461 err(EXIT_FAILURE,
"IPC: write()");
463 uint32_t reply_length;
467 &reply_length, &reply)) != 0) {
469 err(EXIT_FAILURE,
"IPC: read()");
472 printf(
"%.*s\n", reply_length, reply);
481 struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY };
482 setrlimit(RLIMIT_CORE, &limit);
487 LOG(
"CORE DUMPS: You are running a development version of i3, so coredumps were automatically enabled (ulimit -c unlimited).\n");
488 if (getcwd(cwd,
sizeof(cwd)) != NULL)
489 LOG(
"CORE DUMPS: Your current working directory is \"%s\".\n", cwd);
491 if ((patternfd = open(
"/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) {
492 memset(cwd,
'\0',
sizeof(cwd));
493 if (read(patternfd, cwd,
sizeof(cwd)) > 0)
495 LOG(
"CORE DUMPS: Your core_pattern is: %s", cwd);
500 LOG(
"i3 " I3_VERSION
" starting\n");
503 if (xcb_connection_has_error(
conn))
504 errx(EXIT_FAILURE,
"Cannot open display\n");
513 die(
"Could not initialize libev. Bad LIBEV_FLAGS?\n");
528 xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(
conn,
root);
529 xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(
conn,
root);
533 LOG(
"Done checking configuration file. Exiting.\n");
545 uint32_t mask = XCB_CW_EVENT_MASK;
546 uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
547 XCB_EVENT_MASK_BUTTON_PRESS |
548 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
551 XCB_EVENT_MASK_POINTER_MOTION |
552 XCB_EVENT_MASK_PROPERTY_CHANGE |
553 XCB_EVENT_MASK_ENTER_WINDOW };
554 xcb_void_cookie_t cookie;
555 cookie = xcb_change_window_attributes_checked(
conn,
root, mask, values);
556 check_error(
conn, cookie,
"Another window manager seems to be running");
558 xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(
conn, gcookie, NULL);
559 if (greply == NULL) {
560 ELOG(
"Could not get geometry of the root window, exiting\n");
563 DLOG(
"root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
566 #define xmacro(atom) \
567 xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
568 #include "atoms.xmacro"
576 ELOG(
"ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n");
579 }
else if (fcntl(ConnectionNumber(
xlibdpy), F_SETFD, FD_CLOEXEC) == -1) {
580 ELOG(
"Could not set FD_CLOEXEC on xkbdpy\n");
595 major = XkbMajorVersion,
596 minor = XkbMinorVersion;
598 if (fcntl(ConnectionNumber(
xkbdpy), F_SETFD, FD_CLOEXEC) == -1) {
599 fprintf(stderr,
"Could not set FD_CLOEXEC on xkbdpy\n");
605 fprintf(stderr,
"XKB not supported by X-server\n");
610 if (!XkbSelectEvents(
xkbdpy, XkbUseCoreKbd,
611 XkbMapNotifyMask | XkbStateNotifyMask,
612 XkbMapNotifyMask | XkbStateNotifyMask)) {
613 fprintf(stderr,
"Could not set XKB event mask\n");
619 #define xmacro(name) \
621 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
623 ELOG("Could not get atom " #name "\n"); \
626 A_ ## name = reply->atom; \
629 #include "atoms.xmacro"
643 bool needs_tree_init =
true;
645 LOG(
"Trying to restore the layout from %s...", layout_path);
647 if (delete_layout_path)
660 if (fake_outputs != NULL) {
670 DLOG(
"Checking for XRandR...\n");
676 xcb_query_pointer_reply_t *pointerreply;
678 if (!(pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL))) {
679 ELOG(
"Could not query pointer position, using first screen\n");
681 DLOG(
"Pointer at %d, %d\n", pointerreply->root_x, pointerreply->root_y);
684 ELOG(
"ERROR: No screen at (%d, %d), starting on the first screen\n",
685 pointerreply->root_x, pointerreply->root_y);
696 if (ipc_socket == -1) {
697 ELOG(
"Could not create the IPC socket, IPC disabled\n");
700 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
710 ELOG(
"socket activation: Error in sd_listen_fds\n");
712 DLOG(
"socket activation: no sockets passed\n");
718 DLOG(
"socket activation: also listening on fd %d\n", fd);
723 if ((flags = fcntl(fd, F_GETFD)) < 0 ||
724 fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
725 ELOG(
"Could not disable FD_CLOEXEC on fd %d\n", fd);
728 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
737 struct ev_io *xcb_watcher =
scalloc(
sizeof(
struct ev_io));
738 struct ev_io *xkb =
scalloc(
sizeof(
struct ev_io));
739 struct ev_check *xcb_check =
scalloc(
sizeof(
struct ev_check));
740 struct ev_prepare *xcb_prepare =
scalloc(
sizeof(
struct ev_prepare));
758 ev_prepare_start(
main_loop, xcb_prepare);
775 xcb_grab_server(
conn);
778 xcb_generic_event_t *event;
779 while ((event = xcb_poll_for_event(
conn)) != NULL) {
784 xcb_ungrab_server(
conn);
786 struct sigaction action;
789 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
790 sigemptyset(&action.sa_mask);
792 if (!disable_signalhandler)
796 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
797 sigaction(SIGILL, &action, NULL) == -1 ||
798 sigaction(SIGABRT, &action, NULL) == -1 ||
799 sigaction(SIGFPE, &action, NULL) == -1 ||
800 sigaction(SIGSEGV, &action, NULL) == -1)
801 ELOG(
"Could not setup signal handler");
805 if (sigaction(SIGHUP, &action, NULL) == -1 ||
806 sigaction(SIGINT, &action, NULL) == -1 ||
807 sigaction(SIGALRM, &action, NULL) == -1 ||
808 sigaction(SIGUSR1, &action, NULL) == -1 ||
809 sigaction(SIGUSR2, &action, NULL) == -1)
810 ELOG(
"Could not setup signal handler");
814 signal(SIGPIPE, SIG_IGN);
828 LOG(
"auto-starting (always!) %s\n", exec_always->
command);
836 sasprintf(&command,
"%s --bar_id=%s --socket=\"%s\"",
839 LOG(
"Starting bar process: %s\n", command);