screen: store RandR information

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2009-09-21 16:29:19 +02:00
parent 6a1ce5ce05
commit 8c87b7cb57
2 changed files with 150 additions and 60 deletions

205
screen.c
View File

@ -23,6 +23,7 @@
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xinerama.h> #include <xcb/xinerama.h>
#include <xcb/randr.h>
#include "screen.h" #include "screen.h"
#include "ewmh.h" #include "ewmh.h"
@ -33,6 +34,16 @@
#include "luaa.h" #include "luaa.h"
#include "common/xutil.h" #include "common/xutil.h"
struct screen_output_t
{
/** The XRandR names of the output */
char *name;
/** The size in millimeters */
uint32_t mm_width, mm_height;
};
ARRAY_FUNCS(screen_output_t, screen_output, DO_NOTHING)
static inline area_t static inline area_t
screen_xsitoarea(xcb_xinerama_screen_info_t si) screen_xsitoarea(xcb_xinerama_screen_info_t si)
{ {
@ -66,76 +77,150 @@ screen_default_visual(xcb_screen_t *s)
void void
screen_scan(void) screen_scan(void)
{ {
/* Check for extension before checking for Xinerama */ /* Check for extension before checking for XRandR */
if(xcb_get_extension_data(globalconf.connection, &xcb_xinerama_id)->present) if(xcb_get_extension_data(globalconf.connection, &xcb_randr_id)->present)
{ {
xcb_xinerama_is_active_reply_t *xia; xcb_randr_query_version_reply_t *version_reply =
xia = xcb_xinerama_is_active_reply(globalconf.connection, xcb_xinerama_is_active(globalconf.connection), NULL); xcb_randr_query_version_reply(globalconf.connection,
globalconf.xinerama_is_active = xia->state; xcb_randr_query_version(globalconf.connection, 1, 1), 0);
p_delete(&xia); if(version_reply)
}
if(globalconf.xinerama_is_active)
{
xcb_xinerama_query_screens_reply_t *xsq;
xcb_xinerama_screen_info_t *xsi;
int xinerama_screen_number;
xsq = xcb_xinerama_query_screens_reply(globalconf.connection,
xcb_xinerama_query_screens_unchecked(globalconf.connection),
NULL);
xsi = xcb_xinerama_query_screens_screen_info(xsq);
xinerama_screen_number = xcb_xinerama_query_screens_screen_info_length(xsq);
/* now check if screens overlaps (same x,y): if so, we take only the biggest one */
for(int screen = 0; screen < xinerama_screen_number; screen++)
{ {
bool drop = false; /* A quick XRandR recall:
foreach(screen_to_test, globalconf.screens) * You have CRTC that manages a part of a SCREEN.
if(xsi[screen].x_org == screen_to_test->geometry.x * Each CRTC can draw stuff on one or more OUTPUT. */
&& xsi[screen].y_org == screen_to_test->geometry.y) xcb_screen_t *screen = xutil_screen_get(globalconf.connection, globalconf.default_screen);
{
/* we already have a screen for this area, just check if xcb_randr_get_screen_resources_cookie_t screen_res_c = xcb_randr_get_screen_resources(globalconf.connection, screen->root);
* it's not bigger and drop it */ xcb_randr_get_screen_resources_reply_t *screen_res_r = xcb_randr_get_screen_resources_reply(globalconf.connection, screen_res_c, NULL);
drop = true;
int i = screen_array_indexof(&globalconf.screens, screen_to_test); /* We go through CRTC, and build a screen for each one. */
screen_to_test->geometry.width = xcb_randr_crtc_t *randr_crtcs = xcb_randr_get_screen_resources_crtcs(screen_res_r);
MAX(xsi[screen].width, xsi[i].width);
screen_to_test->geometry.height = for(int i = 0; i < screen_res_r->num_crtcs; i++)
MAX(xsi[screen].height, xsi[i].height);
}
if(!drop)
{ {
screen_t s; /* Get info on the output crtc */
p_clear(&s, 1); xcb_randr_get_crtc_info_cookie_t crtc_info_c = xcb_randr_get_crtc_info(globalconf.connection, randr_crtcs[i], XCB_CURRENT_TIME);
s.geometry = screen_xsitoarea(xsi[screen]); xcb_randr_get_crtc_info_reply_t *crtc_info_r = xcb_randr_get_crtc_info_reply(globalconf.connection, crtc_info_c, NULL);
screen_array_append(&globalconf.screens, s);
/* If CRTC has no OUTPUT, ignore it */
if(!xcb_randr_get_crtc_info_outputs_length(crtc_info_r))
continue;
/* Prepare the new screen */
screen_t new_screen;
p_clear(&new_screen, 1);
new_screen.geometry.x = crtc_info_r->x;
new_screen.geometry.y = crtc_info_r->y;
new_screen.geometry.width= crtc_info_r->width;
new_screen.geometry.height= crtc_info_r->height;
xcb_randr_output_t *randr_outputs = xcb_randr_get_crtc_info_outputs(crtc_info_r);
for(int j = 0; j < xcb_randr_get_crtc_info_outputs_length(crtc_info_r); j++)
{
xcb_randr_get_output_info_cookie_t output_info_c = xcb_randr_get_output_info(globalconf.connection, randr_outputs[j], XCB_CURRENT_TIME);
xcb_randr_get_output_info_reply_t *output_info_r = xcb_randr_get_output_info_reply(globalconf.connection, output_info_c, NULL);
int len = xcb_randr_get_output_info_name_length(output_info_r);
/* name is not NULL terminated */
char *name = memcpy(p_new(char *, len + 1), xcb_randr_get_output_info_name(output_info_r), len);
name[len] = '\0';
screen_output_array_append(&new_screen.outputs,
(screen_output_t) { .name = name,
.mm_width = output_info_r->mm_width,
.mm_height = output_info_r->mm_height });
p_delete(&output_info_r);
}
screen_array_append(&globalconf.screens, new_screen);
p_delete(&crtc_info_r);
} }
p_delete(&screen_res_r);
/* If RandR provides more than 2 active CRTC, Xinerama is enabled */
if(globalconf.screens.len > 1)
globalconf.xinerama_is_active = true;
globalconf.screens.tab[0].visual = screen_default_visual(xutil_screen_get(globalconf.connection, globalconf.default_screen));
} }
p_delete(&xsq);
xcb_screen_t *s = xutil_screen_get(globalconf.connection, globalconf.default_screen);
globalconf.screens.tab[0].visual = screen_default_visual(s);
} }
else else
/* One screen only / Zaphod mode */ {
for(int screen = 0; /* Check for extension before checking for Xinerama */
screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); if(xcb_get_extension_data(globalconf.connection, &xcb_xinerama_id)->present)
screen++)
{ {
xcb_screen_t *xcb_screen = xutil_screen_get(globalconf.connection, screen); xcb_xinerama_is_active_reply_t *xia;
screen_t s; xia = xcb_xinerama_is_active_reply(globalconf.connection, xcb_xinerama_is_active(globalconf.connection), NULL);
p_clear(&s, 1); globalconf.xinerama_is_active = xia->state;
s.geometry.x = 0; p_delete(&xia);
s.geometry.y = 0;
s.geometry.width = xcb_screen->width_in_pixels;
s.geometry.height = xcb_screen->height_in_pixels;
s.visual = screen_default_visual(xcb_screen);
screen_array_append(&globalconf.screens, s);
} }
if(globalconf.xinerama_is_active)
{
xcb_xinerama_query_screens_reply_t *xsq;
xcb_xinerama_screen_info_t *xsi;
int xinerama_screen_number;
xsq = xcb_xinerama_query_screens_reply(globalconf.connection,
xcb_xinerama_query_screens_unchecked(globalconf.connection),
NULL);
xsi = xcb_xinerama_query_screens_screen_info(xsq);
xinerama_screen_number = xcb_xinerama_query_screens_screen_info_length(xsq);
/* now check if screens overlaps (same x,y): if so, we take only the biggest one */
for(int screen = 0; screen < xinerama_screen_number; screen++)
{
bool drop = false;
foreach(screen_to_test, globalconf.screens)
if(xsi[screen].x_org == screen_to_test->geometry.x
&& xsi[screen].y_org == screen_to_test->geometry.y)
{
/* we already have a screen for this area, just check if
* it's not bigger and drop it */
drop = true;
int i = screen_array_indexof(&globalconf.screens, screen_to_test);
screen_to_test->geometry.width =
MAX(xsi[screen].width, xsi[i].width);
screen_to_test->geometry.height =
MAX(xsi[screen].height, xsi[i].height);
}
if(!drop)
{
screen_t s;
p_clear(&s, 1);
s.geometry = screen_xsitoarea(xsi[screen]);
screen_array_append(&globalconf.screens, s);
}
}
p_delete(&xsq);
xcb_screen_t *s = xutil_screen_get(globalconf.connection, globalconf.default_screen);
globalconf.screens.tab[0].visual = screen_default_visual(s);
}
else
/* One screen only / Zaphod mode */
for(int screen = 0;
screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
screen++)
{
xcb_screen_t *xcb_screen = xutil_screen_get(globalconf.connection, screen);
screen_t s;
p_clear(&s, 1);
s.geometry.x = 0;
s.geometry.y = 0;
s.geometry.width = xcb_screen->width_in_pixels;
s.geometry.height = xcb_screen->height_in_pixels;
s.visual = screen_default_visual(xcb_screen);
screen_array_append(&globalconf.screens, s);
}
}
globalconf.screen_focus = globalconf.screens.tab; globalconf.screen_focus = globalconf.screens.tab;
} }

View File

@ -25,6 +25,9 @@
#include "globalconf.h" #include "globalconf.h"
#include "draw.h" #include "draw.h"
typedef struct screen_output_t screen_output_t;
ARRAY_TYPE(screen_output_t, screen_output)
struct a_screen struct a_screen
{ {
/** Screen geometry */ /** Screen geometry */
@ -50,6 +53,8 @@ struct a_screen
signal_array_t signals; signal_array_t signals;
/** True if the banning on this screen needs to be updated */ /** True if the banning on this screen needs to be updated */
bool need_lazy_banning; bool need_lazy_banning;
/** The screen outputs informations */
screen_output_array_t outputs;
}; };
ARRAY_FUNCS(screen_t, screen, DO_NOTHING) ARRAY_FUNCS(screen_t, screen, DO_NOTHING)