Add --force-xinerama when starting i3 to use Xinerama instead of RandR.
This should *ONLY* be done if you have no other choice (nvidia’s
binary driver uses twinview and does not expose the monitor information
through RandR).
LDFLAGS += -lxcb-atom
LDFLAGS += -lxcb-aux
LDFLAGS += -lxcb-icccm
+LDFLAGS += -lxcb-xinerama
LDFLAGS += -lxcb-randr
LDFLAGS += -lxcb
LDFLAGS += -lX11
extern TAILQ_HEAD(assignments_head, Assignment) assignments;
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
extern xcb_event_handlers_t evenths;
-extern int num_screens;
extern uint8_t root_depth;
extern bool xkb_supported;
extern xcb_atom_t atoms[NUM_ATOMS];
*/
void initialize_randr(xcb_connection_t *conn, int *event_base);
+/**
+ * Disables RandR support by creating exactly one output with the size of the
+ * X11 screen.
+ *
+ */
+void disable_randr(xcb_connection_t *conn);
+
+/**
+ * Initializes the specified output, assigning the specified workspace to it.
+ *
+ */
+void initialize_output(xcb_connection_t *conn, Output *output, Workspace *workspace);
+
/**
* (Re-)queries the outputs via RandR and stores them in the list of outputs.
*
--- /dev/null
+/*
+ * vim:ts=8:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ *
+ * © 2009-2010 Michael Stapelberg and contributors
+ *
+ * See file LICENSE for license information.
+ *
+ */
+#include "data.h"
+
+#ifndef _XINERAMA_H
+#define _XINERAMA_H
+
+/**
+ * We have just established a connection to the X server and need the initial
+ * Xinerama information to setup workspaces for each screen.
+ *
+ */
+void initialize_xinerama(xcb_connection_t *conn);
+
+#endif
#include "util.h"
#include "xcb.h"
#include "randr.h"
+#include "xinerama.h"
#include "manage.h"
#include "ipc.h"
#include "log.h"
char *override_configpath = NULL;
bool autostart = true;
bool only_check_config = false;
+ bool force_xinerama = false;
xcb_connection_t *conn;
xcb_property_handlers_t prophs;
xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
{"config", required_argument, 0, 'c'},
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
+ {"force-xinerama", no_argument, 0, 0},
{0, 0, 0, 0}
};
int option_index = 0;
case 'l':
/* DEPRECATED, ignored for the next 3 versions (3.e, 3.f, 3.g) */
break;
+ case 0:
+ if (strcmp(long_options[option_index].name, "force-xinerama") == 0) {
+ force_xinerama = true;
+ ELOG("Using Xinerama instead of RandR. This option should be "
+ "avoided at all cost because it does not refresh the list "
+ "of screens, so you cannot configure displays at runtime. "
+ "Please check if your driver really does not support RandR "
+ "and disable this option as soon as you can.\n");
+ break;
+ }
+ /* fall-through */
default:
fprintf(stderr, "Usage: %s [-c configfile] [-d loglevel] [-a] [-v] [-V] [-C]\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "-d <loglevel>: enable debug loglevel <loglevel>\n");
fprintf(stderr, "-c <configfile>: use the provided configfile instead\n");
fprintf(stderr, "-C: check configuration file and exit\n");
+ fprintf(stderr, "--force-xinerama: Use Xinerama instead of RandR. This "
+ "option should only be used if you are stuck with the "
+ "nvidia closed source driver which does not support RandR.\n");
exit(EXIT_FAILURE);
}
}
grab_all_keys(conn);
- DLOG("Checking for XRandR...\n");
int randr_base;
- initialize_randr(conn, &randr_base);
-
- xcb_event_set_handler(&evenths,
- randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY,
- handle_screen_change,
- NULL);
+ if (force_xinerama) {
+ initialize_xinerama(conn);
+ } else {
+ DLOG("Checking for XRandR...\n");
+ initialize_randr(conn, &randr_base);
+
+ xcb_event_set_handler(&evenths,
+ randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY,
+ handle_screen_change,
+ NULL);
+ }
xcb_flush(conn);
return candidate;
}
-static void initialize_output(xcb_connection_t *conn, Output *output,
- Workspace *workspace) {
+/*
+ * Initializes the specified output, assigning the specified workspace to it.
+ *
+ */
+void initialize_output(xcb_connection_t *conn, Output *output, Workspace *workspace) {
i3Font *font = load_font(conn, config.font);
workspace->output = output;
* X11 screen.
*
*/
-static void disable_randr(xcb_connection_t *conn) {
+void disable_randr(xcb_connection_t *conn) {
xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
DLOG("RandR extension unusable, disabling.\n");
--- /dev/null
+/*
+ * vim:ts=8:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ *
+ * © 2009-2010 Michael Stapelberg and contributors
+ *
+ * See file LICENSE for license information.
+ *
+ * This is LEGACY code (we support RandR, which can do much more than
+ * Xinerama), but necessary for the poor users of the nVidia binary
+ * driver which does not support RandR in 2010 *sigh*.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xcb/xcb.h>
+#include <xcb/xinerama.h>
+
+#include "queue.h"
+#include "data.h"
+#include "util.h"
+#include "xinerama.h"
+#include "workspace.h"
+#include "log.h"
+#include "randr.h"
+
+static int num_screens;
+
+/*
+ * Looks in outputs for the Output whose start coordinates are x, y
+ *
+ */
+static Output *get_screen_at(int x, int y) {
+ Output *output;
+ TAILQ_FOREACH(output, &outputs, outputs)
+ if (output->rect.x == x && output->rect.y == y)
+ return output;
+
+ return NULL;
+}
+
+/*
+ * Gets the Xinerama screens and converts them to virtual Outputs (only one screen for two
+ * Xinerama screen which are configured in clone mode) in the given screenlist
+ *
+ */
+static void query_screens(xcb_connection_t *conn) {
+ xcb_xinerama_query_screens_reply_t *reply;
+ xcb_xinerama_screen_info_t *screen_info;
+
+ reply = xcb_xinerama_query_screens_reply(conn, xcb_xinerama_query_screens_unchecked(conn), NULL);
+ if (!reply) {
+ ELOG("Couldn't get Xinerama screens\n");
+ return;
+ }
+ screen_info = xcb_xinerama_query_screens_screen_info(reply);
+ int screens = xcb_xinerama_query_screens_screen_info_length(reply);
+
+ for (int screen = 0; screen < screens; screen++) {
+ Output *s = get_screen_at(screen_info[screen].x_org, screen_info[screen].y_org);
+ if (s != NULL) {
+ DLOG("Re-used old Xinerama screen %p\n", s);
+ /* This screen already exists. We use the littlest screen so that the user
+ can always see the complete workspace */
+ s->rect.width = min(s->rect.width, screen_info[screen].width);
+ s->rect.height = min(s->rect.height, screen_info[screen].height);
+ } else {
+ s = scalloc(sizeof(Output));
+ asprintf(&(s->name), "xinerama-%d", num_screens);
+ DLOG("Created new Xinerama screen %s (%p)\n", s->name, s);
+ s->active = true;
+ s->rect.x = screen_info[screen].x_org;
+ s->rect.y = screen_info[screen].y_org;
+ s->rect.width = screen_info[screen].width;
+ s->rect.height = screen_info[screen].height;
+ /* We always treat the screen at 0x0 as the primary screen */
+ if (s->rect.x == 0 && s->rect.y == 0)
+ TAILQ_INSERT_HEAD(&outputs, s, outputs);
+ else TAILQ_INSERT_TAIL(&outputs, s, outputs);
+ num_screens++;
+ }
+
+ DLOG("found Xinerama screen: %d x %d at %d x %d\n",
+ screen_info[screen].width, screen_info[screen].height,
+ screen_info[screen].x_org, screen_info[screen].y_org);
+ }
+
+ free(reply);
+
+ if (num_screens == 0) {
+ ELOG("No screens found. Please fix your setup. i3 will exit now.\n");
+ exit(0);
+ }
+}
+
+/*
+ * We have just established a connection to the X server and need the initial Xinerama
+ * information to setup workspaces for each screen.
+ *
+ */
+void initialize_xinerama(xcb_connection_t *conn) {
+ if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) {
+ DLOG("Xinerama extension not found, disabling.\n");
+ disable_randr(conn);
+ } else {
+ xcb_xinerama_is_active_reply_t *reply;
+ reply = xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL);
+
+ if (reply == NULL || !reply->state) {
+ DLOG("Xinerama is not active (in your X-Server), disabling.\n");
+ disable_randr(conn);
+ } else
+ query_screens(conn);
+
+ FREE(reply);
+ }
+
+ Output *output;
+ Workspace *ws;
+ /* Just go through each active output and associate one workspace */
+ TAILQ_FOREACH(output, &outputs, outputs) {
+ ws = get_first_workspace_for_output(output);
+ initialize_output(conn, output, ws);
+ }
+}