summaryrefslogtreecommitdiff
path: root/lbx/lbxcmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'lbx/lbxcmap.c')
-rw-r--r--lbx/lbxcmap.c1148
1 files changed, 1148 insertions, 0 deletions
diff --git a/lbx/lbxcmap.c b/lbx/lbxcmap.c
new file mode 100644
index 000000000..6af20b03b
--- /dev/null
+++ b/lbx/lbxcmap.c
@@ -0,0 +1,1148 @@
+/* $Xorg: lbxcmap.c,v 1.4 2001/02/09 02:05:16 xorgcvs Exp $ */
+
+/*
+Copyright 1996, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+*/
+
+#include <sys/types.h>
+#define NEED_REPLIES
+#define NEED_EVENTS
+#include "X.h"
+#include "Xproto.h"
+#include "Xos.h"
+#include "misc.h"
+#include "os.h"
+#include "dixstruct.h"
+#include "resource.h"
+#include "scrnintstr.h"
+#include "colormapst.h"
+#define _XLBX_SERVER_
+#include "lbxstr.h"
+#include "lbxserve.h"
+#include "Xfuncproto.h"
+#include <stdio.h>
+
+static int lbxScreenPrivIndex; /* lbx screen private index */
+static int lbxColormapPrivIndex; /* lbx colormap private index */
+
+typedef struct { /* lbx screen private */
+ CreateColormapProcPtr CreateColormap;
+ DestroyColormapProcPtr DestroyColormap;
+} LbxScreenPriv;
+
+typedef struct _LbxStalled {
+ XID id;
+ struct _LbxStalled *next;
+} LbxStalled;
+
+typedef struct _LbxColormapPriv { /* lbx colormap private */
+ char grab_status;
+ char smart_grab;
+ LbxProxyPtr grabber;
+ int last_grabber; /* uid, not pid */
+ LbxStalled *stalled_clients;
+ ColormapPtr next; /* proxy chain */
+} LbxColormapPriv;
+
+#define CMAP_NOT_GRABBED 0
+#define CMAP_GRABBED 1
+#define CMAP_WAITING_FOR_UNGRAB 2
+
+static int LbxUnstallClient();
+void LbxReleaseCmap();
+
+static RESTYPE StalledResType;
+
+/*
+ * Initialize the fields in the colormap private allocated for LBX.
+ */
+
+static LbxColormapPriv *
+LbxColormapPrivInit (pmap)
+ ColormapPtr pmap;
+{
+ LbxColormapPriv *cmapPriv;
+
+ cmapPriv = (LbxColormapPriv *) xalloc (sizeof (LbxColormapPriv));
+ if (!cmapPriv)
+ return cmapPriv;
+
+ pmap->devPrivates[lbxColormapPrivIndex].ptr = (pointer) cmapPriv;
+
+ cmapPriv->grab_status = CMAP_NOT_GRABBED;
+ cmapPriv->grabber = NULL;
+ cmapPriv->last_grabber = 0;
+ cmapPriv->smart_grab = FALSE;
+ cmapPriv->stalled_clients = NULL;
+ cmapPriv->next = NULL;
+
+ return cmapPriv;
+}
+
+
+static int
+LbxDefCmapPrivInit (pmap)
+ ColormapPtr pmap;
+{
+ pmap->devPrivates[lbxColormapPrivIndex].ptr = NULL;
+ return 1;
+}
+
+static Bool
+LbxCreateColormap (pmap)
+ ColormapPtr pmap;
+{
+ ScreenPtr pScreen = pmap->pScreen;
+ Bool ret;
+
+ pScreen->CreateColormap = ((LbxScreenPriv *) (pScreen->devPrivates[
+ lbxScreenPrivIndex].ptr))->CreateColormap;
+
+ pmap->devPrivates[lbxColormapPrivIndex].ptr = NULL;
+ ret = (*pScreen->CreateColormap) (pmap);
+
+ pScreen->CreateColormap = LbxCreateColormap;
+
+ return ret;
+}
+
+static void
+LbxDestroyColormap (pmap)
+ ColormapPtr pmap;
+{
+ ScreenPtr pScreen = pmap->pScreen;
+
+ LbxReleaseCmap(pmap, FALSE);
+ pScreen->DestroyColormap = ((LbxScreenPriv *) (pScreen->devPrivates[
+ lbxScreenPrivIndex].ptr))->DestroyColormap;
+ (*pScreen->DestroyColormap) (pmap);
+ if (pmap->devPrivates && pmap->devPrivates[lbxColormapPrivIndex].ptr)
+ xfree(pmap->devPrivates[lbxColormapPrivIndex].ptr);
+ pScreen->DestroyColormap = LbxDestroyColormap;
+}
+
+/*
+ * Initialize LBX colormap private.
+ */
+
+int
+LbxCmapInit ()
+
+{
+ LbxScreenPriv *pScreenPriv;
+ ScreenPtr pScreen;
+ int i;
+
+ StalledResType = CreateNewResourceType(LbxUnstallClient);
+
+ lbxScreenPrivIndex = AllocateScreenPrivateIndex ();
+ if (lbxScreenPrivIndex < 0)
+ return 0;
+
+ lbxColormapPrivIndex = AllocateColormapPrivateIndex (LbxDefCmapPrivInit);
+ if (lbxColormapPrivIndex < 0)
+ return 0;
+
+ for (i = 0; i < screenInfo.numScreens; i++)
+ {
+ pScreen = screenInfo.screens[i];
+
+ pScreenPriv = (LbxScreenPriv *) xalloc (sizeof (LbxScreenPriv));
+ if (!pScreenPriv)
+ return 0;
+
+ pScreenPriv->CreateColormap = pScreen->CreateColormap;
+ pScreen->CreateColormap = LbxCreateColormap;
+ pScreenPriv->DestroyColormap = pScreen->DestroyColormap;
+ pScreen->DestroyColormap = LbxDestroyColormap;
+ pScreen->devPrivates[lbxScreenPrivIndex].ptr = (pointer) pScreenPriv;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Return the number of allocated cells in the PSEUDO colormap.
+ */
+
+static int
+NumAllocatedCells (pent, size)
+ EntryPtr pent;
+ int size;
+{
+ Pixel pixel;
+ int count = 0;
+
+ for (pixel = 0; pixel < size; pixel++)
+ {
+ if (pent[pixel].refcnt != 0 && pent[pixel].refcnt != AllocTemporary)
+ count++;
+ }
+
+ return count;
+}
+
+#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1)
+#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1)
+#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1)
+
+#define PIX_OUT(ptr,is2,val) \
+ if (is2) *ptr++ = (val) >> 8; \
+ *ptr++ = (val)
+#define RGB_OUT(ptr,is2,shift,val) \
+ *ptr++ = (val) >> shift; \
+ if (is2) *ptr++ = (val)
+
+/*
+ * Return the list of allocated cells in the channel in
+ * the format required by LbxGrabCmapReply.
+ */
+
+static CARD8 *
+OutputChannel(pmap, chan, size, ptr, flags, channels)
+ ColormapPtr pmap;
+ EntryPtr chan;
+ int size;
+ CARD8 *ptr;
+ CARD8 flags;
+ CARD8 channels;
+{
+ Bool px2;
+ Bool rgb2;
+ int shift;
+ int rgb_sz;
+ Pixel pixel;
+ EntryPtr pent;
+ CARD8 *pixel_private_range_ptr = NULL;
+ CARD8 *pixel_shared_range_ptr = NULL;
+ int allocpriv;
+
+ px2 = (flags & LBX_2BYTE_PIXELS) != 0;
+ rgb2 = (flags & LBX_RGB_BITS_MASK) > 7;
+ if (rgb2)
+ shift = 8;
+ else
+ shift = 15 - (flags & LBX_RGB_BITS_MASK);
+ rgb_sz = rgb2 + 1;
+ if (channels == DoRed|DoGreen|DoBlue)
+ rgb_sz *= 3;
+ /* kinda gross, but ddxen use AllocAll on static maps */
+ allocpriv = (pmap->pVisual->class & DynamicClass) ? AllocPrivate : 0;
+ for (pixel = 0; pixel < size; pixel++)
+ {
+ pent = (EntryPtr) &chan[pixel];
+
+ if (pent->refcnt == 0 || pent->refcnt == AllocTemporary)
+ {
+ /*
+ * A free pixel. This disrupts all ranges.
+ */
+
+ pixel_private_range_ptr = pixel_shared_range_ptr = NULL;
+
+ continue;
+ }
+ else if (pent->refcnt == allocpriv)
+ {
+ /*
+ * A private pixel. This disrupts any PIXEL_SHARED_RANGE.
+ */
+
+ pixel_shared_range_ptr = NULL;
+
+ if (!pixel_private_range_ptr)
+ {
+ pixel_private_range_ptr = ptr;
+
+ *ptr++ = LBX_PIXEL_PRIVATE;
+ PIX_OUT(ptr, px2, pixel);
+ }
+ else
+ {
+ CARD8 *pos = pixel_private_range_ptr + 2 + px2;
+ if (*pixel_private_range_ptr == LBX_PIXEL_PRIVATE) {
+ *pixel_private_range_ptr = LBX_PIXEL_RANGE_PRIVATE;
+ ptr += 1 + px2;
+ }
+ PIX_OUT(pos, px2, pixel);
+ }
+ }
+ else
+ {
+ /*
+ * A shared pixel. This disrupts any PIXEL_PRIVATE_RANGE.
+ */
+
+ pixel_private_range_ptr = NULL;
+
+ if (!pixel_shared_range_ptr)
+ {
+ pixel_shared_range_ptr = ptr;
+
+ *ptr++ = LBX_PIXEL_SHARED;
+ PIX_OUT(ptr, px2, pixel);
+ }
+ else
+ {
+ CARD8 *pos = pixel_shared_range_ptr + 2 + px2;
+ if (*pixel_shared_range_ptr == LBX_PIXEL_SHARED)
+ {
+ *pixel_shared_range_ptr = LBX_PIXEL_RANGE_SHARED;
+ memmove (pos + 1 + px2, pos, rgb_sz);
+ ptr += 1 + px2;
+ }
+ PIX_OUT(pos, px2, pixel);
+ }
+
+ if (channels & DoRed) {
+ RGB_OUT(ptr, rgb2, shift, pent->co.local.red);
+ }
+ if (channels & DoGreen) {
+ RGB_OUT(ptr, rgb2, shift, pent->co.local.green);
+ }
+ if (channels & DoBlue) {
+ RGB_OUT(ptr, rgb2, shift, pent->co.local.blue);
+ }
+ }
+ }
+ return ptr;
+}
+
+static void
+GetAllocatedCells (pmap, flags, buf, bytes)
+ ColormapPtr pmap;
+ CARD8 *flags;
+ CARD8 *buf;
+ int *bytes;
+{
+ CARD8 *ptr;
+
+ *flags = pmap->pVisual->bitsPerRGBValue - 1;
+ if (pmap->pVisual->ColormapEntries > 256)
+ *flags |= LBX_2BYTE_PIXELS;
+ if (!(pmap->pVisual->class & DynamicClass))
+ *flags |= LBX_AUTO_RELEASE;
+ if ((pmap->pVisual->class | DynamicClass) == DirectColor) {
+ *flags |= LBX_3CHANNELS;
+ ptr = OutputChannel(pmap, pmap->red, NUMRED(pmap->pVisual),
+ buf, *flags, DoRed);
+ *ptr++ = LBX_NEXT_CHANNEL;
+ ptr = OutputChannel(pmap, pmap->green, NUMGREEN(pmap->pVisual),
+ ptr, *flags, DoGreen);
+ *ptr++ = LBX_NEXT_CHANNEL;
+ ptr = OutputChannel(pmap, pmap->blue, NUMBLUE(pmap->pVisual),
+ ptr, *flags, DoBlue);
+ } else
+ ptr = OutputChannel(pmap, pmap->red, pmap->pVisual->ColormapEntries,
+ buf, *flags, DoRed|DoGreen|DoBlue);
+ *ptr++ = LBX_LIST_END;
+ *bytes = ptr - buf;
+}
+
+
+/*
+ * Send an LbxReleaseCmapEvent to a proxy.
+ */
+
+static void
+SendReleaseCmapEvent (proxy, cmap)
+ LbxProxyPtr proxy;
+ Colormap cmap;
+{
+ xLbxReleaseCmapEvent ev;
+ ClientPtr client;
+ LbxClientPtr lbxcp;
+ int n;
+
+ lbxcp = proxy->lbxClients[0];
+
+ if (lbxcp && (client = lbxcp->client))
+ {
+ ev.type = LbxEventCode;
+ ev.lbxType = LbxReleaseCmapEvent;
+ ev.sequenceNumber = client->sequence;
+ ev.colormap = cmap;
+ ev.pad1 = ev.pad2 = ev.pad3 = ev.pad4 = ev.pad5 = ev.pad6 = 0;
+
+ if (client->swapped)
+ {
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.colormap, n);
+ }
+
+ WriteToClient(client, sz_xLbxReleaseCmapEvent, (char *) &ev);
+ LbxForceOutput(proxy);
+
+#ifdef COLOR_DEBUG
+ fprintf (stderr,
+ "Sent LbxReleaseCmapEvent to proxy %d, seq = 0x%x, cmap = 0x%x\n",
+ proxy->pid, client->sequence, cmap);
+#endif
+ }
+}
+
+
+/*
+ * WaitForServerCmapControl checks if the colormap is grabbed by a proxy,
+ * and if so, sends an LbxReleaseCmapEvent to the proxy. It then suspends
+ * the current request until the server gets the ReleaseCmap message from
+ * the proxy.
+ */
+
+static Bool
+WaitForServerCmapControl (client, pmap)
+ register ClientPtr client;
+ register ColormapPtr pmap;
+{
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+ LbxStalled *stalled;
+
+ if (cmapPriv->grab_status == CMAP_GRABBED)
+ {
+ /*
+ * Send an LbxReleaseCmapEvent to the proxy that has the grab.
+ */
+
+ SendReleaseCmapEvent (cmapPriv->grabber, pmap->mid);
+ cmapPriv->grab_status = CMAP_WAITING_FOR_UNGRAB;
+ }
+
+ stalled = (LbxStalled *)xalloc(sizeof(LbxStalled));
+ if (!stalled)
+ return FALSE;
+ stalled->id = FakeClientID(client->index);
+ stalled->next = cmapPriv->stalled_clients;
+ cmapPriv->stalled_clients = stalled;
+ return AddResource(stalled->id, StalledResType, (pointer)cmapPriv);
+}
+
+
+/*
+ * When the X server gets any of the requests that allocate color cells,
+ * it calls LbxCheckColorRequest on the request. This function will check
+ * if the colormap is grabbed by a proxy, and if so, will suspend the
+ * current request and wait for the proxy to release the colormap.
+ */
+
+Bool
+LbxCheckColorRequest (client, pmap, req)
+ ClientPtr client;
+ ColormapPtr pmap;
+ xReq *req;
+{
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+
+ if (!cmapPriv)
+ return FALSE;
+
+ if (cmapPriv->grab_status != CMAP_NOT_GRABBED)
+ {
+ /*
+ * The colormap is grabbed by a proxy. Reset this request, and
+ * process it after the server gets back control of the colormap.
+ * Before we reset the request, we must put it back in the
+ * client's byte order.
+ */
+
+ if (!WaitForServerCmapControl (client, pmap))
+ return FALSE;
+
+ if (client->swapped)
+ {
+ register int n;
+
+ switch (req->reqType)
+ {
+ case X_AllocColor:
+ {
+ xAllocColorReq *stuff = (xAllocColorReq *) req;
+ swaps(&stuff->length, n);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->red, n);
+ swaps(&stuff->green, n);
+ swaps(&stuff->blue, n);
+ break;
+ }
+ case X_AllocNamedColor:
+ {
+ xAllocNamedColorReq *stuff = (xAllocNamedColorReq *) req;
+ swaps(&stuff->length, n);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->nbytes, n);
+ break;
+ }
+ case X_AllocColorCells:
+ {
+ xAllocColorCellsReq *stuff = (xAllocColorCellsReq *) req;
+ swaps(&stuff->length, n);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->colors, n);
+ swaps(&stuff->planes, n);
+ break;
+ }
+ case X_AllocColorPlanes:
+ {
+ xAllocColorPlanesReq *stuff = (xAllocColorPlanesReq *) req;
+ swaps(&stuff->length, n);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->colors, n);
+ swaps(&stuff->red, n);
+ swaps(&stuff->green, n);
+ swaps(&stuff->blue, n);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ ResetCurrentRequest(client);
+ client->sequence--;
+ IgnoreClient(client);
+
+ return TRUE;
+ }
+
+ if (!LbxClient(client) ||
+ LbxProxy(client)->uid != cmapPriv->last_grabber)
+ {
+ /*
+ * Next time the proxy for this client does a colormap grab, it
+ * will have to get the colormap state (a non-smart grab).
+ */
+
+ cmapPriv->smart_grab = FALSE;
+ }
+
+ return FALSE;
+}
+
+static Bool
+LbxGrabbedByClient (client, pmap)
+ ClientPtr client;
+ ColormapPtr pmap;
+{
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+ return (cmapPriv &&
+ (cmapPriv->grab_status != CMAP_NOT_GRABBED) &&
+ (cmapPriv->grabber == LbxProxy(client)));
+}
+
+/*
+ * Check if a colormap is grabbed by a proxy.
+ */
+
+int
+LbxCheckCmapGrabbed (pmap)
+ ColormapPtr pmap;
+{
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+
+ return (cmapPriv && (cmapPriv->grab_status == CMAP_GRABBED));
+}
+
+
+/*
+ * Disable a smart grab on the specified colormap.
+ */
+
+void
+LbxDisableSmartGrab (pmap)
+ ColormapPtr pmap;
+{
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+
+ if (cmapPriv)
+ cmapPriv->smart_grab = FALSE;
+}
+
+
+/*
+ * Send an LbxFreeCellsEvent to the specified proxy.
+ */
+
+static void
+SendFreeCellsEvent (proxy, cmap, pixel_start, pixel_end)
+ LbxProxyPtr proxy;
+ Colormap cmap;
+ Pixel pixel_start;
+ Pixel pixel_end;
+{
+ xLbxFreeCellsEvent ev;
+ ClientPtr client;
+ LbxClientPtr lbxcp;
+ int n;
+
+ lbxcp = proxy->lbxClients[0];
+
+ if (lbxcp && (client = lbxcp->client))
+ {
+ ev.type = LbxEventCode;
+ ev.lbxType = LbxFreeCellsEvent;
+ ev.sequenceNumber = client->sequence;
+ ev.colormap = cmap;
+ ev.pixelStart = pixel_start;
+ ev.pixelEnd = pixel_end;
+ ev.pad1 = ev.pad2 = ev.pad3 = ev.pad4 = 0;
+
+ if (client->swapped)
+ {
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.colormap, n);
+ swapl(&ev.pixelStart, n);
+ swapl(&ev.pixelEnd, n);
+ }
+
+ WriteToClient(client, sz_xLbxFreeCellsEvent, (char *) &ev);
+ LbxForceOutput(proxy);
+#ifdef COLOR_DEBUG
+ fprintf (stderr, "Sent LbxFreeCellsEvent to proxy %d, seq = 0x%x\n",
+ proxy->pid, client->sequence);
+ fprintf (stderr, " cmap = 0x%x, pixelStart = %d, pixelEnd = %d\n",
+ cmap, pixel_start, pixel_end);
+#endif
+ }
+}
+
+/* XXX use of globals like this is gross */
+static long pixel_start;
+static long pixel_end;
+
+
+/*
+ * LbxFreeCellsEvent generation functions.
+ */
+
+/*ARGSUSED*/
+void
+LbxBeginFreeCellsEvent (pmap)
+ ColormapPtr pmap;
+{
+ pixel_start = -1;
+ pixel_end = -1;
+}
+
+
+void
+LbxAddFreeCellToEvent (pmap, pixel)
+ ColormapPtr pmap;
+ Pixel pixel;
+{
+ /*
+ * We must notify the proxy that has this colormap
+ * grabbed which cells are being freed (their refcount
+ * has reached zero).
+ */
+
+ if (pixel_start == -1)
+ pixel_start = pixel;
+ else
+ {
+ if (pixel_end == -1)
+ pixel_end = pixel;
+ else
+ {
+ if (pixel_end + 1 == pixel)
+ pixel_end = pixel;
+ else if (pixel > pixel_end + 1)
+ {
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+
+ SendFreeCellsEvent (cmapPriv->grabber,
+ pmap->mid, pixel_start, pixel_end);
+
+ pixel_start = pixel;
+ pixel_end = -1;
+ }
+ }
+ }
+}
+
+void
+LbxEndFreeCellsEvent (pmap)
+ ColormapPtr pmap;
+{
+ /*
+ * Check if there is an LbxFreeCellEvent we need to write.
+ */
+
+ if (pixel_start != -1)
+ {
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+
+ SendFreeCellsEvent (cmapPriv->grabber,
+ pmap->mid, pixel_start,
+ pixel_end == -1 ? pixel_start : pixel_end);
+ }
+}
+
+
+/*
+ * Sort the specified pixel list. This optimizes generation
+ * of LbxFreeCellsEvent.
+ */
+
+void
+LbxSortPixelList (pixels, count)
+ Pixel *pixels;
+ int count;
+{
+ int i, j;
+
+ for (i = 0; i <= count - 2; i++)
+ for (j = count - 1; j > i; j--)
+ if (pixels[j - 1] > pixels[j])
+ {
+ Pixel temp = pixels[j - 1];
+ pixels[j - 1] = pixels[j];
+ pixels[j] = temp;
+ }
+}
+
+
+/*
+ * Handle a colormap grab request from a proxy.
+ */
+
+int
+ProcLbxGrabCmap(client)
+ register ClientPtr client;
+{
+ REQUEST(xLbxGrabCmapReq);
+ xLbxGrabCmapReply *reply;
+ Bool smartGrab;
+ LbxColormapPriv *cmapPriv;
+ ColormapPtr pmap;
+ int bytes, n;
+ LbxProxyPtr proxy = LbxProxy(client);
+
+ client->sequence--; /* not a counted request */
+
+ pmap = (ColormapPtr) SecurityLookupIDByType (client, stuff->cmap,
+ RT_COLORMAP,
+ SecurityWriteAccess);
+
+ if (!pmap)
+ {
+ client->errorValue = stuff->cmap;
+ return BadColor;
+ }
+
+ cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+ if (!cmapPriv)
+ {
+ cmapPriv = LbxColormapPrivInit (pmap);
+ if (!cmapPriv)
+ return BadAlloc;
+ }
+
+
+ /*
+ * We have a SMART GRAB if since this proxy last ungrabbed the
+ * colormap, no color cell was alloc'd by an entity other than
+ * this proxy (this includes other proxies as well as clients
+ * directly connected to the X server without a proxy).
+ *
+ * We want to optimize this special case because a proxy may give
+ * up a grab because it got a request that it could not handle
+ * (e.g. AllocNamedColor or LookupColor). When it asks back for
+ * the grab, there is no need for the server to send the colormap
+ * state, because the proxy is already up to date on the state of
+ * the colormap.
+ *
+ * In order for this to work, the following assumptions are made
+ * about the proxy:
+ *
+ * - the proxy is kept up to date on all cell allocations made on its
+ * behalf resulting from the following requests: AllocNamedColor,
+ * AllocColorCells, AllocColorPlanes
+ * - the proxy is kept up to date on all cells freed by any client
+ * via the LbxFreeCell event.
+ */
+
+ /* if proxy is this confused, give it full info */
+ if (cmapPriv->grab_status == CMAP_GRABBED && cmapPriv->grabber == proxy)
+ LbxReleaseCmap(pmap, FALSE);
+
+ if (proxy->uid != cmapPriv->last_grabber)
+ cmapPriv->smart_grab = FALSE;
+ smartGrab = cmapPriv->smart_grab;
+
+#ifdef COLOR_DEBUG
+ fprintf (stderr, "\nGot colormap grab request, ");
+ fprintf (stderr, "seq = 0x%x, proxy = %d, client = %d, cmap = 0x%x\n",
+ client->sequence, proxy->pid, client->index, stuff->cmap);
+
+ if (cmapPriv->grab_status == CMAP_NOT_GRABBED)
+ {
+ fprintf (stderr, "cmap 0x%x is not grabbed by any proxy\n",
+ stuff->cmap);
+ if (smartGrab)
+ fprintf (stderr, "This is a smart grab\n");
+ }
+ else if (cmapPriv->grab_status == CMAP_GRABBED)
+ {
+ if (cmapPriv->grabber == proxy)
+ {
+ fprintf (stderr, "cmap 0x%x is already grabbed by proxy %d\n",
+ stuff->cmap, proxy->pid);
+ }
+ else
+ {
+ fprintf (stderr, "cmap 0x%x is currently grabbed by proxy %d\n",
+ stuff->cmap, cmapPriv->grabber->pid);
+ }
+ }
+ else if (cmapPriv->grab_status == CMAP_WAITING_FOR_UNGRAB)
+ {
+ fprintf (stderr,
+ "Already waiting for cmap 0x%x to be ungrabbed by proxy %d\n",
+ stuff->cmap, cmapPriv->grabber->pid);
+ }
+#endif
+
+ if (cmapPriv->grab_status != CMAP_NOT_GRABBED &&
+ cmapPriv->grabber != proxy)
+ {
+ /*
+ * The colormap is grabbed by a proxy other than the one that
+ * is requesting this grab. Reset this grab request, and process
+ * it after the server gets back control of the colormap. Before
+ * we reset the request, we must put it back in the client's byte
+ * order.
+ */
+
+ if (!WaitForServerCmapControl (client, pmap))
+ return BadAlloc;
+
+ if (client->swapped)
+ {
+ swaps(&stuff->length, n);
+ swapl(&stuff->cmap, n);
+ }
+
+ ResetCurrentRequest(client);
+ IgnoreClient(client);
+
+ return Success;
+ }
+
+ if (pmap->pVisual->class & DynamicClass) {
+ cmapPriv->grabber = proxy;
+ cmapPriv->grab_status = CMAP_GRABBED;
+ cmapPriv->next = proxy->grabbedCmaps;
+ proxy->grabbedCmaps = pmap;
+ } else
+ smartGrab = FALSE;
+
+ /*
+ * For an smart grab (see comments above), there is no information
+ * sent about the colormap cells because the proxy is all up to date.
+ * Otherwise, the server sends the proxy the state of all allocated
+ * cells in the colormap. All cells not specified are assumed free.
+ */
+
+ bytes = 0;
+ if (!smartGrab) {
+ if ((pmap->pVisual->class | DynamicClass) == DirectColor) {
+ bytes = NumAllocatedCells(pmap->red,
+ NUMRED(pmap->pVisual)) * 9;
+ bytes += NumAllocatedCells(pmap->green,
+ NUMGREEN(pmap->pVisual)) * 9;
+ bytes += NumAllocatedCells(pmap->blue,
+ NUMBLUE(pmap->pVisual)) * 9;
+ bytes += 2;
+ } else
+ bytes = NumAllocatedCells(pmap->red,
+ pmap->pVisual->ColormapEntries) * 9;
+ }
+ bytes += sz_xLbxGrabCmapReply + 1;
+ reply = (xLbxGrabCmapReply *) xalloc (bytes);
+ bzero (reply, sz_xLbxGrabCmapReply);
+
+ if (smartGrab)
+ {
+ reply->flags = LBX_SMART_GRAB;
+ reply->length = 0;
+ }
+ else
+ {
+ GetAllocatedCells (pmap, &reply->flags,
+ (CARD8 *) reply + sz_xLbxGrabCmapReplyHdr, &bytes);
+ if (bytes <= (sz_xLbxGrabCmapReply - sz_xLbxGrabCmapReplyHdr))
+ reply->length = 0;
+ else
+ reply->length = (sz_xLbxGrabCmapReplyHdr +
+ bytes - sz_xLbxGrabCmapReply + 3) >> 2;
+ }
+
+ reply->type = X_Reply;
+ reply->sequenceNumber = client->sequence;
+
+ bytes = sz_xLbxGrabCmapReply + (reply->length << 2);
+
+ if (client->swapped)
+ {
+ register char n;
+
+ swaps (&reply->sequenceNumber, n);
+ swapl (&reply->length, n);
+ }
+
+ WriteToClient (client, bytes, (char *)reply);
+
+ xfree (reply);
+
+ return (client->noClientException);
+}
+
+static int
+LbxUnstallClient(data, id)
+ pointer data;
+ XID id;
+{
+ LbxColormapPriv *cmapPriv = (LbxColormapPriv *)data;
+ LbxStalled **prev;
+ ClientPtr client;
+
+ for (prev = &cmapPriv->stalled_clients; *prev && (*prev)->id != id; )
+ prev = &(*prev)->next;
+ *prev = (*prev)->next;
+ client = clients[CLIENT_ID(id)];
+ if (!client->clientGone)
+ AttendClient(client);
+ return 0;
+}
+
+void
+LbxReleaseCmap(pmap, smart)
+ ColormapPtr pmap;
+ Bool smart;
+{
+ LbxColormapPriv *cmapPriv;
+ ColormapPtr *prev;
+
+ if (!pmap->devPrivates)
+ return;
+ cmapPriv = (LbxColormapPriv *)
+ (pmap->devPrivates[lbxColormapPrivIndex].ptr);
+ if (!cmapPriv || (cmapPriv->grab_status == CMAP_NOT_GRABBED))
+ return;
+
+ for (prev = &cmapPriv->grabber->grabbedCmaps; *prev && *prev != pmap; )
+ prev = &((LbxColormapPriv *)
+ (*prev)->devPrivates[lbxColormapPrivIndex].ptr)->next;
+ if (*prev == pmap)
+ *prev = cmapPriv->next;
+
+ while (cmapPriv->stalled_clients)
+ FreeResource(cmapPriv->stalled_clients->id, 0);
+
+ cmapPriv->grab_status = CMAP_NOT_GRABBED;
+ cmapPriv->last_grabber = smart ? cmapPriv->grabber->uid : 0;
+ cmapPriv->grabber = NULL;
+ cmapPriv->smart_grab = smart;
+}
+
+/*
+ * Handle a colormap release request from a proxy.
+ */
+
+int
+ProcLbxReleaseCmap(client)
+ register ClientPtr client;
+{
+ REQUEST(xLbxReleaseCmapReq);
+ ColormapPtr pmap;
+
+#ifdef COLOR_DEBUG
+ fprintf (stderr, "Got colormap release request, ");
+ fprintf (stderr, "seq = 0x%x, proxy = %d, client = %d, cmap = 0x%x\n",
+ client->sequence, LbxProxyID(client), client->index, stuff->cmap);
+#endif
+
+ pmap = (ColormapPtr) SecurityLookupIDByType (client, stuff->cmap,
+ RT_COLORMAP,
+ SecurityWriteAccess);
+
+ if (!pmap)
+ {
+ client->errorValue = stuff->cmap;
+ return BadColor;
+ }
+
+ if (LbxGrabbedByClient(client, pmap))
+ LbxReleaseCmap(pmap, TRUE);
+ return Success;
+}
+
+
+/*
+ * Handle an LbxAllocColor request. The proxy did the alloc and
+ * is telling the server what rgb and pixel value to use.
+ */
+
+int
+ProcLbxAllocColor(client)
+ register ClientPtr client;
+{
+ REQUEST(xLbxAllocColorReq);
+ ColormapPtr pmap;
+ CARD32 pixel = stuff->pixel;
+
+ REQUEST_SIZE_MATCH (xLbxAllocColorReq);
+ pmap = (ColormapPtr) SecurityLookupIDByType (client, stuff->cmap,
+ RT_COLORMAP,
+ SecurityWriteAccess);
+
+#ifdef COLOR_DEBUG
+ fprintf (stderr,
+ "Got LBX alloc color: seq = 0x%x, proxy = %d, client = %d\n",
+ client->sequence, LbxProxyID(client), client->index);
+ fprintf (stderr, " cmap = 0x%x, pixel = %d, rgb = (%d,%d,%d)\n",
+ stuff->cmap, stuff->pixel, stuff->red, stuff->green, stuff->blue);
+#endif
+
+ if (pmap)
+ {
+ int status;
+ if (!LbxGrabbedByClient(client, pmap))
+ return BadAccess;
+
+ status = AllocColor (pmap,
+ &stuff->red, &stuff->green, &stuff->blue,
+ &pixel, client->index);
+
+ if (status == Success && pixel != stuff->pixel)
+ {
+ /*
+ * Internal error - Proxy allocated different pixel from server
+ */
+#ifdef COLOR_DEBUG
+ fprintf(stderr, "got pixel %d (%d, %d, %d), expected %d\n",
+ pixel, stuff->red, stuff->green, stuff->blue, stuff->pixel);
+#endif
+ FreeColors (pmap, client->index, 1, &pixel, 0L);
+ return BadAlloc;
+ }
+
+ return status;
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return (BadColor);
+ }
+}
+
+
+/*
+ * The proxy sends an LbxIncrementPixel request when it short circuits
+ * an AllocColor. The server must bump up the reference count the
+ * specified amount.
+ */
+
+int
+ProcLbxIncrementPixel(client)
+ register ClientPtr client;
+{
+ REQUEST(xLbxIncrementPixelReq);
+ ColormapPtr pmap;
+ EntryPtr pent;
+ Pixel pixel;
+ unsigned short red, green, blue;
+ VisualPtr pVisual;
+ int status;
+
+#ifdef COLOR_DEBUG
+ fprintf (stderr,
+ "Got LBX increment pixel: seq = 0x%x, proxy = %d, client = %d\n",
+ client->sequence, LbxProxyID(client), client->index);
+ fprintf (stderr, " cmap = 0x%x, pixel = %d\n",
+ stuff->cmap, stuff->pixel);
+#endif
+
+ /*
+ * Looks up the color associated with the pixel, and then call
+ * AllocColor() - a bit round-about, but it should work.
+ */
+
+ pmap = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap,
+ RT_COLORMAP,
+ SecurityWriteAccess);
+ if (!pmap) {
+ client->errorValue = stuff->cmap;
+ return BadColor;
+ }
+
+ pixel = stuff->pixel;
+
+ switch (pmap->class) {
+ case StaticColor:
+ case StaticGray:
+ red = pmap->red[pixel].co.local.red;
+ green = pmap->red[pixel].co.local.green;
+ blue = pmap->red[pixel].co.local.blue;
+ break;
+ case GrayScale:
+ case PseudoColor:
+ pent = pmap->red + pixel;
+ red = pent->co.local.red;
+ green = pent->co.local.green;
+ blue = pent->co.local.blue;
+ break;
+ default:
+ pVisual = pmap->pVisual;
+ red = pmap->red[(pixel & pVisual->redMask) >> pVisual->offsetRed].co.local.red;
+ green = pmap->green[(pixel & pVisual->greenMask) >> pVisual->offsetGreen].co.local.green;
+ blue = pmap->blue[(pixel & pVisual->blueMask) >> pVisual->offsetBlue].co.local.blue;
+ break;
+ }
+
+ status = AllocColor(pmap, &red, &green, &blue, &pixel, client->index);
+
+ if (status == Success && pixel != stuff->pixel)
+ {
+ /*
+ * Internal error - Proxy allocated different pixel from server
+ */
+#ifdef COLOR_DEBUG
+ fprintf(stderr, "got pixel %d, expected %d\n", pixel, stuff->pixel);
+#endif
+ FreeColors (pmap, client->index, 1, &pixel, 0L);
+ return BadAlloc;
+ }
+
+ return status;
+}