Commit 106cc9bc authored by Keith Packard's avatar Keith Packard Committed by Roman Gilg
Browse files

composite: 0.5. Window scaling and events



Output scaling:

 * Changes to mivaltree to reset window clip to owner window size
   instead of server window size when compositing

 * Allocate owner window size pixmap for composite pixmap

 * Paint scaled image for automatic compositing

 * Report owner window size in events to the window owner.

 * Scale exposure damage in compSetRedirectBorderClip from
   current size to owner size to make sure the correct parts of
   the window are repainted.

Input scaling:

 * Change miSpriteTrace to scale cursor coordinates when transiting an
   owner-sized window. Do all computations in double to handle
   multiple such transitions without losing bits

 * Add ScaleRootCoordinate in events.c. This function takes a window
   and a root x/y and walks up the tree scaling each time there is an
   owner size set.

 * Use ScaleRootCoordinate in FixUpEventFromWindow.

 * Wrap event delivery in DeliverEvent in new
   SaveEventRootCoord/RestoreEventRootCoord functions so that
   different windows receiving the same event will all receive the
   correct coordinates.

Composite events:

 * Deliver CompositePixmapNotify events from compSetPixmapVisitWindow
   so that applications will be notified each time the pixmap changes.

 * Deliver CompositeOwnerWindowSizeNotify events when owner window
   size is set.
