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);
void load_configuration(xcb_connection_t *conn, const char *override_configpath, bool reload)
Reads the configuration from ~/.i3/config or /etc/i3/config if not found.
void randr_init(int *event_base)
We have just established a connection to the X server and need the initial XRandR information to setu...
A 'Con' represents everything from the X11 root window down to a single X11 window.
int ipc_send_message(int sockfd, const uint32_t message_size, const uint32_t message_type, const uint8_t *payload)
Formats a message (payload) of the given size and type and sends it to i3 via the given socket file d...
uint32_t aio_get_mod_mask_for(uint32_t keysym, xcb_key_symbols_t *symbols)
All-in-one function which returns the modifier mask (XCB_MOD_MASK_*) for the given keysymbol...
void fake_outputs_init(const char *output_spec)
Creates outputs according to the given specification.
static void i3_exit(void)
void ewmh_update_workarea(void)
i3 currently does not support _NET_WORKAREA, because it does not correspond to i3’s concept of worksp...
struct barconfig_head barconfigs
xcb_timestamp_t last_timestamp
The last timestamp we got from X11 (timestamps are included in some events and are used for some thin...
void init_logging(void)
Initializes logging by creating an error logfile in /tmp (or XDG_RUNTIME_DIR, see get_process_filenam...
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
void ewmh_setup_hints(void)
Set up the EWMH hints on the root window.
static int xkb_event_base
char * fake_outputs
Overwrites output detection (for testing), see src/fake_outputs.c.
void * scalloc(size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
bool force_xinerama
By default, use the RandR API for multi-monitor setups.
static void xcb_check_cb(EV_P_ ev_check *w, int revents)
void xcursor_set_root_cursor(int cursor_id)
Sets the cursor of the root window to the 'pointer' cursor.
Output * get_first_output(void)
Returns the first output which is active.
bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry)
Loads tree from ~/.i3/_restart.json (used for in-place restarts).
void xcursor_load_cursors(void)
static void handle_signal(int sig, siginfo_t *info, void *data)
struct ws_assignments_head ws_assignments
#define SD_LISTEN_FDS_START
int sd_listen_fds(int unset_environment)
#define TAILQ_HEAD_INITIALIZER(head)
char * root_atom_contents(const char *atomname)
Try to get the contents of the given atom (for example I3_SOCKET_PATH) from the X11 root window and r...
int main(int argc, char *argv[])
struct autostarts_head autostarts
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
int ipc_create_socket(const char *filename)
Creates the UNIX domain socket at the given path, sets it to non-blocking mode, bind()s and listen()s...
bool event_is_ignored(const int sequence, const int response_type)
Checks if the given sequence is ignored and returns true if so.
char * id
Automatically generated ID for this bar config.
int sasprintf(char **strp, const char *fmt,...)
Safe-wrapper around asprintf which exits if it returns -1 (meaning that there is no more memory avail...
xcb_screen_t * root_screen
bool no_startup_id
no_startup_id flag for start_application().
int ipc_recv_message(int sockfd, uint32_t *message_type, uint32_t *reply_length, uint8_t **reply)
Reads a message from the given socket file descriptor and stores its length (reply_length) as well as...
void display_running_version(void)
Connects to i3 to find out the currently running version.
void xinerama_init(void)
We have just established a connection to the X server and need the initial Xinerama information to se...
struct autostarts_always_head autostarts_always
static void xkb_got_event(EV_P_ struct ev_io *w, int revents)
void con_focus(Con *con)
Sets input focus to the given container.
char * i3bar_command
Command that should be run to execute i3bar, give a full path if i3bar is not in your $PATH...
char * current_socketpath
void start_application(const char *command, bool no_startup_id)
Starts the given application by passing it through a shell.
An Output is a physical output on your graphics driver.
void x_set_i3_atoms(void)
Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
void manage_existing_windows(xcb_window_t root)
Go through all existing windows (if the window manager is restarted) and manage them.
Output * get_output_containing(int x, int y)
Returns the active (!) output which contains the coordinates x, y or NULL if there is no output which...
static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents)
#define TAILQ_FOREACH(var, head, field)
char * get_process_filename(const char *prefix)
Returns the name of a temporary file with the specified prefix.
void translate_keysyms(void)
Translates keysymbols to keycodes for all bindings which use keysyms.
struct ev_loop * main_loop
int listen_fds
The number of file descriptors passed via socket activation.
void tree_init(xcb_get_geometry_reply_t *geometry)
Initializes the tree by creating the root node, adding all RandR outputs to the tree (that means rand...
void handle_event(int type, xcb_generic_event_t *event)
Takes an xcb_generic_event_t and calls the appropriate handler, based on the event type...
Con * output_get_content(Con *output)
Returns the output container below the given output container.
char * command
Command, like in command mode.
void setup_signal_handler(void)
Setup signal handlers to safely handle SIGSEGV and SIGFPE.
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
struct bindings_head * bindings
Con * con
Pointer to the Con which represents this output.
bool is_debug_build() __attribute__((const ))
Returns true if this version of i3 is a debug build (anything which is not a release version)...
void set_verbosity(bool _verbose)
Set verbosity of i3.
void ungrab_all_keys(xcb_connection_t *conn)
Ungrabs all keys, to be called before re-grabbing the keys because of a mapping_notify event or a con...
void property_handlers_init(void)
Sets the appropriate atoms for the property handlers after the atoms were received from X11...
Holds the status bar configuration (i3bar).
struct reservedpx __attribute__
void set_debug_logging(const bool _debug_logging)
Set debug logging.
xcb_key_symbols_t * keysyms
void grab_all_keys(xcb_connection_t *conn, bool bind_mode_switch)
Grab the bound keys (tell X to send us keypress events for those keycodes)
static void xcb_got_event(EV_P_ struct ev_io *w, int revents)
struct assignments_head assignments
const int default_shmlog_size
Holds a command specified by either an:
unsigned int xcb_numlock_mask
struct rlimit original_rlimit_core
The original value of RLIMIT_CORE when i3 was started.
void xcb_set_root_cursor(int cursor)
Set the cursor of the root window to the given cursor id.
void ipc_new_client(EV_P_ struct ev_io *w, int revents)
Handler for activity on the listening socket, meaning that a new client has just connected and we sho...
void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_message)
Checks a generic cookie for errors and quits with the given message if there was an error...
void scratchpad_fix_resolution(void)
When starting i3 initially (and after each change to the connected outputs), this function fixes the ...