* vim:ts=4:sw=4:expandtab
*
* i3 - an improved dynamic tiling window manager
- * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE)
*
* main.c: Initialization, main loop
*
#include <sys/mman.h>
#include <sys/stat.h>
#include "all.h"
+#include "shmlog.h"
#include "sd-daemon.h"
/** The number of file descriptors passed via socket activation. */
int listen_fds;
+/* We keep the xcb_check watcher around to be able to enable and disable it
+ * temporarily for drag_pointer(). */
+static struct ev_check *xcb_check;
+
static int xkb_event_base;
int xkb_current_group;
/* Those are our connections to X11 for use with libXcursor and XKB */
Display *xlibdpy, *xkbdpy;
+/* Default shmlog size if not set by user. */
+const int default_shmlog_size = 25 * 1024 * 1024;
+
/* The list of key bindings */
struct bindings_head *bindings;
}
}
+/*
+ * Enable or disable the main X11 event handling function.
+ * This is used by drag_pointer() which has its own, modal event handler, which
+ * takes precedence over the normal event handler.
+ *
+ */
+void main_set_x11_cb(bool enable) {
+ DLOG("Setting main X11 callback to enabled=%d\n", enable);
+ if (enable) {
+ ev_check_start(main_loop, xcb_check);
+ /* Trigger the watcher explicitly to handle all remaining X11 events.
+ * drag_pointer()’s event handler exits in the middle of the loop. */
+ ev_feed_event(main_loop, xcb_check, 0);
+ } else {
+ ev_check_stop(main_loop, xcb_check);
+ }
+}
/*
* When using xmodmap to change the keyboard mapping, this event
* (file) logging. */
init_logging();
- /* On non-release builds, disable SHM logging by default. */
- shmlog_size = (is_debug_build() ? 25 * 1024 * 1024 : 0);
+ /* On release builds, disable SHM logging by default. */
+ shmlog_size = (is_debug_build() || strstr(argv[0], "i3-with-shmlog") != NULL ? default_shmlog_size : 0);
start_argv = argv;
only_check_config = true;
break;
case 'v':
- printf("i3 version " I3_VERSION " © 2009-2012 Michael Stapelberg and contributors\n");
+ printf("i3 version " I3_VERSION " © 2009-2013 Michael Stapelberg and contributors\n");
exit(EXIT_SUCCESS);
break;
case 'm':
- printf("Binary i3 version: " I3_VERSION " © 2009-2012 Michael Stapelberg and contributors\n");
+ printf("Binary i3 version: " I3_VERSION " © 2009-2013 Michael Stapelberg and contributors\n");
display_running_version();
exit(EXIT_SUCCESS);
break;
break;
} else if (strcmp(long_options[option_index].name, "get-socketpath") == 0 ||
strcmp(long_options[option_index].name, "get_socketpath") == 0) {
- char *socket_path = root_atom_contents("I3_SOCKET_PATH");
+ char *socket_path = root_atom_contents("I3_SOCKET_PATH", NULL, 0);
if (socket_path) {
printf("%s\n", socket_path);
exit(EXIT_SUCCESS);
fake_outputs = sstrdup(optarg);
break;
} else if (strcmp(long_options[option_index].name, "force-old-config-parser-v4.4-only") == 0) {
- LOG("FORCING OLD CONFIG PARSER!\n");
- force_old_config_parser = true;
+ ELOG("You are passing --force-old-config-parser-v4.4-only, but that flag was removed by now.\n");
break;
}
/* fall-through */
optind++;
}
DLOG("Command is: %s (%zd bytes)\n", payload, strlen(payload));
- char *socket_path = root_atom_contents("I3_SOCKET_PATH");
+ char *socket_path = root_atom_contents("I3_SOCKET_PATH", NULL, 0);
if (!socket_path) {
ELOG("Could not get i3 IPC socket path\n");
return 1;
err(EXIT_FAILURE, "IPC: write()");
uint32_t reply_length;
+ uint32_t reply_type;
uint8_t *reply;
int ret;
- if ((ret = ipc_recv_message(sockfd, I3_IPC_MESSAGE_TYPE_COMMAND,
- &reply_length, &reply)) != 0) {
+ if ((ret = ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) {
if (ret == -1)
err(EXIT_FAILURE, "IPC: read()");
return 1;
}
+ if (reply_type != I3_IPC_MESSAGE_TYPE_COMMAND)
+ errx(EXIT_FAILURE, "IPC: received reply of type %d but expected %d (COMMAND)", reply_type, I3_IPC_MESSAGE_TYPE_COMMAND);
printf("%.*s\n", reply_length, reply);
return 0;
}
/* The following code is helpful, but not required. We thus don’t pay
* much attention to error handling, non-linux or other edge cases. */
- char cwd[PATH_MAX];
LOG("CORE DUMPS: You are running a development version of i3, so coredumps were automatically enabled (ulimit -c unlimited).\n");
- if (getcwd(cwd, sizeof(cwd)) != NULL)
+ size_t cwd_size = 1024;
+ char *cwd = smalloc(cwd_size);
+ char *cwd_ret;
+ while ((cwd_ret = getcwd(cwd, cwd_size)) == NULL && errno == ERANGE) {
+ cwd_size = cwd_size * 2;
+ cwd = srealloc(cwd, cwd_size);
+ }
+ if (cwd_ret != NULL)
LOG("CORE DUMPS: Your current working directory is \"%s\".\n", cwd);
int patternfd;
if ((patternfd = open("/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) {
- memset(cwd, '\0', sizeof(cwd));
- if (read(patternfd, cwd, sizeof(cwd)) > 0)
+ memset(cwd, '\0', cwd_size);
+ if (read(patternfd, cwd, cwd_size) > 0)
/* a trailing newline is included in cwd */
LOG("CORE DUMPS: Your core_pattern is: %s", cwd);
close(patternfd);
}
+ free(cwd);
}
LOG("i3 " I3_VERSION " starting\n");
config.ipc_socket_path = sstrdup(config.ipc_socket_path);
}
- uint32_t mask = XCB_CW_EVENT_MASK;
- uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
- XCB_EVENT_MASK_BUTTON_PRESS |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY | /* when the user adds a screen (e.g. video
- projector), the root window gets a
- ConfigureNotify */
- XCB_EVENT_MASK_POINTER_MOTION |
- XCB_EVENT_MASK_PROPERTY_CHANGE |
- XCB_EVENT_MASK_ENTER_WINDOW };
xcb_void_cookie_t cookie;
- cookie = xcb_change_window_attributes_checked(conn, root, mask, values);
+ cookie = xcb_change_window_attributes_checked(conn, root, XCB_CW_EVENT_MASK, (uint32_t[]){ ROOT_EVENT_MASK });
check_error(conn, cookie, "Another window manager seems to be running");
xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(conn, gcookie, NULL);
int i1;
if (!XkbQueryExtension(xkbdpy,&i1,&xkb_event_base,&errBase,&major,&minor)) {
fprintf(stderr, "XKB not supported by X-server\n");
- return 1;
+ xkb_supported = false;
}
/* end of ugliness */
- if (!XkbSelectEvents(xkbdpy, XkbUseCoreKbd,
- XkbMapNotifyMask | XkbStateNotifyMask,
- XkbMapNotifyMask | XkbStateNotifyMask)) {
+ if (xkb_supported && !XkbSelectEvents(xkbdpy, XkbUseCoreKbd,
+ XkbMapNotifyMask | XkbStateNotifyMask,
+ XkbMapNotifyMask | XkbStateNotifyMask)) {
fprintf(stderr, "Could not set XKB event mask\n");
return 1;
}
}
+ restore_connect();
+
/* Setup NetWM atoms */
#define xmacro(name) \
do { \
/* Set up i3 specific atoms like I3_SOCKET_PATH and I3_CONFIG_PATH */
x_set_i3_atoms();
+ ewmh_update_workarea();
struct ev_io *xcb_watcher = scalloc(sizeof(struct ev_io));
struct ev_io *xkb = scalloc(sizeof(struct ev_io));
- struct ev_check *xcb_check = scalloc(sizeof(struct ev_check));
+ xcb_check = scalloc(sizeof(struct ev_check));
struct ev_prepare *xcb_prepare = scalloc(sizeof(struct ev_prepare));
ev_io_init(xcb_watcher, xcb_got_event, xcb_get_file_descriptor(conn), EV_READ);
}
xcb_ungrab_server(conn);
+ if (autostart) {
+ LOG("This is not an in-place restart, copying root window contents to a pixmap\n");
+ xcb_screen_t *root = xcb_aux_get_screen(conn, conn_screen);
+ uint16_t width = root->width_in_pixels;
+ uint16_t height = root->height_in_pixels;
+ xcb_pixmap_t pixmap = xcb_generate_id(conn);
+ xcb_gcontext_t gc = xcb_generate_id(conn);
+
+ xcb_create_pixmap(conn, root->root_depth, pixmap, root->root, width, height);
+
+ xcb_create_gc(conn, gc, root->root,
+ XCB_GC_FUNCTION | XCB_GC_PLANE_MASK | XCB_GC_FILL_STYLE | XCB_GC_SUBWINDOW_MODE,
+ (uint32_t[]){ XCB_GX_COPY, ~0, XCB_FILL_STYLE_SOLID, XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS });
+
+ xcb_copy_area(conn, root->root, pixmap, gc, 0, 0, 0, 0, width, height);
+ xcb_change_window_attributes_checked(conn, root->root, XCB_CW_BACK_PIXMAP, (uint32_t[]){ pixmap });
+ xcb_flush(conn);
+ xcb_free_gc(conn, gc);
+ xcb_free_pixmap(conn, pixmap);
+ }
+
struct sigaction action;
action.sa_sigaction = handle_signal;