Signed-off-by: Keith Packard's avatarKeith Packard <keithp@keithp.com>
parent 247aedf2
......@@ -9,6 +9,7 @@ endif
libcomposite_la_SOURCES = \
compalloc.c \
compext.c \
compevent.c \
compint.h \
compinit.c \
compoverlay.c \
......
......@@ -599,8 +599,8 @@ compAllocPixmap(WindowPtr pWin)
int bw = (int) pWin->borderWidth;
int x = pWin->drawable.x - bw;
int y = pWin->drawable.y - bw;
int w = pWin->drawable.width + (bw << 1);
int h = pWin->drawable.height + (bw << 1);
int w = OwnerWindowWidth(pWin) + (bw << 1);
int h = OwnerWindowHeight(pWin) + (bw << 1);
PixmapPtr pPixmap = compNewPixmap(pWin, x, y, w, h);
CompWindowPtr cw = GetCompWindow(pWin);
......
/*
* Copyright © 2018 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "compint.h"
static void
compEventSwap(xGenericEvent *from, xGenericEvent *to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
switch (from->evtype) {
case CompositePixmapNotify: {
xCompositePixmapNotify *c = (xCompositePixmapNotify *) to;
swapl(&c->window);
swaps(&c->windowWidth);
swaps(&c->windowHeight);
swaps(&c->pixmapWidth);
swaps(&c->pixmapHeight);
break;
}
case CompositeOwnerWindowSizeNotify:
{
xCompositeOwnerWindowSizeNotify *c = (xCompositeOwnerWindowSizeNotify *) to;
swapl(&c->window);
swaps(&c->windowWidth);
swaps(&c->windowHeight);
swaps(&c->ownerWidth);
swaps(&c->ownerHeight);
break;
}
}
}
static void
compDeliverEvents(WindowPtr pWin, CompEventWindowPtr *head, xEvent *event, CARD32 mask)
{
CompEventWindowPtr cew;
for (cew = *head; cew; cew = cew->next) {
if (cew->eventMask & mask)
WriteEventsToClient(clients[CLIENT_ID(cew->id)], 1, event);
}
}
void
compSendPixmapNotify(WindowPtr pWin, PixmapPtr pPix)
{
CompEventWindowPtr *head = GetCompEventWindowHead(pWin);
if (*head) {
xCompositePixmapNotify pn = {
.type = GenericEvent,
.extension = CompositeReqCode,
.length = (sizeof(xCompositePixmapNotify) - 32) >> 2,
.evtype = CompositePixmapNotify,
.window = pWin->drawable.id,
.windowWidth = pWin->drawable.width,
.windowHeight = pWin->drawable.height,
.pixmapWidth = pPix ? pPix->drawable.width : 0,
.pixmapHeight = pPix ? pPix->drawable.height : 0,
};
compDeliverEvents(pWin, head, (xEvent *) &pn, CompositePixmapNotifyMask);
}
}
void
compSendOwnerWindowSizeNotify(WindowPtr pWin)
{
CompEventWindowPtr *head = GetCompEventWindowHead(pWin);
if (*head) {
xCompositeOwnerWindowSizeNotify pn = {
.type = GenericEvent,
.extension = CompositeReqCode,
.length = (sizeof(xCompositeOwnerWindowSizeNotify) - 32) >> 2,
.evtype = CompositeOwnerWindowSizeNotify,
.window = pWin->drawable.id,
.windowWidth = pWin->drawable.width,
.windowHeight = pWin->drawable.height,
.ownerWidth = wOwnerWidth(pWin),
.ownerHeight = wOwnerHeight(pWin),
};
compDeliverEvents(pWin, head, (xEvent *) &pn, CompositeOwnerWindowSizeNotifyMask);
}
}
void
compFreeEventWindow(WindowPtr pWin, XID id)
{
CompEventWindowPtr *next = GetCompEventWindowHead(pWin);
CompEventWindowPtr cew;
for (cew = *next; cew; cew = *next) {
if (cew->id == id) {
*next = cew->next;
free(cew);
return;
}
next = &cew->next;
}
}
void
compFreeEvents(WindowPtr pWin)
{
CompEventWindowPtr *head = GetCompEventWindowHead(pWin);
while (*head)
FreeResource((*head)->id, RT_NONE);
}
int
compSelectInput(ClientPtr pClient, WindowPtr pWin, CARD32 event_mask)
{
CompEventWindowPtr *head = GetCompEventWindowHead(pWin);
CompEventWindowPtr cew;
for (cew = *head; cew; cew = cew->next)
if (pClient->clientAsMask == CLIENT_BITS(cew->id))
break;
if (cew) {
if (!event_mask) {
FreeResource(cew->id, RT_NONE);
return Success;
}
} else {
cew = calloc (1, sizeof (CompEventWindowRec));
if (!cew)
return BadAlloc;
cew->next = *head;
*head = cew;
cew->id = FakeClientID(pClient->index);
}
cew->eventMask = event_mask;
return Success;
}
void
compEventInit(void)
{
GERegisterExtension(CompositeReqCode, compEventSwap);
}
......@@ -50,13 +50,14 @@
#include "protocol-versions.h"
#include "extinit.h"
static CARD8 CompositeReqCode;
CARD8 CompositeReqCode;
static DevPrivateKeyRec CompositeClientPrivateKeyRec;
#define CompositeClientPrivateKey (&CompositeClientPrivateKeyRec)
RESTYPE CompositeClientWindowType;
RESTYPE CompositeClientSubwindowsType;
RESTYPE CompositeClientOverlayType;
RESTYPE CompositeEventWindowType;
typedef struct _CompositeClient {
int major_version;
......@@ -93,6 +94,15 @@ FreeCompositeClientOverlay(void *value, XID ccwid)
return Success;
}
static int
FreeCompositeEventWindow(void *value, XID cewid)
{
WindowPtr pWin = value;
compFreeEventWindow(pWin, cewid);
return Success;
}
static int
ProcCompositeQueryVersion(ClientPtr client)
{
......@@ -354,15 +364,88 @@ ProcCompositeReleaseOverlayWindow(ClientPtr client)
return Success;
}
static int
ProcCompositeSelectInput(ClientPtr client)
{
REQUEST(xCompositeSelectInputReq);
WindowPtr pWin;
REQUEST_SIZE_MATCH(xCompositeSelectInputReq);
VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess);
if (stuff->eventMask & ~(CompositeAllEvents)) {
client->errorValue = stuff->eventMask;
return BadValue;
}
return compSelectInput(client, pWin, stuff->eventMask);
}
static int
ProcCompositeSetOwnerWindowSize(ClientPtr client)
{
REQUEST(xCompositeSetOwnerWindowSizeReq);
WindowPtr pWin;
int rc;
REQUEST_SIZE_MATCH(xCompositeSetOwnerWindowSizeReq);
VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess);
if (!pWin->parent)
return BadMatch;
if ((stuff->width == 0) != (stuff->height == 0))
return BadMatch;
rc = compSetOwnerSize(pWin, stuff->width, stuff->height, client);
if (rc != Success)
return rc;
return compSendOwnerSizeCoreEvents(pWin);
}
static int
ProcCompositeGetOwnerWindowSize(ClientPtr client)
{
REQUEST(xCompositeGetOwnerWindowSizeReq);
xCompositeGetOwnerWindowSizeReply rep;
WindowPtr pWin;
REQUEST_SIZE_MATCH(xCompositeGetOwnerWindowSizeReq);
VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess);
rep = (xCompositeGetOwnerWindowSizeReply) {
.type = X_Reply,
.sequenceNumber = client->sequence,
.length = 0,
.width = wOwnerWidth(pWin),
.height = wOwnerHeight(pWin)
};
if (client->swapped) {
swaps(&rep.sequenceNumber);
swapl(&rep.length);
swaps(&rep.width);
swaps(&rep.height);
}
WriteToClient(client, sz_xCompositeGetOwnerWindowSizeReply, &rep);
return Success;
}
static int (*ProcCompositeVector[CompositeNumberRequests]) (ClientPtr) = {
ProcCompositeQueryVersion,
ProcCompositeRedirectWindow,
ProcCompositeRedirectSubwindows,
ProcCompositeUnredirectWindow,
ProcCompositeUnredirectSubwindows,
ProcCompositeCreateRegionFromBorderClip,
ProcCompositeNameWindowPixmap,
ProcCompositeGetOverlayWindow, ProcCompositeReleaseOverlayWindow,};
ProcCompositeQueryVersion,
ProcCompositeRedirectWindow,
ProcCompositeRedirectSubwindows,
ProcCompositeUnredirectWindow,
ProcCompositeUnredirectSubwindows,
ProcCompositeCreateRegionFromBorderClip,
ProcCompositeNameWindowPixmap,
ProcCompositeGetOverlayWindow,
ProcCompositeReleaseOverlayWindow,
ProcCompositeSelectInput,
ProcCompositeSetOwnerWindowSize,
ProcCompositeGetOwnerWindowSize,
};
static int
ProcCompositeDispatch(ClientPtr client)
......@@ -477,6 +560,42 @@ SProcCompositeReleaseOverlayWindow(ClientPtr client)
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int _X_COLD
SProcCompositeSelectInput(ClientPtr client)
{
REQUEST(xCompositeSelectInputReq);
swaps(&stuff->length);
REQUEST_SIZE_MATCH(xCompositeSelectInputReq);
swapl(&stuff->window);
swapl(&stuff->eventMask);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int _X_COLD
SProcCompositeSetOwnerWindowSize(ClientPtr client)
{
REQUEST(xCompositeSetOwnerWindowSizeReq);
swaps(&stuff->length);
REQUEST_SIZE_MATCH(xCompositeSetOwnerWindowSizeReq);
swapl(&stuff->window);
swaps(&stuff->width);
swaps(&stuff->height);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int _X_COLD
SProcCompositeGetOwnerWindowSize(ClientPtr client)
{
REQUEST(xCompositeGetOwnerWindowSizeReq);
swaps(&stuff->length);
REQUEST_SIZE_MATCH(xCompositeGetOwnerWindowSizeReq);
swapl(&stuff->window);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
(*SProcCompositeVector[CompositeNumberRequests]) (ClientPtr) = {
SProcCompositeQueryVersion,
......@@ -488,6 +607,9 @@ static int
SProcCompositeNameWindowPixmap,
SProcCompositeGetOverlayWindow,
SProcCompositeReleaseOverlayWindow,
SProcCompositeSelectInput,
SProcCompositeSetOwnerWindowSize,
SProcCompositeGetOwnerWindowSize,
};
static int _X_COLD
......@@ -569,6 +691,11 @@ CompositeExtensionInit(void)
if (!CompositeClientOverlayType)
return;
CompositeEventWindowType = CreateNewResourceType
(FreeCompositeEventWindow, "CompositeEventWindow");
if (!CompositeEventWindowType)
return;
if (!dixRegisterPrivateKey(&CompositeClientPrivateKeyRec, PRIVATE_CLIENT,
sizeof(CompositeClientRec)))
return;
......@@ -584,6 +711,8 @@ CompositeExtensionInit(void)
return;
CompositeReqCode = (CARD8) extEntry->base;
compEventInit();
/* Initialization succeeded */
noCompositeExtension = FALSE;
}
......@@ -904,6 +1033,40 @@ PanoramiXCompositeReleaseOverlayWindow(ClientPtr client)
return Success;
}
static int
PanoramiXCompositeSetOwnerWindowSize(ClientPtr client)
{
PanoramiXRes *win;
int rc = 0, j;
REQUEST(xCompositeSetOwnerWindowSizeReq);
REQUEST_SIZE_MATCH(xCompositeSetOwnerWindowSizeReq);
if ((rc = dixLookupResourceByType((void **) &win, stuff->window, XRT_WINDOW,
client, DixUnknownAccess))) {
client->errorValue = stuff->window;
return rc;
}
FOR_NSCREENS_FORWARD(j) {
stuff->window = win->info[j].id;
rc = (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client);
if (rc != Success)
break;
}
return rc;
}
static int
PanoramiXCompositeGetOwnerWindowSize(ClientPtr client)
{
REQUEST(xCompositeGetOwnerWindowSizeReq);
return (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client);
}
void
PanoramiXCompositeInit(void)
{
......@@ -928,6 +1091,10 @@ PanoramiXCompositeInit(void)
PanoramiXCompositeGetOverlayWindow;
ProcCompositeVector[X_CompositeReleaseOverlayWindow] =
PanoramiXCompositeReleaseOverlayWindow;
ProcCompositeVector[X_CompositeSetOwnerWindowSize] =
PanoramiXCompositeSetOwnerWindowSize;
ProcCompositeVector[X_CompositeGetOwnerWindowSize] =
PanoramiXCompositeGetOwnerWindowSize;
}
void
......
......@@ -51,6 +51,7 @@
DevPrivateKeyRec CompScreenPrivateKeyRec;
DevPrivateKeyRec CompWindowPrivateKeyRec;
DevPrivateKeyRec CompSubwindowsPrivateKeyRec;
DevPrivateKeyRec CompEventWindowPrivateKeyRec;
static Bool
compCloseScreen(ScreenPtr pScreen)
......@@ -376,6 +377,8 @@ compScreenInit(ScreenPtr pScreen)
return FALSE;
if (!dixRegisterPrivateKey(&CompSubwindowsPrivateKeyRec, PRIVATE_WINDOW, 0))
return FALSE;
if (!dixRegisterPrivateKey(&CompEventWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
return FALSE;
if (GetCompScreen(pScreen))
return TRUE;
......
......@@ -106,6 +106,12 @@ typedef struct _CompSubwindows {
CompClientWindowPtr clients;
} CompSubwindowsRec, *CompSubwindowsPtr;
typedef struct _CompEventWindow {
struct _CompEventWindow *next;
XID id;
CARD32 eventMask;
} CompEventWindowRec, *CompEventWindowPtr;
#ifndef COMP_INCLUDE_RGB24_VISUAL
#define COMP_INCLUDE_RGB24_VISUAL 0
#endif
......@@ -173,6 +179,8 @@ typedef struct _CompScreen {
SourceValidateProcPtr SourceValidate;
} CompScreenRec, *CompScreenPtr;
extern CARD8 CompositeReqCode;
extern DevPrivateKeyRec CompScreenPrivateKeyRec;
#define CompScreenPrivateKey (&CompScreenPrivateKeyRec)
......@@ -185,12 +193,18 @@ extern DevPrivateKeyRec CompSubwindowsPrivateKeyRec;
#define CompSubwindowsPrivateKey (&CompSubwindowsPrivateKeyRec)
extern DevPrivateKeyRec CompEventWindowPrivateKeyRec;
#define CompEventWindowPrivateKey (&CompEventWindowPrivateKeyRec)
#define GetCompScreen(s) ((CompScreenPtr) \
dixLookupPrivate(&(s)->devPrivates, CompScreenPrivateKey))
#define GetCompWindow(w) ((CompWindowPtr) \
dixLookupPrivate(&(w)->devPrivates, CompWindowPrivateKey))
#define GetCompSubwindows(w) ((CompSubwindowsPtr) \
dixLookupPrivate(&(w)->devPrivates, CompSubwindowsPrivateKey))
#define GetCompEventWindowHead(w) ((CompEventWindowPtr *) \
dixLookupPrivateAddr(&(w)->devPrivates, CompEventWindowPrivateKey))
extern RESTYPE CompositeClientSubwindowsType;
extern RESTYPE CompositeClientOverlayType;
......@@ -239,6 +253,28 @@ compReallocPixmap(WindowPtr pWin, int x, int y,
void compMarkAncestors(WindowPtr pWin);
/*
* compevent.c
*/
void
compSendPixmapNotify(WindowPtr pWin, PixmapPtr pPix);
void
compSendOwnerWindowSizeNotify(WindowPtr pWin);
void
compFreeEventWindow(WindowPtr pWin, XID id);
void
compFreeEvents(WindowPtr pWin);
int
compSelectInput(ClientPtr pClient, WindowPtr pWin, CARD32 event_mask);
void
compEventInit(void);
/*
* compinit.c
*/
......@@ -337,6 +373,12 @@ int
compConfigNotify(WindowPtr pWin, int x, int y, int w, int h,
int bw, WindowPtr pSib);
int
compSetOwnerSize(WindowPtr pWin, CARD16 ownerWidth, CARD16 ownerHeight, ClientPtr client);
int
compSendOwnerSizeCoreEvents(WindowPtr pWin);
void PanoramiXCompositeInit(void);
void PanoramiXCompositeReset(void);
......
......@@ -120,6 +120,9 @@ compSetPixmapVisitWindow(WindowPtr pWindow, void *data)
if (pWindow != pVisit->pWindow && pWindow->redirectDraw != RedirectDrawNone)
return WT_DONTWALKCHILDREN;
(*pScreen->SetWindowPixmap) (pWindow, pVisit->pPixmap);
compSendPixmapNotify(pWindow, pVisit->pPixmap);
/*
* Recompute winSize and borderSize. This is duplicate effort
* when resizing pixmaps, but necessary when changing redirection.
......@@ -604,6 +607,8 @@ compDestroyWindow(WindowPtr pWin)
while ((csw = GetCompSubwindows(pWin)))
FreeResource(csw->clients->id, RT_NONE);
compFreeEvents(pWin);
if (pWin->redirectDraw != RedirectDrawNone) {
PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
......@@ -617,6 +622,56 @@ compDestroyWindow(WindowPtr pWin)
return ret;
}
static Bool
compScaleBox(BoxPtr pBox, double xscale, double yscale)
{
pBox->x1 = floor((pBox->x1 - 0.5) * xscale);
pBox->x2 = ceil ((pBox->x2 + 0.5) * xscale);
pBox->y1 = floor((pBox->y1 - 0.5) * yscale);
pBox->y2 = ceil ((pBox->y2 + 0.5) * yscale);
assert (pBox->x1 <= pBox->x2 && pBox->y1 <= pBox->y2);
return pBox->x1 < pBox->x2 && pBox->y1 < pBox->y2;
}
static void
compScaleRegion(RegionPtr pRegion, double xscale, double yscale)
{
if (!compScaleBox(&pRegion->extents, xscale, yscale)) {
RegionEmpty(pRegion);
return;
}
if (pRegion->data != NULL)
{
BoxPtr pBox = RegionRects(pRegion);
int nBox = RegionNumRects(pRegion);
Bool overlap;
while (nBox--) {
if (compScaleBox(pBox, xscale, yscale))
pBox++;
else {
memmove(pBox, pBox + 1, nBox * sizeof (*pBox));
if (--pRegion->data->numRects == 0) {
break;
}
}
}
switch (pRegion->data->numRects) {
case 0:
RegionEmpty(pRegion);
break;
case 1:
pRegion->extents = RegionRects(pRegion)[0];
RegionUninit(pRegion);
break;
default:
pRegion->extents = (BoxRec) { 0, 0, 0, 0 };
RegionValidate(pRegion, &overlap);
break;
}
}
}
void
compSetRedirectBorderClip(WindowPtr pWin, RegionPtr pRegion)
{
......@@ -637,6 +692,13 @@ compSetRedirectBorderClip(WindowPtr pWin, RegionPtr pRegion)
/*
* Report that as damaged so it will be redrawn
*/
if (RegionNotEmpty(&damage) && wOwnerSized(pWin)) {
RegionTranslate(&damage, -pWin->drawable.x, -pWin->drawable.y);