+#undef I3__FILE__
+#define I3__FILE__ "main.c"
/*
* 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"
/* 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;
DLOG("Expected X11 Error received for sequence %x\n", event->sequence);
else {
xcb_generic_error_t *error = (xcb_generic_error_t*)event;
- ELOG("X11 Error received! sequence 0x%x, error_code = %d\n",
+ DLOG("X11 Error received (probably harmless)! sequence 0x%x, error_code = %d\n",
error->sequence, error->error_code);
}
free(event);
*
*/
static void handle_signal(int sig, siginfo_t *info, void *data) {
- fprintf(stderr, "Received signal %d, terminating\n", sig);
if (*shmlogname != '\0') {
- fprintf(stderr, "Closing SHM log \"%s\"\n", shmlogname);
shm_unlink(shmlogname);
}
- fflush(stderr);
raise(sig);
}
{"no-autostart", no_argument, 0, 'a'},
{"config", required_argument, 0, 'c'},
{"version", no_argument, 0, 'v'},
+ {"moreversion", no_argument, 0, 'm'},
+ {"more-version", no_argument, 0, 'm'},
+ {"more_version", no_argument, 0, 'm'},
{"help", no_argument, 0, 'h'},
{"layout", required_argument, 0, 'L'},
{"restart", required_argument, 0, 0},
{"get_socketpath", no_argument, 0, 0},
{"fake_outputs", required_argument, 0, 0},
{"fake-outputs", required_argument, 0, 0},
+ {"force-old-config-parser-v4.4-only", no_argument, 0, 0},
{0, 0, 0, 0}
};
int option_index = 0, opt;
init_logging();
/* On non-release builds, disable SHM logging by default. */
- shmlog_size = (is_debug_build() ? 25 * 1024 * 1024 : 0);
+ shmlog_size = (is_debug_build() ? default_shmlog_size : 0);
start_argv = argv;
- while ((opt = getopt_long(argc, argv, "c:CvaL:hld:V", long_options, &option_index)) != -1) {
+ while ((opt = getopt_long(argc, argv, "c:CvmaL:hld:V", long_options, &option_index)) != -1) {
switch (opt) {
case 'a':
LOG("Autostart disabled using -a\n");
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-2013 Michael Stapelberg and contributors\n");
+ display_running_version();
exit(EXIT_SUCCESS);
+ break;
case 'V':
set_verbosity(true);
break;
char *socket_path = root_atom_contents("I3_SOCKET_PATH");
if (socket_path) {
printf("%s\n", socket_path);
- return 0;
+ exit(EXIT_SUCCESS);
}
- return 1;
+ exit(EXIT_FAILURE);
} else if (strcmp(long_options[option_index].name, "shmlog-size") == 0 ||
strcmp(long_options[option_index].name, "shmlog_size") == 0) {
shmlog_size = atoi(optarg);
LOG("Initializing fake outputs: %s\n", optarg);
fake_outputs = sstrdup(optarg);
break;
+ } else if (strcmp(long_options[option_index].name, "force-old-config-parser-v4.4-only") == 0) {
+ ELOG("You are passing --force-old-config-parser-v4.4-only, but that flag was removed by now.\n");
+ break;
}
/* fall-through */
default:
fprintf(stderr, "\t--force-xinerama\n"
"\tUse Xinerama instead of RandR.\n"
"\tThis option should only be used if you are stuck with the\n"
- "\tnvidia closed source driver which does not support RandR.\n");
+ "\told nVidia closed source driver (older than 302.17), which does\n"
+ "\tnot support RandR.\n");
fprintf(stderr, "\n");
fprintf(stderr, "\t--get-socketpath\n"
"\tRetrieve the i3 IPC socket path from X11, print it, then exit.\n");
}
optind++;
}
- LOG("Command is: %s (%d bytes)\n", payload, strlen(payload));
+ DLOG("Command is: %s (%zd bytes)\n", payload, strlen(payload));
char *socket_path = root_atom_contents("I3_SOCKET_PATH");
if (!socket_path) {
ELOG("Could not get i3 IPC socket path\n");
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;
}
}
}
- LOG("i3 (tree) version " I3_VERSION " starting\n");
+ LOG("i3 " I3_VERSION " starting\n");
conn = xcb_connect(NULL, &conn_screen);
if (xcb_connection_has_error(conn))
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_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;
}
randr_init(&randr_base);
}
+ scratchpad_fix_resolution();
+
xcb_query_pointer_reply_t *pointerreply;
Output *output = NULL;
if (!(pointerreply = xcb_query_pointer_reply(conn, pointercookie, NULL))) {
ELOG("Could not query pointer position, using first screen\n");
- output = get_first_output();
} else {
DLOG("Pointer at %d, %d\n", pointerreply->root_x, pointerreply->root_y);
output = get_output_containing(pointerreply->root_x, pointerreply->root_y);
xcb_flush(conn);
- manage_existing_windows(root);
+ /* What follows is a fugly consequence of X11 protocol race conditions like
+ * the following: In an i3 in-place restart, i3 will reparent all windows
+ * to the root window, then exec() itself. In the new process, it calls
+ * manage_existing_windows. However, in case any application sent a
+ * generated UnmapNotify message to the WM (as GIMP does), this message
+ * will be handled by i3 *after* managing the window, thus i3 thinks the
+ * window just closed itself. In reality, the message was sent in the time
+ * period where i3 wasn’t running yet.
+ *
+ * To prevent this, we grab the server (disables processing of any other
+ * connections), then discard all pending events (since we didn’t do
+ * anything, there cannot be any meaningful responses), then ungrab the
+ * server. */
+ xcb_grab_server(conn);
+ {
+ xcb_aux_sync(conn);
+ xcb_generic_event_t *event;
+ while ((event = xcb_poll_for_event(conn)) != NULL) {
+ if (event->response_type == 0) {
+ free(event);
+ continue;
+ }
+
+ /* Strip off the highest bit (set if the event is generated) */
+ int type = (event->response_type & 0x7F);
+
+ /* We still need to handle MapRequests which are sent in the
+ * timespan starting from when we register as a window manager and
+ * this piece of code which drops events. */
+ if (type == XCB_MAP_REQUEST)
+ handle_event(type, event);
+
+ free(event);
+ }
+ manage_existing_windows(root);
+ }
+ xcb_ungrab_server(conn);
struct sigaction action;