Re-add old Xinerama code for the poor nvidia users

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).
This commit is contained in:
Michael Stapelberg 2010-03-09 20:00:56 +01:00
parent 4dfe61c2d4
commit bd76e994b8
7 changed files with 198 additions and 10 deletions

View File

@ -37,6 +37,7 @@ LDFLAGS += -lxcb-keysyms
LDFLAGS += -lxcb-atom LDFLAGS += -lxcb-atom
LDFLAGS += -lxcb-aux LDFLAGS += -lxcb-aux
LDFLAGS += -lxcb-icccm LDFLAGS += -lxcb-icccm
LDFLAGS += -lxcb-xinerama
LDFLAGS += -lxcb-randr LDFLAGS += -lxcb-randr
LDFLAGS += -lxcb LDFLAGS += -lxcb
LDFLAGS += -lX11 LDFLAGS += -lX11

View File

@ -32,7 +32,6 @@ extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
extern TAILQ_HEAD(assignments_head, Assignment) assignments; extern TAILQ_HEAD(assignments_head, Assignment) assignments;
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins; extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
extern xcb_event_handlers_t evenths; extern xcb_event_handlers_t evenths;
extern int num_screens;
extern uint8_t root_depth; extern uint8_t root_depth;
extern bool xkb_supported; extern bool xkb_supported;
extern xcb_atom_t atoms[NUM_ATOMS]; extern xcb_atom_t atoms[NUM_ATOMS];

View File

@ -24,6 +24,19 @@ extern struct outputs_head outputs;
*/ */
void initialize_randr(xcb_connection_t *conn, int *event_base); 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. * (Re-)queries the outputs via RandR and stores them in the list of outputs.
* *

23
include/xinerama.h Normal file
View File

@ -0,0 +1,23 @@
/*
* 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

View File

@ -45,6 +45,7 @@
#include "util.h" #include "util.h"
#include "xcb.h" #include "xcb.h"
#include "randr.h" #include "randr.h"
#include "xinerama.h"
#include "manage.h" #include "manage.h"
#include "ipc.h" #include "ipc.h"
#include "log.h" #include "log.h"
@ -150,6 +151,7 @@ int main(int argc, char *argv[], char *env[]) {
char *override_configpath = NULL; char *override_configpath = NULL;
bool autostart = true; bool autostart = true;
bool only_check_config = false; bool only_check_config = false;
bool force_xinerama = false;
xcb_connection_t *conn; xcb_connection_t *conn;
xcb_property_handlers_t prophs; xcb_property_handlers_t prophs;
xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
@ -158,6 +160,7 @@ int main(int argc, char *argv[], char *env[]) {
{"config", required_argument, 0, 'c'}, {"config", required_argument, 0, 'c'},
{"version", no_argument, 0, 'v'}, {"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"force-xinerama", no_argument, 0, 0},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
int option_index = 0; int option_index = 0;
@ -196,6 +199,17 @@ int main(int argc, char *argv[], char *env[]) {
case 'l': case 'l':
/* DEPRECATED, ignored for the next 3 versions (3.e, 3.f, 3.g) */ /* DEPRECATED, ignored for the next 3 versions (3.e, 3.f, 3.g) */
break; 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: default:
fprintf(stderr, "Usage: %s [-c configfile] [-d loglevel] [-a] [-v] [-V] [-C]\n", argv[0]); fprintf(stderr, "Usage: %s [-c configfile] [-d loglevel] [-a] [-v] [-V] [-C]\n", argv[0]);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
@ -205,6 +219,9 @@ int main(int argc, char *argv[], char *env[]) {
fprintf(stderr, "-d <loglevel>: enable debug loglevel <loglevel>\n"); fprintf(stderr, "-d <loglevel>: enable debug loglevel <loglevel>\n");
fprintf(stderr, "-c <configfile>: use the provided configfile instead\n"); fprintf(stderr, "-c <configfile>: use the provided configfile instead\n");
fprintf(stderr, "-C: check configuration file and exit\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); exit(EXIT_FAILURE);
} }
} }
@ -460,14 +477,18 @@ int main(int argc, char *argv[], char *env[]) {
grab_all_keys(conn); grab_all_keys(conn);
DLOG("Checking for XRandR...\n");
int randr_base; int randr_base;
initialize_randr(conn, &randr_base); if (force_xinerama) {
initialize_xinerama(conn);
} else {
DLOG("Checking for XRandR...\n");
initialize_randr(conn, &randr_base);
xcb_event_set_handler(&evenths, xcb_event_set_handler(&evenths,
randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY, randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY,
handle_screen_change, handle_screen_change,
NULL); NULL);
}
xcb_flush(conn); xcb_flush(conn);

View File

@ -157,8 +157,11 @@ Output *get_output_most(direction_t direction, Output *current) {
return candidate; 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); i3Font *font = load_font(conn, config.font);
workspace->output = output; workspace->output = output;
@ -192,7 +195,7 @@ static void initialize_output(xcb_connection_t *conn, Output *output,
* X11 screen. * 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; xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
DLOG("RandR extension unusable, disabling.\n"); DLOG("RandR extension unusable, disabling.\n");

128
src/xinerama.c Normal file
View File

@ -0,0 +1,128 @@
/*
* 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);
}
}