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-aux
|
||||
LDFLAGS += -lxcb-icccm
|
||||
LDFLAGS += -lxcb-xinerama
|
||||
LDFLAGS += -lxcb-randr
|
||||
LDFLAGS += -lxcb
|
||||
LDFLAGS += -lX11
|
||||
|
|
|
@ -32,7 +32,6 @@ extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
|
|||
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];
|
||||
|
|
|
@ -24,6 +24,19 @@ extern struct outputs_head outputs;
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -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
|
23
src/mainx.c
23
src/mainx.c
|
@ -45,6 +45,7 @@
|
|||
#include "util.h"
|
||||
#include "xcb.h"
|
||||
#include "randr.h"
|
||||
#include "xinerama.h"
|
||||
#include "manage.h"
|
||||
#include "ipc.h"
|
||||
#include "log.h"
|
||||
|
@ -150,6 +151,7 @@ int main(int argc, char *argv[], char *env[]) {
|
|||
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];
|
||||
|
@ -158,6 +160,7 @@ int main(int argc, char *argv[], char *env[]) {
|
|||
{"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;
|
||||
|
@ -196,6 +199,17 @@ int main(int argc, char *argv[], char *env[]) {
|
|||
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");
|
||||
|
@ -205,6 +219,9 @@ int main(int argc, char *argv[], char *env[]) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
@ -460,14 +477,18 @@ int main(int argc, char *argv[], char *env[]) {
|
|||
|
||||
grab_all_keys(conn);
|
||||
|
||||
DLOG("Checking for XRandR...\n");
|
||||
int randr_base;
|
||||
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);
|
||||
|
||||
|
|
|
@ -157,8 +157,11 @@ Output *get_output_most(direction_t direction, Output *current) {
|
|||
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;
|
||||
|
@ -192,7 +195,7 @@ static void initialize_output(xcb_connection_t *conn, 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");
|
||||
|
|
|
@ -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