aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xgl/xglarea.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xgl/xglarea.c')
-rw-r--r--xorg-server/hw/xgl/xglarea.c323
1 files changed, 323 insertions, 0 deletions
diff --git a/xorg-server/hw/xgl/xglarea.c b/xorg-server/hw/xgl/xglarea.c
new file mode 100644
index 000000000..cdf652d0f
--- /dev/null
+++ b/xorg-server/hw/xgl/xglarea.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include "xgl.h"
+
+static Bool
+xglAreaMoveIn (xglAreaPtr pArea,
+ pointer closure)
+{
+ pArea->closure = closure;
+ pArea->state = xglAreaOccupied;
+
+ return (*pArea->pRoot->funcs->MoveIn) (pArea, closure);
+}
+
+static void
+xglAreaMoveOut (xglAreaPtr pArea)
+{
+ (*pArea->pRoot->funcs->MoveOut) (pArea, pArea->closure);
+
+ pArea->closure = (pointer) 0;
+ pArea->state = xglAreaAvailable;
+}
+
+static xglAreaPtr
+xglAreaCreate (xglRootAreaPtr pRoot,
+ int level,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ xglAreaPtr pArea;
+ int n = 4;
+
+ pArea = xalloc (sizeof (xglAreaRec) + pRoot->devPrivateSize);
+ if (!pArea)
+ return NULL;
+
+ pArea->level = level;
+ pArea->x = x;
+ pArea->y = y;
+ pArea->width = width;
+ pArea->height = height;
+ pArea->pRoot = pRoot;
+ pArea->closure = (pointer) 0;
+ pArea->state = xglAreaAvailable;
+
+ while (n--)
+ pArea->pArea[n] = NULL;
+
+ if (pRoot->devPrivateSize)
+ pArea->devPrivate.ptr = pArea + 1;
+ else
+ pArea->devPrivate.ptr = (pointer) 0;
+
+ if (!(*pArea->pRoot->funcs->Create) (pArea))
+ {
+ free (pArea);
+ return NULL;
+ }
+
+ return pArea;
+}
+
+static void
+xglAreaDestroy (xglAreaPtr pArea)
+{
+ if (!pArea)
+ return;
+
+ if (pArea->state == xglAreaOccupied)
+ {
+ xglAreaMoveOut (pArea);
+ }
+ else
+ {
+ int n = 4;
+
+ while (n--)
+ xglAreaDestroy (pArea->pArea[n]);
+ }
+
+ xfree (pArea);
+}
+
+static xglAreaPtr
+xglAreaGetTopScoredSubArea (xglAreaPtr pArea)
+{
+ if (!pArea)
+ return NULL;
+
+ switch (pArea->state) {
+ case xglAreaOccupied:
+ return pArea;
+ case xglAreaAvailable:
+ break;
+ case xglAreaDivided: {
+ xglAreaPtr tmp, top = NULL;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ tmp = xglAreaGetTopScoredSubArea (pArea->pArea[i]);
+ if (tmp && top)
+ {
+ if ((*pArea->pRoot->funcs->CompareScore) (tmp,
+ tmp->closure,
+ top->closure) > 0)
+ top = tmp;
+ }
+ else if (tmp)
+ {
+ top = tmp;
+ }
+ }
+ return top;
+ }
+ }
+
+ return NULL;
+}
+
+static Bool
+xglAreaFind (xglAreaPtr pArea,
+ int width,
+ int height,
+ Bool kickOut,
+ pointer closure)
+{
+ if (pArea->width < width || pArea->height < height)
+ return FALSE;
+
+ switch (pArea->state) {
+ case xglAreaOccupied:
+ if (kickOut)
+ {
+ if ((*pArea->pRoot->funcs->CompareScore) (pArea,
+ pArea->closure,
+ closure) >= 0)
+ return FALSE;
+
+ xglAreaMoveOut (pArea);
+ } else
+ return FALSE;
+
+ /* fall-through */
+ case xglAreaAvailable:
+ {
+ if (pArea->level == pArea->pRoot->maxLevel ||
+ (pArea->width == width && pArea->height == height))
+ {
+ if (xglAreaMoveIn (pArea, closure))
+ return TRUE;
+ }
+ else
+ {
+ int dx[4], dy[4], w[4], h[4], i;
+
+ dx[0] = dx[2] = dy[0] = dy[1] = 0;
+
+ w[0] = w[2] = dx[1] = dx[3] = width;
+ h[0] = h[1] = dy[2] = dy[3] = height;
+
+ w[1] = w[3] = pArea->width - width;
+ h[2] = h[3] = pArea->height - height;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (w[i])
+ pArea->pArea[i] =
+ xglAreaCreate (pArea->pRoot,
+ pArea->level + 1,
+ pArea->x + dx[i],
+ pArea->y + dy[i],
+ w[i], h[i]);
+ }
+
+ for (; i < 4; i++)
+ {
+ if (w[i] && h[i])
+ pArea->pArea[i] =
+ xglAreaCreate (pArea->pRoot,
+ pArea->level + 1,
+ pArea->x + dx[i],
+ pArea->y + dy[i],
+ w[i], h[i]);
+ }
+
+ pArea->state = xglAreaDivided;
+
+ if (xglAreaFind (pArea->pArea[0], width, height, kickOut, closure))
+ return TRUE;
+ }
+ } break;
+ case xglAreaDivided:
+ {
+ xglAreaPtr topArea;
+ int i, rejected = FALSE;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (pArea->pArea[i])
+ {
+ if (pArea->pArea[i]->width >= width &&
+ pArea->pArea[i]->height >= height)
+ {
+ if (xglFindArea (pArea->pArea[i], width, height, kickOut,
+ closure))
+ return TRUE;
+
+ rejected = TRUE;
+ }
+ }
+ }
+
+ if (rejected)
+ return FALSE;
+
+ topArea = xglAreaGetTopScoredSubArea (pArea);
+ if (topArea)
+ {
+ if (kickOut)
+ {
+ if ((*pArea->pRoot->funcs->CompareScore) (topArea,
+ topArea->closure,
+ closure) >= 0)
+ return FALSE;
+ } else
+ return FALSE;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ xglAreaDestroy (pArea->pArea[i]);
+ pArea->pArea[i] = NULL;
+ }
+
+ pArea->closure = (pointer) 0;
+ pArea->state = xglAreaAvailable;
+ if (xglFindArea (pArea, width, height, TRUE, closure))
+ return TRUE;
+
+ } break;
+ }
+
+ return FALSE;
+}
+
+Bool
+xglRootAreaInit (xglRootAreaPtr pRoot,
+ int maxLevel,
+ int width,
+ int height,
+ int devPrivateSize,
+ xglAreaFuncsPtr funcs,
+ pointer closure)
+{
+ pRoot->maxLevel = maxLevel;
+ pRoot->funcs = funcs;
+ pRoot->devPrivateSize = devPrivateSize;
+ pRoot->closure = closure;
+
+ pRoot->pArea = xglAreaCreate (pRoot, 0, 0, 0, width, height);
+ if (!pRoot->pArea)
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+xglRootAreaFini (xglRootAreaPtr pRoot)
+{
+ xglAreaDestroy (pRoot->pArea);
+}
+
+void
+xglLeaveArea (xglAreaPtr pArea)
+{
+ xglAreaMoveOut (pArea);
+}
+
+void
+xglWithdrawArea (xglAreaPtr pArea)
+{
+ pArea->closure = NULL;
+ pArea->state = xglAreaAvailable;
+}
+
+Bool
+xglFindArea (xglAreaPtr pArea,
+ int width,
+ int height,
+ Bool kickOut,
+ pointer closure)
+{
+ if (width < 1 || height < 0)
+ return FALSE;
+
+ return xglAreaFind (pArea, width, height, kickOut, closure);
+}