diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-11-10 10:28:01 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-11-12 20:18:48 +0000 |
commit | 20e318c292a4e1336093dfbc77cb44d099c80050 (patch) | |
tree | 71f0ecad9194327b99368a2df94ec876eb8d739f /tools | |
parent | 04d2cad65dbb07a2f03835a71fb7f5efc0235ea6 (diff) |
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>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/virtual.c | 139 |
1 files changed, 117 insertions, 22 deletions
diff --git a/tools/virtual.c b/tools/virtual.c index 504a68d3..c3d7024c 100644 --- a/tools/virtual.c +++ b/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) { |