2 #define I3__FILE__ "main.c"
14 #include <sys/types.h>
15 #include <sys/socket.h>
18 #include <sys/resource.h>
127 xcb_generic_event_t *event;
129 while ((event = xcb_poll_for_event(
conn)) != NULL) {
130 if (event->response_type == 0) {
132 DLOG(
"Expected X11 Error received for sequence %x\n", event->sequence);
134 xcb_generic_error_t *error = (xcb_generic_error_t *)event;
135 DLOG(
"X11 Error received (probably harmless)! sequence 0x%x, error_code = %d\n",
136 error->sequence, error->error_code);
143 int type = (
event->response_type & 0x7F);
158 DLOG(
"Setting main X11 callback to enabled=%d\n", enable);
175 DLOG(
"Handling XKB event\n");
181 bool mapping_changed =
false;
182 while (XPending(
xkbdpy)) {
183 XNextEvent(
xkbdpy, (XEvent *)&ev);
189 if (ev.any.xkb_type == XkbMapNotify) {
190 mapping_changed =
true;
194 if (ev.any.xkb_type != XkbStateNotify) {
195 ELOG(
"Unknown XKB event received (type %d)\n", ev.any.xkb_type);
208 if (ev.state.group == XkbGroup2Index) {
209 DLOG(
"Mode_switch enabled\n");
213 if (ev.state.group == XkbGroup1Index) {
214 DLOG(
"Mode_switch disabled\n");
220 if (!mapping_changed)
223 DLOG(
"Keyboard mapping changed, updating keybindings\n");
230 DLOG(
"Re-grabbing...\n");
244 #if EV_VERSION_MAJOR >= 4
249 fprintf(stderr,
"Closing SHM log \"%s\"\n",
shmlogname);
268 int main(
int argc,
char *argv[]) {
272 char *override_configpath = NULL;
273 bool autostart =
true;
274 char *layout_path = NULL;
275 bool delete_layout_path =
false;
276 bool force_xinerama =
false;
277 char *fake_outputs = NULL;
278 bool disable_signalhandler =
false;
279 static struct option long_options[] = {
280 {
"no-autostart", no_argument, 0,
'a'},
281 {
"config", required_argument, 0,
'c'},
282 {
"version", no_argument, 0,
'v'},
283 {
"moreversion", no_argument, 0,
'm'},
284 {
"more-version", no_argument, 0,
'm'},
285 {
"more_version", no_argument, 0,
'm'},
286 {
"help", no_argument, 0,
'h'},
287 {
"layout", required_argument, 0,
'L'},
288 {
"restart", required_argument, 0, 0},
289 {
"force-xinerama", no_argument, 0, 0},
290 {
"force_xinerama", no_argument, 0, 0},
291 {
"disable-signalhandler", no_argument, 0, 0},
292 {
"shmlog-size", required_argument, 0, 0},
293 {
"shmlog_size", required_argument, 0, 0},
294 {
"get-socketpath", no_argument, 0, 0},
295 {
"get_socketpath", no_argument, 0, 0},
296 {
"fake_outputs", required_argument, 0, 0},
297 {
"fake-outputs", required_argument, 0, 0},
298 {
"force-old-config-parser-v4.4-only", no_argument, 0, 0},
300 int option_index = 0, opt;
302 setlocale(LC_ALL,
"");
309 if (!isatty(fileno(stdout)))
310 setbuf(stdout, NULL);
323 while ((opt = getopt_long(argc, argv,
"c:CvmaL:hld:V", long_options, &option_index)) != -1) {
326 LOG(
"Autostart disabled using -a\n");
332 delete_layout_path =
false;
335 FREE(override_configpath);
336 override_configpath =
sstrdup(optarg);
339 LOG(
"Checking configuration file only (-C)\n");
343 printf(
"i3 version " I3_VERSION
" © 2009-2014 Michael Stapelberg and contributors\n");
347 printf(
"Binary i3 version: " I3_VERSION
" © 2009-2014 Michael Stapelberg and contributors\n");
355 LOG(
"Enabling debug logging\n");
362 if (strcmp(long_options[option_index].name,
"force-xinerama") == 0 ||
363 strcmp(long_options[option_index].name,
"force_xinerama") == 0) {
364 force_xinerama =
true;
365 ELOG(
"Using Xinerama instead of RandR. This option should be "
366 "avoided at all cost because it does not refresh the list "
367 "of screens, so you cannot configure displays at runtime. "
368 "Please check if your driver really does not support RandR "
369 "and disable this option as soon as you can.\n");
371 }
else if (strcmp(long_options[option_index].name,
"disable-signalhandler") == 0) {
372 disable_signalhandler =
true;
374 }
else if (strcmp(long_options[option_index].name,
"get-socketpath") == 0 ||
375 strcmp(long_options[option_index].name,
"get_socketpath") == 0) {
378 printf(
"%s\n", socket_path);
383 }
else if (strcmp(long_options[option_index].name,
"shmlog-size") == 0 ||
384 strcmp(long_options[option_index].name,
"shmlog_size") == 0) {
391 }
else if (strcmp(long_options[option_index].name,
"restart") == 0) {
394 delete_layout_path =
true;
396 }
else if (strcmp(long_options[option_index].name,
"fake-outputs") == 0 ||
397 strcmp(long_options[option_index].name,
"fake_outputs") == 0) {
398 LOG(
"Initializing fake outputs: %s\n", optarg);
399 fake_outputs =
sstrdup(optarg);
401 }
else if (strcmp(long_options[option_index].name,
"force-old-config-parser-v4.4-only") == 0) {
402 ELOG(
"You are passing --force-old-config-parser-v4.4-only, but that flag was removed by now.\n");
407 fprintf(stderr,
"Usage: %s [-c configfile] [-d all] [-a] [-v] [-V] [-C]\n", argv[0]);
408 fprintf(stderr,
"\n");
409 fprintf(stderr,
"\t-a disable autostart ('exec' lines in config)\n");
410 fprintf(stderr,
"\t-c <file> use the provided configfile instead\n");
411 fprintf(stderr,
"\t-C validate configuration file and exit\n");
412 fprintf(stderr,
"\t-d all enable debug output\n");
413 fprintf(stderr,
"\t-L <file> path to the serialized layout during restarts\n");
414 fprintf(stderr,
"\t-v display version and exit\n");
415 fprintf(stderr,
"\t-V enable verbose mode\n");
416 fprintf(stderr,
"\n");
417 fprintf(stderr,
"\t--force-xinerama\n"
418 "\tUse Xinerama instead of RandR.\n"
419 "\tThis option should only be used if you are stuck with the\n"
420 "\told nVidia closed source driver (older than 302.17), which does\n"
421 "\tnot support RandR.\n");
422 fprintf(stderr,
"\n");
423 fprintf(stderr,
"\t--get-socketpath\n"
424 "\tRetrieve the i3 IPC socket path from X11, print it, then exit.\n");
425 fprintf(stderr,
"\n");
426 fprintf(stderr,
"\t--shmlog-size <limit>\n"
427 "\tLimits the size of the i3 SHM log to <limit> bytes. Setting this\n"
428 "\tto 0 disables SHM logging entirely.\n"
429 "\tThe default is %d bytes.\n",
431 fprintf(stderr,
"\n");
432 fprintf(stderr,
"If you pass plain text arguments, i3 will interpret them as a command\n"
433 "to send to a currently running i3 (like i3-msg). This allows you to\n"
434 "use nice and logical commands, such as:\n"
437 "\ti3 floating toggle\n"
453 LOG(
"Additional arguments passed. Sending them as a command to i3.\n");
454 char *payload = NULL;
455 while (optind < argc) {
457 payload =
sstrdup(argv[optind]);
460 sasprintf(&both,
"%s %s", payload, argv[optind]);
466 DLOG(
"Command is: %s (%zd bytes)\n", payload, strlen(payload));
469 ELOG(
"Could not get i3 IPC socket path\n");
473 int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
475 err(EXIT_FAILURE,
"Could not create socket");
477 struct sockaddr_un addr;
478 memset(&addr, 0,
sizeof(
struct sockaddr_un));
479 addr.sun_family = AF_LOCAL;
480 strncpy(addr.sun_path, socket_path,
sizeof(addr.sun_path) - 1);
481 if (connect(sockfd, (
const struct sockaddr *)&addr,
sizeof(
struct sockaddr_un)) < 0)
482 err(EXIT_FAILURE,
"Could not connect to i3");
485 (uint8_t *)payload) == -1)
486 err(EXIT_FAILURE,
"IPC: write()");
488 uint32_t reply_length;
492 if ((ret =
ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) {
494 err(EXIT_FAILURE,
"IPC: read()");
497 if (reply_type != I3_IPC_MESSAGE_TYPE_COMMAND)
498 errx(EXIT_FAILURE,
"IPC: received reply of type %d but expected %d (COMMAND)", reply_type, I3_IPC_MESSAGE_TYPE_COMMAND);
499 printf(
"%.*s\n", reply_length, reply);
508 struct rlimit limit = {RLIM_INFINITY, RLIM_INFINITY};
509 setrlimit(RLIMIT_CORE, &limit);
513 LOG(
"CORE DUMPS: You are running a development version of i3, so coredumps were automatically enabled (ulimit -c unlimited).\n");
514 size_t cwd_size = 1024;
517 while ((cwd_ret = getcwd(cwd, cwd_size)) == NULL && errno == ERANGE) {
518 cwd_size = cwd_size * 2;
522 LOG(
"CORE DUMPS: Your current working directory is \"%s\".\n", cwd);
524 if ((patternfd = open(
"/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) {
525 memset(cwd,
'\0', cwd_size);
526 if (read(patternfd, cwd, cwd_size) > 0)
528 LOG(
"CORE DUMPS: Your core_pattern is: %s", cwd);
534 LOG(
"i3 " I3_VERSION
" starting\n");
537 if (xcb_connection_has_error(
conn))
538 errx(EXIT_FAILURE,
"Cannot open display\n");
547 die(
"Could not initialize libev. Bad LIBEV_FLAGS?\n");
562 xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(
conn,
root);
563 xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(
conn,
root);
567 LOG(
"Done checking configuration file. Exiting.\n");
579 xcb_void_cookie_t cookie;
581 check_error(
conn, cookie,
"Another window manager seems to be running");
583 xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(
conn, gcookie, NULL);
584 if (greply == NULL) {
585 ELOG(
"Could not get geometry of the root window, exiting\n");
588 DLOG(
"root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
591 #define xmacro(atom) \
592 xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
593 #include "atoms.xmacro"
601 ELOG(
"ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n");
604 }
else if (fcntl(ConnectionNumber(
xlibdpy), F_SETFD, FD_CLOEXEC) == -1) {
605 ELOG(
"Could not set FD_CLOEXEC on xkbdpy\n");
621 major = XkbMajorVersion,
622 minor = XkbMinorVersion;
624 if (fcntl(ConnectionNumber(
xkbdpy), F_SETFD, FD_CLOEXEC) == -1) {
625 fprintf(stderr,
"Could not set FD_CLOEXEC on xkbdpy\n");
631 fprintf(stderr,
"XKB not supported by X-server\n");
636 if (
xkb_supported && !XkbSelectEvents(
xkbdpy, XkbUseCoreKbd, XkbMapNotifyMask | XkbStateNotifyMask, XkbMapNotifyMask | XkbStateNotifyMask)) {
637 fprintf(stderr,
"Could not set XKB event mask\n");
645 #define xmacro(name) \
647 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
649 ELOG("Could not get atom " #name "\n"); \
652 A_##name = reply->atom; \
655 #include "atoms.xmacro"
669 bool needs_tree_init =
true;
671 LOG(
"Trying to restore the layout from %s...", layout_path);
673 if (delete_layout_path) {
675 const char *dir = dirname(layout_path);
691 if (fake_outputs != NULL) {
701 DLOG(
"Checking for XRandR...\n");
707 xcb_query_pointer_reply_t *pointerreply;
709 if (!(pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL))) {
710 ELOG(
"Could not query pointer position, using first screen\n");
712 DLOG(
"Pointer at %d, %d\n", pointerreply->root_x, pointerreply->root_y);
715 ELOG(
"ERROR: No screen at (%d, %d), starting on the first screen\n",
716 pointerreply->root_x, pointerreply->root_y);
727 if (ipc_socket == -1) {
728 ELOG(
"Could not create the IPC socket, IPC disabled\n");
730 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
740 ELOG(
"socket activation: Error in sd_listen_fds\n");
742 DLOG(
"socket activation: no sockets passed\n");
748 DLOG(
"socket activation: also listening on fd %d\n", fd);
753 if ((flags = fcntl(fd, F_GETFD)) < 0 ||
754 fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
755 ELOG(
"Could not disable FD_CLOEXEC on fd %d\n", fd);
758 struct ev_io *ipc_io =
scalloc(
sizeof(
struct ev_io));
771 struct ev_io *xcb_watcher =
scalloc(
sizeof(
struct ev_io));
772 struct ev_io *xkb =
scalloc(
sizeof(
struct ev_io));
774 struct ev_prepare *xcb_prepare =
scalloc(
sizeof(
struct ev_prepare));
791 ev_prepare_start(
main_loop, xcb_prepare);
808 xcb_grab_server(
conn);
811 xcb_generic_event_t *event;
812 while ((event = xcb_poll_for_event(
conn)) != NULL) {
813 if (event->response_type == 0) {
819 int type = (
event->response_type & 0x7F);
824 if (type == XCB_MAP_REQUEST)
831 xcb_ungrab_server(
conn);
834 LOG(
"This is not an in-place restart, copying root window contents to a pixmap\n");
836 uint16_t
width = root->width_in_pixels;
837 uint16_t
height = root->height_in_pixels;
839 xcb_gcontext_t gc = xcb_generate_id(
conn);
841 xcb_create_pixmap(
conn, root->root_depth, pixmap, root->root, width, height);
843 xcb_create_gc(
conn, gc, root->root,
844 XCB_GC_FUNCTION | XCB_GC_PLANE_MASK | XCB_GC_FILL_STYLE | XCB_GC_SUBWINDOW_MODE,
845 (uint32_t[]) {XCB_GX_COPY, ~0, XCB_FILL_STYLE_SOLID, XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS});
848 xcb_change_window_attributes_checked(
conn,
root->root, XCB_CW_BACK_PIXMAP, (uint32_t[]) {
pixmap});
850 xcb_free_gc(
conn, gc);
854 struct sigaction action;
857 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
858 sigemptyset(&action.sa_mask);
860 if (!disable_signalhandler)
864 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
865 sigaction(SIGILL, &action, NULL) == -1 ||
866 sigaction(SIGABRT, &action, NULL) == -1 ||
867 sigaction(SIGFPE, &action, NULL) == -1 ||
868 sigaction(SIGSEGV, &action, NULL) == -1)
869 ELOG(
"Could not setup signal handler");
873 if (sigaction(SIGHUP, &action, NULL) == -1 ||
874 sigaction(SIGINT, &action, NULL) == -1 ||
875 sigaction(SIGALRM, &action, NULL) == -1 ||
876 sigaction(SIGUSR1, &action, NULL) == -1 ||
877 sigaction(SIGUSR2, &action, NULL) == -1)
878 ELOG(
"Could not setup signal handler");
882 signal(SIGPIPE, SIG_IGN);
896 LOG(
"auto-starting (always!) %s\n", exec_always->
command);
904 sasprintf(&command,
"%s --bar_id=%s --socket=\"%s\"",
907 LOG(
"Starting bar process: %s\n", command);
#define SD_LISTEN_FDS_START
struct reservedpx __attribute__
bool is_debug_build() __attribute__((const ))
Returns true if this version of i3 is a debug build (anything which is not a release version)...
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
int sd_listen_fds(int unset_environment)
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
int listen_fds
The number of file descriptors passed via socket activation.
char * get_process_filename(const char *prefix)
Returns the name of a temporary file with the specified prefix.
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 xinerama_init(void)
We have just established a connection to the X server and need the initial Xinerama information to se...
void translate_keysyms(void)
Translates keysymbols to keycodes for all bindings which use keysyms.
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
char * fake_outputs
Overwrites output detection (for testing), see src/fake_outputs.c.
xcb_screen_t * root_screen
static void xcb_got_event(EV_P_ struct ev_io *w, int revents)
struct ev_loop * main_loop
xcb_timestamp_t last_timestamp
The last timestamp we got from X11 (timestamps are included in some events and are used for some thin...
An Output is a physical output on your graphics driver.
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 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)
void display_running_version(void)
Connects to i3 to find out the currently running version.
void set_verbosity(bool _verbose)
Set verbosity of i3.
static void handle_signal(int sig, siginfo_t *info, void *data)
void manage_existing_windows(xcb_window_t root)
Go through all existing windows (if the window manager is restarted) and manage them.
char * root_atom_contents(const char *atomname, xcb_connection_t *provided_conn, int screen)
Try to get the contents of the given atom (for example I3_SOCKET_PATH) from the X11 root window and r...
static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents)
static xcb_pixmap_t pixmap
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...
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 tree_restore(const char *path, xcb_get_geometry_reply_t *geometry)
Loads tree from ~/.i3/_restart.json (used for in-place restarts).
Con * con
Pointer to the Con which represents this output.
void ewmh_update_workarea(void)
i3 currently does not support _NET_WORKAREA, because it does not correspond to i3’s concept of worksp...
char * id
Automatically generated ID for this bar config.
void main_set_x11_cb(bool enable)
Enable or disable the main X11 event handling function.
bool event_is_ignored(const int sequence, const int response_type)
Checks if the given sequence is ignored and returns true if so.
void ewmh_update_current_desktop(void)
Updates _NET_CURRENT_DESKTOP with the current desktop number.
struct autostarts_head autostarts
bool no_startup_id
no_startup_id flag for start_application().
void con_focus(Con *con)
Sets input focus to the given container.
void xcursor_set_root_cursor(int cursor_id)
Sets the cursor of the root window to the 'pointer' cursor.
void setup_signal_handler(void)
Setup signal handlers to safely handle SIGSEGV and SIGFPE.
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...
Output * get_first_output(void)
Returns the first output which is active.
static void i3_exit(void)
struct assignments_head assignments
void fake_outputs_init(const char *output_spec)
Creates outputs according to the given specification.
const int default_shmlog_size
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 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...
char * i3bar_command
Command that should be run to execute i3bar, give a full path if i3bar is not in your $PATH...
void ewmh_setup_hints(void)
Set up the EWMH hints on the root window.
void xcursor_load_cursors(void)
void randr_init(int *event_base)
We have just established a connection to the X server and need the initial XRandR information to setu...
unsigned int xcb_numlock_mask
A 'Con' represents everything from the X11 root window down to a single X11 window.
void xcb_set_root_cursor(int cursor)
Set the cursor of the root window to the given cursor id.
void * scalloc(size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
struct bindings_head * bindings
char * current_socketpath
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 scratchpad_fix_resolution(void)
When starting i3 initially (and after each change to the connected outputs), this function fixes the ...
bool force_xinerama
By default, use the RandR API for multi-monitor setups.
Output * get_output_containing(unsigned int x, unsigned int y)
Returns the active (!) output which contains the coordinates x, y or NULL if there is no output which...
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...
#define TAILQ_HEAD_INITIALIZER(head)
char * command
Command, like in command mode.
static void xcb_check_cb(EV_P_ ev_check *w, int revents)
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...
struct barconfig_head barconfigs
void init_logging(void)
Initializes logging by creating an error logfile in /tmp (or XDG_RUNTIME_DIR, see get_process_filenam...
int main(int argc, char *argv[])
Con * output_get_content(Con *output)
Returns the output container below the given output container.
void start_application(const char *command, bool no_startup_id)
Starts the given application by passing it through a shell.
void * smalloc(size_t size)
Safe-wrapper around malloc which exits if malloc returns NULL (meaning that there is no more memory a...
void x_set_i3_atoms(void)
Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
xcb_key_symbols_t * keysyms
#define TAILQ_FOREACH(var, head, field)
void restore_connect(void)
Opens a separate connection to X11 for placeholder windows when restoring layouts.
static struct ev_check * xcb_check
void * srealloc(void *ptr, size_t size)
Safe-wrapper around realloc which exits if realloc returns NULL (meaning that there is no more memory...
Holds the status bar configuration (i3bar).
struct rlimit original_rlimit_core
The original value of RLIMIT_CORE when i3 was started.
struct autostarts_always_head autostarts_always
void property_handlers_init(void)
Sets the appropriate atoms for the property handlers after the atoms were received from X11...
Holds a command specified by either an:
static int xkb_event_base
static void xkb_got_event(EV_P_ struct ev_io *w, int revents)
struct ws_assignments_head ws_assignments
void set_debug_logging(const bool _debug_logging)
Set debug logging.
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...