intel-virtual-output: Manually adjust screen size
When we modify the outputs and end up with a different screen size, we need to actually tell the display to resize with an explicit XRRSetScreenSize. Reported-by: Jethro Beekman <freedesktop-bugs@jbeekman.nl> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=71441 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
04d2cad65d
commit
20e318c292
139
tools/virtual.c
139
tools/virtual.c
|
|
@ -86,7 +86,10 @@ struct display {
|
|||
Window root;
|
||||
Visual *visual;
|
||||
Damage damage;
|
||||
long timestamp;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int depth;
|
||||
|
||||
XRenderPictFormat *root_format;
|
||||
|
|
@ -144,6 +147,7 @@ struct clone {
|
|||
struct clone *active;
|
||||
|
||||
struct output src, dst;
|
||||
long timestamp;
|
||||
|
||||
XShmSegmentInfo shm;
|
||||
XImage image;
|
||||
|
|
@ -432,6 +436,12 @@ static int clone_update_modes__randr(struct clone *clone)
|
|||
if (from_info == NULL)
|
||||
goto err;
|
||||
|
||||
DBG(("%s(%s-%s): timestamp %ld (last %ld)\n", __func__,
|
||||
DisplayString(clone->src.dpy), clone->src.name,
|
||||
from_info->timestamp, clone->timestamp));
|
||||
if (from_info->timestamp == clone->timestamp)
|
||||
goto err;
|
||||
|
||||
to_res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
|
||||
if (to_res == NULL)
|
||||
goto err;
|
||||
|
|
@ -440,6 +450,30 @@ static int clone_update_modes__randr(struct clone *clone)
|
|||
if (to_info == NULL)
|
||||
goto err;
|
||||
|
||||
if (clone->dst.rr_crtc == from_info->crtc) {
|
||||
for (i = 0; i < to_info->nmode; i++) {
|
||||
XRRModeInfo *mode, *old;
|
||||
|
||||
mode = lookup_mode(to_res, to_info->modes[i]);
|
||||
if (mode == NULL)
|
||||
break;
|
||||
for (j = 0; j < from_info->nmode; j++) {
|
||||
old = lookup_mode(from_res, from_info->modes[j]);
|
||||
if (old && mode_equal(mode, old)) {
|
||||
mode = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mode)
|
||||
break;
|
||||
}
|
||||
if (i == from_info->nmode && i == to_info->nmode) {
|
||||
DBG(("%s(%s-%s): no change in output\n", __func__,
|
||||
DisplayString(clone->src.dpy), clone->src.name));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
clone->dst.rr_crtc = from_info->crtc;
|
||||
|
||||
/* Clear all current UserModes on the output, including any active ones */
|
||||
|
|
@ -495,12 +529,16 @@ static int clone_update_modes__randr(struct clone *clone)
|
|||
m.name = buf;
|
||||
|
||||
id = XRRCreateMode(clone->src.dpy, clone->src.window, &m);
|
||||
DBG(("%s(%s-%s): adding mode %ld: %s\n", __func__,
|
||||
DisplayString(clone->src.dpy), clone->src.name, id, mode->name));
|
||||
}
|
||||
|
||||
XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id);
|
||||
}
|
||||
XUngrabServer(clone->src.dpy);
|
||||
done:
|
||||
ret = 0;
|
||||
clone->timestamp = from_info->timestamp;
|
||||
|
||||
err:
|
||||
if (to_info)
|
||||
|
|
@ -824,7 +862,7 @@ static void clone_update(struct clone *clone)
|
|||
clone->rr_update = 0;
|
||||
}
|
||||
|
||||
static void context_update(struct context *ctx)
|
||||
static int context_update(struct context *ctx)
|
||||
{
|
||||
Display *dpy = ctx->display->dpy;
|
||||
XRRScreenResources *res;
|
||||
|
|
@ -835,8 +873,15 @@ static void context_update(struct context *ctx)
|
|||
|
||||
res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root);
|
||||
if (res == NULL)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
DBG(("%s timestamp %ld (last %ld)\n", DisplayString(dpy), res->timestamp, ctx->display->timestamp));
|
||||
if (res->timestamp == ctx->display->timestamp) {
|
||||
XRRFreeScreenResources(res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->display->timestamp = res->timestamp;
|
||||
for (n = 0; n < ctx->nclone; n++) {
|
||||
struct output *output = &ctx->clones[n].src;
|
||||
XRROutputInfo *o;
|
||||
|
|
@ -902,7 +947,7 @@ static void context_update(struct context *ctx)
|
|||
|
||||
DBG(("%s changed? %d\n", DisplayString(dpy), context_changed));
|
||||
if (!context_changed)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
for (n = 1; n < ctx->ndisplay; n++) {
|
||||
struct display *display = &ctx->display[n];
|
||||
|
|
@ -950,12 +995,42 @@ static void context_update(struct context *ctx)
|
|||
continue;
|
||||
|
||||
XGrabServer(display->dpy);
|
||||
|
||||
DBG(("%s: current size %dx%d, need %dx%d\n",
|
||||
DisplayString(display->dpy),
|
||||
display->width, display->height,
|
||||
x2, y2));
|
||||
|
||||
if (display->width != x2 || display->height != y2) {
|
||||
/* When shrinking we have to manually resize the fb */
|
||||
for (clone = display->clone; clone; clone = clone->next) {
|
||||
struct output *dst = &clone->dst;
|
||||
|
||||
if (!dst->rr_crtc)
|
||||
continue;
|
||||
|
||||
DBG(("%s: disabling output '%s'\n",
|
||||
DisplayString(dst->dpy), dst->name));
|
||||
XRRSetCrtcConfig(dst->dpy, res, dst->rr_crtc, CurrentTime,
|
||||
0, 0, None, RR_Rotate_0, NULL, 0);
|
||||
dst->rr_crtc = 0;
|
||||
dst->mode.id = 0;
|
||||
}
|
||||
|
||||
DBG(("%s: XRRSetScreenSize %dx%d\n", DisplayString(display->dpy), x2, y2));
|
||||
XRRSetScreenSize(display->dpy, display->root, x2, y2, x2 * 96 / 25.4, y2 * 96 / 25.4);
|
||||
display->width = x2;
|
||||
display->height = y2;
|
||||
}
|
||||
|
||||
for (clone = display->clone; clone; clone = clone->next) {
|
||||
struct output *src = &clone->src;
|
||||
struct output *dst = &clone->dst;
|
||||
XRROutputInfo *o;
|
||||
XRRPanning panning;
|
||||
struct clone *set;
|
||||
RRCrtc rr_crtc;
|
||||
Status ret;
|
||||
|
||||
DBG(("%s: copying configuration from %s (mode=%ld) to %s\n",
|
||||
DisplayString(dst->dpy), src->name, (long)src->mode.id, dst->name));
|
||||
|
|
@ -1030,9 +1105,12 @@ err:
|
|||
DBG(("%s: enabling output '%s' (%d,%d)x(%d,%d) on CRTC:%ld\n",
|
||||
DisplayString(dst->dpy), dst->name,
|
||||
dst->x, dst->y, dst->mode.width, dst->mode.height, (long)rr_crtc));
|
||||
XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime,
|
||||
dst->x, dst->y, dst->mode.id, dst->rotation,
|
||||
&dst->rr_output, 1);
|
||||
ret = XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime,
|
||||
dst->x, dst->y, dst->mode.id, dst->rotation,
|
||||
&dst->rr_output, 1);
|
||||
DBG(("%s-%s: XRRSetCrtcConfig %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
|
||||
ret = XRRSetPanning(dst->dpy, res, rr_crtc, memset(&panning, 0, sizeof(panning)));
|
||||
DBG(("%s-%s: XRRSetPanning %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
|
||||
dst->rr_crtc = rr_crtc;
|
||||
}
|
||||
XUngrabServer(display->dpy);
|
||||
|
|
@ -1050,6 +1128,8 @@ err:
|
|||
clone->active = ctx->active;
|
||||
ctx->active = clone;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Cursor display_load_invisible_cursor(struct display *display)
|
||||
|
|
@ -1357,7 +1437,13 @@ static int clone_paint(struct clone *c)
|
|||
DisplayString(c->dst.dpy), c->dst.name,
|
||||
(long)c->dst.serial, (long)LastKnownRequestProcessed(c->dst.dpy)));
|
||||
if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
|
||||
XPending(c->dst.dpy);
|
||||
struct pollfd pfd;
|
||||
|
||||
pfd.fd = ConnectionNumber(c->dst.dpy);
|
||||
pfd.events = POLLIN;
|
||||
XEventsQueued(c->dst.dpy,
|
||||
poll(&pfd, 1, 0) ? QueuedAfterReading : QueuedAfterFlush);
|
||||
|
||||
if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
|
||||
c->dst.display->skip_clone++;
|
||||
return EAGAIN;
|
||||
|
|
@ -1850,6 +1936,7 @@ static void display_init_randr_hpd(struct display *display)
|
|||
if (!XRRQueryVersion(display->dpy, &major, &minor))
|
||||
return;
|
||||
|
||||
DBG(("%s - randr version %d.%d\n", DisplayString(display->dpy), major, minor));
|
||||
if (major > 1 || (major == 1 && minor >= 2))
|
||||
XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask);
|
||||
}
|
||||
|
|
@ -1957,6 +2044,13 @@ static int last_display_add_clones__randr(struct context *ctx)
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
if (o->crtc) {
|
||||
DBG(("%s - disabling active output\n", DisplayString(display->dpy)));
|
||||
XRRSetCrtcConfig(display->dpy, res, o->crtc, CurrentTime,
|
||||
0, 0, None, RR_Rotate_0, NULL, 0);
|
||||
}
|
||||
|
||||
XRRFreeOutputInfo(o);
|
||||
}
|
||||
XRRFreeScreenResources(res);
|
||||
|
|
@ -2100,6 +2194,10 @@ static int last_display_add_clones(struct context *ctx)
|
|||
{
|
||||
struct display *display = last_display(ctx);
|
||||
|
||||
display->width = DisplayWidth(display->dpy, DefaultScreen(display->dpy));
|
||||
display->height = DisplayHeight(display->dpy, DefaultScreen(display->dpy));
|
||||
DBG(("%s - initial size %dx%d\n", DisplayString(display->dpy), display->width, display->height));
|
||||
|
||||
if (display->rr_active)
|
||||
return last_display_add_clones__randr(ctx);
|
||||
|
||||
|
|
@ -2636,7 +2734,7 @@ int main(int argc, char **argv)
|
|||
int reconfigure = 0;
|
||||
int rr_update = 0;
|
||||
|
||||
DBG(("polling - enable timer? %d, nfd=%d\n", ctx.timer_active, ctx.nfd));
|
||||
DBG(("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
|
||||
ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
|
@ -2644,7 +2742,7 @@ int main(int argc, char **argv)
|
|||
/* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */
|
||||
|
||||
DBG(("poll reports %d fd awake\n", ret));
|
||||
if (ctx.pfd[1].revents) {
|
||||
if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) {
|
||||
DBG(("%s woken up\n", DisplayString(ctx.display[0].dpy)));
|
||||
do {
|
||||
XNextEvent(ctx.display->dpy, &e);
|
||||
|
|
@ -2702,13 +2800,11 @@ int main(int argc, char **argv)
|
|||
} else {
|
||||
DBG(("unknown event %d\n", e.type));
|
||||
}
|
||||
} while (XPending(ctx.display->dpy) || poll(&ctx.pfd[1], 1, 0) > 0);
|
||||
|
||||
ret--;
|
||||
} while (XEventsQueued(ctx.display->dpy, QueuedAfterReading));
|
||||
}
|
||||
|
||||
for (i = 1; ret && i < ctx.ndisplay; i++) {
|
||||
if (ctx.pfd[i+2].revents == 0)
|
||||
for (i = 1; i < ctx.ndisplay; i++) {
|
||||
if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy))
|
||||
continue;
|
||||
|
||||
DBG(("%s woken up\n", DisplayString(ctx.display[i].dpy)));
|
||||
|
|
@ -2718,24 +2814,20 @@ int main(int argc, char **argv)
|
|||
DBG(("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type));
|
||||
if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
|
||||
XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
|
||||
|
||||
DBG(("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype));
|
||||
if (re->subtype == RRNotify_OutputChange) {
|
||||
XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re;
|
||||
struct clone *clone;
|
||||
|
||||
DBG(("%s RRNotify_OutputChange, timestamp %ld\n", DisplayString(ctx.display[i].dpy), ro->timestamp));
|
||||
for (clone = ctx.display[i].clone; clone; clone = clone->next) {
|
||||
if (clone->dst.rr_output == ro->output)
|
||||
rr_update = clone->rr_update = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (XPending(ctx.display[i].dpy) || poll(&ctx.pfd[i+2], 1, 0) > 0);
|
||||
|
||||
ret--;
|
||||
}
|
||||
|
||||
if (reconfigure) {
|
||||
context_update(&ctx);
|
||||
display_reset_damage(ctx.display);
|
||||
} while (XEventsQueued(ctx.display[i].dpy, QueuedAfterReading));
|
||||
}
|
||||
|
||||
if (rr_update) {
|
||||
|
|
@ -2743,6 +2835,9 @@ int main(int argc, char **argv)
|
|||
clone_update(&ctx.clones[i]);
|
||||
}
|
||||
|
||||
if (reconfigure && context_update(&ctx))
|
||||
display_reset_damage(ctx.display);
|
||||
|
||||
XPending(ctx.record);
|
||||
|
||||
if (ctx.timer_active && read(ctx.timer, &count, sizeof(count)) > 0) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue