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-2013 Michael Stapelberg and contributors\n");
322 printf(
"Binary i3 version: " I3_VERSION
" © 2009-2013 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 ELOG(
"You are passing --force-old-config-parser-v4.4-only, but that flag was removed by now.\n");
382 fprintf(stderr,
"Usage: %s [-c configfile] [-d all] [-a] [-v] [-V] [-C]\n", argv[0]);
383 fprintf(stderr,
"\n");
384 fprintf(stderr,
"\t-a disable autostart ('exec' lines in config)\n");
385 fprintf(stderr,
"\t-c <file> use the provided configfile instead\n");
386 fprintf(stderr,
"\t-C validate configuration file and exit\n");
387 fprintf(stderr,
"\t-d all enable debug output\n");
388 fprintf(stderr,
"\t-L <file> path to the serialized layout during restarts\n");
389 fprintf(stderr,
"\t-v display version and exit\n");
390 fprintf(stderr,
"\t-V enable verbose mode\n");
391 fprintf(stderr,
"\n");
392 fprintf(stderr,
"\t--force-xinerama\n"
393 "\tUse Xinerama instead of RandR.\n"
394 "\tThis option should only be used if you are stuck with the\n"
395 "\told nVidia closed source driver (older than 302.17), which does\n"
396 "\tnot support RandR.\n");
397 fprintf(stderr,
"\n");
398 fprintf(stderr,
"\t--get-socketpath\n"
399 "\tRetrieve the i3 IPC socket path from X11, print it, then exit.\n");
400 fprintf(stderr,
"\n");
401 fprintf(stderr,
"\t--shmlog-size <limit>\n"
402 "\tLimits the size of the i3 SHM log to <limit> bytes. Setting this\n"
403 "\tto 0 disables SHM logging entirely.\n"
405 fprintf(stderr,
"\n");
406 fprintf(stderr,
"If you pass plain text arguments, i3 will interpret them as a command\n"
407 "to send to a currently running i3 (like i3-msg). This allows you to\n"
408 "use nice and logical commands, such as:\n"
411 "\ti3 floating toggle\n"
427 LOG(
"Additional arguments passed. Sending them as a command to i3.\n");
428 char *payload = NULL;
429 while (optind < argc) {
431 payload =
sstrdup(argv[optind]);
434 sasprintf(&both,
"%s %s", payload, argv[optind]);
440 DLOG(
"Command is: %s (%zd bytes)\n", payload, strlen(payload));
443 ELOG(
"Could not get i3 IPC socket path\n");
447 int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
449 err(EXIT_FAILURE,
"Could not create socket");
451 struct sockaddr_un addr;
452 memset(&addr, 0,
sizeof(
struct sockaddr_un));
453 addr.sun_family = AF_LOCAL;
454 strncpy(addr.sun_path, socket_path,
sizeof(addr.sun_path) - 1);
455 if (connect(sockfd, (
const struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0)
456 err(EXIT_FAILURE,
"Could not connect to i3");
459 (uint8_t*)payload) == -1)
460 err(EXIT_FAILURE,
"IPC: write()");
462 uint32_t reply_length;
466 if ((ret =
ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) {
468 err(EXIT_FAILURE,
"IPC: read()");
471 if (reply_type != I3_IPC_MESSAGE_TYPE_COMMAND)
472 errx(EXIT_FAILURE,
"IPC: received reply of type %d but expected %d (COMMAND)", reply_type, I3_IPC_MESSAGE_TYPE_COMMAND);
473 printf(
"%.*s\n", reply_length, reply);
482 struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY };
483 setrlimit(RLIMIT_CORE, &limit);
488 LOG(
"CORE DUMPS: You are running a development version of i3, so coredumps were automatically enabled (ulimit -c unlimited).\n");
489 if (getcwd(cwd,
sizeof(cwd)) != NULL)
490 LOG(
"CORE DUMPS: Your current working directory is \"%s\".\n", cwd);
492 if ((patternfd = open(
"/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) {
493 memset(cwd,
'\0',
sizeof(cwd));
494 if (read(patternfd, cwd,
sizeof(cwd)) > 0)
496 LOG(
"CORE DUMPS: Your core_pattern is: %s", cwd);
501 LOG(
"i3 " I3_VERSION
" starting\n");
504 if (xcb_connection_has_error(
conn))
505 errx(EXIT_FAILURE,
"Cannot open display\n");
514 die(
"Could not initialize libev. Bad LIBEV_FLAGS?\n");
529 xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(
conn,
root);
530 xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(
conn,
root);
534 LOG(
"Done checking configuration file. Exiting.\n");
546 xcb_void_cookie_t cookie;
548 check_error(
conn, cookie,
"Another window manager seems to be running");
550 xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(
conn, gcookie, NULL);
551 if (greply == NULL) {
552 ELOG(
"Could not get geometry of the root window, exiting\n");
555 DLOG(
"root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
558 #define xmacro(atom) \
559 xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
560 #include "atoms.xmacro"
568 ELOG(
"ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n");
571 }
else if (fcntl(ConnectionNumber(
xlibdpy), F_SETFD, FD_CLOEXEC) == -1) {
572 ELOG(
"Could not set FD_CLOEXEC on xkbdpy\n");
587 major = XkbMajorVersion,
588 minor = XkbMinorVersion;
590 if (fcntl(ConnectionNumber(
xkbdpy), F_SETFD, FD_CLOEXEC) == -1) {
591 fprintf(stderr,
"Could not set FD_CLOEXEC on xkbdpy\n");
597 fprintf(stderr,
"XKB not supported by X-server\n");
603 XkbMapNotifyMask | XkbStateNotifyMask,
604 XkbMapNotifyMask | XkbStateNotifyMask)) {
605 fprintf(stderr,
"Could not set XKB event mask\n");
611 #define xmacro(name) \
613 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
615 ELOG("Could not get atom " #name "\n"); \
618 A_ ## name = reply->atom; \
621 #include "atoms.xmacro"
635 bool needs_tree_init =
true;
637 LOG(
"Trying to restore the layout from %s...", layout_path);
639 if (delete_layout_path)
652 if (fake_outputs != NULL) {
662 DLOG(
"Checking for XRandR...\n");
668 xcb_query_pointer_reply_t *pointerreply;
670 if (!(pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL))) {
671 ELOG(
"Could not query pointer position, using first screen\n");
673 DLOG(
"Pointer at %d, %d\n", pointerreply->root_x, pointerreply->root_y);
676 ELOG(
"ERROR: No screen at (%d, %d), starting on the first screen\n",
677 pointerreply->root_x, pointerreply->root_y);
688 if (ipc_socket == -1) {
689 ELOG(
"Could not create the IPC socket, IPC disabled\n");
692 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
702 ELOG(
"socket activation: Error in sd_listen_fds\n");
704 DLOG(
"socket activation: no sockets passed\n");
710 DLOG(
"socket activation: also listening on fd %d\n", fd);
715 if ((flags = fcntl(fd, F_GETFD)) < 0 ||
716 fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
717 ELOG(
"Could not disable FD_CLOEXEC on fd %d\n", fd);
720 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
729 struct ev_io *xcb_watcher =
scalloc(
sizeof(
struct ev_io));
730 struct ev_io *xkb =
scalloc(
sizeof(
struct ev_io));
731 struct ev_check *xcb_check =
scalloc(
sizeof(
struct ev_check));
732 struct ev_prepare *xcb_prepare =
scalloc(
sizeof(
struct ev_prepare));
750 ev_prepare_start(
main_loop, xcb_prepare);
767 xcb_grab_server(
conn);
770 xcb_generic_event_t *event;
771 while ((event = xcb_poll_for_event(
conn)) != NULL) {
772 if (event->response_type == 0) {
778 int type = (
event->response_type & 0x7F);
783 if (type == XCB_MAP_REQUEST)
790 xcb_ungrab_server(
conn);
792 struct sigaction action;
795 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
796 sigemptyset(&action.sa_mask);
798 if (!disable_signalhandler)
802 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
803 sigaction(SIGILL, &action, NULL) == -1 ||
804 sigaction(SIGABRT, &action, NULL) == -1 ||
805 sigaction(SIGFPE, &action, NULL) == -1 ||
806 sigaction(SIGSEGV, &action, NULL) == -1)
807 ELOG(
"Could not setup signal handler");
811 if (sigaction(SIGHUP, &action, NULL) == -1 ||
812 sigaction(SIGINT, &action, NULL) == -1 ||
813 sigaction(SIGALRM, &action, NULL) == -1 ||
814 sigaction(SIGUSR1, &action, NULL) == -1 ||
815 sigaction(SIGUSR2, &action, NULL) == -1)
816 ELOG(
"Could not setup signal handler");
820 signal(SIGPIPE, SIG_IGN);
834 LOG(
"auto-starting (always!) %s\n", exec_always->
command);
842 sasprintf(&command,
"%s --bar_id=%s --socket=\"%s\"",
845 LOG(
"Starting bar process: %s\n", command);