diff --git a/randr/Makefile.am b/randr/Makefile.am index 91c4bc6dd..9bf0e6531 100644 --- a/randr/Makefile.am +++ b/randr/Makefile.am @@ -15,6 +15,7 @@ librandr_la_SOURCES = \ rrinfo.c \ rrmode.c \ rroutput.c \ + rrpointer.c \ rrproperty.c \ rrscreen.c \ rrsdispatch.c \ diff --git a/randr/mirandr.c b/randr/mirandr.c index 918e55da4..fab0fd1bd 100644 --- a/randr/mirandr.c +++ b/randr/mirandr.c @@ -84,6 +84,9 @@ miRandRInit (ScreenPtr pScreen) pScrPriv->rrGetInfo = miRRGetInfo; #if RANDR_12_INTERFACE pScrPriv->rrCrtcSet = miRRCrtcSet; + pScrPriv->rrCrtcSetGamma = miRRCrtcSetGamma; + pScrPriv->rrOutputSetProperty = miRROutput + RRScreenSetSizeRange (pScreen, pScreen->width, pScreen->height, diff --git a/randr/randr.c b/randr/randr.c index 35f9a4c80..b422efe9d 100644 --- a/randr/randr.c +++ b/randr/randr.c @@ -130,38 +130,71 @@ SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from, cpswaps(from->subpixelOrder, to->subpixelOrder); } -#if 0 static void -SRRMonitorChangeNotifyEvent(xRRMonitorChangeNotifyEvent *from, - xRRMonitorChangeNotifyEvent *to) +SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent *from, + xRRCrtcChangeNotifyEvent *to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->window, to->window); + cpswapl(from->crtc, to->crtc); + cpswapl(from->mode, to->mode); + cpswapl(from->window, to->window); + cpswaps(from->rotation, to->rotation); + cpswaps(from->x, to->x); + cpswaps(from->y, to->y); + cpswaps(from->width, to->width); + cpswaps(from->height, to->height); +} + +static void +SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent *from, + xRROutputChangeNotifyEvent *to) { to->type = from->type; to->subCode = from->subCode; cpswaps(from->sequenceNumber, to->sequenceNumber); cpswapl(from->timestamp, to->timestamp); cpswapl(from->configTimestamp, to->configTimestamp); - cpswapl(from->root, to->root); cpswapl(from->window, to->window); - cpswaps(from->monitor, to->monitor); - cpswaps(from->modeID, to->modeID); + cpswapl(from->output, to->output); + cpswapl(from->crtc, to->crtc); + cpswapl(from->mode, to->mode); cpswaps(from->rotation, to->rotation); - cpswaps(from->subpixelOrder, to->subpixelOrder); - cpswaps(from->x, to->x); - cpswaps(from->y, to->y); } -#endif + +static void +SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent *from, + xRROutputPropertyNotifyEvent *to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->window, to->window); + cpswapl(from->output, to->output); + cpswapl(from->atom, to->atom); + cpswapl(from->timestamp, to->timestamp); +} static void SRRNotifyEvent (xEvent *from, xEvent *to) { switch (from->u.u.detail) { -#if 0 - case RRNotify_MonitorChange: - SRRMonitorChangeNotifyEvent ((xRRMonitorChangeNotifyEvent *) from, - (xRRMonitorChangeNotifyEvent *) to); + case RRNotify_CrtcChange: + SRRCrtcChangeNotifyEvent ((xRRCrtcChangeNotifyEvent *) from, + (xRRCrtcChangeNotifyEvent *) to); + break; + case RRNotify_OutputChange: + SRROutputChangeNotifyEvent ((xRROutputChangeNotifyEvent *) from, + (xRROutputChangeNotifyEvent *) to); + break; + case RRNotify_OutputProperty: + SRROutputPropertyNotifyEvent ((xRROutputPropertyNotifyEvent *) from, + (xRROutputPropertyNotifyEvent *) to); break; -#endif default: break; } @@ -359,6 +392,9 @@ TellChanged (WindowPtr pWin, pointer value) return WT_WALKCHILDREN; } +/* + * Something changed; send events and adjust pointer position + */ void RRTellChanged (ScreenPtr pScreen) { @@ -369,12 +405,18 @@ RRTellChanged (ScreenPtr pScreen) { UpdateCurrentTime (); pScrPriv->lastConfigTime = currentTime; - WalkTree (pScreen, TellChanged, (pointer) pScreen); pScrPriv->changed = FALSE; + WalkTree (pScreen, TellChanged, (pointer) pScreen); for (i = 0; i < pScrPriv->numOutputs; i++) pScrPriv->outputs[i]->changed = FALSE; for (i = 0; i < pScrPriv->numCrtcs; i++) pScrPriv->crtcs[i]->changed = FALSE; + if (pScrPriv->layoutChanged) + { + pScrPriv->layoutChanged = FALSE; + RRPointerScreenConfigured (pScreen); + RRSendConfigNotify (pScreen); + } } } diff --git a/randr/randrstr.h b/randr/randrstr.h index 6690556b4..a8a995026 100644 --- a/randr/randrstr.h +++ b/randr/randrstr.h @@ -202,10 +202,11 @@ typedef struct _rrScrPriv { TimeStamp lastSetTime; /* last changed by client */ TimeStamp lastConfigTime; /* possible configs changed */ RRCloseScreenProcPtr CloseScreen; - Bool changed; + Bool changed; /* some config changed */ CARD16 minWidth, minHeight; CARD16 maxWidth, maxHeight; CARD16 width, height; /* last known screen size */ + Bool layoutChanged; /* screen layout changed */ /* modes, outputs and crtcs */ int numModes; @@ -217,6 +218,9 @@ typedef struct _rrScrPriv { int numCrtcs; RRCrtcPtr *crtcs; + /* Last known pointer position */ + RRCrtcPtr pointerCrtc; + #ifdef RANDR_10_INTERFACE /* * Configuration information @@ -439,6 +443,14 @@ RRSetScreenConfig (ScreenPtr pScreen, #endif /* rrcrtc.c */ + +/* + * Notify the CRTC of some change; layoutChanged indicates that + * some position or size element changed + */ +void +RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged); + /* * Create a CRTC */ @@ -575,6 +587,13 @@ int ProcRRDeleteOutputMode (ClientPtr client); /* rroutput.c */ + +/* + * Notify the output of some change + */ +void +RROutputChanged (RROutputPtr output); + /* * Create an output */ @@ -638,6 +657,13 @@ ProcRRGetOutputInfo (ClientPtr client); Bool RROutputInit (void); +/* rrpointer.c */ +void +RRPointerMoved (ScreenPtr pScreen, int x, int y); + +void +RRPointerScreenConfigured (ScreenPtr pScreen); + /* rrproperty.c */ void @@ -668,3 +694,79 @@ void RRXineramaExtensionInit(void); #endif /* _RANDRSTR_H_ */ + +/* + +randr extension implementation structure + +Query state: + ProcRRGetScreenInfo/ProcRRGetScreenResources + RRGetInfo + + • Request configuration from driver, either 1.0 or 1.2 style + • These functions only record state changes, all + other actions are pended until RRTellChanged is called + + ->rrGetInfo + 1.0: + RRRegisterSize + RRRegisterRate + RRSetCurrentConfig + 1.2: + RRScreenSetSizeRange + RROutputSetCrtcs + RROutputSetCrtc + RROutputSetPossibleOptions + RRSetCurrentOptions + RRModeGet + RROutputSetModes + RROutputSetConnection + RROutputSetSubpixelOrder + RROutputSetClones + RRCrtcNotify + + • Must delay scanning configuration until after ->rrGetInfo returns + because some drivers will call SetCurrentConfig in the middle + of the ->rrGetInfo operation. + + 1.0: + + • Scan old configuration, mirror to new structures + + RRScanOldConfig + RRCrtcCreate + RROutputCreate + RROutputSetCrtcs + RROutputSetCrtc + RROutputSetConnection + RROutputSetSubpixelOrder + RROldModeAdd • This adds modes one-at-a-time + RRModeGet + RRCrtcNotify + + • send events, reset pointer if necessary + + RRTellChanged + WalkTree (sending events) + + • when layout has changed: + RRPointerScreenConfigured + RRSendConfigNotify + +Asynchronous state setting (1.2 only) + When setting state asynchronously, the driver invokes the + ->rrGetInfo function and then calls RRTellChanged to flush + the changes to the clients and reset pointer if necessary + +Set state + + ProcRRSetScreenConfig + RRCrtcSet + 1.2: + ->rrCrtcSet + RRCrtcNotify + 1.0: + ->rrSetConfig + RRCrtcNotify + RRTellChanged + */ diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c index baefd3a15..c662899a4 100644 --- a/randr/rrcrtc.c +++ b/randr/rrcrtc.c @@ -25,6 +25,24 @@ RESTYPE RRCrtcType; +/* + * Notify the CRTC of some change + */ +void +RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged) +{ + ScreenPtr pScreen = crtc->pScreen; + rrScrPriv(pScreen); + + crtc->changed = TRUE; + pScrPriv->changed = TRUE; + /* + * Send ConfigureNotify on any layout change + */ + if (layoutChanged) + pScrPriv->layoutChanged = TRUE; +} + /* * Create a CRTC */ @@ -60,7 +78,7 @@ RRCrtcCreate (ScreenPtr pScreen, crtc->numOutputs = 0; crtc->gammaSize = 0; crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL; - crtc->changed = TRUE; + crtc->changed = FALSE; crtc->devPrivate = devPrivate; if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc)) @@ -68,7 +86,8 @@ RRCrtcCreate (ScreenPtr pScreen, pScrPriv->crtcs = crtcs; pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc; - pScrPriv->changed = TRUE; + + RRCrtcChanged (crtc, TRUE); return crtc; } @@ -85,8 +104,6 @@ RRCrtcNotify (RRCrtcPtr crtc, int numOutputs, RROutputPtr *outputs) { - ScreenPtr pScreen = crtc->pScreen; - rrScrPriv(pScreen); int i, j; /* @@ -100,8 +117,8 @@ RRCrtcNotify (RRCrtcPtr crtc, break; if (j == crtc->numOutputs) { - outputs[i]->changed = TRUE; - crtc->changed = TRUE; + RROutputChanged (outputs[i]); + RRCrtcChanged (crtc, FALSE); } } /* @@ -115,8 +132,8 @@ RRCrtcNotify (RRCrtcPtr crtc, break; if (i == numOutputs) { - crtc->outputs[j]->changed = TRUE; - crtc->changed = TRUE; + RROutputChanged (crtc->outputs[j]); + RRCrtcChanged (crtc, FALSE); } } /* @@ -158,31 +175,22 @@ RRCrtcNotify (RRCrtcPtr crtc, RRModeDestroy (crtc->mode); crtc->mode = mode; mode->refcnt++; - crtc->changed = TRUE; + RRCrtcChanged (crtc, TRUE); } if (x != crtc->x) { crtc->x = x; - crtc->changed = TRUE; + RRCrtcChanged (crtc, TRUE); } if (y != crtc->y) { crtc->y = y; - crtc->changed = TRUE; + RRCrtcChanged (crtc, TRUE); } if (rotation != crtc->rotation) { crtc->rotation = rotation; - crtc->changed = TRUE; - } - /* - * Send events if anything changed - */ - if (crtc->changed) - { - if (!pScrPriv->changed) - RRSendConfigNotify (pScreen); - pScrPriv->changed = TRUE; + RRCrtcChanged (crtc, TRUE); } return TRUE; } @@ -272,10 +280,11 @@ RRCrtcSet (RRCrtcPtr crtc, * Old 1.0 interface tied screen size to mode size */ if (ret) - RRScreenSizeNotify (pScreen); + RRCrtcNotify (crtc, mode, x, y, rotation, return ret; } #endif + RRTellChanged (pScreen); return FALSE; } diff --git a/randr/rroutput.c b/randr/rroutput.c index 618ef1f80..fc84ec1e6 100644 --- a/randr/rroutput.c +++ b/randr/rroutput.c @@ -24,6 +24,19 @@ RESTYPE RROutputType; +/* + * Notify the output of some change + */ +void +RROutputChanged (RROutputPtr output) +{ + ScreenPtr pScreen = output->pScreen; + rrScrPriv (pScreen); + + output->changed = TRUE; + pScrPriv->changed = TRUE; +} + /* * Create an output */ @@ -70,7 +83,7 @@ RROutputCreate (ScreenPtr pScreen, output->numPreferred = 0; output->modes = NULL; output->properties = NULL; - output->changed = TRUE; + output->changed = FALSE; output->devPrivate = devPrivate; if (!AddResource (output->id, RROutputType, (pointer) output)) @@ -78,7 +91,7 @@ RROutputCreate (ScreenPtr pScreen, pScrPriv->outputs = outputs; pScrPriv->outputs[pScrPriv->numOutputs++] = output; - pScrPriv->changed = TRUE; + RROutputChanged (output); return output; } @@ -114,7 +127,7 @@ RROutputSetClones (RROutputPtr output, memcpy (newClones, clones, numClones * sizeof (RROutputPtr)); output->clones = newClones; output->numClones = numClones; - output->changed = TRUE; + RROutputChanged (output); return TRUE; } @@ -158,7 +171,7 @@ RROutputSetModes (RROutputPtr output, output->modes = newModes; output->numModes = numModes; output->numPreferred = numPreferred; - output->changed = TRUE; + RROutputChanged (output); return TRUE; } @@ -191,7 +204,7 @@ RROutputSetCrtcs (RROutputPtr output, memcpy (newCrtcs, crtcs, numCrtcs * sizeof (RRCrtcPtr)); output->crtcs = newCrtcs; output->numCrtcs = numCrtcs; - output->changed = TRUE; + RROutputChanged (output); return TRUE; } @@ -202,7 +215,7 @@ RROutputSetPossibleOptions (RROutputPtr output, if (output->possibleOptions == possibleOptions) return TRUE; output->possibleOptions = possibleOptions; - output->changed = TRUE; + RROutputChanged (output); return TRUE; } @@ -212,7 +225,7 @@ RROutputSetCrtc (RROutputPtr output, RRCrtcPtr crtc) if (output->crtc == crtc) return; output->crtc = crtc; - output->changed = TRUE; + RROutputChanged (output); } Bool @@ -222,7 +235,7 @@ RROutputSetConnection (RROutputPtr output, if (output->connection == connection) return TRUE; output->connection = connection; - output->changed = TRUE; + RROutputChanged (output); return TRUE; } @@ -234,7 +247,7 @@ RROutputSetSubpixelOrder (RROutputPtr output, return TRUE; output->subpixelOrder = subpixelOrder; - output->changed = TRUE; + RROutputChanged (output); return TRUE; } @@ -245,13 +258,41 @@ RROutputSetCurrentOptions (RROutputPtr output, if (output->currentOptions == currentOptions) return TRUE; output->currentOptions = currentOptions; - output->changed = TRUE; + RROutputChanged (output); return TRUE; } void RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output) { + ScreenPtr pScreen = pWin->drawable.pScreen; + rrScrPriv (pScreen); + xRROutputChangeNotifyEvent oe; + RRCrtcPtr crtc = output->crtc; + RRModePtr mode = crtc ? crtc->mode : 0; + + oe.type = RRNotify + RREventBase; + oe.subCode = RRNotify_OutputChange; + oe.sequenceNumber = client->sequence; + oe.timestamp = pScrPriv->lastSetTime.milliseconds; + oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds; + oe.window = pWin->drawable.id; + oe.output = output->id; + if (crtc) + { + oe.crtc = crtc->id; + oe.mode = mode ? mode->mode.id : None; + oe.rotation = crtc->rotation; + } + else + { + oe.crtc = None; + oe.mode = None; + oe.rotation = RR_Rotate_0; + } + oe.connection = output->connection; + oe.subpixelOrder = output->subpixelOrder; + WriteEventsToClient (client, 1, (xEvent *) &oe); } /* diff --git a/randr/rrpointer.c b/randr/rrpointer.c new file mode 100644 index 000000000..7ba0460f5 --- /dev/null +++ b/randr/rrpointer.c @@ -0,0 +1,137 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "randrstr.h" + +/* + * When the pointer moves, check to see if the specified position is outside + * any of theavailable CRTCs and move it to a 'sensible' place if so, where + * sensible is the closest monitor to the departing edge. + * + * Returns whether the position was adjusted + */ + +static Bool +RRCrtcContainsPosition (RRCrtcPtr crtc, int x, int y) +{ + RRModePtr mode = crtc->mode; + + if (!mode) + return FALSE; + if (crtc->x <= x && x < crtc->x + mode->mode.width && + crtc->y <= y && y < crtc->y + mode->mode.height) + return TRUE; + return FALSE; +} + +/* + * Find the CRTC nearest the specified position, ignoring 'skip' + */ +static void +RRPointerToNearestCrtc (ScreenPtr pScreen, int x, int y, RRCrtcPtr skip) +{ + rrScrPriv (pScreen); + int c; + RRCrtcPtr nearest = NULL; + int best = 0; + int best_dx = 0, best_dy = 0; + + for (c = 0; c < pScrPriv->numCrtcs; c++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[c]; + RRModePtr mode = crtc->mode; + int dx, dy; + int dist; + + if (!mode) + continue; + if (crtc == skip) + continue; + if (x < crtc->x) + dx = crtc->x - x; + else if (x > crtc->x + mode->mode.width) + dx = x - (crtc->x + mode->mode.width); + else + dx = 0; + if (y < crtc->y) + dy = crtc->y - x; + else if (y > crtc->y + mode->mode.height) + dy = y - (crtc->y + mode->mode.height); + else + dy = 0; + dist = dx + dy; + if (!nearest || dist < best) + { + nearest = crtc; + best_dx = dx; + best_dy = dy; + } + } + if (best_dx || best_dy) + (*pScreen->SetCursorPosition) (pScreen, x + best_dx, y + best_dy, TRUE); + pScrPriv->pointerCrtc = nearest; +} + +void +RRPointerMoved (ScreenPtr pScreen, int x, int y) +{ + rrScrPriv (pScreen); + RRCrtcPtr pointerCrtc = pScrPriv->pointerCrtc;; + int c; + + /* Check last known CRTC */ + if (pointerCrtc && RRCrtcContainsPosition (pointerCrtc, x, y)) + return; + + /* Check all CRTCs */ + for (c = 0; c < pScrPriv->numCrtcs; c++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[c]; + + if (RRCrtcContainsPosition (crtc, x, y)) + { + /* Remember containing CRTC */ + pScrPriv->pointerCrtc = crtc; + return; + } + } + + /* None contain pointer, find nearest */ + RRPointerToNearestCrtc (pScreen, x, y, pointerCrtc); +} + +/* + * When the screen is reconfigured, move the pointer to the nearest + * CRTC + */ +void +RRPointerScreenConfigured (ScreenPtr pScreen) +{ + WindowPtr pRoot = GetCurrentRootWindow (); + ScreenPtr pCurrentScreen = pRoot ? pRoot->drawable.pScreen : NULL; + int x, y; + + if (pScreen != pCurrentScreen) + return FALSE; + GetSpritePosition (&x, &y); + RRPointerToNearestCrtc (pScreen, x, y, NULL); +} diff --git a/randr/rrproperty.c b/randr/rrproperty.c index cdafb5c9b..44f1f0ace 100644 --- a/randr/rrproperty.c +++ b/randr/rrproperty.c @@ -27,6 +27,7 @@ static void RRDeliverEvent (ScreenPtr pScreen, xEvent *event, CARD32 mask) { + } void diff --git a/randr/rrscreen.c b/randr/rrscreen.c index 7b53f0468..6d38e96b5 100644 --- a/randr/rrscreen.c +++ b/randr/rrscreen.c @@ -164,10 +164,13 @@ RRScreenSizeNotify (ScreenPtr pScreen) pScrPriv->width = pScreen->width; pScrPriv->height = pScreen->height; pScrPriv->changed = TRUE; + pScrPriv->sizeChanged = TRUE; + RRTellChanged (pScreen); RRSendConfigNotify (pScreen); RREditConnectionInfo (pScreen); + RRPointerScreenConfigured (pScreen); /* * Fix pointer bounds and location */ @@ -836,9 +839,37 @@ ProcRRSetScreenConfig (ClientPtr client) goto sendReply; } + /* + * If the screen size is changing, adjust all of the other outputs + * to fit the new size, mirroring as much as possible + */ + if (mode->mode.width != pScreen->width || + mode->mode.height != pScreen->height) + { + int c; + + for (c = 0; c < pScrPriv->numCrtcs; c++) + { + rep.status = RRCrtcSet (pScrPriv->->crtc, NULL, 0, 0, RR_Rotate_0, + 0, NULL); + if (rep.status != Success) + goto sendReply; + } + if (!RRScreenSizeSet (pScreen, mode->mode.width, mode->mode.height, + pScreen->mmWidth, pScreen->mmHeight)) + { + rep.status RRSetConfigFailed; + goto sendReply; + } + } + rep.status = RRCrtcSet (output.output->crtc, mode, 0, 0, stuff->rotation, 1, &output); + /* + * XXX Configure other crtcs to mirror as much as possible + */ + sendReply: if (pData)