forked from pool/xorg-x11-server
393 lines
14 KiB
Diff
393 lines
14 KiB
Diff
|
From 3a51418b2db353519a1779cf3cebbcc9afba2520 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?La=C3=A9rcio=20de=20Sousa?=
|
||
|
<laerciosousa@sme-mogidascruzes.sp.gov.br>
|
||
|
Date: Mon, 18 Aug 2014 08:45:43 -0300
|
||
|
Subject: ephyr: set screen size & origin from host X server output's CRTC
|
||
|
geometry
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
If a given output is passed via new -output option, Xephyr will query
|
||
|
host X server for its info. If the following conditions are met:
|
||
|
|
||
|
a. RandR extension is enabled in host X server;
|
||
|
b. supported RandR version in host X server is 1.2 or newer;
|
||
|
c. the given output name is valid;
|
||
|
d. the given output is connected;
|
||
|
|
||
|
then Xephyr will get output's CRTC geometry and use it to set its own
|
||
|
screen size and origin. It's just like starting Xephyr in fullscreen mode,
|
||
|
but restricted to the given output's CRTC geometry (fake "Zaphod mode").
|
||
|
|
||
|
This is the main feature needed for Xephyr-based single-card multiseat
|
||
|
setups where we don't have separate screens to start Xephyr in fullscreen
|
||
|
mode safely.
|
||
|
|
||
|
Signed-off-by: Laércio de Sousa <laerciosousa@sme-mogidascruzes.sp.gov.br>
|
||
|
Reviewed-by: Keith Packard <keithp@keithp.com>
|
||
|
Signed-off-by: Keith Packard <keithp@keithp.com>
|
||
|
|
||
|
diff --git a/configure.ac b/configure.ac
|
||
|
index f3d9654..cba7d24 100644
|
||
|
--- a/configure.ac
|
||
|
+++ b/configure.ac
|
||
|
@@ -2364,7 +2364,7 @@ if test "$KDRIVE" = yes; then
|
||
|
AC_DEFINE(KDRIVE_MOUSE, 1, [Enable KDrive mouse driver])
|
||
|
fi
|
||
|
|
||
|
- XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms"
|
||
|
+ XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms xcb-randr"
|
||
|
if test "x$XV" = xyes; then
|
||
|
XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv"
|
||
|
fi
|
||
|
diff --git a/hw/kdrive/ephyr/ephyr.c b/hw/kdrive/ephyr/ephyr.c
|
||
|
index b039c68..85d4193 100644
|
||
|
--- a/hw/kdrive/ephyr/ephyr.c
|
||
|
+++ b/hw/kdrive/ephyr/ephyr.c
|
||
|
@@ -111,13 +111,16 @@ Bool
|
||
|
ephyrScreenInitialize(KdScreenInfo *screen)
|
||
|
{
|
||
|
EphyrScrPriv *scrpriv = screen->driver;
|
||
|
+ int x = 0, y = 0;
|
||
|
int width = 640, height = 480;
|
||
|
CARD32 redMask, greenMask, blueMask;
|
||
|
|
||
|
- if (hostx_want_screen_size(screen, &width, &height)
|
||
|
+ if (hostx_want_screen_geometry(screen, &width, &height, &x, &y)
|
||
|
|| !screen->width || !screen->height) {
|
||
|
screen->width = width;
|
||
|
screen->height = height;
|
||
|
+ screen->x = x;
|
||
|
+ screen->y = y;
|
||
|
}
|
||
|
|
||
|
if (EphyrWantGrayScale)
|
||
|
diff --git a/hw/kdrive/ephyr/ephyr.h b/hw/kdrive/ephyr/ephyr.h
|
||
|
index 5c4936b..4e753f1 100644
|
||
|
--- a/hw/kdrive/ephyr/ephyr.h
|
||
|
+++ b/hw/kdrive/ephyr/ephyr.h
|
||
|
@@ -74,8 +74,10 @@ typedef struct _ephyrScrPriv {
|
||
|
xcb_window_t peer_win; /* Used for GL; should be at most one */
|
||
|
xcb_image_t *ximg;
|
||
|
Bool win_explicit_position;
|
||
|
+ int win_x, win_y;
|
||
|
int win_width, win_height;
|
||
|
int server_depth;
|
||
|
+ const char *output; /* Set via -output option */
|
||
|
unsigned char *fb_data; /* only used when host bpp != server bpp */
|
||
|
xcb_shm_segment_info_t shminfo;
|
||
|
|
||
|
diff --git a/hw/kdrive/ephyr/ephyrinit.c b/hw/kdrive/ephyr/ephyrinit.c
|
||
|
index e04c8dc..38acc52 100644
|
||
|
--- a/hw/kdrive/ephyr/ephyrinit.c
|
||
|
+++ b/hw/kdrive/ephyr/ephyrinit.c
|
||
|
@@ -47,6 +47,8 @@ extern KdPointerDriver LinuxEvdevMouseDriver;
|
||
|
extern KdKeyboardDriver LinuxEvdevKeyboardDriver;
|
||
|
#endif
|
||
|
|
||
|
+void processScreenOrOutputArg(const char *screen_size, const char *output, char *parent_id);
|
||
|
+void processOutputArg(const char *output, char *parent_id);
|
||
|
void processScreenArg(const char *screen_size, char *parent_id);
|
||
|
|
||
|
void
|
||
|
@@ -134,6 +136,7 @@ ddxUseMsg(void)
|
||
|
ErrorF("-parent <XID> Use existing window as Xephyr root win\n");
|
||
|
ErrorF("-sw-cursor Render cursors in software in Xephyr\n");
|
||
|
ErrorF("-fullscreen Attempt to run Xephyr fullscreen\n");
|
||
|
+ ErrorF("-output <NAME> Attempt to run Xephyr fullscreen (restricted to given output geometry)\n");
|
||
|
ErrorF("-grayscale Simulate 8bit grayscale\n");
|
||
|
ErrorF("-resizeable Make Xephyr windows resizeable\n");
|
||
|
#ifdef GLAMOR
|
||
|
@@ -154,7 +157,7 @@ ddxUseMsg(void)
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-processScreenArg(const char *screen_size, char *parent_id)
|
||
|
+processScreenOrOutputArg(const char *screen_size, const char *output, char *parent_id)
|
||
|
{
|
||
|
KdCardInfo *card;
|
||
|
|
||
|
@@ -178,13 +181,25 @@ processScreenArg(const char *screen_size, char *parent_id)
|
||
|
|
||
|
use_geometry = (strchr(screen_size, '+') != NULL);
|
||
|
EPHYR_DBG("screen number:%d\n", screen->mynum);
|
||
|
- hostx_add_screen(screen, p_id, screen->mynum, use_geometry);
|
||
|
+ hostx_add_screen(screen, p_id, screen->mynum, use_geometry, output);
|
||
|
}
|
||
|
else {
|
||
|
ErrorF("No matching card found!\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+processScreenArg(const char *screen_size, char *parent_id)
|
||
|
+{
|
||
|
+ processScreenOrOutputArg(screen_size, NULL, parent_id);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+processOutputArg(const char *output, char *parent_id)
|
||
|
+{
|
||
|
+ processScreenOrOutputArg("100x100+0+0", output, parent_id);
|
||
|
+}
|
||
|
+
|
||
|
int
|
||
|
ddxProcessArgument(int argc, char **argv, int i)
|
||
|
{
|
||
|
@@ -226,6 +241,15 @@ ddxProcessArgument(int argc, char **argv, int i)
|
||
|
UseMsg();
|
||
|
exit(1);
|
||
|
}
|
||
|
+ else if (!strcmp(argv[i], "-output")) {
|
||
|
+ if (i + 1 < argc) {
|
||
|
+ processOutputArg(argv[i + 1], NULL);
|
||
|
+ return 2;
|
||
|
+ }
|
||
|
+
|
||
|
+ UseMsg();
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
else if (!strcmp(argv[i], "-sw-cursor")) {
|
||
|
hostx_use_sw_cursor();
|
||
|
return 1;
|
||
|
diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c
|
||
|
index 92a8ada..2161ad5 100644
|
||
|
--- a/hw/kdrive/ephyr/hostx.c
|
||
|
+++ b/hw/kdrive/ephyr/hostx.c
|
||
|
@@ -51,6 +51,7 @@
|
||
|
#include <xcb/xcb_image.h>
|
||
|
#include <xcb/shape.h>
|
||
|
#include <xcb/xcb_keysyms.h>
|
||
|
+#include <xcb/randr.h>
|
||
|
#ifdef XF86DRI
|
||
|
#include <xcb/xf86dri.h>
|
||
|
#include <xcb/glx.h>
|
||
|
@@ -104,12 +105,15 @@ static void
|
||
|
#define host_depth_matches_server(_vars) (HostX.depth == (_vars)->server_depth)
|
||
|
|
||
|
int
|
||
|
-hostx_want_screen_size(KdScreenInfo *screen, int *width, int *height)
|
||
|
+hostx_want_screen_geometry(KdScreenInfo *screen, int *width, int *height, int *x, int *y)
|
||
|
{
|
||
|
EphyrScrPriv *scrpriv = screen->driver;
|
||
|
|
||
|
if (scrpriv && (scrpriv->win_pre_existing != None ||
|
||
|
+ scrpriv->output != NULL ||
|
||
|
HostX.use_fullscreen == TRUE)) {
|
||
|
+ *x = scrpriv->win_x;
|
||
|
+ *y = scrpriv->win_y;
|
||
|
*width = scrpriv->win_width;
|
||
|
*height = scrpriv->win_height;
|
||
|
return 1;
|
||
|
@@ -119,7 +123,7 @@ hostx_want_screen_size(KdScreenInfo *screen, int *width, int *height)
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-hostx_add_screen(KdScreenInfo *screen, unsigned long win_id, int screen_num, Bool use_geometry)
|
||
|
+hostx_add_screen(KdScreenInfo *screen, unsigned long win_id, int screen_num, Bool use_geometry, const char *output)
|
||
|
{
|
||
|
EphyrScrPriv *scrpriv = screen->driver;
|
||
|
int index = HostX.n_screens;
|
||
|
@@ -132,6 +136,7 @@ hostx_add_screen(KdScreenInfo *screen, unsigned long win_id, int screen_num, Boo
|
||
|
scrpriv->screen = screen;
|
||
|
scrpriv->win_pre_existing = win_id;
|
||
|
scrpriv->win_explicit_position = use_geometry;
|
||
|
+ scrpriv->output = output;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
@@ -211,6 +216,119 @@ hostx_want_preexisting_window(KdScreenInfo *screen)
|
||
|
}
|
||
|
|
||
|
void
|
||
|
+hostx_get_output_geometry(const char *output,
|
||
|
+ int *x, int *y,
|
||
|
+ int *width, int *height)
|
||
|
+{
|
||
|
+ int i, name_len = 0, output_found = FALSE;
|
||
|
+ char *name = NULL;
|
||
|
+ xcb_generic_error_t *error;
|
||
|
+ xcb_randr_query_version_cookie_t version_c;
|
||
|
+ xcb_randr_query_version_reply_t *version_r;
|
||
|
+ xcb_randr_get_screen_resources_cookie_t screen_resources_c;
|
||
|
+ xcb_randr_get_screen_resources_reply_t *screen_resources_r;
|
||
|
+ xcb_randr_output_t *randr_outputs;
|
||
|
+ xcb_randr_get_output_info_cookie_t output_info_c;
|
||
|
+ xcb_randr_get_output_info_reply_t *output_info_r;
|
||
|
+ xcb_randr_get_crtc_info_cookie_t crtc_info_c;
|
||
|
+ xcb_randr_get_crtc_info_reply_t *crtc_info_r;
|
||
|
+
|
||
|
+ /* First of all, check for extension */
|
||
|
+ if (!xcb_get_extension_data(HostX.conn, &xcb_randr_id)->present)
|
||
|
+ {
|
||
|
+ fprintf(stderr, "\nHost X server does not support RANDR extension (or it's disabled).\n");
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Check RandR version */
|
||
|
+ version_c = xcb_randr_query_version(HostX.conn, 1, 2);
|
||
|
+ version_r = xcb_randr_query_version_reply(HostX.conn,
|
||
|
+ version_c,
|
||
|
+ &error);
|
||
|
+
|
||
|
+ if (error != NULL || version_r == NULL)
|
||
|
+ {
|
||
|
+ fprintf(stderr, "\nFailed to get RandR version supported by host X server.\n");
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+ else if (version_r->major_version < 1 || version_r->minor_version < 2)
|
||
|
+ {
|
||
|
+ free(version_r);
|
||
|
+ fprintf(stderr, "\nHost X server doesn't support RandR 1.2, needed for -output usage.\n");
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+
|
||
|
+ free(version_r);
|
||
|
+
|
||
|
+ /* Get list of outputs from screen resources */
|
||
|
+ screen_resources_c = xcb_randr_get_screen_resources(HostX.conn,
|
||
|
+ HostX.winroot);
|
||
|
+ screen_resources_r = xcb_randr_get_screen_resources_reply(HostX.conn,
|
||
|
+ screen_resources_c,
|
||
|
+ NULL);
|
||
|
+ randr_outputs = xcb_randr_get_screen_resources_outputs(screen_resources_r);
|
||
|
+
|
||
|
+ for (i = 0; !output_found && i < screen_resources_r->num_outputs; i++)
|
||
|
+ {
|
||
|
+ /* Get info on the output */
|
||
|
+ output_info_c = xcb_randr_get_output_info(HostX.conn,
|
||
|
+ randr_outputs[i],
|
||
|
+ XCB_CURRENT_TIME);
|
||
|
+ output_info_r = xcb_randr_get_output_info_reply(HostX.conn,
|
||
|
+ output_info_c,
|
||
|
+ NULL);
|
||
|
+
|
||
|
+ /* Get output name */
|
||
|
+ name_len = xcb_randr_get_output_info_name_length(output_info_r);
|
||
|
+ name = malloc(name_len + 1);
|
||
|
+ strncpy(name, (char*)xcb_randr_get_output_info_name(output_info_r), name_len);
|
||
|
+ name[name_len] = '\0';
|
||
|
+
|
||
|
+ if (!strcmp(name, output))
|
||
|
+ {
|
||
|
+ output_found = TRUE;
|
||
|
+
|
||
|
+ /* Check if output is connected */
|
||
|
+ if (output_info_r->crtc == XCB_NONE)
|
||
|
+ {
|
||
|
+ free(name);
|
||
|
+ free(output_info_r);
|
||
|
+ free(screen_resources_r);
|
||
|
+ fprintf(stderr, "\nOutput %s is currently disabled (or not connected).\n", output);
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Get CRTC from output info */
|
||
|
+ crtc_info_c = xcb_randr_get_crtc_info(HostX.conn,
|
||
|
+ output_info_r->crtc,
|
||
|
+ XCB_CURRENT_TIME);
|
||
|
+ crtc_info_r = xcb_randr_get_crtc_info_reply(HostX.conn,
|
||
|
+ crtc_info_c,
|
||
|
+ NULL);
|
||
|
+
|
||
|
+ /* Get CRTC geometry */
|
||
|
+ *x = crtc_info_r->x;
|
||
|
+ *y = crtc_info_r->y;
|
||
|
+ *width = crtc_info_r->width;
|
||
|
+ *height = crtc_info_r->height;
|
||
|
+
|
||
|
+ free(crtc_info_r);
|
||
|
+ }
|
||
|
+
|
||
|
+ free(name);
|
||
|
+ free(output_info_r);
|
||
|
+ }
|
||
|
+
|
||
|
+ free(screen_resources_r);
|
||
|
+
|
||
|
+ if (!output_found)
|
||
|
+ {
|
||
|
+ fprintf(stderr, "\nOutput %s not available in host X server.\n", output);
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
hostx_use_fullscreen(void)
|
||
|
{
|
||
|
HostX.use_fullscreen = TRUE;
|
||
|
@@ -359,6 +477,8 @@ hostx_init(void)
|
||
|
scrpriv->win = xcb_generate_id(HostX.conn);
|
||
|
scrpriv->server_depth = HostX.depth;
|
||
|
scrpriv->ximg = NULL;
|
||
|
+ scrpriv->win_x = 0;
|
||
|
+ scrpriv->win_y = 0;
|
||
|
|
||
|
if (scrpriv->win_pre_existing != XCB_WINDOW_NONE) {
|
||
|
xcb_get_geometry_reply_t *prewin_geom;
|
||
|
@@ -416,6 +536,17 @@ hostx_init(void)
|
||
|
|
||
|
hostx_set_fullscreen_hint();
|
||
|
}
|
||
|
+ else if (scrpriv->output) {
|
||
|
+ hostx_get_output_geometry(scrpriv->output,
|
||
|
+ &scrpriv->win_x,
|
||
|
+ &scrpriv->win_y,
|
||
|
+ &scrpriv->win_width,
|
||
|
+ &scrpriv->win_height);
|
||
|
+
|
||
|
+ HostX.use_fullscreen = TRUE;
|
||
|
+ hostx_set_fullscreen_hint();
|
||
|
+ }
|
||
|
+
|
||
|
|
||
|
tmpstr = getenv("RESOURCE_NAME");
|
||
|
if (tmpstr && (!ephyrResNameFromCmd))
|
||
|
@@ -759,6 +890,8 @@ hostx_screen_init(KdScreenInfo *screen,
|
||
|
|
||
|
scrpriv->win_width = width;
|
||
|
scrpriv->win_height = height;
|
||
|
+ scrpriv->win_x = x;
|
||
|
+ scrpriv->win_y = y;
|
||
|
|
||
|
#ifdef GLAMOR
|
||
|
if (ephyr_glamor) {
|
||
|
diff --git a/hw/kdrive/ephyr/hostx.h b/hw/kdrive/ephyr/hostx.h
|
||
|
index c554ca3..80894c8 100644
|
||
|
--- a/hw/kdrive/ephyr/hostx.h
|
||
|
+++ b/hw/kdrive/ephyr/hostx.h
|
||
|
@@ -74,7 +74,7 @@ typedef struct {
|
||
|
} EphyrRect;
|
||
|
|
||
|
int
|
||
|
-hostx_want_screen_size(KdScreenInfo *screen, int *width, int *height);
|
||
|
+hostx_want_screen_geometry(KdScreenInfo *screen, int *width, int *height, int *x, int *y);
|
||
|
|
||
|
int
|
||
|
hostx_want_host_cursor(void);
|
||
|
@@ -83,6 +83,11 @@ void
|
||
|
hostx_use_sw_cursor(void);
|
||
|
|
||
|
void
|
||
|
+ hostx_get_output_geometry(const char *output,
|
||
|
+ int *x, int *y,
|
||
|
+ int *width, int *height);
|
||
|
+
|
||
|
+void
|
||
|
hostx_use_fullscreen(void);
|
||
|
|
||
|
int
|
||
|
@@ -107,7 +112,7 @@ int
|
||
|
hostx_init(void);
|
||
|
|
||
|
void
|
||
|
-hostx_add_screen(KdScreenInfo *screen, unsigned long win_id, int screen_num, Bool use_geometry);
|
||
|
+hostx_add_screen(KdScreenInfo *screen, unsigned long win_id, int screen_num, Bool use_geometry, const char *output);
|
||
|
|
||
|
void
|
||
|
hostx_set_display_name(char *name);
|
||
|
--
|
||
|
cgit v0.10.2
|
||
|
|