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:
parent
4dfe61c2d4
commit
bd76e994b8
|
@ -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
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
33
src/mainx.c
33
src/mainx.c
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue