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);
236 fprintf(stderr,
"Received signal %d, terminating\n", sig);
238 fprintf(stderr,
"Closing SHM log \"%s\"\n",
shmlogname);
245 int main(
int argc,
char *argv[]) {
248 const char *i3_version
__attribute__ ((unused)) = I3_VERSION;
249 char *override_configpath = NULL;
250 bool autostart =
true;
251 char *layout_path = NULL;
252 bool delete_layout_path =
false;
253 bool force_xinerama =
false;
254 char *fake_outputs = NULL;
255 bool disable_signalhandler =
false;
256 static struct option long_options[] = {
257 {
"no-autostart", no_argument, 0,
'a'},
258 {
"config", required_argument, 0,
'c'},
259 {
"version", no_argument, 0,
'v'},
260 {
"moreversion", no_argument, 0,
'm'},
261 {
"more-version", no_argument, 0,
'm'},
262 {
"more_version", no_argument, 0,
'm'},
263 {
"help", no_argument, 0,
'h'},
264 {
"layout", required_argument, 0,
'L'},
265 {
"restart", required_argument, 0, 0},
266 {
"force-xinerama", no_argument, 0, 0},
267 {
"force_xinerama", no_argument, 0, 0},
268 {
"disable-signalhandler", no_argument, 0, 0},
269 {
"shmlog-size", required_argument, 0, 0},
270 {
"shmlog_size", required_argument, 0, 0},
271 {
"get-socketpath", no_argument, 0, 0},
272 {
"get_socketpath", no_argument, 0, 0},
273 {
"fake_outputs", required_argument, 0, 0},
274 {
"fake-outputs", required_argument, 0, 0},
277 int option_index = 0, opt;
279 setlocale(LC_ALL,
"");
286 if (!isatty(fileno(stdout)))
287 setbuf(stdout, NULL);
300 while ((opt = getopt_long(argc, argv,
"c:CvmaL:hld:V", long_options, &option_index)) != -1) {
303 LOG(
"Autostart disabled using -a\n");
309 delete_layout_path =
false;
312 FREE(override_configpath);
313 override_configpath =
sstrdup(optarg);
316 LOG(
"Checking configuration file only (-C)\n");
320 printf(
"i3 version " I3_VERSION
" © 2009-2012 Michael Stapelberg and contributors\n");
324 printf(
"Binary i3 version: " I3_VERSION
" © 2009-2012 Michael Stapelberg and contributors\n");
332 LOG(
"Enabling debug logging\n");
339 if (strcmp(long_options[option_index].name,
"force-xinerama") == 0 ||
340 strcmp(long_options[option_index].name,
"force_xinerama") == 0) {
341 force_xinerama =
true;
342 ELOG(
"Using Xinerama instead of RandR. This option should be "
343 "avoided at all cost because it does not refresh the list "
344 "of screens, so you cannot configure displays at runtime. "
345 "Please check if your driver really does not support RandR "
346 "and disable this option as soon as you can.\n");
348 }
else if (strcmp(long_options[option_index].name,
"disable-signalhandler") == 0) {
349 disable_signalhandler =
true;
351 }
else if (strcmp(long_options[option_index].name,
"get-socketpath") == 0 ||
352 strcmp(long_options[option_index].name,
"get_socketpath") == 0) {
355 printf(
"%s\n", socket_path);
360 }
else if (strcmp(long_options[option_index].name,
"shmlog-size") == 0 ||
361 strcmp(long_options[option_index].name,
"shmlog_size") == 0) {
368 }
else if (strcmp(long_options[option_index].name,
"restart") == 0) {
371 delete_layout_path =
true;
373 }
else if (strcmp(long_options[option_index].name,
"fake-outputs") == 0 ||
374 strcmp(long_options[option_index].name,
"fake_outputs") == 0) {
375 LOG(
"Initializing fake outputs: %s\n", optarg);
376 fake_outputs =
sstrdup(optarg);
381 fprintf(stderr,
"Usage: %s [-c configfile] [-d all] [-a] [-v] [-V] [-C]\n", argv[0]);
382 fprintf(stderr,
"\n");
383 fprintf(stderr,
"\t-a disable autostart ('exec' lines in config)\n");
384 fprintf(stderr,
"\t-c <file> use the provided configfile instead\n");
385 fprintf(stderr,
"\t-C validate configuration file and exit\n");
386 fprintf(stderr,
"\t-d all enable debug output\n");
387 fprintf(stderr,
"\t-L <file> path to the serialized layout during restarts\n");
388 fprintf(stderr,
"\t-v display version and exit\n");
389 fprintf(stderr,
"\t-V enable verbose mode\n");
390 fprintf(stderr,
"\n");
391 fprintf(stderr,
"\t--force-xinerama\n"
392 "\tUse Xinerama instead of RandR.\n"
393 "\tThis option should only be used if you are stuck with the\n"
394 "\told nVidia closed source driver (older than 302.17), which does\n"
395 "\tnot support RandR.\n");
396 fprintf(stderr,
"\n");
397 fprintf(stderr,
"\t--get-socketpath\n"
398 "\tRetrieve the i3 IPC socket path from X11, print it, then exit.\n");
399 fprintf(stderr,
"\n");
400 fprintf(stderr,
"\t--shmlog-size <limit>\n"
401 "\tLimits the size of the i3 SHM log to <limit> bytes. Setting this\n"
402 "\tto 0 disables SHM logging entirely.\n"
404 fprintf(stderr,
"\n");
405 fprintf(stderr,
"If you pass plain text arguments, i3 will interpret them as a command\n"
406 "to send to a currently running i3 (like i3-msg). This allows you to\n"
407 "use nice and logical commands, such as:\n"
410 "\ti3 floating toggle\n"
426 LOG(
"Additional arguments passed. Sending them as a command to i3.\n");
427 char *payload = NULL;
428 while (optind < argc) {
430 payload =
sstrdup(argv[optind]);
433 sasprintf(&both,
"%s %s", payload, argv[optind]);
439 DLOG(
"Command is: %s (%zd bytes)\n", payload, strlen(payload));
442 ELOG(
"Could not get i3 IPC socket path\n");
446 int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
448 err(EXIT_FAILURE,
"Could not create socket");
450 struct sockaddr_un addr;
451 memset(&addr, 0,
sizeof(
struct sockaddr_un));
452 addr.sun_family = AF_LOCAL;
453 strncpy(addr.sun_path, socket_path,
sizeof(addr.sun_path) - 1);
454 if (connect(sockfd, (
const struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0)
455 err(EXIT_FAILURE,
"Could not connect to i3");
458 (uint8_t*)payload) == -1)
459 err(EXIT_FAILURE,
"IPC: write()");
461 uint32_t reply_length;
465 &reply_length, &reply)) != 0) {
467 err(EXIT_FAILURE,
"IPC: read()");
470 printf(
"%.*s\n", reply_length, reply);
479 struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY };
480 setrlimit(RLIMIT_CORE, &limit);
485 LOG(
"CORE DUMPS: You are running a development version of i3, so coredumps were automatically enabled (ulimit -c unlimited).\n");
486 if (getcwd(cwd,
sizeof(cwd)) != NULL)
487 LOG(
"CORE DUMPS: Your current working directory is \"%s\".\n", cwd);
489 if ((patternfd = open(
"/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) {
490 memset(cwd,
'\0',
sizeof(cwd));
491 if (read(patternfd, cwd,
sizeof(cwd)) > 0)
493 LOG(
"CORE DUMPS: Your core_pattern is: %s", cwd);
498 LOG(
"i3 " I3_VERSION
" starting\n");
501 if (xcb_connection_has_error(
conn))
502 errx(EXIT_FAILURE,
"Cannot open display\n");
511 die(
"Could not initialize libev. Bad LIBEV_FLAGS?\n");
526 xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(
conn,
root);
527 xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(
conn,
root);
531 LOG(
"Done checking configuration file. Exiting.\n");
543 uint32_t mask = XCB_CW_EVENT_MASK;
544 uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
545 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
548 XCB_EVENT_MASK_POINTER_MOTION |
549 XCB_EVENT_MASK_PROPERTY_CHANGE |
550 XCB_EVENT_MASK_ENTER_WINDOW };
551 xcb_void_cookie_t cookie;
552 cookie = xcb_change_window_attributes_checked(
conn,
root, mask, values);
553 check_error(
conn, cookie,
"Another window manager seems to be running");
555 xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(
conn, gcookie, NULL);
556 if (greply == NULL) {
557 ELOG(
"Could not get geometry of the root window, exiting\n");
560 DLOG(
"root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
563 #define xmacro(atom) \
564 xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
565 #include "atoms.xmacro"
573 ELOG(
"ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n");
576 }
else if (fcntl(ConnectionNumber(
xlibdpy), F_SETFD, FD_CLOEXEC) == -1) {
577 ELOG(
"Could not set FD_CLOEXEC on xkbdpy\n");
592 major = XkbMajorVersion,
593 minor = XkbMinorVersion;
595 if (fcntl(ConnectionNumber(
xkbdpy), F_SETFD, FD_CLOEXEC) == -1) {
596 fprintf(stderr,
"Could not set FD_CLOEXEC on xkbdpy\n");
602 fprintf(stderr,
"XKB not supported by X-server\n");
607 if (!XkbSelectEvents(
xkbdpy, XkbUseCoreKbd,
608 XkbMapNotifyMask | XkbStateNotifyMask,
609 XkbMapNotifyMask | XkbStateNotifyMask)) {
610 fprintf(stderr,
"Could not set XKB event mask\n");
616 #define xmacro(name) \
618 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
620 ELOG("Could not get atom " #name "\n"); \
623 A_ ## name = reply->atom; \
626 #include "atoms.xmacro"
640 bool needs_tree_init =
true;
642 LOG(
"Trying to restore the layout from %s...", layout_path);
644 if (delete_layout_path)
657 if (fake_outputs != NULL) {
667 DLOG(
"Checking for XRandR...\n");
673 xcb_query_pointer_reply_t *pointerreply;
675 if (!(pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL))) {
676 ELOG(
"Could not query pointer position, using first screen\n");
678 DLOG(
"Pointer at %d, %d\n", pointerreply->root_x, pointerreply->root_y);
681 ELOG(
"ERROR: No screen at (%d, %d), starting on the first screen\n",
682 pointerreply->root_x, pointerreply->root_y);
693 if (ipc_socket == -1) {
694 ELOG(
"Could not create the IPC socket, IPC disabled\n");
697 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
707 ELOG(
"socket activation: Error in sd_listen_fds\n");
709 DLOG(
"socket activation: no sockets passed\n");
715 DLOG(
"socket activation: also listening on fd %d\n", fd);
720 if ((flags = fcntl(fd, F_GETFD)) < 0 ||
721 fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
722 ELOG(
"Could not disable FD_CLOEXEC on fd %d\n", fd);
725 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) {
781 xcb_ungrab_server(
conn);
783 struct sigaction action;
786 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
787 sigemptyset(&action.sa_mask);
789 if (!disable_signalhandler)
793 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
794 sigaction(SIGILL, &action, NULL) == -1 ||
795 sigaction(SIGABRT, &action, NULL) == -1 ||
796 sigaction(SIGFPE, &action, NULL) == -1 ||
797 sigaction(SIGSEGV, &action, NULL) == -1)
798 ELOG(
"Could not setup signal handler");
802 if (sigaction(SIGHUP, &action, NULL) == -1 ||
803 sigaction(SIGINT, &action, NULL) == -1 ||
804 sigaction(SIGALRM, &action, NULL) == -1 ||
805 sigaction(SIGUSR1, &action, NULL) == -1 ||
806 sigaction(SIGUSR2, &action, NULL) == -1)
807 ELOG(
"Could not setup signal handler");
811 signal(SIGPIPE, SIG_IGN);
825 LOG(
"auto-starting (always!) %s\n", exec_always->
command);
833 sasprintf(&command,
"%s --bar_id=%s --socket=\"%s\"",
836 LOG(
"Starting bar process: %s\n", command);