diff options
author | marha <marha@users.sourceforge.net> | 2011-07-04 14:21:49 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-07-04 14:21:49 +0200 |
commit | 5c671fd7f8198bed2fc32b33b81d1081f1486ed9 (patch) | |
tree | 96fc6a6d761473737def7c35256fed9bbe52753e /xorg-server | |
parent | d9f970a847e1af706f07560ef163b229bb592307 (diff) | |
download | vcxsrv-5c671fd7f8198bed2fc32b33b81d1081f1486ed9.tar.gz vcxsrv-5c671fd7f8198bed2fc32b33b81d1081f1486ed9.tar.bz2 vcxsrv-5c671fd7f8198bed2fc32b33b81d1081f1486ed9.zip |
xserver mesa git update 4 July 2011
Diffstat (limited to 'xorg-server')
58 files changed, 11659 insertions, 11397 deletions
diff --git a/xorg-server/Xext/xtest.c b/xorg-server/Xext/xtest.c index daa6430f1..cc675c116 100644 --- a/xorg-server/Xext/xtest.c +++ b/xorg-server/Xext/xtest.c @@ -679,12 +679,19 @@ GetXTestDevice(DeviceIntPtr master) return NULL; } +static void +XTestExtensionTearDown(ExtensionEntry *e) +{ + FreeEventList(xtest_evlist, GetMaximumEventsNum()); + xtest_evlist = NULL; +} + void XTestExtensionInit(INITARGS) { AddExtension(XTestExtensionName, 0, 0, ProcXTestDispatch, SProcXTestDispatch, - NULL, StandardMinorOpcode); + XTestExtensionTearDown, StandardMinorOpcode); xtest_evlist = InitEventList(GetMaximumEventsNum()); } diff --git a/xorg-server/dix/dixutils.c b/xorg-server/dix/dixutils.c index c23c87e9a..1e3134663 100644 --- a/xorg-server/dix/dixutils.c +++ b/xorg-server/dix/dixutils.c @@ -1,893 +1,895 @@ -/***********************************************************
-
-Copyright 1987, 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.
-
-
-Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-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 Digital not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-DIGITAL 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.
-
-******************************************************************/
-
-/*
-
-(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved.
-
-Permission to use, copy, modify, distribute, and sublicense this software and its
-documentation for any purpose and without fee is hereby granted, provided that
-the above copyright notices appear in all copies and that both those copyright
-notices and this permission notice appear in supporting documentation and that
-the name of Adobe Systems Incorporated not be used in advertising or publicity
-pertaining to distribution of the software without specific, written prior
-permission. No trademark license to use the Adobe trademarks is hereby
-granted. If the Adobe trademark "Display PostScript"(tm) is used to describe
-this software, its functionality or for any other purpose, such use shall be
-limited to a statement that this software works in conjunction with the Display
-PostScript system. Proper trademark attribution to reflect Adobe's ownership
-of the trademark shall be given whenever any such reference to the Display
-PostScript system is made.
-
-ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY
-PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE
-DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
-WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU
-OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
-DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT
-LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER
-SUPPORT FOR THE SOFTWARE.
-
-Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
-Incorporated which may be registered in certain jurisdictions.
-
-Author: Adobe Systems Incorporated
-
-*/
-
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include <X11/Xmd.h>
-#include "misc.h"
-#include "windowstr.h"
-#include "dixstruct.h"
-#include "pixmapstr.h"
-#include "gcstruct.h"
-#include "scrnintstr.h"
-#define XK_LATIN1
-#include <X11/keysymdef.h>
-#include "xace.h"
-
-/*
- * CompareTimeStamps returns -1, 0, or +1 depending on if the first
- * argument is less than, equal to or greater than the second argument.
- */
-
-int
-CompareTimeStamps(TimeStamp a, TimeStamp b)
-{
- if (a.months < b.months)
- return EARLIER;
- if (a.months > b.months)
- return LATER;
- if (a.milliseconds < b.milliseconds)
- return EARLIER;
- if (a.milliseconds > b.milliseconds)
- return LATER;
- return SAMETIME;
-}
-
-/*
- * convert client times to server TimeStamps
- */
-
-#define HALFMONTH ((unsigned long) 1<<31)
-TimeStamp
-ClientTimeToServerTime(CARD32 c)
-{
- TimeStamp ts;
- if (c == CurrentTime)
- return currentTime;
- ts.months = currentTime.months;
- ts.milliseconds = c;
- if (c > currentTime.milliseconds)
- {
- if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
- ts.months -= 1;
- }
- else if (c < currentTime.milliseconds)
- {
- if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH)
- ts.months += 1;
- }
- return ts;
-}
-
-/*
- * ISO Latin-1 case conversion routine
- *
- * this routine always null-terminates the result, so
- * beware of too-small buffers
- */
-
-static unsigned char
-ISOLatin1ToLower (unsigned char source)
-{
- unsigned char dest;
- if ((source >= XK_A) && (source <= XK_Z))
- dest = source + (XK_a - XK_A);
- else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
- dest = source + (XK_agrave - XK_Agrave);
- else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
- dest = source + (XK_oslash - XK_Ooblique);
- else
- dest = source;
- return dest;
-}
-
-
-int
-CompareISOLatin1Lowered(unsigned char *s1, int s1len,
- unsigned char *s2, int s2len)
-{
- unsigned char c1, c2;
-
- for (;;)
- {
- /* note -- compare against zero so that -1 ignores len */
- c1 = s1len-- ? *s1++ : '\0';
- c2 = s2len-- ? *s2++ : '\0';
- if (!c1 ||
- (c1 != c2 &&
- (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2))))
- break;
- }
- return (int) c1 - (int) c2;
-}
-
-/*
- * dixLookupWindow and dixLookupDrawable:
- * Look up the window/drawable taking into account the client doing the
- * lookup, the type of drawable desired, and the type of access desired.
- * Return Success with *pDraw set if the window/drawable exists and the client
- * is allowed access, else return an error code with *pDraw set to NULL. The
- * access mask values are defined in resource.h. The type mask values are
- * defined in pixmap.h, with zero equivalent to M_DRAWABLE.
- */
-int
-dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
- Mask type, Mask access)
-{
- DrawablePtr pTmp;
- int rc;
-
- *pDraw = NULL;
- client->errorValue = id;
-
- if (id == INVALID)
- return BadDrawable;
-
- rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access);
-
- if (rc == BadValue)
- return BadDrawable;
- if (rc != Success)
- return rc;
- if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE)))
- return BadMatch;
-
- *pDraw = pTmp;
- return Success;
-}
-
-int
-dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
-{
- int rc;
- rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access);
- return (rc == BadDrawable) ? BadWindow : rc;
-}
-
-int
-dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
-{
- return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access);
-}
-
-int
-dixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access)
-{
- int rc;
- GC *pGC;
- client->errorValue = id; /* EITHER font or gc */
- rc = dixLookupResourceByType((pointer *) pFont, id, RT_FONT, client, access);
- if (rc != BadFont)
- return rc;
- rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access);
- if (rc == BadGC)
- return BadFont;
- if (rc == Success)
- *pFont = pGC->font;
- return rc;
-}
-
-int
-dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access)
-{
- pointer pRes;
- int rc = BadValue, clientIndex = CLIENT_ID(rid);
-
- if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT))
- goto bad;
-
- rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess);
- if (rc != Success)
- goto bad;
-
- rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access);
- if (rc != Success)
- goto bad;
-
- *pClient = clients[clientIndex];
- return Success;
-bad:
- if(client)
- client->errorValue = rid;
- *pClient = NULL;
- return rc;
-}
-
-int
-AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
- Bool toRoot, Bool map)
-{
- int numnow;
- SaveSetElt *pTmp = NULL;
- int j;
-
- numnow = client->numSaved;
- j = 0;
- if (numnow)
- {
- pTmp = client->saveSet;
- while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin))
- j++;
- }
- if (mode == SetModeInsert)
- {
- if (j < numnow) /* duplicate */
- return Success;
- numnow++;
- pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow);
- if (!pTmp)
- return BadAlloc;
- client->saveSet = pTmp;
- client->numSaved = numnow;
- SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
- SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
- SaveSetAssignMap(client->saveSet[numnow - 1], map);
- return Success;
- }
- else if ((mode == SetModeDelete) && (j < numnow))
- {
- while (j < numnow-1)
- {
- pTmp[j] = pTmp[j+1];
- j++;
- }
- numnow--;
- if (numnow)
- {
- pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow);
- if (pTmp)
- client->saveSet = pTmp;
- }
- else
- {
- free(client->saveSet);
- client->saveSet = (SaveSetElt *)NULL;
- }
- client->numSaved = numnow;
- return Success;
- }
- return Success;
-}
-
-void
-DeleteWindowFromAnySaveSet(WindowPtr pWin)
-{
- int i;
- ClientPtr client;
-
- for (i = 0; i< currentMaxClients; i++)
- {
- client = clients[i];
- if (client && client->numSaved)
- (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE);
- }
-}
-
-/* No-op Don't Do Anything : sometimes we need to be able to call a procedure
- * that doesn't do anything. For example, on screen with only static
- * colormaps, if someone calls install colormap, it's easier to have a dummy
- * procedure to call than to check if there's a procedure
- */
-void
-NoopDDA(void)
-{
-}
-
-typedef struct _BlockHandler {
- BlockHandlerProcPtr BlockHandler;
- WakeupHandlerProcPtr WakeupHandler;
- pointer blockData;
- Bool deleted;
-} BlockHandlerRec, *BlockHandlerPtr;
-
-static BlockHandlerPtr handlers;
-static int numHandlers;
-static int sizeHandlers;
-static Bool inHandler;
-static Bool handlerDeleted;
-
-/**
- *
- * \param pTimeout DIX doesn't want to know how OS represents time
- * \param pReadMask nor how it represents the det of descriptors
- */
-void
-BlockHandler(pointer pTimeout, pointer pReadmask)
-{
- int i, j;
-
- ++inHandler;
- for (i = 0; i < screenInfo.numScreens; i++)
- (* screenInfo.screens[i]->BlockHandler)(i,
- screenInfo.screens[i]->blockData,
- pTimeout, pReadmask);
- for (i = 0; i < numHandlers; i++)
- (*handlers[i].BlockHandler) (handlers[i].blockData,
- pTimeout, pReadmask);
- if (handlerDeleted)
- {
- for (i = 0; i < numHandlers;)
- if (handlers[i].deleted)
- {
- for (j = i; j < numHandlers - 1; j++)
- handlers[j] = handlers[j+1];
- numHandlers--;
- }
- else
- i++;
- handlerDeleted = FALSE;
- }
- --inHandler;
-}
-
-/**
- *
- * \param result 32 bits of undefined result from the wait
- * \param pReadmask the resulting descriptor mask
- */
-void
-WakeupHandler(int result, pointer pReadmask)
-{
- int i, j;
-
- ++inHandler;
- for (i = numHandlers - 1; i >= 0; i--)
- (*handlers[i].WakeupHandler) (handlers[i].blockData,
- result, pReadmask);
- for (i = 0; i < screenInfo.numScreens; i++)
- (* screenInfo.screens[i]->WakeupHandler)(i,
- screenInfo.screens[i]->wakeupData,
- result, pReadmask);
- if (handlerDeleted)
- {
- for (i = 0; i < numHandlers;)
- if (handlers[i].deleted)
- {
- for (j = i; j < numHandlers - 1; j++)
- handlers[j] = handlers[j+1];
- numHandlers--;
- }
- else
- i++;
- handlerDeleted = FALSE;
- }
- --inHandler;
-}
-
-/**
- * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
- * get called until next time
- */
-Bool
-RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
- WakeupHandlerProcPtr wakeupHandler,
- pointer blockData)
-{
- BlockHandlerPtr new;
-
- if (numHandlers >= sizeHandlers)
- {
- new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
- sizeof (BlockHandlerRec));
- if (!new)
- return FALSE;
- handlers = new;
- sizeHandlers = numHandlers + 1;
- }
- handlers[numHandlers].BlockHandler = blockHandler;
- handlers[numHandlers].WakeupHandler = wakeupHandler;
- handlers[numHandlers].blockData = blockData;
- handlers[numHandlers].deleted = FALSE;
- numHandlers = numHandlers + 1;
- return TRUE;
-}
-
-void
-RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
- WakeupHandlerProcPtr wakeupHandler,
- pointer blockData)
-{
- int i;
-
- for (i = 0; i < numHandlers; i++)
- if (handlers[i].BlockHandler == blockHandler &&
- handlers[i].WakeupHandler == wakeupHandler &&
- handlers[i].blockData == blockData)
- {
- if (inHandler)
- {
- handlerDeleted = TRUE;
- handlers[i].deleted = TRUE;
- }
- else
- {
- for (; i < numHandlers - 1; i++)
- handlers[i] = handlers[i+1];
- numHandlers--;
- }
- break;
- }
-}
-
-void
-InitBlockAndWakeupHandlers (void)
-{
- free(handlers);
- handlers = (BlockHandlerPtr) 0;
- numHandlers = 0;
- sizeHandlers = 0;
-}
-
-/*
- * A general work queue. Perform some task before the server
- * sleeps for input.
- */
-
-WorkQueuePtr workQueue;
-static WorkQueuePtr *workQueueLast = &workQueue;
-
-void
-ProcessWorkQueue(void)
-{
- WorkQueuePtr q, *p;
-
- p = &workQueue;
- /*
- * Scan the work queue once, calling each function. Those
- * which return TRUE are removed from the queue, otherwise
- * they will be called again. This must be reentrant with
- * QueueWorkProc.
- */
- while ((q = *p))
- {
- if ((*q->function) (q->client, q->closure))
- {
- /* remove q from the list */
- *p = q->next; /* don't fetch until after func called */
- free(q);
- }
- else
- {
- p = &q->next; /* don't fetch until after func called */
- }
- }
- workQueueLast = p;
-}
-
-void
-ProcessWorkQueueZombies(void)
-{
- WorkQueuePtr q, *p;
-
- p = &workQueue;
- while ((q = *p))
- {
- if (q->client && q->client->clientGone)
- {
- (void) (*q->function) (q->client, q->closure);
- /* remove q from the list */
- *p = q->next; /* don't fetch until after func called */
- free(q);
- }
- else
- {
- p = &q->next; /* don't fetch until after func called */
- }
- }
- workQueueLast = p;
-}
-
-Bool
-QueueWorkProc (
- Bool (*function)(ClientPtr /* pClient */, pointer /* closure */),
- ClientPtr client, pointer closure)
-{
- WorkQueuePtr q;
-
- q = malloc(sizeof *q);
- if (!q)
- return FALSE;
- q->function = function;
- q->client = client;
- q->closure = closure;
- q->next = NULL;
- *workQueueLast = q;
- workQueueLast = &q->next;
- return TRUE;
-}
-
-/*
- * Manage a queue of sleeping clients, awakening them
- * when requested, by using the OS functions IgnoreClient
- * and AttendClient. Note that this *ignores* the troubles
- * with request data interleaving itself with events, but
- * we'll leave that until a later time.
- */
-
-typedef struct _SleepQueue {
- struct _SleepQueue *next;
- ClientPtr client;
- ClientSleepProcPtr function;
- pointer closure;
-} SleepQueueRec, *SleepQueuePtr;
-
-static SleepQueuePtr sleepQueue = NULL;
-
-Bool
-ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure)
-{
- SleepQueuePtr q;
-
- q = malloc(sizeof *q);
- if (!q)
- return FALSE;
-
- IgnoreClient (client);
- q->next = sleepQueue;
- q->client = client;
- q->function = function;
- q->closure = closure;
- sleepQueue = q;
- return TRUE;
-}
-
-Bool
-ClientSignal (ClientPtr client)
-{
- SleepQueuePtr q;
-
- for (q = sleepQueue; q; q = q->next)
- if (q->client == client)
- {
- return QueueWorkProc (q->function, q->client, q->closure);
- }
- return FALSE;
-}
-
-void
-ClientWakeup (ClientPtr client)
-{
- SleepQueuePtr q, *prev;
-
- prev = &sleepQueue;
- while ( (q = *prev) )
- {
- if (q->client == client)
- {
- *prev = q->next;
- free(q);
- if (client->clientGone)
- /* Oops -- new zombie cleanup code ensures this only
- * happens from inside CloseDownClient; don't want to
- * recurse here...
- */
- /* CloseDownClient(client) */;
- else
- AttendClient (client);
- break;
- }
- prev = &q->next;
- }
-}
-
-Bool
-ClientIsAsleep (ClientPtr client)
-{
- SleepQueuePtr q;
-
- for (q = sleepQueue; q; q = q->next)
- if (q->client == client)
- return TRUE;
- return FALSE;
-}
-
-/*
- * Generic Callback Manager
- */
-
-/* ===== Private Procedures ===== */
-
-static int numCallbackListsToCleanup = 0;
-static CallbackListPtr **listsToCleanup = NULL;
-
-static Bool
-_AddCallback(
- CallbackListPtr *pcbl,
- CallbackProcPtr callback,
- pointer data)
-{
- CallbackPtr cbr;
-
- cbr = malloc(sizeof(CallbackRec));
- if (!cbr)
- return FALSE;
- cbr->proc = callback;
- cbr->data = data;
- cbr->next = (*pcbl)->list;
- cbr->deleted = FALSE;
- (*pcbl)->list = cbr;
- return TRUE;
-}
-
-static Bool
-_DeleteCallback(
- CallbackListPtr *pcbl,
- CallbackProcPtr callback,
- pointer data)
-{
- CallbackListPtr cbl = *pcbl;
- CallbackPtr cbr, pcbr;
-
- for (pcbr = NULL, cbr = cbl->list;
- cbr != NULL;
- pcbr = cbr, cbr = cbr->next)
- {
- if ((cbr->proc == callback) && (cbr->data == data))
- break;
- }
- if (cbr != NULL)
- {
- if (cbl->inCallback)
- {
- ++(cbl->numDeleted);
- cbr->deleted = TRUE;
- }
- else
- {
- if (pcbr == NULL)
- cbl->list = cbr->next;
- else
- pcbr->next = cbr->next;
- free(cbr);
- }
- return TRUE;
- }
- return FALSE;
-}
-
-void
-_CallCallbacks(
- CallbackListPtr *pcbl,
- pointer call_data)
-{
- CallbackListPtr cbl = *pcbl;
- CallbackPtr cbr, pcbr;
-
- ++(cbl->inCallback);
- for (cbr = cbl->list; cbr != NULL; cbr = cbr->next)
- {
- (*(cbr->proc)) (pcbl, cbr->data, call_data);
- }
- --(cbl->inCallback);
-
- if (cbl->inCallback) return;
-
- /* Was the entire list marked for deletion? */
-
- if (cbl->deleted)
- {
- DeleteCallbackList(pcbl);
- return;
- }
-
- /* Were some individual callbacks on the list marked for deletion?
- * If so, do the deletions.
- */
-
- if (cbl->numDeleted)
- {
- for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; )
- {
- if (cbr->deleted)
- {
- if (pcbr)
- {
- cbr = cbr->next;
- free(pcbr->next);
- pcbr->next = cbr;
- } else
- {
- cbr = cbr->next;
- free(cbl->list);
- cbl->list = cbr;
- }
- cbl->numDeleted--;
- }
- else /* this one wasn't deleted */
- {
- pcbr = cbr;
- cbr = cbr->next;
- }
- }
- }
-}
-
-static void
-_DeleteCallbackList(
- CallbackListPtr *pcbl)
-{
- CallbackListPtr cbl = *pcbl;
- CallbackPtr cbr, nextcbr;
- int i;
-
- if (cbl->inCallback)
- {
- cbl->deleted = TRUE;
- return;
- }
-
- for (i = 0; i < numCallbackListsToCleanup; i++)
- {
- if (listsToCleanup[i] == pcbl)
- {
- listsToCleanup[i] = NULL;
- break;
- }
- }
-
- for (cbr = cbl->list; cbr != NULL; cbr = nextcbr)
- {
- nextcbr = cbr->next;
- free(cbr);
- }
- free(cbl);
- *pcbl = NULL;
-}
-
-static Bool
-CreateCallbackList(CallbackListPtr *pcbl)
-{
- CallbackListPtr cbl;
- int i;
-
- if (!pcbl) return FALSE;
- cbl = malloc(sizeof(CallbackListRec));
- if (!cbl) return FALSE;
- cbl->inCallback = 0;
- cbl->deleted = FALSE;
- cbl->numDeleted = 0;
- cbl->list = NULL;
- *pcbl = cbl;
-
- for (i = 0; i < numCallbackListsToCleanup; i++)
- {
- if (!listsToCleanup[i])
- {
- listsToCleanup[i] = pcbl;
- return TRUE;
- }
- }
-
- listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup,
- sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1));
- listsToCleanup[numCallbackListsToCleanup] = pcbl;
- numCallbackListsToCleanup++;
- return TRUE;
-}
-
-/* ===== Public Procedures ===== */
-
-Bool
-AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
-{
- if (!pcbl) return FALSE;
- if (!*pcbl)
- { /* list hasn't been created yet; go create it */
- if (!CreateCallbackList(pcbl))
- return FALSE;
- }
- return _AddCallback(pcbl, callback, data);
-}
-
-Bool
-DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
-{
- if (!pcbl || !*pcbl) return FALSE;
- return _DeleteCallback(pcbl, callback, data);
-}
-
-void
-DeleteCallbackList(CallbackListPtr *pcbl)
-{
- if (!pcbl || !*pcbl) return;
- _DeleteCallbackList(pcbl);
-}
-
-void
-InitCallbackManager(void)
-{
- int i;
-
- for (i = 0; i < numCallbackListsToCleanup; i++)
- {
- DeleteCallbackList(listsToCleanup[i]);
- }
- free(listsToCleanup);
-
- numCallbackListsToCleanup = 0;
- listsToCleanup = NULL;
-}
+/*********************************************************** + +Copyright 1987, 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. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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. + +******************************************************************/ + +/* + +(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved. + +Permission to use, copy, modify, distribute, and sublicense this software and its +documentation for any purpose and without fee is hereby granted, provided that +the above copyright notices appear in all copies and that both those copyright +notices and this permission notice appear in supporting documentation and that +the name of Adobe Systems Incorporated not be used in advertising or publicity +pertaining to distribution of the software without specific, written prior +permission. No trademark license to use the Adobe trademarks is hereby +granted. If the Adobe trademark "Display PostScript"(tm) is used to describe +this software, its functionality or for any other purpose, such use shall be +limited to a statement that this software works in conjunction with the Display +PostScript system. Proper trademark attribution to reflect Adobe's ownership +of the trademark shall be given whenever any such reference to the Display +PostScript system is made. + +ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY +PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- +INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU +OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT +LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER +SUPPORT FOR THE SOFTWARE. + +Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems +Incorporated which may be registered in certain jurisdictions. + +Author: Adobe Systems Incorporated + +*/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include "misc.h" +#include "windowstr.h" +#include "dixstruct.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#define XK_LATIN1 +#include <X11/keysymdef.h> +#include "xace.h" + +/* + * CompareTimeStamps returns -1, 0, or +1 depending on if the first + * argument is less than, equal to or greater than the second argument. + */ + +int +CompareTimeStamps(TimeStamp a, TimeStamp b) +{ + if (a.months < b.months) + return EARLIER; + if (a.months > b.months) + return LATER; + if (a.milliseconds < b.milliseconds) + return EARLIER; + if (a.milliseconds > b.milliseconds) + return LATER; + return SAMETIME; +} + +/* + * convert client times to server TimeStamps + */ + +#define HALFMONTH ((unsigned long) 1<<31) +TimeStamp +ClientTimeToServerTime(CARD32 c) +{ + TimeStamp ts; + if (c == CurrentTime) + return currentTime; + ts.months = currentTime.months; + ts.milliseconds = c; + if (c > currentTime.milliseconds) + { + if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) + ts.months -= 1; + } + else if (c < currentTime.milliseconds) + { + if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH) + ts.months += 1; + } + return ts; +} + +/* + * ISO Latin-1 case conversion routine + * + * this routine always null-terminates the result, so + * beware of too-small buffers + */ + +static unsigned char +ISOLatin1ToLower (unsigned char source) +{ + unsigned char dest; + if ((source >= XK_A) && (source <= XK_Z)) + dest = source + (XK_a - XK_A); + else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) + dest = source + (XK_agrave - XK_Agrave); + else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) + dest = source + (XK_oslash - XK_Ooblique); + else + dest = source; + return dest; +} + + +int +CompareISOLatin1Lowered(unsigned char *s1, int s1len, + unsigned char *s2, int s2len) +{ + unsigned char c1, c2; + + for (;;) + { + /* note -- compare against zero so that -1 ignores len */ + c1 = s1len-- ? *s1++ : '\0'; + c2 = s2len-- ? *s2++ : '\0'; + if (!c1 || + (c1 != c2 && + (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2)))) + break; + } + return (int) c1 - (int) c2; +} + +/* + * dixLookupWindow and dixLookupDrawable: + * Look up the window/drawable taking into account the client doing the + * lookup, the type of drawable desired, and the type of access desired. + * Return Success with *pDraw set if the window/drawable exists and the client + * is allowed access, else return an error code with *pDraw set to NULL. The + * access mask values are defined in resource.h. The type mask values are + * defined in pixmap.h, with zero equivalent to M_DRAWABLE. + */ +int +dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client, + Mask type, Mask access) +{ + DrawablePtr pTmp; + int rc; + + *pDraw = NULL; + client->errorValue = id; + + if (id == INVALID) + return BadDrawable; + + rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access); + + if (rc == BadValue) + return BadDrawable; + if (rc != Success) + return rc; + if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) + return BadMatch; + + *pDraw = pTmp; + return Success; +} + +int +dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) +{ + int rc; + rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); + return (rc == BadDrawable) ? BadWindow : rc; +} + +int +dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) +{ + return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access); +} + +int +dixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access) +{ + int rc; + GC *pGC; + client->errorValue = id; /* EITHER font or gc */ + rc = dixLookupResourceByType((pointer *) pFont, id, RT_FONT, client, access); + if (rc != BadFont) + return rc; + rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access); + if (rc == BadGC) + return BadFont; + if (rc == Success) + *pFont = pGC->font; + return rc; +} + +int +dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) +{ + pointer pRes; + int rc = BadValue, clientIndex = CLIENT_ID(rid); + + if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT)) + goto bad; + + rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess); + if (rc != Success) + goto bad; + + rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access); + if (rc != Success) + goto bad; + + *pClient = clients[clientIndex]; + return Success; +bad: + if(client) + client->errorValue = rid; + *pClient = NULL; + return rc; +} + +int +AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, + Bool toRoot, Bool map) +{ + int numnow; + SaveSetElt *pTmp = NULL; + int j; + + numnow = client->numSaved; + j = 0; + if (numnow) + { + pTmp = client->saveSet; + while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin)) + j++; + } + if (mode == SetModeInsert) + { + if (j < numnow) /* duplicate */ + return Success; + numnow++; + pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); + if (!pTmp) + return BadAlloc; + client->saveSet = pTmp; + client->numSaved = numnow; + SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); + SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); + SaveSetAssignMap(client->saveSet[numnow - 1], map); + return Success; + } + else if ((mode == SetModeDelete) && (j < numnow)) + { + while (j < numnow-1) + { + pTmp[j] = pTmp[j+1]; + j++; + } + numnow--; + if (numnow) + { + pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); + if (pTmp) + client->saveSet = pTmp; + } + else + { + free(client->saveSet); + client->saveSet = (SaveSetElt *)NULL; + } + client->numSaved = numnow; + return Success; + } + return Success; +} + +void +DeleteWindowFromAnySaveSet(WindowPtr pWin) +{ + int i; + ClientPtr client; + + for (i = 0; i< currentMaxClients; i++) + { + client = clients[i]; + if (client && client->numSaved) + (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE); + } +} + +/* No-op Don't Do Anything : sometimes we need to be able to call a procedure + * that doesn't do anything. For example, on screen with only static + * colormaps, if someone calls install colormap, it's easier to have a dummy + * procedure to call than to check if there's a procedure + */ +void +NoopDDA(void) +{ +} + +typedef struct _BlockHandler { + BlockHandlerProcPtr BlockHandler; + WakeupHandlerProcPtr WakeupHandler; + pointer blockData; + Bool deleted; +} BlockHandlerRec, *BlockHandlerPtr; + +static BlockHandlerPtr handlers; +static int numHandlers; +static int sizeHandlers; +static Bool inHandler; +static Bool handlerDeleted; + +/** + * + * \param pTimeout DIX doesn't want to know how OS represents time + * \param pReadMask nor how it represents the det of descriptors + */ +void +BlockHandler(pointer pTimeout, pointer pReadmask) +{ + int i, j; + + ++inHandler; + for (i = 0; i < screenInfo.numScreens; i++) + (* screenInfo.screens[i]->BlockHandler)(i, + screenInfo.screens[i]->blockData, + pTimeout, pReadmask); + for (i = 0; i < numHandlers; i++) + if (!handlers[i].deleted) + (*handlers[i].BlockHandler) (handlers[i].blockData, + pTimeout, pReadmask); + if (handlerDeleted) + { + for (i = 0; i < numHandlers;) + if (handlers[i].deleted) + { + for (j = i; j < numHandlers - 1; j++) + handlers[j] = handlers[j+1]; + numHandlers--; + } + else + i++; + handlerDeleted = FALSE; + } + --inHandler; +} + +/** + * + * \param result 32 bits of undefined result from the wait + * \param pReadmask the resulting descriptor mask + */ +void +WakeupHandler(int result, pointer pReadmask) +{ + int i, j; + + ++inHandler; + for (i = numHandlers - 1; i >= 0; i--) + if (!handlers[i].deleted) + (*handlers[i].WakeupHandler) (handlers[i].blockData, + result, pReadmask); + for (i = 0; i < screenInfo.numScreens; i++) + (* screenInfo.screens[i]->WakeupHandler)(i, + screenInfo.screens[i]->wakeupData, + result, pReadmask); + if (handlerDeleted) + { + for (i = 0; i < numHandlers;) + if (handlers[i].deleted) + { + for (j = i; j < numHandlers - 1; j++) + handlers[j] = handlers[j+1]; + numHandlers--; + } + else + i++; + handlerDeleted = FALSE; + } + --inHandler; +} + +/** + * Reentrant with BlockHandler and WakeupHandler, except wakeup won't + * get called until next time + */ +Bool +RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, + WakeupHandlerProcPtr wakeupHandler, + pointer blockData) +{ + BlockHandlerPtr new; + + if (numHandlers >= sizeHandlers) + { + new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) * + sizeof (BlockHandlerRec)); + if (!new) + return FALSE; + handlers = new; + sizeHandlers = numHandlers + 1; + } + handlers[numHandlers].BlockHandler = blockHandler; + handlers[numHandlers].WakeupHandler = wakeupHandler; + handlers[numHandlers].blockData = blockData; + handlers[numHandlers].deleted = FALSE; + numHandlers = numHandlers + 1; + return TRUE; +} + +void +RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, + WakeupHandlerProcPtr wakeupHandler, + pointer blockData) +{ + int i; + + for (i = 0; i < numHandlers; i++) + if (handlers[i].BlockHandler == blockHandler && + handlers[i].WakeupHandler == wakeupHandler && + handlers[i].blockData == blockData) + { + if (inHandler) + { + handlerDeleted = TRUE; + handlers[i].deleted = TRUE; + } + else + { + for (; i < numHandlers - 1; i++) + handlers[i] = handlers[i+1]; + numHandlers--; + } + break; + } +} + +void +InitBlockAndWakeupHandlers (void) +{ + free(handlers); + handlers = (BlockHandlerPtr) 0; + numHandlers = 0; + sizeHandlers = 0; +} + +/* + * A general work queue. Perform some task before the server + * sleeps for input. + */ + +WorkQueuePtr workQueue; +static WorkQueuePtr *workQueueLast = &workQueue; + +void +ProcessWorkQueue(void) +{ + WorkQueuePtr q, *p; + + p = &workQueue; + /* + * Scan the work queue once, calling each function. Those + * which return TRUE are removed from the queue, otherwise + * they will be called again. This must be reentrant with + * QueueWorkProc. + */ + while ((q = *p)) + { + if ((*q->function) (q->client, q->closure)) + { + /* remove q from the list */ + *p = q->next; /* don't fetch until after func called */ + free(q); + } + else + { + p = &q->next; /* don't fetch until after func called */ + } + } + workQueueLast = p; +} + +void +ProcessWorkQueueZombies(void) +{ + WorkQueuePtr q, *p; + + p = &workQueue; + while ((q = *p)) + { + if (q->client && q->client->clientGone) + { + (void) (*q->function) (q->client, q->closure); + /* remove q from the list */ + *p = q->next; /* don't fetch until after func called */ + free(q); + } + else + { + p = &q->next; /* don't fetch until after func called */ + } + } + workQueueLast = p; +} + +Bool +QueueWorkProc ( + Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), + ClientPtr client, pointer closure) +{ + WorkQueuePtr q; + + q = malloc(sizeof *q); + if (!q) + return FALSE; + q->function = function; + q->client = client; + q->closure = closure; + q->next = NULL; + *workQueueLast = q; + workQueueLast = &q->next; + return TRUE; +} + +/* + * Manage a queue of sleeping clients, awakening them + * when requested, by using the OS functions IgnoreClient + * and AttendClient. Note that this *ignores* the troubles + * with request data interleaving itself with events, but + * we'll leave that until a later time. + */ + +typedef struct _SleepQueue { + struct _SleepQueue *next; + ClientPtr client; + ClientSleepProcPtr function; + pointer closure; +} SleepQueueRec, *SleepQueuePtr; + +static SleepQueuePtr sleepQueue = NULL; + +Bool +ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) +{ + SleepQueuePtr q; + + q = malloc(sizeof *q); + if (!q) + return FALSE; + + IgnoreClient (client); + q->next = sleepQueue; + q->client = client; + q->function = function; + q->closure = closure; + sleepQueue = q; + return TRUE; +} + +Bool +ClientSignal (ClientPtr client) +{ + SleepQueuePtr q; + + for (q = sleepQueue; q; q = q->next) + if (q->client == client) + { + return QueueWorkProc (q->function, q->client, q->closure); + } + return FALSE; +} + +void +ClientWakeup (ClientPtr client) +{ + SleepQueuePtr q, *prev; + + prev = &sleepQueue; + while ( (q = *prev) ) + { + if (q->client == client) + { + *prev = q->next; + free(q); + if (client->clientGone) + /* Oops -- new zombie cleanup code ensures this only + * happens from inside CloseDownClient; don't want to + * recurse here... + */ + /* CloseDownClient(client) */; + else + AttendClient (client); + break; + } + prev = &q->next; + } +} + +Bool +ClientIsAsleep (ClientPtr client) +{ + SleepQueuePtr q; + + for (q = sleepQueue; q; q = q->next) + if (q->client == client) + return TRUE; + return FALSE; +} + +/* + * Generic Callback Manager + */ + +/* ===== Private Procedures ===== */ + +static int numCallbackListsToCleanup = 0; +static CallbackListPtr **listsToCleanup = NULL; + +static Bool +_AddCallback( + CallbackListPtr *pcbl, + CallbackProcPtr callback, + pointer data) +{ + CallbackPtr cbr; + + cbr = malloc(sizeof(CallbackRec)); + if (!cbr) + return FALSE; + cbr->proc = callback; + cbr->data = data; + cbr->next = (*pcbl)->list; + cbr->deleted = FALSE; + (*pcbl)->list = cbr; + return TRUE; +} + +static Bool +_DeleteCallback( + CallbackListPtr *pcbl, + CallbackProcPtr callback, + pointer data) +{ + CallbackListPtr cbl = *pcbl; + CallbackPtr cbr, pcbr; + + for (pcbr = NULL, cbr = cbl->list; + cbr != NULL; + pcbr = cbr, cbr = cbr->next) + { + if ((cbr->proc == callback) && (cbr->data == data)) + break; + } + if (cbr != NULL) + { + if (cbl->inCallback) + { + ++(cbl->numDeleted); + cbr->deleted = TRUE; + } + else + { + if (pcbr == NULL) + cbl->list = cbr->next; + else + pcbr->next = cbr->next; + free(cbr); + } + return TRUE; + } + return FALSE; +} + +void +_CallCallbacks( + CallbackListPtr *pcbl, + pointer call_data) +{ + CallbackListPtr cbl = *pcbl; + CallbackPtr cbr, pcbr; + + ++(cbl->inCallback); + for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) + { + (*(cbr->proc)) (pcbl, cbr->data, call_data); + } + --(cbl->inCallback); + + if (cbl->inCallback) return; + + /* Was the entire list marked for deletion? */ + + if (cbl->deleted) + { + DeleteCallbackList(pcbl); + return; + } + + /* Were some individual callbacks on the list marked for deletion? + * If so, do the deletions. + */ + + if (cbl->numDeleted) + { + for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; ) + { + if (cbr->deleted) + { + if (pcbr) + { + cbr = cbr->next; + free(pcbr->next); + pcbr->next = cbr; + } else + { + cbr = cbr->next; + free(cbl->list); + cbl->list = cbr; + } + cbl->numDeleted--; + } + else /* this one wasn't deleted */ + { + pcbr = cbr; + cbr = cbr->next; + } + } + } +} + +static void +_DeleteCallbackList( + CallbackListPtr *pcbl) +{ + CallbackListPtr cbl = *pcbl; + CallbackPtr cbr, nextcbr; + int i; + + if (cbl->inCallback) + { + cbl->deleted = TRUE; + return; + } + + for (i = 0; i < numCallbackListsToCleanup; i++) + { + if (listsToCleanup[i] == pcbl) + { + listsToCleanup[i] = NULL; + break; + } + } + + for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) + { + nextcbr = cbr->next; + free(cbr); + } + free(cbl); + *pcbl = NULL; +} + +static Bool +CreateCallbackList(CallbackListPtr *pcbl) +{ + CallbackListPtr cbl; + int i; + + if (!pcbl) return FALSE; + cbl = malloc(sizeof(CallbackListRec)); + if (!cbl) return FALSE; + cbl->inCallback = 0; + cbl->deleted = FALSE; + cbl->numDeleted = 0; + cbl->list = NULL; + *pcbl = cbl; + + for (i = 0; i < numCallbackListsToCleanup; i++) + { + if (!listsToCleanup[i]) + { + listsToCleanup[i] = pcbl; + return TRUE; + } + } + + listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup, + sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1)); + listsToCleanup[numCallbackListsToCleanup] = pcbl; + numCallbackListsToCleanup++; + return TRUE; +} + +/* ===== Public Procedures ===== */ + +Bool +AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + if (!pcbl) return FALSE; + if (!*pcbl) + { /* list hasn't been created yet; go create it */ + if (!CreateCallbackList(pcbl)) + return FALSE; + } + return _AddCallback(pcbl, callback, data); +} + +Bool +DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + if (!pcbl || !*pcbl) return FALSE; + return _DeleteCallback(pcbl, callback, data); +} + +void +DeleteCallbackList(CallbackListPtr *pcbl) +{ + if (!pcbl || !*pcbl) return; + _DeleteCallbackList(pcbl); +} + +void +InitCallbackManager(void) +{ + int i; + + for (i = 0; i < numCallbackListsToCleanup; i++) + { + DeleteCallbackList(listsToCleanup[i]); + } + free(listsToCleanup); + + numCallbackListsToCleanup = 0; + listsToCleanup = NULL; +} diff --git a/xorg-server/dix/getevents.c b/xorg-server/dix/getevents.c index c935c971c..a12462a4a 100644 --- a/xorg-server/dix/getevents.c +++ b/xorg-server/dix/getevents.c @@ -320,6 +320,8 @@ updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) * position of the pointer */ pDev->last.valuators[0] = master->last.valuators[0]; pDev->last.valuators[1] = master->last.valuators[1]; + pDev->last.remainder[0] = master->last.remainder[0]; + pDev->last.remainder[1] = master->last.remainder[1]; if (!pDev->valuator) return; @@ -339,14 +341,19 @@ updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) if ((lastSlave = master->last.slave) && lastSlave->valuator) { for (i = 2; i < pDev->valuator->numAxes; i++) { if (i >= lastSlave->valuator->numAxes) + { pDev->last.valuators[i] = 0; + pDev->last.remainder[i] = 0; + } else + { pDev->last.valuators[i] = rescaleValuatorAxis(pDev->last.valuators[i], pDev->last.remainder[i], &pDev->last.remainder[i], lastSlave->valuator->axes + i, pDev->valuator->axes + i, 0); + } } } @@ -1164,14 +1171,17 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); - raw = &events->raw_event; - events++; - num_events++; - valuator_mask_copy(&mask, mask_in); - init_raw(pDev, raw, ms, type, buttons); - set_raw_valuators(raw, &mask, raw->valuators.data_raw); + if ((flags & POINTER_NORAW) == 0) + { + raw = &events->raw_event; + events++; + num_events++; + + init_raw(pDev, raw, ms, type, buttons); + set_raw_valuators(raw, &mask, raw->valuators.data_raw); + } if (flags & POINTER_ABSOLUTE) { @@ -1210,7 +1220,8 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons moveRelative(pDev, &x, &y, &mask); } - set_raw_valuators(raw, &mask, raw->valuators.data); + if ((flags & POINTER_NORAW) == 0) + set_raw_valuators(raw, &mask, raw->valuators.data); positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac); diff --git a/xorg-server/dix/grabs.c b/xorg-server/dix/grabs.c index a14181108..85ca9eee0 100644 --- a/xorg-server/dix/grabs.c +++ b/xorg-server/dix/grabs.c @@ -1,557 +1,669 @@ -/*
-
-Copyright 1987, 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.
-
-
-Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-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 Digital not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-DIGITAL 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 <X11/X.h>
-#include "misc.h"
-#include <X11/Xproto.h>
-#include <X11/extensions/XI2.h>
-#include "windowstr.h"
-#include "inputstr.h"
-#include "cursorstr.h"
-#include "dixgrabs.h"
-#include "xace.h"
-#include "exevents.h"
-
-#define BITMASK(i) (((Mask)1) << ((i) & 31))
-#define MASKIDX(i) ((i) >> 5)
-#define MASKWORD(buf, i) buf[MASKIDX(i)]
-#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
-#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
-#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
-
-GrabPtr
-CreateGrab(
- int client,
- DeviceIntPtr device,
- DeviceIntPtr modDevice,
- WindowPtr window,
- GrabType grabtype,
- GrabMask *mask,
- GrabParameters *param,
- int type,
- KeyCode keybut, /* key or button */
- WindowPtr confineTo,
- CursorPtr cursor)
-{
- GrabPtr grab;
-
- grab = calloc(1, sizeof(GrabRec));
- if (!grab)
- return (GrabPtr)NULL;
- grab->resource = FakeClientID(client);
- grab->device = device;
- grab->window = window;
- grab->eventMask = mask->core; /* same for XI */
- grab->deviceMask = 0;
- grab->ownerEvents = param->ownerEvents;
- grab->keyboardMode = param->this_device_mode;
- grab->pointerMode = param->other_devices_mode;
- grab->modifiersDetail.exact = param->modifiers;
- grab->modifiersDetail.pMask = NULL;
- grab->modifierDevice = modDevice;
- grab->type = type;
- grab->grabtype = grabtype;
- grab->detail.exact = keybut;
- grab->detail.pMask = NULL;
- grab->confineTo = confineTo;
- grab->cursor = cursor;
- grab->next = NULL;
-
- if (grabtype == GRABTYPE_XI2)
- memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask));
- if (cursor)
- cursor->refcnt++;
- return grab;
-
-}
-
-static void
-FreeGrab(GrabPtr pGrab)
-{
- free(pGrab->modifiersDetail.pMask);
- free(pGrab->detail.pMask);
-
- if (pGrab->cursor)
- FreeCursor(pGrab->cursor, (Cursor)0);
-
- free(pGrab);
-}
-
-int
-DeletePassiveGrab(pointer value, XID id)
-{
- GrabPtr g, prev;
- GrabPtr pGrab = (GrabPtr)value;
-
- /* it is OK if the grab isn't found */
- prev = 0;
- for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
- {
- if (pGrab == g)
- {
- if (prev)
- prev->next = g->next;
- else
- if (!(pGrab->window->optional->passiveGrabs = g->next))
- CheckWindowOptionalNeed (pGrab->window);
- break;
- }
- prev = g;
- }
- FreeGrab(pGrab);
- return Success;
-}
-
-static Mask *
-DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
-{
- Mask *mask;
- int i;
-
- mask = malloc(sizeof(Mask) * MasksPerDetailMask);
- if (mask)
- {
- if (pDetailMask)
- for (i = 0; i < MasksPerDetailMask; i++)
- mask[i]= pDetailMask[i];
- else
- for (i = 0; i < MasksPerDetailMask; i++)
- mask[i]= ~0L;
- BITCLEAR(mask, detail);
- }
- return mask;
-}
-
-static Bool
-IsInGrabMask(
- DetailRec firstDetail,
- DetailRec secondDetail,
- unsigned int exception)
-{
- if (firstDetail.exact == exception)
- {
- if (firstDetail.pMask == NULL)
- return TRUE;
-
- /* (at present) never called with two non-null pMasks */
- if (secondDetail.exact == exception)
- return FALSE;
-
- if (GETBIT(firstDetail.pMask, secondDetail.exact))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static Bool
-IdenticalExactDetails(
- unsigned int firstExact,
- unsigned int secondExact,
- unsigned int exception)
-{
- if ((firstExact == exception) || (secondExact == exception))
- return FALSE;
-
- if (firstExact == secondExact)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool
-DetailSupersedesSecond(
- DetailRec firstDetail,
- DetailRec secondDetail,
- unsigned int exception)
-{
- if (IsInGrabMask(firstDetail, secondDetail, exception))
- return TRUE;
-
- if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
- exception))
- return TRUE;
-
- return FALSE;
-}
-
-static Bool
-GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
-{
- unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier :
- (unsigned int)AnyModifier;
- if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
- pSecondGrab->modifiersDetail,
- any_modifier))
- return FALSE;
-
- if (DetailSupersedesSecond(pFirstGrab->detail,
- pSecondGrab->detail, (unsigned int)AnyKey))
- return TRUE;
-
- return FALSE;
-}
-
-/**
- * Compares two grabs and returns TRUE if the first grab matches the second
- * grab.
- *
- * A match is when
- * - the devices set for the grab are equal (this is optional).
- * - the event types for both grabs are equal.
- * - XXX
- *
- * @param ignoreDevice TRUE if the device settings on the grabs are to be
- * ignored.
- * @return TRUE if the grabs match or FALSE otherwise.
- */
-Bool
-GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
-{
- unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier :
- (unsigned int)AnyModifier;
-
- if (pFirstGrab->grabtype != pSecondGrab->grabtype)
- return FALSE;
-
- if (pFirstGrab->grabtype == GRABTYPE_XI2)
- {
- if (pFirstGrab->device == inputInfo.all_devices ||
- pSecondGrab->device == inputInfo.all_devices)
- {
- /* do nothing */
- } else if (pFirstGrab->device == inputInfo.all_master_devices)
- {
- if (pSecondGrab->device != inputInfo.all_master_devices &&
- !IsMaster(pSecondGrab->device))
- return FALSE;
- } else if (pSecondGrab->device == inputInfo.all_master_devices)
- {
- if (pFirstGrab->device != inputInfo.all_master_devices &&
- !IsMaster(pFirstGrab->device))
- return FALSE;
- } else if (pSecondGrab->device != pFirstGrab->device)
- return FALSE;
- } else if (!ignoreDevice &&
- ((pFirstGrab->device != pSecondGrab->device) ||
- (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
- return FALSE;
-
- if (pFirstGrab->type != pSecondGrab->type)
- return FALSE;
-
- if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
- GrabSupersedesSecond(pSecondGrab, pFirstGrab))
- return TRUE;
-
- if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
- (unsigned int)AnyKey)
- &&
- DetailSupersedesSecond(pFirstGrab->modifiersDetail,
- pSecondGrab->modifiersDetail,
- any_modifier))
- return TRUE;
-
- if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
- (unsigned int)AnyKey)
- &&
- DetailSupersedesSecond(pSecondGrab->modifiersDetail,
- pFirstGrab->modifiersDetail,
- any_modifier))
- return TRUE;
-
- return FALSE;
-}
-
-static Bool
-GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
-{
- unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier :
- (unsigned int)AnyModifier;
-
- if (pFirstGrab->grabtype != pSecondGrab->grabtype)
- return FALSE;
-
- if (pFirstGrab->device != pSecondGrab->device ||
- (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
- (pFirstGrab->type != pSecondGrab->type))
- return FALSE;
-
- if (!(DetailSupersedesSecond(pFirstGrab->detail,
- pSecondGrab->detail,
- (unsigned int)AnyKey) &&
- DetailSupersedesSecond(pSecondGrab->detail,
- pFirstGrab->detail,
- (unsigned int)AnyKey)))
- return FALSE;
-
-
- if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
- pSecondGrab->modifiersDetail,
- any_modifier) &&
- DetailSupersedesSecond(pSecondGrab->modifiersDetail,
- pFirstGrab->modifiersDetail,
- any_modifier)))
- return FALSE;
-
- return TRUE;
-}
-
-
-/**
- * Prepend the new grab to the list of passive grabs on the window.
- * Any previously existing grab that matches the new grab will be removed.
- * Adding a new grab that would override another client's grab will result in
- * a BadAccess.
- *
- * @return Success or X error code on failure.
- */
-int
-AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
-{
- GrabPtr grab;
- Mask access_mode = DixGrabAccess;
- int rc;
-
- for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
- {
- if (GrabMatchesSecond(pGrab, grab, FALSE))
- {
- if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
- {
- FreeGrab(pGrab);
- return BadAccess;
- }
- }
- }
-
- if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync)
- access_mode |= DixFreezeAccess;
- rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
- if (rc != Success)
- return rc;
-
- /* Remove all grabs that match the new one exactly */
- for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
- {
- if (GrabsAreIdentical(pGrab, grab))
- {
- DeletePassiveGrabFromList(grab);
- break;
- }
- }
-
- if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
- {
- FreeGrab(pGrab);
- return BadAlloc;
- }
-
- pGrab->next = pGrab->window->optional->passiveGrabs;
- pGrab->window->optional->passiveGrabs = pGrab;
- if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
- return Success;
- return BadAlloc;
-}
-
-/* the following is kinda complicated, because we need to be able to back out
- * if any allocation fails
- */
-
-Bool
-DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
-{
- GrabPtr grab;
- GrabPtr *deletes, *adds;
- Mask ***updates, **details;
- int i, ndels, nadds, nups;
- Bool ok;
- unsigned int any_modifier;
- unsigned int any_key;
-
-#define UPDATE(mask,exact) \
- if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
- ok = FALSE; \
- else \
- updates[nups++] = &(mask)
-
- i = 0;
- for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
- i++;
- if (!i)
- return TRUE;
- deletes = malloc(i * sizeof(GrabPtr));
- adds = malloc(i * sizeof(GrabPtr));
- updates = malloc(i * sizeof(Mask **));
- details = malloc(i * sizeof(Mask *));
- if (!deletes || !adds || !updates || !details)
- {
- free(details);
- free(updates);
- free(adds);
- free(deletes);
- return FALSE;
- }
-
- any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier : (unsigned int)AnyModifier;
- any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyKeycode : (unsigned int)AnyKey;
- ndels = nadds = nups = 0;
- ok = TRUE;
- for (grab = wPassiveGrabs(pMinuendGrab->window);
- grab && ok;
- grab = grab->next)
- {
- if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
- !GrabMatchesSecond(grab, pMinuendGrab,
- (grab->grabtype == GRABTYPE_CORE)))
- continue;
- if (GrabSupersedesSecond(pMinuendGrab, grab))
- {
- deletes[ndels++] = grab;
- }
- else if ((grab->detail.exact == any_key)
- && (grab->modifiersDetail.exact != any_modifier))
- {
- UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
- }
- else if ((grab->modifiersDetail.exact == any_modifier)
- && (grab->detail.exact != any_key))
- {
- UPDATE(grab->modifiersDetail.pMask,
- pMinuendGrab->modifiersDetail.exact);
- }
- else if ((pMinuendGrab->detail.exact != any_key)
- && (pMinuendGrab->modifiersDetail.exact != any_modifier))
- {
- GrabPtr pNewGrab;
- GrabParameters param;
-
- UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
-
- memset(¶m, 0, sizeof(param));
- param.ownerEvents = grab->ownerEvents;
- param.this_device_mode = grab->keyboardMode;
- param.other_devices_mode = grab->pointerMode;
- param.modifiers = any_modifier;
-
- pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
- grab->modifierDevice, grab->window,
- grab->grabtype,
- (GrabMask*)&grab->eventMask,
- ¶m, (int)grab->type,
- pMinuendGrab->detail.exact,
- grab->confineTo, grab->cursor);
- if (!pNewGrab)
- ok = FALSE;
- else if (!(pNewGrab->modifiersDetail.pMask =
- DeleteDetailFromMask(grab->modifiersDetail.pMask,
- pMinuendGrab->modifiersDetail.exact))
- ||
- (!pNewGrab->window->optional &&
- !MakeWindowOptional(pNewGrab->window)))
- {
- FreeGrab(pNewGrab);
- ok = FALSE;
- }
- else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
- (pointer)pNewGrab))
- ok = FALSE;
- else
- adds[nadds++] = pNewGrab;
- }
- else if (pMinuendGrab->detail.exact == any_key)
- {
- UPDATE(grab->modifiersDetail.pMask,
- pMinuendGrab->modifiersDetail.exact);
- }
- else
- {
- UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
- }
- }
-
- if (!ok)
- {
- for (i = 0; i < nadds; i++)
- FreeResource(adds[i]->resource, RT_NONE);
- for (i = 0; i < nups; i++)
- free(details[i]);
- }
- else
- {
- for (i = 0; i < ndels; i++)
- FreeResource(deletes[i]->resource, RT_NONE);
- for (i = 0; i < nadds; i++)
- {
- grab = adds[i];
- grab->next = grab->window->optional->passiveGrabs;
- grab->window->optional->passiveGrabs = grab;
- }
- for (i = 0; i < nups; i++)
- {
- free(*updates[i]);
- *updates[i] = details[i];
- }
- }
- free(details);
- free(updates);
- free(adds);
- free(deletes);
- return ok;
-
-#undef UPDATE
-}
+/* + +Copyright 1987, 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. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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 <X11/X.h> +#include "misc.h" +#include <X11/Xproto.h> +#include <X11/extensions/XI2.h> +#include "windowstr.h" +#include "inputstr.h" +#include "cursorstr.h" +#include "dixgrabs.h" +#include "xace.h" +#include "exevents.h" + +#define BITMASK(i) (((Mask)1) << ((i) & 31)) +#define MASKIDX(i) ((i) >> 5) +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) + +void +PrintDeviceGrabInfo(DeviceIntPtr dev) +{ + ClientPtr client; + LocalClientCredRec *lcc; + int i, j; + GrabInfoPtr devGrab = &dev->deviceGrab; + GrabPtr grab = devGrab->grab; + + ErrorF("Active grab 0x%lx (%s) on device '%s' (%d):", + (unsigned long) grab->resource, + (grab->grabtype == GRABTYPE_XI2) ? "xi2" : + ((grab->grabtype == GRABTYPE_CORE) ? "core" : "xi1"), + dev->name, dev->id); + + client = clients[CLIENT_ID(grab->resource)]; + if (client && GetLocalClientCreds(client, &lcc) != -1) + { + ErrorF(" client pid %ld uid %ld gid %ld\n", + (lcc->fieldsSet & LCC_PID_SET) ? (long) lcc->pid : 0, + (lcc->fieldsSet & LCC_UID_SET) ? (long) lcc->euid : 0, + (lcc->fieldsSet & LCC_GID_SET) ? (long) lcc->egid : 0); + FreeLocalClientCreds(lcc); + } + else + { + ErrorF(" (no client information available)\n"); + } + + /* XXX is this even correct? */ + if (devGrab->sync.other) + ErrorF(" grab ID 0x%lx from paired device\n", + (unsigned long) devGrab->sync.other->resource); + + ErrorF(" at %ld (from %s grab)%s (device %s, state %d)\n", + (unsigned long) devGrab->grabTime.milliseconds, + devGrab->fromPassiveGrab ? "passive" : "active", + devGrab->implicitGrab ? " (implicit)" : "", + devGrab->sync.frozen ? "frozen" : "thawed", + devGrab->sync.state); + + if (grab->grabtype == GRABTYPE_CORE) + { + ErrorF(" core event mask 0x%lx\n", + (unsigned long) grab->eventMask); + } + else if (grab->grabtype == GRABTYPE_XI) + { + ErrorF(" xi1 event mask 0x%lx\n", + devGrab->implicitGrab ? (unsigned long) grab->deviceMask : + (unsigned long) grab->eventMask); + } + else if (grab->grabtype == GRABTYPE_XI2) + { + for (i = 0; i < EMASKSIZE; i++) + { + int print; + print = 0; + for (j = 0; j < XI2MASKSIZE; j++) + { + if (grab->xi2mask[i][j]) + { + print = 1; + break; + } + } + if (!print) + continue; + ErrorF(" xi2 event mask for device %d: 0x", dev->id); + for (j = 0; j < XI2MASKSIZE; j++) + ErrorF("%x", grab->xi2mask[i][j]); + ErrorF("\n"); + } + } + + if (devGrab->fromPassiveGrab) + { + ErrorF(" passive grab type %d, detail 0x%x, " + "activating key %d\n", grab->type, grab->detail.exact, + devGrab->activatingKey); + } + + ErrorF(" owner-events %s, kb %d ptr %d, confine %lx, cursor 0x%lx\n", + grab->ownerEvents ? "true" : "false", + grab->keyboardMode, grab->pointerMode, + grab->confineTo ? (unsigned long) grab->confineTo->drawable.id : 0, + grab->cursor ? (unsigned long) grab->cursor->id : 0); +} + +void +UngrabAllDevices(Bool kill_client) +{ + DeviceIntPtr dev; + ClientPtr client; + + ErrorF("Ungrabbing all devices%s; grabs listed below:\n", + kill_client ? " and killing their owners" : ""); + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->deviceGrab.grab) + continue; + PrintDeviceGrabInfo(dev); + client = clients[CLIENT_ID(dev->deviceGrab.grab->resource)]; + if (!client || client->clientGone) + dev->deviceGrab.DeactivateGrab(dev); + CloseDownClient(client); + } + + ErrorF("End list of ungrabbed devices\n"); +} + +GrabPtr +CreateGrab( + int client, + DeviceIntPtr device, + DeviceIntPtr modDevice, + WindowPtr window, + GrabType grabtype, + GrabMask *mask, + GrabParameters *param, + int type, + KeyCode keybut, /* key or button */ + WindowPtr confineTo, + CursorPtr cursor) +{ + GrabPtr grab; + + grab = calloc(1, sizeof(GrabRec)); + if (!grab) + return (GrabPtr)NULL; + grab->resource = FakeClientID(client); + grab->device = device; + grab->window = window; + grab->eventMask = mask->core; /* same for XI */ + grab->deviceMask = 0; + grab->ownerEvents = param->ownerEvents; + grab->keyboardMode = param->this_device_mode; + grab->pointerMode = param->other_devices_mode; + grab->modifiersDetail.exact = param->modifiers; + grab->modifiersDetail.pMask = NULL; + grab->modifierDevice = modDevice; + grab->type = type; + grab->grabtype = grabtype; + grab->detail.exact = keybut; + grab->detail.pMask = NULL; + grab->confineTo = confineTo; + grab->cursor = cursor; + grab->next = NULL; + + if (grabtype == GRABTYPE_XI2) + memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask)); + if (cursor) + cursor->refcnt++; + return grab; + +} + +static void +FreeGrab(GrabPtr pGrab) +{ + free(pGrab->modifiersDetail.pMask); + free(pGrab->detail.pMask); + + if (pGrab->cursor) + FreeCursor(pGrab->cursor, (Cursor)0); + + free(pGrab); +} + +int +DeletePassiveGrab(pointer value, XID id) +{ + GrabPtr g, prev; + GrabPtr pGrab = (GrabPtr)value; + + /* it is OK if the grab isn't found */ + prev = 0; + for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next) + { + if (pGrab == g) + { + if (prev) + prev->next = g->next; + else + if (!(pGrab->window->optional->passiveGrabs = g->next)) + CheckWindowOptionalNeed (pGrab->window); + break; + } + prev = g; + } + FreeGrab(pGrab); + return Success; +} + +static Mask * +DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail) +{ + Mask *mask; + int i; + + mask = malloc(sizeof(Mask) * MasksPerDetailMask); + if (mask) + { + if (pDetailMask) + for (i = 0; i < MasksPerDetailMask; i++) + mask[i]= pDetailMask[i]; + else + for (i = 0; i < MasksPerDetailMask; i++) + mask[i]= ~0L; + BITCLEAR(mask, detail); + } + return mask; +} + +static Bool +IsInGrabMask( + DetailRec firstDetail, + DetailRec secondDetail, + unsigned int exception) +{ + if (firstDetail.exact == exception) + { + if (firstDetail.pMask == NULL) + return TRUE; + + /* (at present) never called with two non-null pMasks */ + if (secondDetail.exact == exception) + return FALSE; + + if (GETBIT(firstDetail.pMask, secondDetail.exact)) + return TRUE; + } + + return FALSE; +} + +static Bool +IdenticalExactDetails( + unsigned int firstExact, + unsigned int secondExact, + unsigned int exception) +{ + if ((firstExact == exception) || (secondExact == exception)) + return FALSE; + + if (firstExact == secondExact) + return TRUE; + + return FALSE; +} + +static Bool +DetailSupersedesSecond( + DetailRec firstDetail, + DetailRec secondDetail, + unsigned int exception) +{ + if (IsInGrabMask(firstDetail, secondDetail, exception)) + return TRUE; + + if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, + exception)) + return TRUE; + + return FALSE; +} + +static Bool +GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier)) + return FALSE; + + if (DetailSupersedesSecond(pFirstGrab->detail, + pSecondGrab->detail, (unsigned int)AnyKey)) + return TRUE; + + return FALSE; +} + +/** + * Compares two grabs and returns TRUE if the first grab matches the second + * grab. + * + * A match is when + * - the devices set for the grab are equal (this is optional). + * - the event types for both grabs are equal. + * - XXX + * + * @param ignoreDevice TRUE if the device settings on the grabs are to be + * ignored. + * @return TRUE if the grabs match or FALSE otherwise. + */ +Bool +GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; + + if (pFirstGrab->grabtype == GRABTYPE_XI2) + { + if (pFirstGrab->device == inputInfo.all_devices || + pSecondGrab->device == inputInfo.all_devices) + { + /* do nothing */ + } else if (pFirstGrab->device == inputInfo.all_master_devices) + { + if (pSecondGrab->device != inputInfo.all_master_devices && + !IsMaster(pSecondGrab->device)) + return FALSE; + } else if (pSecondGrab->device == inputInfo.all_master_devices) + { + if (pFirstGrab->device != inputInfo.all_master_devices && + !IsMaster(pFirstGrab->device)) + return FALSE; + } else if (pSecondGrab->device != pFirstGrab->device) + return FALSE; + } else if (!ignoreDevice && + ((pFirstGrab->device != pSecondGrab->device) || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) + return FALSE; + + if (pFirstGrab->type != pSecondGrab->type) + return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || + GrabSupersedesSecond(pSecondGrab, pFirstGrab)) + return TRUE; + + if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, + (unsigned int)AnyKey) + && + DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier)) + return TRUE; + + if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, + (unsigned int)AnyKey) + && + DetailSupersedesSecond(pSecondGrab->modifiersDetail, + pFirstGrab->modifiersDetail, + any_modifier)) + return TRUE; + + return FALSE; +} + +static Bool +GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; + + if (pFirstGrab->device != pSecondGrab->device || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || + (pFirstGrab->type != pSecondGrab->type)) + return FALSE; + + if (!(DetailSupersedesSecond(pFirstGrab->detail, + pSecondGrab->detail, + (unsigned int)AnyKey) && + DetailSupersedesSecond(pSecondGrab->detail, + pFirstGrab->detail, + (unsigned int)AnyKey))) + return FALSE; + + + if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier) && + DetailSupersedesSecond(pSecondGrab->modifiersDetail, + pFirstGrab->modifiersDetail, + any_modifier))) + return FALSE; + + return TRUE; +} + + +/** + * Prepend the new grab to the list of passive grabs on the window. + * Any previously existing grab that matches the new grab will be removed. + * Adding a new grab that would override another client's grab will result in + * a BadAccess. + * + * @return Success or X error code on failure. + */ +int +AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) +{ + GrabPtr grab; + Mask access_mode = DixGrabAccess; + int rc; + + for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) + { + if (GrabMatchesSecond(pGrab, grab, FALSE)) + { + if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) + { + FreeGrab(pGrab); + return BadAccess; + } + } + } + + if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); + if (rc != Success) + return rc; + + /* Remove all grabs that match the new one exactly */ + for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) + { + if (GrabsAreIdentical(pGrab, grab)) + { + DeletePassiveGrabFromList(grab); + break; + } + } + + if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window)) + { + FreeGrab(pGrab); + return BadAlloc; + } + + pGrab->next = pGrab->window->optional->passiveGrabs; + pGrab->window->optional->passiveGrabs = pGrab; + if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab)) + return Success; + return BadAlloc; +} + +/* the following is kinda complicated, because we need to be able to back out + * if any allocation fails + */ + +Bool +DeletePassiveGrabFromList(GrabPtr pMinuendGrab) +{ + GrabPtr grab; + GrabPtr *deletes, *adds; + Mask ***updates, **details; + int i, ndels, nadds, nups; + Bool ok; + unsigned int any_modifier; + unsigned int any_key; + +#define UPDATE(mask,exact) \ + if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \ + ok = FALSE; \ + else \ + updates[nups++] = &(mask) + + i = 0; + for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next) + i++; + if (!i) + return TRUE; + deletes = malloc(i * sizeof(GrabPtr)); + adds = malloc(i * sizeof(GrabPtr)); + updates = malloc(i * sizeof(Mask **)); + details = malloc(i * sizeof(Mask *)); + if (!deletes || !adds || !updates || !details) + { + free(details); + free(updates); + free(adds); + free(deletes); + return FALSE; + } + + any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : (unsigned int)AnyModifier; + any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyKeycode : (unsigned int)AnyKey; + ndels = nadds = nups = 0; + ok = TRUE; + for (grab = wPassiveGrabs(pMinuendGrab->window); + grab && ok; + grab = grab->next) + { + if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) || + !GrabMatchesSecond(grab, pMinuendGrab, + (grab->grabtype == GRABTYPE_CORE))) + continue; + if (GrabSupersedesSecond(pMinuendGrab, grab)) + { + deletes[ndels++] = grab; + } + else if ((grab->detail.exact == any_key) + && (grab->modifiersDetail.exact != any_modifier)) + { + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + } + else if ((grab->modifiersDetail.exact == any_modifier) + && (grab->detail.exact != any_key)) + { + UPDATE(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact); + } + else if ((pMinuendGrab->detail.exact != any_key) + && (pMinuendGrab->modifiersDetail.exact != any_modifier)) + { + GrabPtr pNewGrab; + GrabParameters param; + + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + + memset(¶m, 0, sizeof(param)); + param.ownerEvents = grab->ownerEvents; + param.this_device_mode = grab->keyboardMode; + param.other_devices_mode = grab->pointerMode; + param.modifiers = any_modifier; + + pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, + grab->modifierDevice, grab->window, + grab->grabtype, + (GrabMask*)&grab->eventMask, + ¶m, (int)grab->type, + pMinuendGrab->detail.exact, + grab->confineTo, grab->cursor); + if (!pNewGrab) + ok = FALSE; + else if (!(pNewGrab->modifiersDetail.pMask = + DeleteDetailFromMask(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact)) + || + (!pNewGrab->window->optional && + !MakeWindowOptional(pNewGrab->window))) + { + FreeGrab(pNewGrab); + ok = FALSE; + } + else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB, + (pointer)pNewGrab)) + ok = FALSE; + else + adds[nadds++] = pNewGrab; + } + else if (pMinuendGrab->detail.exact == any_key) + { + UPDATE(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact); + } + else + { + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + } + } + + if (!ok) + { + for (i = 0; i < nadds; i++) + FreeResource(adds[i]->resource, RT_NONE); + for (i = 0; i < nups; i++) + free(details[i]); + } + else + { + for (i = 0; i < ndels; i++) + FreeResource(deletes[i]->resource, RT_NONE); + for (i = 0; i < nadds; i++) + { + grab = adds[i]; + grab->next = grab->window->optional->passiveGrabs; + grab->window->optional->passiveGrabs = grab; + } + for (i = 0; i < nups; i++) + { + free(*updates[i]); + *updates[i] = details[i]; + } + } + free(details); + free(updates); + free(adds); + free(deletes); + return ok; + +#undef UPDATE +} diff --git a/xorg-server/dix/window.c b/xorg-server/dix/window.c index 5defe5849..556509ac3 100644 --- a/xorg-server/dix/window.c +++ b/xorg-server/dix/window.c @@ -108,6 +108,7 @@ Equipment Corporation. #include "regionstr.h" #include "validate.h" #include "windowstr.h" +#include "propertyst.h" #include "input.h" #include "inputstr.h" #include "resource.h" @@ -124,10 +125,13 @@ Equipment Corporation. #include "dixevents.h" #include "globals.h" #include "mi.h" /* miPaintWindow */ +#include "compint.h" #include "privates.h" #include "xace.h" +#include <X11/Xatom.h> /* must come after server includes */ + /****** * Window stuff for server * @@ -176,46 +180,129 @@ static Bool TileScreenSaver(ScreenPtr pScreen, int kind); #define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) -#ifdef DEBUG -/****** - * PrintWindowTree - * For debugging only - ******/ +static const char *overlay_win_name = "<composite overlay>"; -static void -PrintChildren(WindowPtr p1, int indent) +static const char * +get_window_name(WindowPtr pWin) { - WindowPtr p2; - int i; +#define WINDOW_NAME_BUF_LEN 512 + PropertyPtr prop; + CompScreenPtr comp_screen = GetCompScreen(pWin->drawable.pScreen); + static char buf[WINDOW_NAME_BUF_LEN]; + int len; + + if (comp_screen && pWin == comp_screen->pOverlayWin) + return overlay_win_name; - while (p1) + for (prop = wUserProps(pWin); prop; prop = prop->next) { - p2 = p1->firstChild; - ErrorF("[dix] "); - for (i=0; i<indent; i++) ErrorF(" "); - ErrorF("%lx\n", p1->drawable.id); - RegionPrint(&p1->clipList); - PrintChildren(p2, indent+4); - p1 = p1->nextSib; + if (prop->propertyName == XA_WM_NAME && prop->type == XA_STRING && + prop->data) + { + len = min(prop->size, WINDOW_NAME_BUF_LEN - 1); + memcpy(buf, prop->data, len); + buf[len] = '\0'; + return buf; + } } + + return NULL; +#undef WINDOW_NAME_BUF_LEN } -static void -PrintWindowTree(void) +static void log_window_info(WindowPtr pWin, int depth) { int i; - WindowPtr pWin, p1; + const char *win_name, *visibility; + BoxPtr rects; + ScreenPtr pScreen = pWin->drawable.pScreen; + + for (i = 0; i < (depth << 2); i++) + ErrorF(" "); + + win_name = get_window_name(pWin); + ErrorF("win 0x%.8x (%s), [%d, %d] to [%d, %d]", + pWin->drawable.id, + win_name ? win_name : "no name", + pWin->drawable.x, pWin->drawable.y, + pWin->drawable.x + pWin->drawable.width, + pWin->drawable.y + pWin->drawable.height); + + if (pWin->overrideRedirect) + ErrorF(" (override redirect)"); + if (pWin->redirectDraw) + ErrorF(" (%s compositing: pixmap %x)", + (pWin->redirectDraw == RedirectDrawAutomatic) ? + "automatic" : "manual", + pScreen->GetWindowPixmap(pWin)->drawable.id); + + switch (pWin->visibility) + { + case VisibilityUnobscured: + visibility = "unobscured"; + break; + case VisibilityPartiallyObscured: + visibility = "partially obscured"; + break; + case VisibilityFullyObscured: + visibility = "fully obscured"; + break; + case VisibilityNotViewable: + visibility = "unviewable"; + break; + } + ErrorF(", %s", visibility); + + if (REGION_NOTEMPTY(pScreen, &pWin->clipList)) + { + ErrorF(", clip list:"); + rects = REGION_RECTS(&pWin->clipList); + for (i = 0; i < REGION_NUM_RECTS(&pWin->clipList); i++) + ErrorF(" [(%d, %d) to (%d, %d)]", + rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2); + ErrorF("; extents [(%d, %d) to (%d, %d)]", + pWin->clipList.extents.x1, pWin->clipList.extents.y1, + pWin->clipList.extents.x2, pWin->clipList.extents.y2); + } + + ErrorF("\n"); +} + +void +PrintWindowTree(void) +{ + int scrnum, depth; + ScreenPtr pScreen; + WindowPtr pWin; - for (i=0; i<screenInfo.numScreens; i++) + for (scrnum = 0; scrnum < screenInfo.numScreens; scrnum++) { - ErrorF("[dix] WINDOW %d\n", i); - pWin = screenInfo.screens[i]->root; - RegionPrint(&pWin->clipList); - p1 = pWin->firstChild; - PrintChildren(p1, 4); + pScreen = screenInfo.screens[scrnum]; + ErrorF("[dix] Dumping windows for screen %d (pixmap %x):\n", scrnum, + pScreen->GetScreenPixmap(pScreen)->drawable.id); + pWin = pScreen->root; + depth = 1; + while (pWin) + { + log_window_info(pWin, depth); + if (pWin->firstChild) + { + pWin = pWin->firstChild; + depth++; + continue; + } + while (pWin && !pWin->nextSib) + { + pWin = pWin->parent; + depth--; + } + if (!pWin) + break; + pWin = pWin->nextSib; + } } } -#endif int TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data) diff --git a/xorg-server/exa/exa.c b/xorg-server/exa/exa.c index a4e294a71..4ce983bc3 100644 --- a/xorg-server/exa/exa.c +++ b/xorg-server/exa/exa.c @@ -1,7 +1,7 @@ /* - * Copyright © 2001 Keith Packard + * Copyright © 2001 Keith Packard * - * Partly based on code that is Copyright © The XFree86 Project Inc. + * Partly based on code that is Copyright © The XFree86 Project Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that diff --git a/xorg-server/exa/exa_accel.c b/xorg-server/exa/exa_accel.c index 9192f7e74..5600539d6 100644 --- a/xorg-server/exa/exa_accel.c +++ b/xorg-server/exa/exa_accel.c @@ -1,1306 +1,1306 @@ -/*
- * Copyright © 2001 Keith Packard
- *
- * Partly based on code that is Copyright © The XFree86 Project 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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.
- *
- * Authors:
- * Eric Anholt <eric@anholt.net>
- * Michel Dänzer <michel@tungstengraphics.com>
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-#include "exa_priv.h"
-#include <X11/fonts/fontstruct.h>
-#include "dixfontstr.h"
-#include "exa.h"
-
-static void
-exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
- DDXPointPtr ppt, int *pwidth, int fSorted)
-{
- ScreenPtr pScreen = pDrawable->pScreen;
- ExaScreenPriv (pScreen);
- RegionPtr pClip = fbGetCompositeClip(pGC);
- PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv (pPixmap);
- BoxPtr pextent, pbox;
- int nbox;
- int extentX1, extentX2, extentY1, extentY2;
- int fullX1, fullX2, fullY1;
- int partX1, partX2;
- int off_x, off_y;
-
- if (pExaScr->fallback_counter ||
- pExaScr->swappedOut ||
- pGC->fillStyle != FillSolid ||
- pExaPixmap->accel_blocked)
- {
- ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
- return;
- }
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = NULL;
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
- !(*pExaScr->info->PrepareSolid) (pPixmap,
- pGC->alu,
- pGC->planemask,
- pGC->fgPixel))
- {
- ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
- return;
- }
-
- pextent = RegionExtents(pClip);
- extentX1 = pextent->x1;
- extentY1 = pextent->y1;
- extentX2 = pextent->x2;
- extentY2 = pextent->y2;
- while (n--)
- {
- fullX1 = ppt->x;
- fullY1 = ppt->y;
- fullX2 = fullX1 + (int) *pwidth;
- ppt++;
- pwidth++;
-
- if (fullY1 < extentY1 || extentY2 <= fullY1)
- continue;
-
- if (fullX1 < extentX1)
- fullX1 = extentX1;
-
- if (fullX2 > extentX2)
- fullX2 = extentX2;
-
- if (fullX1 >= fullX2)
- continue;
-
- nbox = RegionNumRects (pClip);
- if (nbox == 1)
- {
- (*pExaScr->info->Solid) (pPixmap,
- fullX1 + off_x, fullY1 + off_y,
- fullX2 + off_x, fullY1 + 1 + off_y);
- }
- else
- {
- pbox = RegionRects(pClip);
- while(nbox--)
- {
- if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
- {
- partX1 = pbox->x1;
- if (partX1 < fullX1)
- partX1 = fullX1;
- partX2 = pbox->x2;
- if (partX2 > fullX2)
- partX2 = fullX2;
- if (partX2 > partX1) {
- (*pExaScr->info->Solid) (pPixmap,
- partX1 + off_x, fullY1 + off_y,
- partX2 + off_x, fullY1 + 1 + off_y);
- }
- }
- pbox++;
- }
- }
- }
- (*pExaScr->info->DoneSolid) (pPixmap);
- exaMarkSync(pScreen);
-}
-
-static Bool
-exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
- int w, int h, int format, char *bits, int src_stride)
-{
- ExaScreenPriv (pDrawable->pScreen);
- PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv(pPix);
- RegionPtr pClip;
- BoxPtr pbox;
- int nbox;
- int xoff, yoff;
- int bpp = pDrawable->bitsPerPixel;
- Bool ret = TRUE;
-
- if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen)
- return FALSE;
-
- /* If there's a system copy, we want to save the result there */
- if (pExaPixmap->pDamage)
- return FALSE;
-
- /* Don't bother with under 8bpp, XYPixmaps. */
- if (format != ZPixmap || bpp < 8)
- return FALSE;
-
- /* Only accelerate copies: no rop or planemask. */
- if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
- return FALSE;
-
- if (pExaScr->swappedOut)
- return FALSE;
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPix;
- pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
- if (!pPix)
- return FALSE;
-
- x += pDrawable->x;
- y += pDrawable->y;
-
- pClip = fbGetCompositeClip(pGC);
- for (nbox = RegionNumRects(pClip),
- pbox = RegionRects(pClip);
- nbox--;
- pbox++)
- {
- int x1 = x;
- int y1 = y;
- int x2 = x + w;
- int y2 = y + h;
- char *src;
- Bool ok;
-
- if (x1 < pbox->x1)
- x1 = pbox->x1;
- if (y1 < pbox->y1)
- y1 = pbox->y1;
- if (x2 > pbox->x2)
- x2 = pbox->x2;
- if (y2 > pbox->y2)
- y2 = pbox->y2;
- if (x1 >= x2 || y1 >= y2)
- continue;
-
- src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
- ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
- x2 - x1, y2 - y1, src, src_stride);
- /* We have to fall back completely, and ignore what has already been completed.
- * Messing with the fb layer directly like we used to is completely unacceptable.
- */
- if (!ok) {
- ret = FALSE;
- break;
- }
- }
-
- if (ret)
- exaMarkSync(pDrawable->pScreen);
-
- return ret;
-}
-
-static void
-exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
- int w, int h, int leftPad, int format, char *bits)
-{
- if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
- PixmapBytePad(w, pDrawable->depth)))
- ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
- bits);
-}
-
-static Bool inline
-exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
- GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
-{
- ExaScreenPriv (pDstDrawable->pScreen);
- PixmapPtr pSrcPixmap, pDstPixmap;
- int src_off_x, src_off_y, dst_off_x, dst_off_y;
- int dirsetup;
-
- /* Need to get both pixmaps to call the driver routines */
- pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
- pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
- if (!pSrcPixmap || !pDstPixmap)
- return FALSE;
-
- /*
- * Now the case of a chip that only supports xdir = ydir = 1 or
- * xdir = ydir = -1, but we have xdir != ydir.
- */
- dirsetup = 0; /* No direction set up yet. */
- for (; nbox; pbox++, nbox--) {
- if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
- /* Do a xdir = ydir = -1 blit instead. */
- if (dirsetup != -1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = -1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- -1, -1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1,
- pbox->x2 - pbox->x1,
- pbox->y2 - pbox->y1);
- } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
- /* Do a xdir = ydir = 1 blit instead. */
- if (dirsetup != 1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = 1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- 1, 1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1,
- pbox->x2 - pbox->x1,
- pbox->y2 - pbox->y1);
- } else if (dx >= 0) {
- /*
- * xdir = 1, ydir = -1.
- * Perform line-by-line xdir = ydir = 1 blits, going up.
- */
- int i;
- if (dirsetup != 1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = 1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- 1, 1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy + i,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1 + i,
- pbox->x2 - pbox->x1, 1);
- } else {
- /*
- * xdir = -1, ydir = 1.
- * Perform line-by-line xdir = ydir = -1 blits, going down.
- */
- int i;
- if (dirsetup != -1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = -1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- -1, -1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- for (i = 0; i < pbox->y2 - pbox->y1; i++)
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy + i,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1 + i,
- pbox->x2 - pbox->x1, 1);
- }
- }
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- exaMarkSync(pDstDrawable->pScreen);
- return TRUE;
-}
-
-Bool
-exaHWCopyNtoN (DrawablePtr pSrcDrawable,
- DrawablePtr pDstDrawable,
- GCPtr pGC,
- BoxPtr pbox,
- int nbox,
- int dx,
- int dy,
- Bool reverse,
- Bool upsidedown)
-{
- ExaScreenPriv (pDstDrawable->pScreen);
- PixmapPtr pSrcPixmap, pDstPixmap;
- ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
- int src_off_x, src_off_y;
- int dst_off_x, dst_off_y;
- RegionPtr srcregion = NULL, dstregion = NULL;
- xRectangle *rects;
- Bool ret = TRUE;
-
- /* avoid doing copy operations if no boxes */
- if (nbox == 0)
- return TRUE;
-
- pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
- pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
-
- exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
- exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
-
- rects = malloc(nbox * sizeof(xRectangle));
-
- if (rects) {
- int i;
- int ordering;
-
- for (i = 0; i < nbox; i++) {
- rects[i].x = pbox[i].x1 + dx + src_off_x;
- rects[i].y = pbox[i].y1 + dy + src_off_y;
- rects[i].width = pbox[i].x2 - pbox[i].x1;
- rects[i].height = pbox[i].y2 - pbox[i].y1;
- }
-
- /* This must match the RegionCopy() logic for reversing rect order */
- if (nbox == 1 || (dx > 0 && dy > 0) ||
- (pDstDrawable != pSrcDrawable &&
- (pDstDrawable->type != DRAWABLE_WINDOW ||
- pSrcDrawable->type != DRAWABLE_WINDOW)))
- ordering = CT_YXBANDED;
- else
- ordering = CT_UNSORTED;
-
- srcregion = RegionFromRects(nbox, rects, ordering);
- free(rects);
-
- if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
- pGC->fillStyle, pGC->alu,
- pGC->clientClipType)) {
- dstregion = RegionCreate(NullBox, 0);
- RegionCopy(dstregion, srcregion);
- RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
- dst_off_y - dy - src_off_y);
- }
- }
-
-
- pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
- pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
-
- /* Check whether the accelerator can use this pixmap.
- * If the pitch of the pixmaps is out of range, there's nothing
- * we can do but fall back to software rendering.
- */
- if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
- pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
- goto fallback;
-
- /* If the width or the height of either of the pixmaps
- * is out of range, check whether the boxes are actually out of the
- * addressable range as well. If they aren't, we can still do
- * the copying in hardware.
- */
- if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
- int i;
-
- for (i = 0; i < nbox; i++) {
- /* src */
- if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
- (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
- goto fallback;
-
- /* dst */
- if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
- (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
- goto fallback;
- }
- }
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[2];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pDstPixmap;
- pixmaps[0].pReg = dstregion;
- pixmaps[1].as_dst = FALSE;
- pixmaps[1].as_src = TRUE;
- pixmaps[1].pPix = pSrcPixmap;
- pixmaps[1].pReg = srcregion;
-
- exaDoMigration (pixmaps, 2, TRUE);
- }
-
- /* Mixed directions must be handled specially if the card is lame */
- if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
- reverse != upsidedown) {
- if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
- dx, dy))
- goto out;
- goto fallback;
- }
-
- if (exaPixmapHasGpuCopy(pDstPixmap)) {
- /* Normal blitting. */
- if (exaPixmapHasGpuCopy(pSrcPixmap)) {
- if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
- upsidedown ? -1 : 1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask : FB_ALLONES)) {
- goto fallback;
- }
-
- while (nbox--)
- {
- (*pExaScr->info->Copy) (pDstPixmap,
- pbox->x1 + dx + src_off_x,
- pbox->y1 + dy + src_off_y,
- pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
- pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
- pbox++;
- }
-
- (*pExaScr->info->DoneCopy) (pDstPixmap);
- exaMarkSync (pDstDrawable->pScreen);
- /* UTS: mainly for SHM PutImage's secondary path.
- *
- * Only taking this path for directly accessible pixmaps.
- */
- } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
- int bpp = pSrcDrawable->bitsPerPixel;
- int src_stride = exaGetPixmapPitch(pSrcPixmap);
- CARD8 *src = NULL;
-
- if (!pExaScr->info->UploadToScreen)
- goto fallback;
-
- if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
- goto fallback;
-
- if (pSrcDrawable->bitsPerPixel < 8)
- goto fallback;
-
- if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask)))
- goto fallback;
-
- while (nbox--)
- {
- src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8);
- if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
- pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
- (char *) src, src_stride))
- goto fallback;
-
- pbox++;
- }
- } else
- goto fallback;
- } else
- goto fallback;
-
- goto out;
-
-fallback:
- ret = FALSE;
-
-out:
- if (dstregion) {
- RegionUninit(dstregion);
- RegionDestroy(dstregion);
- }
- if (srcregion) {
- RegionUninit(srcregion);
- RegionDestroy(srcregion);
- }
-
- return ret;
-}
-
-void
-exaCopyNtoN (DrawablePtr pSrcDrawable,
- DrawablePtr pDstDrawable,
- GCPtr pGC,
- BoxPtr pbox,
- int nbox,
- int dx,
- int dy,
- Bool reverse,
- Bool upsidedown,
- Pixel bitplane,
- void *closure)
-{
- ExaScreenPriv(pDstDrawable->pScreen);
-
- if (pExaScr->fallback_counter ||
- (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
- return;
-
- if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown))
- return;
-
- /* This is a CopyWindow, it's cleaner to fallback at the original call. */
- if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
- pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
- return;
- }
-
- /* fallback */
- ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
-}
-
-RegionPtr
-exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
- int srcx, int srcy, int width, int height, int dstx, int dsty)
-{
- ExaScreenPriv (pDstDrawable->pScreen);
-
- if (pExaScr->fallback_counter || pExaScr->swappedOut) {
- return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
- srcx, srcy, width, height, dstx, dsty);
- }
-
- return miDoCopy (pSrcDrawable, pDstDrawable, pGC,
- srcx, srcy, width, height,
- dstx, dsty, exaCopyNtoN, 0, NULL);
-}
-
-static void
-exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
- DDXPointPtr ppt)
-{
- ExaScreenPriv (pDrawable->pScreen);
- int i;
- xRectangle *prect;
-
- /* If we can't reuse the current GC as is, don't bother accelerating the
- * points.
- */
- if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
- ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- prect = malloc(sizeof(xRectangle) * npt);
- for (i = 0; i < npt; i++) {
- prect[i].x = ppt[i].x;
- prect[i].y = ppt[i].y;
- if (i > 0 && mode == CoordModePrevious) {
- prect[i].x += prect[i - 1].x;
- prect[i].y += prect[i - 1].y;
- }
- prect[i].width = 1;
- prect[i].height = 1;
- }
- pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
- free(prect);
-}
-
-/**
- * exaPolylines() checks if it can accelerate the lines as a group of
- * horizontal or vertical lines (rectangles), and uses existing rectangle fill
- * acceleration if so.
- */
-static void
-exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
- DDXPointPtr ppt)
-{
- ExaScreenPriv (pDrawable->pScreen);
- xRectangle *prect;
- int x1, x2, y1, y2;
- int i;
-
- if (pExaScr->fallback_counter) {
- ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- /* Don't try to do wide lines or non-solid fill style. */
- if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
- pGC->fillStyle != FillSolid) {
- ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- prect = malloc(sizeof(xRectangle) * (npt - 1));
- x1 = ppt[0].x;
- y1 = ppt[0].y;
- /* If we have any non-horizontal/vertical, fall back. */
- for (i = 0; i < npt - 1; i++) {
- if (mode == CoordModePrevious) {
- x2 = x1 + ppt[i + 1].x;
- y2 = y1 + ppt[i + 1].y;
- } else {
- x2 = ppt[i + 1].x;
- y2 = ppt[i + 1].y;
- }
-
- if (x1 != x2 && y1 != y2) {
- free(prect);
- ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- if (x1 < x2) {
- prect[i].x = x1;
- prect[i].width = x2 - x1 + 1;
- } else {
- prect[i].x = x2;
- prect[i].width = x1 - x2 + 1;
- }
- if (y1 < y2) {
- prect[i].y = y1;
- prect[i].height = y2 - y1 + 1;
- } else {
- prect[i].y = y2;
- prect[i].height = y1 - y2 + 1;
- }
-
- x1 = x2;
- y1 = y2;
- }
- pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
- free(prect);
-}
-
-/**
- * exaPolySegment() checks if it can accelerate the lines as a group of
- * horizontal or vertical lines (rectangles), and uses existing rectangle fill
- * acceleration if so.
- */
-static void
-exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
- xSegment *pSeg)
-{
- ExaScreenPriv (pDrawable->pScreen);
- xRectangle *prect;
- int i;
-
- /* Don't try to do wide lines or non-solid fill style. */
- if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
- pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid)
- {
- ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
- return;
- }
-
- /* If we have any non-horizontal/vertical, fall back. */
- for (i = 0; i < nseg; i++) {
- if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
- ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
- return;
- }
- }
-
- prect = malloc(sizeof(xRectangle) * nseg);
- for (i = 0; i < nseg; i++) {
- if (pSeg[i].x1 < pSeg[i].x2) {
- prect[i].x = pSeg[i].x1;
- prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
- } else {
- prect[i].x = pSeg[i].x2;
- prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
- }
- if (pSeg[i].y1 < pSeg[i].y2) {
- prect[i].y = pSeg[i].y1;
- prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
- } else {
- prect[i].y = pSeg[i].y2;
- prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
- }
-
- /* don't paint last pixel */
- if (pGC->capStyle == CapNotLast) {
- if (prect[i].width == 1)
- prect[i].height--;
- else
- prect[i].width--;
- }
- }
- pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
- free(prect);
-}
-
-static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
- Pixel pixel, CARD32 planemask, CARD32 alu,
- unsigned int clientClipType);
-
-static void
-exaPolyFillRect(DrawablePtr pDrawable,
- GCPtr pGC,
- int nrect,
- xRectangle *prect)
-{
- ExaScreenPriv (pDrawable->pScreen);
- RegionPtr pClip = fbGetCompositeClip(pGC);
- PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
- ExaPixmapPriv (pPixmap);
- register BoxPtr pbox;
- BoxPtr pextent;
- int extentX1, extentX2, extentY1, extentY2;
- int fullX1, fullX2, fullY1, fullY2;
- int partX1, partX2, partY1, partY2;
- int xoff, yoff;
- int xorg, yorg;
- int n;
- RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
-
- /* Compute intersection of rects and clip region */
- RegionTranslate(pReg, pDrawable->x, pDrawable->y);
- RegionIntersect(pReg, pClip, pReg);
-
- if (!RegionNumRects(pReg)) {
- goto out;
- }
-
- exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
-
- if (pExaScr->fallback_counter || pExaScr->swappedOut ||
- pExaPixmap->accel_blocked)
- {
- goto fallback;
- }
-
- /* For ROPs where overlaps don't matter, convert rectangles to region and
- * call exaFillRegion{Solid,Tiled}.
- */
- if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
- (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
- pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
- pGC->alu == GXset)) {
- if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
- exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
- pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
- pGC->alu, pGC->clientClipType)) ||
- (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
- exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
- pGC->planemask, pGC->alu,
- pGC->clientClipType))) {
- goto out;
- }
- }
-
- if (pGC->fillStyle != FillSolid &&
- !(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
- {
- goto fallback;
- }
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = NULL;
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- if (!exaPixmapHasGpuCopy (pPixmap) ||
- !(*pExaScr->info->PrepareSolid) (pPixmap,
- pGC->alu,
- pGC->planemask,
- pGC->fgPixel))
- {
-fallback:
- ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
- goto out;
- }
-
- xorg = pDrawable->x;
- yorg = pDrawable->y;
-
- pextent = RegionExtents(pClip);
- extentX1 = pextent->x1;
- extentY1 = pextent->y1;
- extentX2 = pextent->x2;
- extentY2 = pextent->y2;
- while (nrect--)
- {
- fullX1 = prect->x + xorg;
- fullY1 = prect->y + yorg;
- fullX2 = fullX1 + (int) prect->width;
- fullY2 = fullY1 + (int) prect->height;
- prect++;
-
- if (fullX1 < extentX1)
- fullX1 = extentX1;
-
- if (fullY1 < extentY1)
- fullY1 = extentY1;
-
- if (fullX2 > extentX2)
- fullX2 = extentX2;
-
- if (fullY2 > extentY2)
- fullY2 = extentY2;
-
- if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
- continue;
- n = RegionNumRects (pClip);
- if (n == 1)
- {
- (*pExaScr->info->Solid) (pPixmap,
- fullX1 + xoff, fullY1 + yoff,
- fullX2 + xoff, fullY2 + yoff);
- }
- else
- {
- pbox = RegionRects(pClip);
- /*
- * clip the rectangle to each box in the clip region
- * this is logically equivalent to calling Intersect(),
- * but rectangles may overlap each other here.
- */
- while(n--)
- {
- partX1 = pbox->x1;
- if (partX1 < fullX1)
- partX1 = fullX1;
- partY1 = pbox->y1;
- if (partY1 < fullY1)
- partY1 = fullY1;
- partX2 = pbox->x2;
- if (partX2 > fullX2)
- partX2 = fullX2;
- partY2 = pbox->y2;
- if (partY2 > fullY2)
- partY2 = fullY2;
-
- pbox++;
-
- if (partX1 < partX2 && partY1 < partY2) {
- (*pExaScr->info->Solid) (pPixmap,
- partX1 + xoff, partY1 + yoff,
- partX2 + xoff, partY2 + yoff);
- }
- }
- }
- }
- (*pExaScr->info->DoneSolid) (pPixmap);
- exaMarkSync(pDrawable->pScreen);
-
-out:
- RegionUninit(pReg);
- RegionDestroy(pReg);
-}
-
-const GCOps exaOps = {
- exaFillSpans,
- ExaCheckSetSpans,
- exaPutImage,
- exaCopyArea,
- ExaCheckCopyPlane,
- exaPolyPoint,
- exaPolylines,
- exaPolySegment,
- miPolyRectangle,
- ExaCheckPolyArc,
- miFillPolygon,
- exaPolyFillRect,
- miPolyFillArc,
- miPolyText8,
- miPolyText16,
- miImageText8,
- miImageText16,
- ExaCheckImageGlyphBlt,
- ExaCheckPolyGlyphBlt,
- ExaCheckPushPixels,
-};
-
-void
-exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
-{
- RegionRec rgnDst;
- int dx, dy;
- PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
- ExaScreenPriv(pWin->drawable.pScreen);
-
- dx = ptOldOrg.x - pWin->drawable.x;
- dy = ptOldOrg.y - pWin->drawable.y;
- RegionTranslate(prgnSrc, -dx, -dy);
-
- RegionInit(&rgnDst, NullBox, 0);
-
- RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
-#ifdef COMPOSITE
- if (pPixmap->screen_x || pPixmap->screen_y)
- RegionTranslate(&rgnDst,
- -pPixmap->screen_x, -pPixmap->screen_y);
-#endif
-
- if (pExaScr->fallback_counter) {
- pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
- goto fallback;
- }
-
- pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
- miCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
- NULL,
- &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
- pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
-
-fallback:
- RegionUninit(&rgnDst);
-
- if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
- pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
- RegionTranslate(prgnSrc, dx, dy);
- ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
- }
-}
-
-static Bool
-exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel,
- CARD32 planemask, CARD32 alu, unsigned int clientClipType)
-{
- ExaScreenPriv(pDrawable->pScreen);
- PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv (pPixmap);
- int xoff, yoff;
- Bool ret = FALSE;
-
- exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
- RegionTranslate(pRegion, xoff, yoff);
-
- if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
- goto out;
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
- alu, clientClipType) ? NULL : pRegion;
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- if (exaPixmapHasGpuCopy (pPixmap) &&
- (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
- {
- int nbox;
- BoxPtr pBox;
-
- nbox = RegionNumRects (pRegion);
- pBox = RegionRects (pRegion);
-
- while (nbox--)
- {
- (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
- pBox->y2);
- pBox++;
- }
- (*pExaScr->info->DoneSolid) (pPixmap);
- exaMarkSync(pDrawable->pScreen);
-
- if (pExaPixmap->pDamage &&
- pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
- pDrawable->width == 1 && pDrawable->height == 1 &&
- pDrawable->bitsPerPixel != 24) {
- ExaPixmapPriv(pPixmap);
- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
-
- switch (pDrawable->bitsPerPixel) {
- case 32:
- *(CARD32*)pExaPixmap->sys_ptr = pixel;
- break;
- case 16:
- *(CARD16*)pExaPixmap->sys_ptr = pixel;
- break;
- case 8:
- case 4:
- case 1:
- *(CARD8*)pExaPixmap->sys_ptr = pixel;
- }
-
- RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
- pRegion);
- RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
- pRegion);
- RegionSubtract(pending_damage, pending_damage, pRegion);
- }
-
- ret = TRUE;
- }
-
-out:
- RegionTranslate(pRegion, -xoff, -yoff);
-
- return ret;
-}
-
-/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
- * Based on fbFillRegionTiled(), fbTile().
- */
-Bool
-exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
- DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
- unsigned int clientClipType)
-{
- ExaScreenPriv(pDrawable->pScreen);
- PixmapPtr pPixmap;
- ExaPixmapPrivPtr pExaPixmap;
- ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
- int xoff, yoff;
- int tileWidth, tileHeight;
- int nbox = RegionNumRects (pRegion);
- BoxPtr pBox = RegionRects (pRegion);
- Bool ret = FALSE;
- int i;
-
- tileWidth = pTile->drawable.width;
- tileHeight = pTile->drawable.height;
-
- /* If we're filling with a solid color, grab it out and go to
- * FillRegionSolid, saving numerous copies.
- */
- if (tileWidth == 1 && tileHeight == 1)
- return exaFillRegionSolid(pDrawable, pRegion,
- exaGetPixmapFirstPixel (pTile), planemask,
- alu, clientClipType);
-
- pPixmap = exaGetDrawablePixmap (pDrawable);
- pExaPixmap = ExaGetPixmapPriv (pPixmap);
-
- if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
- pTileExaPixmap->accel_blocked)
- return FALSE;
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[2];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
- alu, clientClipType) ? NULL : pRegion;
- pixmaps[1].as_dst = FALSE;
- pixmaps[1].as_src = TRUE;
- pixmaps[1].pPix = pTile;
- pixmaps[1].pReg = NULL;
-
- exaDoMigration (pixmaps, 2, TRUE);
- }
-
- pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
- if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
- return FALSE;
-
- if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
- {
- if (xoff || yoff)
- RegionTranslate(pRegion, xoff, yoff);
-
- for (i = 0; i < nbox; i++)
- {
- int height = pBox[i].y2 - pBox[i].y1;
- int dstY = pBox[i].y1;
- int tileY;
-
- if (alu == GXcopy)
- height = min(height, tileHeight);
-
- modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
-
- while (height > 0) {
- int width = pBox[i].x2 - pBox[i].x1;
- int dstX = pBox[i].x1;
- int tileX;
- int h = tileHeight - tileY;
-
- if (alu == GXcopy)
- width = min(width, tileWidth);
-
- if (h > height)
- h = height;
- height -= h;
-
- modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
- tileX);
-
- while (width > 0) {
- int w = tileWidth - tileX;
- if (w > width)
- w = width;
- width -= w;
-
- (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
- w, h);
- dstX += w;
- tileX = 0;
- }
- dstY += h;
- tileY = 0;
- }
- }
- (*pExaScr->info->DoneCopy) (pPixmap);
-
- /* With GXcopy, we only need to do the basic algorithm up to the tile
- * size; then, we can just keep doubling the destination in each
- * direction until it fills the box. This way, the number of copy
- * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
- * rx/ry is the ratio between box and tile width/height. This can make
- * a big difference if each driver copy incurs a significant constant
- * overhead.
- */
- if (alu != GXcopy)
- ret = TRUE;
- else {
- Bool more_copy = FALSE;
-
- for (i = 0; i < nbox; i++) {
- int dstX = pBox[i].x1 + tileWidth;
- int dstY = pBox[i].y1 + tileHeight;
-
- if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
- more_copy = TRUE;
- break;
- }
- }
-
- if (more_copy == FALSE)
- ret = TRUE;
-
- if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
- 1, 1, alu, planemask)) {
- for (i = 0; i < nbox; i++)
- {
- int dstX = pBox[i].x1 + tileWidth;
- int dstY = pBox[i].y1 + tileHeight;
- int width = min(pBox[i].x2 - dstX, tileWidth);
- int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
-
- while (dstX < pBox[i].x2) {
- (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
- dstX, pBox[i].y1, width, height);
- dstX += width;
- width = min(pBox[i].x2 - dstX, width * 2);
- }
-
- width = pBox[i].x2 - pBox[i].x1;
- height = min(pBox[i].y2 - dstY, tileHeight);
-
- while (dstY < pBox[i].y2) {
- (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
- pBox[i].x1, dstY, width, height);
- dstY += height;
- height = min(pBox[i].y2 - dstY, height * 2);
- }
- }
-
- (*pExaScr->info->DoneCopy) (pPixmap);
-
- ret = TRUE;
- }
- }
-
- exaMarkSync(pDrawable->pScreen);
-
- if (xoff || yoff)
- RegionTranslate(pRegion, -xoff, -yoff);
- }
-
- return ret;
-}
-
-
-/**
- * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
- *
- * This is probably the only case we actually care about. The rest fall through
- * to migration and fbGetImage, which hopefully will result in migration pushing
- * the pixmap out of framebuffer.
- */
-void
-exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
- unsigned int format, unsigned long planeMask, char *d)
-{
- ExaScreenPriv (pDrawable->pScreen);
- PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv(pPix);
- int xoff, yoff;
- Bool ok;
-
- if (pExaScr->fallback_counter || pExaScr->swappedOut)
- goto fallback;
-
- /* If there's a system copy, we want to save the result there */
- if (pExaPixmap->pDamage)
- goto fallback;
-
- pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
- if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
- goto fallback;
-
- /* Only cover the ZPixmap, solid copy case. */
- if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
- goto fallback;
-
- /* Only try to handle the 8bpp and up cases, since we don't want to think
- * about <8bpp.
- */
- if (pDrawable->bitsPerPixel < 8)
- goto fallback;
-
- ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
- pDrawable->y + y + yoff, w, h, d,
- PixmapBytePad(w, pDrawable->depth));
- if (ok) {
- exaWaitSync(pDrawable->pScreen);
- return;
- }
-
-fallback:
- ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
-}
+/* + * Copyright © 2001 Keith Packard + * + * Partly based on code that is Copyright © The XFree86 Project 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Michel Dänzer <michel@tungstengraphics.com> + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif +#include "exa_priv.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" +#include "exa.h" + +static void +exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv (pScreen); + RegionPtr pClip = fbGetCompositeClip(pGC); + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv (pPixmap); + BoxPtr pextent, pbox; + int nbox; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1; + int partX1, partX2; + int off_x, off_y; + + if (pExaScr->fallback_counter || + pExaScr->swappedOut || + pGC->fillStyle != FillSolid || + pExaPixmap->accel_blocked) + { + ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); + return; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + + exaDoMigration (pixmaps, 1, TRUE); + } + + if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) || + !(*pExaScr->info->PrepareSolid) (pPixmap, + pGC->alu, + pGC->planemask, + pGC->fgPixel)) + { + ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); + return; + } + + pextent = RegionExtents(pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (n--) + { + fullX1 = ppt->x; + fullY1 = ppt->y; + fullX2 = fullX1 + (int) *pwidth; + ppt++; + pwidth++; + + if (fullY1 < extentY1 || extentY2 <= fullY1) + continue; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullX1 >= fullX2) + continue; + + nbox = RegionNumRects (pClip); + if (nbox == 1) + { + (*pExaScr->info->Solid) (pPixmap, + fullX1 + off_x, fullY1 + off_y, + fullX2 + off_x, fullY1 + 1 + off_y); + } + else + { + pbox = RegionRects(pClip); + while(nbox--) + { + if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + if (partX2 > partX1) { + (*pExaScr->info->Solid) (pPixmap, + partX1 + off_x, fullY1 + off_y, + partX2 + off_x, fullY1 + 1 + off_y); + } + } + pbox++; + } + } + } + (*pExaScr->info->DoneSolid) (pPixmap); + exaMarkSync(pScreen); +} + +static Bool +exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + int w, int h, int format, char *bits, int src_stride) +{ + ExaScreenPriv (pDrawable->pScreen); + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv(pPix); + RegionPtr pClip; + BoxPtr pbox; + int nbox; + int xoff, yoff; + int bpp = pDrawable->bitsPerPixel; + Bool ret = TRUE; + + if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) + return FALSE; + + /* If there's a system copy, we want to save the result there */ + if (pExaPixmap->pDamage) + return FALSE; + + /* Don't bother with under 8bpp, XYPixmaps. */ + if (format != ZPixmap || bpp < 8) + return FALSE; + + /* Only accelerate copies: no rop or planemask. */ + if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) + return FALSE; + + if (pExaScr->swappedOut) + return FALSE; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPix; + pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); + + exaDoMigration (pixmaps, 1, TRUE); + } + + pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (!pPix) + return FALSE; + + x += pDrawable->x; + y += pDrawable->y; + + pClip = fbGetCompositeClip(pGC); + for (nbox = RegionNumRects(pClip), + pbox = RegionRects(pClip); + nbox--; + pbox++) + { + int x1 = x; + int y1 = y; + int x2 = x + w; + int y2 = y + h; + char *src; + Bool ok; + + if (x1 < pbox->x1) + x1 = pbox->x1; + if (y1 < pbox->y1) + y1 = pbox->y1; + if (x2 > pbox->x2) + x2 = pbox->x2; + if (y2 > pbox->y2) + y2 = pbox->y2; + if (x1 >= x2 || y1 >= y2) + continue; + + src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); + ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, + x2 - x1, y2 - y1, src, src_stride); + /* We have to fall back completely, and ignore what has already been completed. + * Messing with the fb layer directly like we used to is completely unacceptable. + */ + if (!ok) { + ret = FALSE; + break; + } + } + + if (ret) + exaMarkSync(pDrawable->pScreen); + + return ret; +} + +static void +exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + int w, int h, int leftPad, int format, char *bits) +{ + if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits, + PixmapBytePad(w, pDrawable->depth))) + ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, + bits); +} + +static Bool inline +exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) +{ + ExaScreenPriv (pDstDrawable->pScreen); + PixmapPtr pSrcPixmap, pDstPixmap; + int src_off_x, src_off_y, dst_off_x, dst_off_y; + int dirsetup; + + /* Need to get both pixmaps to call the driver routines */ + pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y); + pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y); + if (!pSrcPixmap || !pDstPixmap) + return FALSE; + + /* + * Now the case of a chip that only supports xdir = ydir = 1 or + * xdir = ydir = -1, but we have xdir != ydir. + */ + dirsetup = 0; /* No direction set up yet. */ + for (; nbox; pbox++, nbox--) { + if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { + /* Do a xdir = ydir = -1 blit instead. */ + if (dirsetup != -1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = -1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + -1, -1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { + /* Do a xdir = ydir = 1 blit instead. */ + if (dirsetup != 1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = 1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + 1, 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } else if (dx >= 0) { + /* + * xdir = 1, ydir = -1. + * Perform line-by-line xdir = ydir = 1 blits, going up. + */ + int i; + if (dirsetup != 1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = 1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + 1, 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy + i, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } else { + /* + * xdir = -1, ydir = 1. + * Perform line-by-line xdir = ydir = -1 blits, going down. + */ + int i; + if (dirsetup != -1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = -1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + -1, -1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + for (i = 0; i < pbox->y2 - pbox->y1; i++) + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy + i, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } + } + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + exaMarkSync(pDstDrawable->pScreen); + return TRUE; +} + +Bool +exaHWCopyNtoN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown) +{ + ExaScreenPriv (pDstDrawable->pScreen); + PixmapPtr pSrcPixmap, pDstPixmap; + ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; + int src_off_x, src_off_y; + int dst_off_x, dst_off_y; + RegionPtr srcregion = NULL, dstregion = NULL; + xRectangle *rects; + Bool ret = TRUE; + + /* avoid doing copy operations if no boxes */ + if (nbox == 0) + return TRUE; + + pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); + pDstPixmap = exaGetDrawablePixmap (pDstDrawable); + + exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); + exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); + + rects = malloc(nbox * sizeof(xRectangle)); + + if (rects) { + int i; + int ordering; + + for (i = 0; i < nbox; i++) { + rects[i].x = pbox[i].x1 + dx + src_off_x; + rects[i].y = pbox[i].y1 + dy + src_off_y; + rects[i].width = pbox[i].x2 - pbox[i].x1; + rects[i].height = pbox[i].y2 - pbox[i].y1; + } + + /* This must match the RegionCopy() logic for reversing rect order */ + if (nbox == 1 || (dx > 0 && dy > 0) || + (pDstDrawable != pSrcDrawable && + (pDstDrawable->type != DRAWABLE_WINDOW || + pSrcDrawable->type != DRAWABLE_WINDOW))) + ordering = CT_YXBANDED; + else + ordering = CT_UNSORTED; + + srcregion = RegionFromRects(nbox, rects, ordering); + free(rects); + + if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, + pGC->fillStyle, pGC->alu, + pGC->clientClipType)) { + dstregion = RegionCreate(NullBox, 0); + RegionCopy(dstregion, srcregion); + RegionTranslate(dstregion, dst_off_x - dx - src_off_x, + dst_off_y - dy - src_off_y); + } + } + + + pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); + pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); + + /* Check whether the accelerator can use this pixmap. + * If the pitch of the pixmaps is out of range, there's nothing + * we can do but fall back to software rendering. + */ + if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || + pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) + goto fallback; + + /* If the width or the height of either of the pixmaps + * is out of range, check whether the boxes are actually out of the + * addressable range as well. If they aren't, we can still do + * the copying in hardware. + */ + if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { + int i; + + for (i = 0; i < nbox; i++) { + /* src */ + if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || + (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) + goto fallback; + + /* dst */ + if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || + (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) + goto fallback; + } + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[2]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pDstPixmap; + pixmaps[0].pReg = dstregion; + pixmaps[1].as_dst = FALSE; + pixmaps[1].as_src = TRUE; + pixmaps[1].pPix = pSrcPixmap; + pixmaps[1].pReg = srcregion; + + exaDoMigration (pixmaps, 2, TRUE); + } + + /* Mixed directions must be handled specially if the card is lame */ + if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && + reverse != upsidedown) { + if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, + dx, dy)) + goto out; + goto fallback; + } + + if (exaPixmapHasGpuCopy(pDstPixmap)) { + /* Normal blitting. */ + if (exaPixmapHasGpuCopy(pSrcPixmap)) { + if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, + upsidedown ? -1 : 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : FB_ALLONES)) { + goto fallback; + } + + while (nbox--) + { + (*pExaScr->info->Copy) (pDstPixmap, + pbox->x1 + dx + src_off_x, + pbox->y1 + dy + src_off_y, + pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + (*pExaScr->info->DoneCopy) (pDstPixmap); + exaMarkSync (pDstDrawable->pScreen); + /* UTS: mainly for SHM PutImage's secondary path. + * + * Only taking this path for directly accessible pixmaps. + */ + } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { + int bpp = pSrcDrawable->bitsPerPixel; + int src_stride = exaGetPixmapPitch(pSrcPixmap); + CARD8 *src = NULL; + + if (!pExaScr->info->UploadToScreen) + goto fallback; + + if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) + goto fallback; + + if (pSrcDrawable->bitsPerPixel < 8) + goto fallback; + + if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) + goto fallback; + + while (nbox--) + { + src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8); + if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, + pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + (char *) src, src_stride)) + goto fallback; + + pbox++; + } + } else + goto fallback; + } else + goto fallback; + + goto out; + +fallback: + ret = FALSE; + +out: + if (dstregion) { + RegionUninit(dstregion); + RegionDestroy(dstregion); + } + if (srcregion) { + RegionUninit(srcregion); + RegionDestroy(srcregion); + } + + return ret; +} + +void +exaCopyNtoN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + ExaScreenPriv(pDstDrawable->pScreen); + + if (pExaScr->fallback_counter || + (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW)) + return; + + if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown)) + return; + + /* This is a CopyWindow, it's cleaner to fallback at the original call. */ + if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) { + pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; + return; + } + + /* fallback */ + ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); +} + +RegionPtr +exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, + int srcx, int srcy, int width, int height, int dstx, int dsty) +{ + ExaScreenPriv (pDstDrawable->pScreen); + + if (pExaScr->fallback_counter || pExaScr->swappedOut) { + return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty); + } + + return miDoCopy (pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, + dstx, dsty, exaCopyNtoN, 0, NULL); +} + +static void +exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + ExaScreenPriv (pDrawable->pScreen); + int i; + xRectangle *prect; + + /* If we can't reuse the current GC as is, don't bother accelerating the + * points. + */ + if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) { + ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = malloc(sizeof(xRectangle) * npt); + for (i = 0; i < npt; i++) { + prect[i].x = ppt[i].x; + prect[i].y = ppt[i].y; + if (i > 0 && mode == CoordModePrevious) { + prect[i].x += prect[i - 1].x; + prect[i].y += prect[i - 1].y; + } + prect[i].width = 1; + prect[i].height = 1; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); + free(prect); +} + +/** + * exaPolylines() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + ExaScreenPriv (pDrawable->pScreen); + xRectangle *prect; + int x1, x2, y1, y2; + int i; + + if (pExaScr->fallback_counter) { + ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); + return; + } + + /* Don't try to do wide lines or non-solid fill style. */ + if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || + pGC->fillStyle != FillSolid) { + ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = malloc(sizeof(xRectangle) * (npt - 1)); + x1 = ppt[0].x; + y1 = ppt[0].y; + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < npt - 1; i++) { + if (mode == CoordModePrevious) { + x2 = x1 + ppt[i + 1].x; + y2 = y1 + ppt[i + 1].y; + } else { + x2 = ppt[i + 1].x; + y2 = ppt[i + 1].y; + } + + if (x1 != x2 && y1 != y2) { + free(prect); + ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); + return; + } + + if (x1 < x2) { + prect[i].x = x1; + prect[i].width = x2 - x1 + 1; + } else { + prect[i].x = x2; + prect[i].width = x1 - x2 + 1; + } + if (y1 < y2) { + prect[i].y = y1; + prect[i].height = y2 - y1 + 1; + } else { + prect[i].y = y2; + prect[i].height = y1 - y2 + 1; + } + + x1 = x2; + y1 = y2; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); + free(prect); +} + +/** + * exaPolySegment() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSeg) +{ + ExaScreenPriv (pDrawable->pScreen); + xRectangle *prect; + int i; + + /* Don't try to do wide lines or non-solid fill style. */ + if (pExaScr->fallback_counter || pGC->lineWidth != 0 || + pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) + { + ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); + return; + } + + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { + ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); + return; + } + } + + prect = malloc(sizeof(xRectangle) * nseg); + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 < pSeg[i].x2) { + prect[i].x = pSeg[i].x1; + prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; + } else { + prect[i].x = pSeg[i].x2; + prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; + } + if (pSeg[i].y1 < pSeg[i].y2) { + prect[i].y = pSeg[i].y1; + prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; + } else { + prect[i].y = pSeg[i].y2; + prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; + } + + /* don't paint last pixel */ + if (pGC->capStyle == CapNotLast) { + if (prect[i].width == 1) + prect[i].height--; + else + prect[i].width--; + } + } + pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); + free(prect); +} + +static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, + Pixel pixel, CARD32 planemask, CARD32 alu, + unsigned int clientClipType); + +static void +exaPolyFillRect(DrawablePtr pDrawable, + GCPtr pGC, + int nrect, + xRectangle *prect) +{ + ExaScreenPriv (pDrawable->pScreen); + RegionPtr pClip = fbGetCompositeClip(pGC); + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaPixmapPriv (pPixmap); + register BoxPtr pbox; + BoxPtr pextent; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1, fullY2; + int partX1, partX2, partY1, partY2; + int xoff, yoff; + int xorg, yorg; + int n; + RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED); + + /* Compute intersection of rects and clip region */ + RegionTranslate(pReg, pDrawable->x, pDrawable->y); + RegionIntersect(pReg, pClip, pReg); + + if (!RegionNumRects(pReg)) { + goto out; + } + + exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); + + if (pExaScr->fallback_counter || pExaScr->swappedOut || + pExaPixmap->accel_blocked) + { + goto fallback; + } + + /* For ROPs where overlaps don't matter, convert rectangles to region and + * call exaFillRegion{Solid,Tiled}. + */ + if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && + (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || + pGC->alu == GXnoop || pGC->alu == GXcopyInverted || + pGC->alu == GXset)) { + if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && + exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? + pGC->fgPixel : pGC->tile.pixel, pGC->planemask, + pGC->alu, pGC->clientClipType)) || + (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && + exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, + pGC->planemask, pGC->alu, + pGC->clientClipType))) { + goto out; + } + } + + if (pGC->fillStyle != FillSolid && + !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) + { + goto fallback; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + + exaDoMigration (pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy (pPixmap) || + !(*pExaScr->info->PrepareSolid) (pPixmap, + pGC->alu, + pGC->planemask, + pGC->fgPixel)) + { +fallback: + ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); + goto out; + } + + xorg = pDrawable->x; + yorg = pDrawable->y; + + pextent = RegionExtents(pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (nrect--) + { + fullX1 = prect->x + xorg; + fullY1 = prect->y + yorg; + fullX2 = fullX1 + (int) prect->width; + fullY2 = fullY1 + (int) prect->height; + prect++; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullY1 < extentY1) + fullY1 = extentY1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullY2 > extentY2) + fullY2 = extentY2; + + if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) + continue; + n = RegionNumRects (pClip); + if (n == 1) + { + (*pExaScr->info->Solid) (pPixmap, + fullX1 + xoff, fullY1 + yoff, + fullX2 + xoff, fullY2 + yoff); + } + else + { + pbox = RegionRects(pClip); + /* + * clip the rectangle to each box in the clip region + * this is logically equivalent to calling Intersect(), + * but rectangles may overlap each other here. + */ + while(n--) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partY1 = pbox->y1; + if (partY1 < fullY1) + partY1 = fullY1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + partY2 = pbox->y2; + if (partY2 > fullY2) + partY2 = fullY2; + + pbox++; + + if (partX1 < partX2 && partY1 < partY2) { + (*pExaScr->info->Solid) (pPixmap, + partX1 + xoff, partY1 + yoff, + partX2 + xoff, partY2 + yoff); + } + } + } + } + (*pExaScr->info->DoneSolid) (pPixmap); + exaMarkSync(pDrawable->pScreen); + +out: + RegionUninit(pReg); + RegionDestroy(pReg); +} + +const GCOps exaOps = { + exaFillSpans, + ExaCheckSetSpans, + exaPutImage, + exaCopyArea, + ExaCheckCopyPlane, + exaPolyPoint, + exaPolylines, + exaPolySegment, + miPolyRectangle, + ExaCheckPolyArc, + miFillPolygon, + exaPolyFillRect, + miPolyFillArc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + ExaCheckImageGlyphBlt, + ExaCheckPolyGlyphBlt, + ExaCheckPushPixels, +}; + +void +exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + RegionRec rgnDst; + int dx, dy; + PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + ExaScreenPriv(pWin->drawable.pScreen); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + RegionTranslate(prgnSrc, -dx, -dy); + + RegionInit(&rgnDst, NullBox, 0); + + RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); +#ifdef COMPOSITE + if (pPixmap->screen_x || pPixmap->screen_y) + RegionTranslate(&rgnDst, + -pPixmap->screen_x, -pPixmap->screen_y); +#endif + + if (pExaScr->fallback_counter) { + pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; + goto fallback; + } + + pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; + miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, + NULL, + &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); + pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; + +fallback: + RegionUninit(&rgnDst); + + if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { + pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; + RegionTranslate(prgnSrc, dx, dy); + ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); + } +} + +static Bool +exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, + CARD32 planemask, CARD32 alu, unsigned int clientClipType) +{ + ExaScreenPriv(pDrawable->pScreen); + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv (pPixmap); + int xoff, yoff; + Bool ret = FALSE; + + exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); + RegionTranslate(pRegion, xoff, yoff); + + if (pExaScr->fallback_counter || pExaPixmap->accel_blocked) + goto out; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, + alu, clientClipType) ? NULL : pRegion; + + exaDoMigration (pixmaps, 1, TRUE); + } + + if (exaPixmapHasGpuCopy (pPixmap) && + (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) + { + int nbox; + BoxPtr pBox; + + nbox = RegionNumRects (pRegion); + pBox = RegionRects (pRegion); + + while (nbox--) + { + (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, + pBox->y2); + pBox++; + } + (*pExaScr->info->DoneSolid) (pPixmap); + exaMarkSync(pDrawable->pScreen); + + if (pExaPixmap->pDamage && + pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP && + pDrawable->width == 1 && pDrawable->height == 1 && + pDrawable->bitsPerPixel != 24) { + ExaPixmapPriv(pPixmap); + RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); + + switch (pDrawable->bitsPerPixel) { + case 32: + *(CARD32*)pExaPixmap->sys_ptr = pixel; + break; + case 16: + *(CARD16*)pExaPixmap->sys_ptr = pixel; + break; + case 8: + case 4: + case 1: + *(CARD8*)pExaPixmap->sys_ptr = pixel; + } + + RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, + pRegion); + RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, + pRegion); + RegionSubtract(pending_damage, pending_damage, pRegion); + } + + ret = TRUE; + } + +out: + RegionTranslate(pRegion, -xoff, -yoff); + + return ret; +} + +/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. + * Based on fbFillRegionTiled(), fbTile(). + */ +Bool +exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, + DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, + unsigned int clientClipType) +{ + ExaScreenPriv(pDrawable->pScreen); + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); + int xoff, yoff; + int tileWidth, tileHeight; + int nbox = RegionNumRects (pRegion); + BoxPtr pBox = RegionRects (pRegion); + Bool ret = FALSE; + int i; + + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; + + /* If we're filling with a solid color, grab it out and go to + * FillRegionSolid, saving numerous copies. + */ + if (tileWidth == 1 && tileHeight == 1) + return exaFillRegionSolid(pDrawable, pRegion, + exaGetPixmapFirstPixel (pTile), planemask, + alu, clientClipType); + + pPixmap = exaGetDrawablePixmap (pDrawable); + pExaPixmap = ExaGetPixmapPriv (pPixmap); + + if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || + pTileExaPixmap->accel_blocked) + return FALSE; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[2]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, + alu, clientClipType) ? NULL : pRegion; + pixmaps[1].as_dst = FALSE; + pixmaps[1].as_src = TRUE; + pixmaps[1].pPix = pTile; + pixmaps[1].pReg = NULL; + + exaDoMigration (pixmaps, 2, TRUE); + } + + pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) + return FALSE; + + if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) + { + if (xoff || yoff) + RegionTranslate(pRegion, xoff, yoff); + + for (i = 0; i < nbox; i++) + { + int height = pBox[i].y2 - pBox[i].y1; + int dstY = pBox[i].y1; + int tileY; + + if (alu == GXcopy) + height = min(height, tileHeight); + + modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); + + while (height > 0) { + int width = pBox[i].x2 - pBox[i].x1; + int dstX = pBox[i].x1; + int tileX; + int h = tileHeight - tileY; + + if (alu == GXcopy) + width = min(width, tileWidth); + + if (h > height) + h = height; + height -= h; + + modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, + tileX); + + while (width > 0) { + int w = tileWidth - tileX; + if (w > width) + w = width; + width -= w; + + (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, + w, h); + dstX += w; + tileX = 0; + } + dstY += h; + tileY = 0; + } + } + (*pExaScr->info->DoneCopy) (pPixmap); + + /* With GXcopy, we only need to do the basic algorithm up to the tile + * size; then, we can just keep doubling the destination in each + * direction until it fills the box. This way, the number of copy + * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where + * rx/ry is the ratio between box and tile width/height. This can make + * a big difference if each driver copy incurs a significant constant + * overhead. + */ + if (alu != GXcopy) + ret = TRUE; + else { + Bool more_copy = FALSE; + + for (i = 0; i < nbox; i++) { + int dstX = pBox[i].x1 + tileWidth; + int dstY = pBox[i].y1 + tileHeight; + + if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { + more_copy = TRUE; + break; + } + } + + if (more_copy == FALSE) + ret = TRUE; + + if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, + 1, 1, alu, planemask)) { + for (i = 0; i < nbox; i++) + { + int dstX = pBox[i].x1 + tileWidth; + int dstY = pBox[i].y1 + tileHeight; + int width = min(pBox[i].x2 - dstX, tileWidth); + int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); + + while (dstX < pBox[i].x2) { + (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, + dstX, pBox[i].y1, width, height); + dstX += width; + width = min(pBox[i].x2 - dstX, width * 2); + } + + width = pBox[i].x2 - pBox[i].x1; + height = min(pBox[i].y2 - dstY, tileHeight); + + while (dstY < pBox[i].y2) { + (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, + pBox[i].x1, dstY, width, height); + dstY += height; + height = min(pBox[i].y2 - dstY, height * 2); + } + } + + (*pExaScr->info->DoneCopy) (pPixmap); + + ret = TRUE; + } + } + + exaMarkSync(pDrawable->pScreen); + + if (xoff || yoff) + RegionTranslate(pRegion, -xoff, -yoff); + } + + return ret; +} + + +/** + * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. + * + * This is probably the only case we actually care about. The rest fall through + * to migration and fbGetImage, which hopefully will result in migration pushing + * the pixmap out of framebuffer. + */ +void +exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + ExaScreenPriv (pDrawable->pScreen); + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv(pPix); + int xoff, yoff; + Bool ok; + + if (pExaScr->fallback_counter || pExaScr->swappedOut) + goto fallback; + + /* If there's a system copy, we want to save the result there */ + if (pExaPixmap->pDamage) + goto fallback; + + pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) + goto fallback; + + /* Only cover the ZPixmap, solid copy case. */ + if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) + goto fallback; + + /* Only try to handle the 8bpp and up cases, since we don't want to think + * about <8bpp. + */ + if (pDrawable->bitsPerPixel < 8) + goto fallback; + + ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, + pDrawable->y + y + yoff, w, h, d, + PixmapBytePad(w, pDrawable->depth)); + if (ok) { + exaWaitSync(pDrawable->pScreen); + return; + } + +fallback: + ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); +} diff --git a/xorg-server/exa/exa_classic.c b/xorg-server/exa/exa_classic.c index 1a1467848..919b29df2 100644 --- a/xorg-server/exa/exa_classic.c +++ b/xorg-server/exa/exa_classic.c @@ -1,266 +1,266 @@ -/*
- * Copyright © 2009 Maarten Maathuis
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#include "exa_priv.h"
-#include "exa.h"
-
-/* This file holds the classic exa specific implementation. */
-
-static _X_INLINE void*
-ExaGetPixmapAddress(PixmapPtr p)
-{
- ExaPixmapPriv(p);
-
- if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr)
- return pExaPixmap->fb_ptr;
- else
- return pExaPixmap->sys_ptr;
-}
-
-/**
- * exaCreatePixmap() creates a new pixmap.
- *
- * If width and height are 0, this won't be a full-fledged pixmap and it will
- * get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because
- * ModifyPixmapHeader() would break migration. These types of pixmaps are used
- * for scratch pixmaps, or to represent the visible screen.
- */
-PixmapPtr
-exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
- unsigned usage_hint)
-{
- PixmapPtr pPixmap;
- ExaPixmapPrivPtr pExaPixmap;
- BoxRec box;
- int bpp;
- ExaScreenPriv(pScreen);
-
- if (w > 32767 || h > 32767)
- return NullPixmap;
-
- swap(pExaScr, pScreen, CreatePixmap);
- pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint);
- swap(pExaScr, pScreen, CreatePixmap);
-
- if (!pPixmap)
- return NULL;
-
- pExaPixmap = ExaGetPixmapPriv(pPixmap);
- pExaPixmap->driverPriv = NULL;
-
- bpp = pPixmap->drawable.bitsPerPixel;
-
- pExaPixmap->driverPriv = NULL;
- /* Scratch pixmaps may have w/h equal to zero, and may not be
- * migrated.
- */
- if (!w || !h)
- pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
- else
- pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
-
- pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
- pExaPixmap->sys_pitch = pPixmap->devKind;
-
- pPixmap->devPrivate.ptr = NULL;
- pExaPixmap->use_gpu_copy = FALSE;
-
- pExaPixmap->fb_ptr = NULL;
- exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
- pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
-
- if (pExaPixmap->fb_pitch > 131071) {
- swap(pExaScr, pScreen, DestroyPixmap);
- pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
- return NULL;
- }
-
- /* Set up damage tracking */
- pExaPixmap->pDamage = DamageCreate (NULL, NULL,
- DamageReportNone, TRUE,
- pScreen, pPixmap);
-
- if (pExaPixmap->pDamage == NULL) {
- swap(pExaScr, pScreen, DestroyPixmap);
- pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
- return NULL;
- }
-
- DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
- /* This ensures that pending damage reflects the current operation. */
- /* This is used by exa to optimize migration. */
- DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
-
- pExaPixmap->area = NULL;
-
- /* We set the initial pixmap as completely valid for a simple reason.
- * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
- * could form single pixel rects as part of a region. Setting the complete region
- * as valid is a natural defragmentation of the region.
- */
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = w;
- box.y2 = h;
- RegionInit(&pExaPixmap->validSys, &box, 0);
- RegionInit(&pExaPixmap->validFB, &box, 0);
-
- exaSetAccelBlock(pExaScr, pExaPixmap,
- w, h, bpp);
-
- /* During a fallback we must prepare access. */
- if (pExaScr->fallback_counter)
- exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
-
- return pPixmap;
-}
-
-Bool
-exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth,
- int bitsPerPixel, int devKind, pointer pPixData)
-{
- ScreenPtr pScreen;
- ExaScreenPrivPtr pExaScr;
- ExaPixmapPrivPtr pExaPixmap;
- Bool ret;
-
- if (!pPixmap)
- return FALSE;
-
- pScreen = pPixmap->drawable.pScreen;
- pExaScr = ExaGetScreenPriv(pScreen);
- pExaPixmap = ExaGetPixmapPriv(pPixmap);
-
- if (pExaPixmap) {
- if (pPixData)
- pExaPixmap->sys_ptr = pPixData;
-
- if (devKind > 0)
- pExaPixmap->sys_pitch = devKind;
-
- /* Classic EXA:
- * - Framebuffer.
- * - Scratch pixmap with gpu memory.
- */
- if (pExaScr->info->memoryBase && pPixData) {
- if ((CARD8 *)pPixData >= pExaScr->info->memoryBase &&
- ((CARD8 *)pPixData - pExaScr->info->memoryBase) <
- pExaScr->info->memorySize) {
- pExaPixmap->fb_ptr = pPixData;
- pExaPixmap->fb_pitch = devKind;
- pExaPixmap->use_gpu_copy = TRUE;
- }
- }
-
- if (width > 0 && height > 0 && bitsPerPixel > 0) {
- exaSetFbPitch(pExaScr, pExaPixmap,
- width, height, bitsPerPixel);
-
- exaSetAccelBlock(pExaScr, pExaPixmap,
- width, height, bitsPerPixel);
- }
-
- /* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
- * gpu memory, so there's no need to track damage.
- */
- if (pExaPixmap->pDamage) {
- DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
- DamageDestroy(pExaPixmap->pDamage);
- pExaPixmap->pDamage = NULL;
- }
- }
-
- swap(pExaScr, pScreen, ModifyPixmapHeader);
- ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
- bitsPerPixel, devKind, pPixData);
- swap(pExaScr, pScreen, ModifyPixmapHeader);
-
- /* Always NULL this, we don't want lingering pointers. */
- pPixmap->devPrivate.ptr = NULL;
-
- return ret;
-}
-
-Bool
-exaDestroyPixmap_classic (PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- Bool ret;
-
- if (pPixmap->refcnt == 1)
- {
- ExaPixmapPriv (pPixmap);
-
- exaDestroyPixmap(pPixmap);
-
- if (pExaPixmap->area)
- {
- DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
- (void*)pPixmap->drawable.id,
- ExaGetPixmapPriv(pPixmap)->area->offset,
- pPixmap->drawable.width,
- pPixmap->drawable.height));
- /* Free the offscreen area */
- exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
- pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
- pPixmap->devKind = pExaPixmap->sys_pitch;
- }
- RegionUninit(&pExaPixmap->validSys);
- RegionUninit(&pExaPixmap->validFB);
- }
-
- swap(pExaScr, pScreen, DestroyPixmap);
- ret = pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
-
- return ret;
-}
-
-Bool
-exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- ExaPixmapPriv(pPixmap);
- Bool ret;
-
- if (pExaScr->info->PixmapIsOffscreen) {
- void* old_ptr = pPixmap->devPrivate.ptr;
- pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
- ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
- pPixmap->devPrivate.ptr = old_ptr;
- } else
- ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr);
-
- return ret;
-}
+/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the classic exa specific implementation. */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr) + return pExaPixmap->fb_ptr; + else + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + * + * If width and height are 0, this won't be a full-fledged pixmap and it will + * get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because + * ModifyPixmapHeader() would break migration. These types of pixmaps are used + * for scratch pixmaps, or to represent the visible screen. + */ +PixmapPtr +exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + BoxRec box; + int bpp; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + pExaPixmap->driverPriv = NULL; + /* Scratch pixmaps may have w/h equal to zero, and may not be + * migrated. + */ + if (!w || !h) + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + else + pExaPixmap->score = EXA_PIXMAP_SCORE_INIT; + + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + + pPixmap->devPrivate.ptr = NULL; + pExaPixmap->use_gpu_copy = FALSE; + + pExaPixmap->fb_ptr = NULL; + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + pExaPixmap->fb_size = pExaPixmap->fb_pitch * h; + + if (pExaPixmap->fb_pitch > 131071) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate (NULL, NULL, + DamageReportNone, TRUE, + pScreen, pPixmap); + + if (pExaPixmap->pDamage == NULL) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); + + pExaPixmap->area = NULL; + + /* We set the initial pixmap as completely valid for a simple reason. + * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which + * could form single pixel rects as part of a region. Setting the complete region + * as valid is a natural defragmentation of the region. + */ + box.x1 = 0; + box.y1 = 0; + box.x2 = w; + box.y2 = h; + RegionInit(&pExaPixmap->validSys, &box, 0); + RegionInit(&pExaPixmap->validFB, &box, 0); + + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret; + + if (!pPixmap) + return FALSE; + + pScreen = pPixmap->drawable.pScreen; + pExaScr = ExaGetScreenPriv(pScreen); + pExaPixmap = ExaGetPixmapPriv(pPixmap); + + if (pExaPixmap) { + if (pPixData) + pExaPixmap->sys_ptr = pPixData; + + if (devKind > 0) + pExaPixmap->sys_pitch = devKind; + + /* Classic EXA: + * - Framebuffer. + * - Scratch pixmap with gpu memory. + */ + if (pExaScr->info->memoryBase && pPixData) { + if ((CARD8 *)pPixData >= pExaScr->info->memoryBase && + ((CARD8 *)pPixData - pExaScr->info->memoryBase) < + pExaScr->info->memorySize) { + pExaPixmap->fb_ptr = pPixData; + pExaPixmap->fb_pitch = devKind; + pExaPixmap->use_gpu_copy = TRUE; + } + } + + if (width > 0 && height > 0 && bitsPerPixel > 0) { + exaSetFbPitch(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + + exaSetAccelBlock(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + } + + /* Pixmaps subject to ModifyPixmapHeader will be pinned to system or + * gpu memory, so there's no need to track damage. + */ + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + } + } + + swap(pExaScr, pScreen, ModifyPixmapHeader); + ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + swap(pExaScr, pScreen, ModifyPixmapHeader); + + /* Always NULL this, we don't want lingering pointers. */ + pPixmap->devPrivate.ptr = NULL; + + return ret; +} + +Bool +exaDestroyPixmap_classic (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + exaDestroyPixmap(pPixmap); + + if (pExaPixmap->area) + { + DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n", + (void*)pPixmap->drawable.id, + ExaGetPixmapPriv(pPixmap)->area->offset, + pPixmap->drawable.width, + pPixmap->drawable.height)); + /* Free the offscreen area */ + exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area); + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + } + RegionUninit(&pExaPixmap->validSys); + RegionUninit(&pExaPixmap->validFB); + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + Bool ret; + + if (pExaScr->info->PixmapIsOffscreen) { + void* old_ptr = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = old_ptr; + } else + ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr); + + return ret; +} diff --git a/xorg-server/exa/exa_driver.c b/xorg-server/exa/exa_driver.c index bfc89295f..795cb00cd 100644 --- a/xorg-server/exa/exa_driver.c +++ b/xorg-server/exa/exa_driver.c @@ -1,226 +1,226 @@ -/*
- * Copyright © 2009 Maarten Maathuis
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#include "exa_priv.h"
-#include "exa.h"
-
-/* This file holds the driver allocated pixmaps specific implementation. */
-
-static _X_INLINE void*
-ExaGetPixmapAddress(PixmapPtr p)
-{
- ExaPixmapPriv(p);
-
- return pExaPixmap->sys_ptr;
-}
-
-/**
- * exaCreatePixmap() creates a new pixmap.
- *
- * Pixmaps are always marked as pinned, because exa has no control over them.
- */
-PixmapPtr
-exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
- unsigned usage_hint)
-{
- PixmapPtr pPixmap;
- ExaPixmapPrivPtr pExaPixmap;
- int bpp;
- size_t paddedWidth, datasize;
- ExaScreenPriv(pScreen);
-
- if (w > 32767 || h > 32767)
- return NullPixmap;
-
- swap(pExaScr, pScreen, CreatePixmap);
- pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
- swap(pExaScr, pScreen, CreatePixmap);
-
- if (!pPixmap)
- return NULL;
-
- pExaPixmap = ExaGetPixmapPriv(pPixmap);
- pExaPixmap->driverPriv = NULL;
-
- bpp = pPixmap->drawable.bitsPerPixel;
-
- /* Set this before driver hooks, to allow for driver pixmaps without gpu
- * memory to back it. These pixmaps have a valid pointer at all times.
- */
- pPixmap->devPrivate.ptr = NULL;
-
- if (pExaScr->info->CreatePixmap2) {
- int new_pitch = 0;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
- paddedWidth = pExaPixmap->fb_pitch = new_pitch;
- }
- else {
- paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
- if (paddedWidth / 4 > 32767 || h > 32767)
- return NullPixmap;
-
- exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
-
- if (paddedWidth < pExaPixmap->fb_pitch)
- paddedWidth = pExaPixmap->fb_pitch;
- datasize = h * paddedWidth;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0);
- }
-
- if (!pExaPixmap->driverPriv) {
- swap(pExaScr, pScreen, DestroyPixmap);
- pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
- return NULL;
- }
-
- /* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
- pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
- pExaPixmap->fb_ptr = NULL;
- pExaPixmap->pDamage = NULL;
- pExaPixmap->sys_ptr = NULL;
-
- (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
- paddedWidth, NULL);
-
- pExaPixmap->area = NULL;
-
- exaSetAccelBlock(pExaScr, pExaPixmap,
- w, h, bpp);
-
- pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
-
- /* During a fallback we must prepare access. */
- if (pExaScr->fallback_counter)
- exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
-
- return pPixmap;
-}
-
-Bool
-exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth,
- int bitsPerPixel, int devKind, pointer pPixData)
-{
- ScreenPtr pScreen;
- ExaScreenPrivPtr pExaScr;
- ExaPixmapPrivPtr pExaPixmap;
- Bool ret;
-
- if (!pPixmap)
- return FALSE;
-
- pScreen = pPixmap->drawable.pScreen;
- pExaScr = ExaGetScreenPriv(pScreen);
- pExaPixmap = ExaGetPixmapPriv(pPixmap);
-
- if (pExaPixmap) {
- if (pPixData)
- pExaPixmap->sys_ptr = pPixData;
-
- if (devKind > 0)
- pExaPixmap->sys_pitch = devKind;
-
- if (width > 0 && height > 0 && bitsPerPixel > 0) {
- exaSetFbPitch(pExaScr, pExaPixmap,
- width, height, bitsPerPixel);
-
- exaSetAccelBlock(pExaScr, pExaPixmap,
- width, height, bitsPerPixel);
- }
- }
-
- if (pExaScr->info->ModifyPixmapHeader) {
- ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
- bitsPerPixel, devKind, pPixData);
- /* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
- * If pPixmap->devPrivate.ptr is non-NULL, then we've got a
- * !has_gpu_copy pixmap. We need to store the pointer,
- * because PrepareAccess won't be called.
- */
- if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
- pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
- pExaPixmap->sys_pitch = pPixmap->devKind;
- }
- if (ret == TRUE)
- goto out;
- }
-
- swap(pExaScr, pScreen, ModifyPixmapHeader);
- ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
- bitsPerPixel, devKind, pPixData);
- swap(pExaScr, pScreen, ModifyPixmapHeader);
-
-out:
- /* Always NULL this, we don't want lingering pointers. */
- pPixmap->devPrivate.ptr = NULL;
-
- return ret;
-}
-
-Bool
-exaDestroyPixmap_driver (PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- Bool ret;
-
- if (pPixmap->refcnt == 1)
- {
- ExaPixmapPriv (pPixmap);
-
- exaDestroyPixmap(pPixmap);
-
- if (pExaPixmap->driverPriv)
- pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
- pExaPixmap->driverPriv = NULL;
- }
-
- swap(pExaScr, pScreen, DestroyPixmap);
- ret = pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
-
- return ret;
-}
-
-Bool
-exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- pointer saved_ptr;
- Bool ret;
-
- saved_ptr = pPixmap->devPrivate.ptr;
- pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
- ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
- pPixmap->devPrivate.ptr = saved_ptr;
-
- return ret;
-}
+/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the driver allocated pixmaps specific implementation. */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + * + * Pixmaps are always marked as pinned, because exa has no control over them. + */ +PixmapPtr +exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + int bpp; + size_t paddedWidth, datasize; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + /* Set this before driver hooks, to allow for driver pixmaps without gpu + * memory to back it. These pixmaps have a valid pointer at all times. + */ + pPixmap->devPrivate.ptr = NULL; + + if (pExaScr->info->CreatePixmap2) { + int new_pitch = 0; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch); + paddedWidth = pExaPixmap->fb_pitch = new_pitch; + } + else { + paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + if (paddedWidth / 4 > 32767 || h > 32767) + return NullPixmap; + + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + + if (paddedWidth < pExaPixmap->fb_pitch) + paddedWidth = pExaPixmap->fb_pitch; + datasize = h * paddedWidth; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0); + } + + if (!pExaPixmap->driverPriv) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + /* Allow ModifyPixmapHeader to set sys_ptr appropriately. */ + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + pExaPixmap->fb_ptr = NULL; + pExaPixmap->pDamage = NULL; + pExaPixmap->sys_ptr = NULL; + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); + + pExaPixmap->area = NULL; + + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret; + + if (!pPixmap) + return FALSE; + + pScreen = pPixmap->drawable.pScreen; + pExaScr = ExaGetScreenPriv(pScreen); + pExaPixmap = ExaGetPixmapPriv(pPixmap); + + if (pExaPixmap) { + if (pPixData) + pExaPixmap->sys_ptr = pPixData; + + if (devKind > 0) + pExaPixmap->sys_pitch = devKind; + + if (width > 0 && height > 0 && bitsPerPixel > 0) { + exaSetFbPitch(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + + exaSetAccelBlock(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + } + } + + if (pExaScr->info->ModifyPixmapHeader) { + ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + /* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL. + * If pPixmap->devPrivate.ptr is non-NULL, then we've got a + * !has_gpu_copy pixmap. We need to store the pointer, + * because PrepareAccess won't be called. + */ + if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) { + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + } + if (ret == TRUE) + goto out; + } + + swap(pExaScr, pScreen, ModifyPixmapHeader); + ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + swap(pExaScr, pScreen, ModifyPixmapHeader); + +out: + /* Always NULL this, we don't want lingering pointers. */ + pPixmap->devPrivate.ptr = NULL; + + return ret; +} + +Bool +exaDestroyPixmap_driver (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + exaDestroyPixmap(pPixmap); + + if (pExaPixmap->driverPriv) + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + pointer saved_ptr; + Bool ret; + + saved_ptr = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = saved_ptr; + + return ret; +} diff --git a/xorg-server/exa/exa_migration_classic.c b/xorg-server/exa/exa_migration_classic.c index 5ec2ac0b8..dd3cd491e 100644 --- a/xorg-server/exa/exa_migration_classic.c +++ b/xorg-server/exa/exa_migration_classic.c @@ -1,745 +1,745 @@ -/*
- * Copyright © 2006 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Authors:
- * Eric Anholt <eric@anholt.net>
- * Michel Dänzer <michel@tungstengraphics.com>
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#include "exa_priv.h"
-#include "exa.h"
-
-#if DEBUG_MIGRATE
-#define DBG_MIGRATE(a) ErrorF a
-#else
-#define DBG_MIGRATE(a)
-#endif
-
-/**
- * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys
- * and exaCopyDirtyToFb both needed to do this loop.
- */
-static void
-exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
- CARD8 *dst, int dst_pitch)
- {
- int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
- int bytes = (pbox->x2 - pbox->x1) * cpp;
-
- src += pbox->y1 * src_pitch + pbox->x1 * cpp;
- dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
-
- for (i = pbox->y2 - pbox->y1; i; i--) {
- memcpy (dst, src, bytes);
- src += src_pitch;
- dst += dst_pitch;
- }
-}
-
-/**
- * Returns TRUE if the pixmap is dirty (has been modified in its current
- * location compared to the other), or lacks a private for tracking
- * dirtiness.
- */
-static Bool
-exaPixmapIsDirty (PixmapPtr pPix)
-{
- ExaPixmapPriv (pPix);
-
- if (pExaPixmap == NULL)
- EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
-
- if (!pExaPixmap->pDamage)
- return FALSE;
-
- return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) ||
- !RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB);
-}
-
-/**
- * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
- * to be considered "should be in framebuffer". That's just anything that has
- * had more acceleration than fallbacks, or has no score yet.
- *
- * Only valid if using a migration scheme that tracks score.
- */
-static Bool
-exaPixmapShouldBeInFB (PixmapPtr pPix)
-{
- ExaPixmapPriv (pPix);
-
- if (exaPixmapIsPinned (pPix))
- return TRUE;
-
- return pExaPixmap->score >= 0;
-}
-
-/**
- * If the pixmap is currently dirty, this copies at least the dirty area from
- * FB to system or vice versa. Both areas must be allocated.
- */
-static void
-exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
- Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
- char *sys, int sys_pitch), int fallback_index,
- void (*sync) (ScreenPtr pScreen))
-{
- PixmapPtr pPixmap = migrate->pPix;
- ExaPixmapPriv (pPixmap);
- RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
- RegionRec CopyReg;
- Bool save_use_gpu_copy;
- int save_pitch;
- BoxPtr pBox;
- int nbox;
- Bool access_prepared = FALSE;
- Bool need_sync = FALSE;
-
- /* Damaged bits are valid in current copy but invalid in other one */
- if (pExaPixmap->use_gpu_copy) {
- RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
- damage);
- RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys,
- damage);
- } else {
- RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
- damage);
- RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB,
- damage);
- }
-
- RegionEmpty(damage);
-
- /* Copy bits valid in source but not in destination */
- RegionNull(&CopyReg);
- RegionSubtract(&CopyReg, pValidSrc, pValidDst);
-
- if (migrate->as_dst) {
- ExaScreenPriv (pPixmap->drawable.pScreen);
-
- /* XXX: The pending damage region will be marked as damaged after the
- * operation, so it should serve as an upper bound for the region that
- * needs to be synchronized for the operation. Unfortunately, this
- * causes corruption in some cases, e.g. when starting compiz. See
- * https://bugs.freedesktop.org/show_bug.cgi?id=12916 .
- */
- if (pExaScr->optimize_migration) {
- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
-
-#if DEBUG_MIGRATE
- if (RegionNil(pending_damage)) {
- static Bool firsttime = TRUE;
-
- if (firsttime) {
- ErrorF("%s: Pending damage region empty!\n", __func__);
- firsttime = FALSE;
- }
- }
-#endif
-
- /* Try to prevent destination valid region from growing too many
- * rects by filling it up to the extents of the union of the
- * destination valid region and the pending damage region.
- */
- if (RegionNumRects(pValidDst) > 10) {
- BoxRec box;
- BoxPtr pValidExt, pDamageExt;
- RegionRec closure;
-
- pValidExt = RegionExtents(pValidDst);
- pDamageExt = RegionExtents(pending_damage);
-
- box.x1 = min(pValidExt->x1, pDamageExt->x1);
- box.y1 = min(pValidExt->y1, pDamageExt->y1);
- box.x2 = max(pValidExt->x2, pDamageExt->x2);
- box.y2 = max(pValidExt->y2, pDamageExt->y2);
-
- RegionInit(&closure, &box, 0);
- RegionIntersect(&CopyReg, &CopyReg, &closure);
- } else
- RegionIntersect(&CopyReg, &CopyReg, pending_damage);
- }
-
- /* The caller may provide a region to be subtracted from the calculated
- * dirty region. This is to avoid migration of bits that don't
- * contribute to the result of the operation.
- */
- if (migrate->pReg)
- RegionSubtract(&CopyReg, &CopyReg, migrate->pReg);
- } else {
- /* The caller may restrict the region to be migrated for source pixmaps
- * to what's relevant for the operation.
- */
- if (migrate->pReg)
- RegionIntersect(&CopyReg, &CopyReg, migrate->pReg);
- }
-
- pBox = RegionRects(&CopyReg);
- nbox = RegionNumRects(&CopyReg);
-
- save_use_gpu_copy = pExaPixmap->use_gpu_copy;
- save_pitch = pPixmap->devKind;
- pExaPixmap->use_gpu_copy = TRUE;
- pPixmap->devKind = pExaPixmap->fb_pitch;
-
- while (nbox--) {
- pBox->x1 = max(pBox->x1, 0);
- pBox->y1 = max(pBox->y1, 0);
- pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
- pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
-
- if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
- continue;
-
- if (!transfer || !transfer (pPixmap,
- pBox->x1, pBox->y1,
- pBox->x2 - pBox->x1,
- pBox->y2 - pBox->y1,
- (char *) (pExaPixmap->sys_ptr
- + pBox->y1 * pExaPixmap->sys_pitch
- + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8),
- pExaPixmap->sys_pitch))
- {
- if (!access_prepared) {
- ExaDoPrepareAccess(pPixmap, fallback_index);
- access_prepared = TRUE;
- }
- if (fallback_index == EXA_PREPARE_DEST) {
- exaMemcpyBox (pPixmap, pBox,
- pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
- pPixmap->devPrivate.ptr, pPixmap->devKind);
- } else {
- exaMemcpyBox (pPixmap, pBox,
- pPixmap->devPrivate.ptr, pPixmap->devKind,
- pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
- }
- } else
- need_sync = TRUE;
-
- pBox++;
- }
-
- pExaPixmap->use_gpu_copy = save_use_gpu_copy;
- pPixmap->devKind = save_pitch;
-
- /* Try to prevent source valid region from growing too many rects by
- * removing parts of it which are also in the destination valid region.
- * Removing anything beyond that would lead to data loss.
- */
- if (RegionNumRects(pValidSrc) > 20)
- RegionSubtract(pValidSrc, pValidSrc, pValidDst);
-
- /* The copied bits are now valid in destination */
- RegionUnion(pValidDst, pValidDst, &CopyReg);
-
- RegionUninit(&CopyReg);
-
- if (access_prepared)
- exaFinishAccess(&pPixmap->drawable, fallback_index);
- else if (need_sync && sync)
- sync (pPixmap->drawable.pScreen);
-}
-
-/**
- * If the pixmap is currently dirty, this copies at least the dirty area from
- * the framebuffer memory copy to the system memory copy. Both areas must be
- * allocated.
- */
-void
-exaCopyDirtyToSys (ExaMigrationPtr migrate)
-{
- PixmapPtr pPixmap = migrate->pPix;
- ExaScreenPriv (pPixmap->drawable.pScreen);
- ExaPixmapPriv (pPixmap);
-
- exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
- pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC,
- exaWaitSync);
-}
-
-/**
- * If the pixmap is currently dirty, this copies at least the dirty area from
- * the system memory copy to the framebuffer memory copy. Both areas must be
- * allocated.
- */
-void
-exaCopyDirtyToFb (ExaMigrationPtr migrate)
-{
- PixmapPtr pPixmap = migrate->pPix;
- ExaScreenPriv (pPixmap->drawable.pScreen);
- ExaPixmapPriv (pPixmap);
-
- exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
- pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL);
-}
-
-/**
- * Allocates a framebuffer copy of the pixmap if necessary, and then copies
- * any necessary pixmap data into the framebuffer copy and points the pixmap at
- * it.
- *
- * Note that when first allocated, a pixmap will have FALSE dirty flag.
- * This is intentional because pixmap data starts out undefined. So if we move
- * it in due to the first operation against it being accelerated, it will have
- * undefined framebuffer contents that we didn't have to upload. If we do
- * moveouts (and moveins) after the first movein, then we will only have to copy
- * back and forth if the pixmap was written to after the last synchronization of
- * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
- * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
- * all the data, since it's almost surely all valid now.
- */
-static void
-exaDoMoveInPixmap (ExaMigrationPtr migrate)
-{
- PixmapPtr pPixmap = migrate->pPix;
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv (pScreen);
- ExaPixmapPriv (pPixmap);
-
- /* If we're VT-switched away, no touching card memory allowed. */
- if (pExaScr->swappedOut)
- return;
-
- /* If we're not allowed to move, then fail. */
- if (exaPixmapIsPinned(pPixmap))
- return;
-
- /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
- * fragility in EXA, and <8bpp is probably not used enough any more to care
- * (at least, not in acceleratd paths).
- */
- if (pPixmap->drawable.bitsPerPixel < 8)
- return;
-
- if (pExaPixmap->accel_blocked)
- return;
-
- if (pExaPixmap->area == NULL) {
- pExaPixmap->area =
- exaOffscreenAlloc (pScreen, pExaPixmap->fb_size,
- pExaScr->info->pixmapOffsetAlign, FALSE,
- exaPixmapSave, (pointer) pPixmap);
- if (pExaPixmap->area == NULL)
- return;
-
- pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
- pExaPixmap->area->offset;
- }
-
- exaCopyDirtyToFb (migrate);
-
- if (exaPixmapHasGpuCopy(pPixmap))
- return;
-
- DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
- (ExaGetPixmapPriv(pPixmap)->area ?
- ExaGetPixmapPriv(pPixmap)->area->offset : 0),
- pPixmap->drawable.width,
- pPixmap->drawable.height,
- exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
-
- pExaPixmap->use_gpu_copy = TRUE;
-
- pPixmap->devKind = pExaPixmap->fb_pitch;
- pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
-}
-
-void
-exaMoveInPixmap_classic (PixmapPtr pPixmap)
-{
- static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
- .pReg = NULL };
-
- migrate.pPix = pPixmap;
- exaDoMoveInPixmap (&migrate);
-}
-
-/**
- * Switches the current active location of the pixmap to system memory, copying
- * updated data out if necessary.
- */
-static void
-exaDoMoveOutPixmap (ExaMigrationPtr migrate)
-{
- PixmapPtr pPixmap = migrate->pPix;
- ExaPixmapPriv (pPixmap);
-
- if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
- return;
-
- exaCopyDirtyToSys (migrate);
-
- if (exaPixmapHasGpuCopy(pPixmap)) {
-
- DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
- (void*)(ExaGetPixmapPriv(pPixmap)->area ?
- ExaGetPixmapPriv(pPixmap)->area->offset : 0),
- pPixmap->drawable.width,
- pPixmap->drawable.height,
- exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
-
- pExaPixmap->use_gpu_copy = FALSE;
-
- pPixmap->devKind = pExaPixmap->sys_pitch;
- pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
- }
-}
-
-void
-exaMoveOutPixmap_classic (PixmapPtr pPixmap)
-{
- static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
- .pReg = NULL };
-
- migrate.pPix = pPixmap;
- exaDoMoveOutPixmap (&migrate);
-}
-
-
-/**
- * Copies out important pixmap data and removes references to framebuffer area.
- * Called when the memory manager decides it's time to kick the pixmap out of
- * framebuffer entirely.
- */
-void
-exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
-{
- PixmapPtr pPixmap = area->privData;
- ExaPixmapPriv(pPixmap);
-
- exaMoveOutPixmap(pPixmap);
-
- pExaPixmap->fb_ptr = NULL;
- pExaPixmap->area = NULL;
-
- /* Mark all FB bits as invalid, so all valid system bits get copied to FB
- * next time */
- RegionEmpty(&pExaPixmap->validFB);
-}
-
-/**
- * For the "greedy" migration scheme, pushes the pixmap toward being located in
- * framebuffer memory.
- */
-static void
-exaMigrateTowardFb (ExaMigrationPtr migrate)
-{
- PixmapPtr pPixmap = migrate->pPix;
- ExaPixmapPriv (pPixmap);
-
- if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
- DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
- (pointer)pPixmap));
- return;
- }
-
- DBG_MIGRATE(("UseScreen %p score %d\n",
- (pointer)pPixmap, pExaPixmap->score));
-
- if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
- exaDoMoveInPixmap(migrate);
- pExaPixmap->score = 0;
- }
-
- if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
- pExaPixmap->score++;
-
- if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
- !exaPixmapHasGpuCopy(pPixmap))
- {
- exaDoMoveInPixmap(migrate);
- }
-
- if (exaPixmapHasGpuCopy(pPixmap)) {
- exaCopyDirtyToFb (migrate);
- ExaOffscreenMarkUsed (pPixmap);
- } else
- exaCopyDirtyToSys (migrate);
-}
-
-/**
- * For the "greedy" migration scheme, pushes the pixmap toward being located in
- * system memory.
- */
-static void
-exaMigrateTowardSys (ExaMigrationPtr migrate)
-{
- PixmapPtr pPixmap = migrate->pPix;
- ExaPixmapPriv (pPixmap);
-
- DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score));
-
- if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
- return;
-
- if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
- pExaPixmap->score = 0;
-
- if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
- pExaPixmap->score--;
-
- if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
- exaDoMoveOutPixmap(migrate);
-
- if (exaPixmapHasGpuCopy(pPixmap)) {
- exaCopyDirtyToFb (migrate);
- ExaOffscreenMarkUsed (pPixmap);
- } else
- exaCopyDirtyToSys (migrate);
-}
-
-/**
- * If the pixmap has both a framebuffer and system memory copy, this function
- * asserts that both of them are the same.
- */
-static Bool
-exaAssertNotDirty (PixmapPtr pPixmap)
-{
- ExaPixmapPriv (pPixmap);
- CARD8 *dst, *src;
- RegionRec ValidReg;
- int dst_pitch, src_pitch, cpp, y, nbox, save_pitch;
- BoxPtr pBox;
- Bool ret = TRUE, save_use_gpu_copy;
-
- if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
- return ret;
-
- RegionNull(&ValidReg);
- RegionIntersect(&ValidReg, &pExaPixmap->validFB,
- &pExaPixmap->validSys);
- nbox = RegionNumRects(&ValidReg);
-
- if (!nbox)
- goto out;
-
- pBox = RegionRects(&ValidReg);
-
- dst_pitch = pExaPixmap->sys_pitch;
- src_pitch = pExaPixmap->fb_pitch;
- cpp = pPixmap->drawable.bitsPerPixel / 8;
-
- save_use_gpu_copy = pExaPixmap->use_gpu_copy;
- save_pitch = pPixmap->devKind;
- pExaPixmap->use_gpu_copy = TRUE;
- pPixmap->devKind = pExaPixmap->fb_pitch;
-
- if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
- goto skip;
-
- while (nbox--) {
- int rowbytes;
-
- pBox->x1 = max(pBox->x1, 0);
- pBox->y1 = max(pBox->y1, 0);
- pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
- pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
-
- if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
- continue;
-
- rowbytes = (pBox->x2 - pBox->x1) * cpp;
- src = (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch + pBox->x1 * cpp;
- dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
-
- for (y = pBox->y1; y < pBox->y2;
- y++, src += src_pitch, dst += dst_pitch) {
- if (memcmp(dst, src, rowbytes) != 0) {
- ret = FALSE;
- exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2,
- pBox->y2);
- break;
- }
- }
- }
-
-skip:
- exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
-
- pExaPixmap->use_gpu_copy = save_use_gpu_copy;
- pPixmap->devKind = save_pitch;
-
-out:
- RegionUninit(&ValidReg);
- return ret;
-}
-
-/**
- * Performs migration of the pixmaps according to the operation information
- * provided in pixmaps and can_accel and the migration scheme chosen in the
- * config file.
- */
-void
-exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
-{
- ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
- ExaScreenPriv(pScreen);
- int i, j;
-
- /* If this debugging flag is set, check each pixmap for whether it is marked
- * as clean, and if so, actually check if that's the case. This should help
- * catch issues with failing to mark a drawable as dirty. While it will
- * catch them late (after the operation happened), it at least explains what
- * went wrong, and instrumenting the code to find what operation happened
- * to the pixmap last shouldn't be hard.
- */
- if (pExaScr->checkDirtyCorrectness) {
- for (i = 0; i < npixmaps; i++) {
- if (!exaPixmapIsDirty (pixmaps[i].pPix) &&
- !exaAssertNotDirty (pixmaps[i].pPix))
- ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i);
- }
- }
- /* If anything is pinned in system memory, we won't be able to
- * accelerate.
- */
- for (i = 0; i < npixmaps; i++) {
- if (exaPixmapIsPinned (pixmaps[i].pPix) &&
- !exaPixmapHasGpuCopy (pixmaps[i].pPix))
- {
- EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
- pixmaps[i].pPix->drawable.width,
- pixmaps[i].pPix->drawable.height));
- can_accel = FALSE;
- break;
- }
- }
-
- if (pExaScr->migration == ExaMigrationSmart) {
- /* If we've got something as a destination that we shouldn't cause to
- * become newly dirtied, take the unaccelerated route.
- */
- for (i = 0; i < npixmaps; i++) {
- if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) &&
- !exaPixmapIsDirty (pixmaps[i].pPix))
- {
- for (i = 0; i < npixmaps; i++) {
- if (!exaPixmapIsDirty (pixmaps[i].pPix))
- exaDoMoveOutPixmap (pixmaps + i);
- }
- return;
- }
- }
-
- /* If we aren't going to accelerate, then we migrate everybody toward
- * system memory, and kick out if it's free.
- */
- if (!can_accel) {
- for (i = 0; i < npixmaps; i++) {
- exaMigrateTowardSys (pixmaps + i);
- if (!exaPixmapIsDirty (pixmaps[i].pPix))
- exaDoMoveOutPixmap (pixmaps + i);
- }
- return;
- }
-
- /* Finally, the acceleration path. Move them all in. */
- for (i = 0; i < npixmaps; i++) {
- exaMigrateTowardFb(pixmaps + i);
- exaDoMoveInPixmap(pixmaps + i);
- }
- } else if (pExaScr->migration == ExaMigrationGreedy) {
- /* If we can't accelerate, either because the driver can't or because one of
- * the pixmaps is pinned in system memory, then we migrate everybody toward
- * system memory.
- *
- * We also migrate toward system if all pixmaps involved are currently in
- * system memory -- this can mitigate thrashing when there are significantly
- * more pixmaps active than would fit in memory.
- *
- * If not, then we migrate toward FB so that hopefully acceleration can
- * happen.
- */
- if (!can_accel) {
- for (i = 0; i < npixmaps; i++)
- exaMigrateTowardSys (pixmaps + i);
- return;
- }
-
- for (i = 0; i < npixmaps; i++) {
- if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
- /* Found one in FB, so move all to FB. */
- for (j = 0; j < npixmaps; j++)
- exaMigrateTowardFb(pixmaps + i);
- return;
- }
- }
-
- /* Nobody's in FB, so move all away from FB. */
- for (i = 0; i < npixmaps; i++)
- exaMigrateTowardSys(pixmaps + i);
- } else if (pExaScr->migration == ExaMigrationAlways) {
- /* Always move the pixmaps out if we can't accelerate. If we can
- * accelerate, try to move them all in. If that fails, then move them
- * back out.
- */
- if (!can_accel) {
- for (i = 0; i < npixmaps; i++)
- exaDoMoveOutPixmap(pixmaps + i);
- return;
- }
-
- /* Now, try to move them all into FB */
- for (i = 0; i < npixmaps; i++) {
- exaDoMoveInPixmap(pixmaps + i);
- }
-
- /* If we couldn't fit everything in, abort */
- for (i = 0; i < npixmaps; i++) {
- if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
- return;
- }
- }
-
- /* Yay, everything has a gpu copy, mark memory as used */
- for (i = 0; i < npixmaps; i++) {
- ExaOffscreenMarkUsed (pixmaps[i].pPix);
- }
- }
-}
-
-void
-exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
-{
- ExaMigrationRec pixmaps[1];
-
- if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- } else {
- pixmaps[0].as_dst = FALSE;
- pixmaps[0].as_src = TRUE;
- }
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = pReg;
-
- exaDoMigration(pixmaps, 1, FALSE);
-
- (void)ExaDoPrepareAccess(pPixmap, index);
-}
+/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Michel Dänzer <michel@tungstengraphics.com> + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +#if DEBUG_MIGRATE +#define DBG_MIGRATE(a) ErrorF a +#else +#define DBG_MIGRATE(a) +#endif + +/** + * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys + * and exaCopyDirtyToFb both needed to do this loop. + */ +static void +exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch, + CARD8 *dst, int dst_pitch) + { + int i, cpp = pPixmap->drawable.bitsPerPixel / 8; + int bytes = (pbox->x2 - pbox->x1) * cpp; + + src += pbox->y1 * src_pitch + pbox->x1 * cpp; + dst += pbox->y1 * dst_pitch + pbox->x1 * cpp; + + for (i = pbox->y2 - pbox->y1; i; i--) { + memcpy (dst, src, bytes); + src += src_pitch; + dst += dst_pitch; + } +} + +/** + * Returns TRUE if the pixmap is dirty (has been modified in its current + * location compared to the other), or lacks a private for tracking + * dirtiness. + */ +static Bool +exaPixmapIsDirty (PixmapPtr pPix) +{ + ExaPixmapPriv (pPix); + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE); + + if (!pExaPixmap->pDamage) + return FALSE; + + return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) || + !RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB); +} + +/** + * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score + * to be considered "should be in framebuffer". That's just anything that has + * had more acceleration than fallbacks, or has no score yet. + * + * Only valid if using a migration scheme that tracks score. + */ +static Bool +exaPixmapShouldBeInFB (PixmapPtr pPix) +{ + ExaPixmapPriv (pPix); + + if (exaPixmapIsPinned (pPix)) + return TRUE; + + return pExaPixmap->score >= 0; +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * FB to system or vice versa. Both areas must be allocated. + */ +static void +exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, + Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, + char *sys, int sys_pitch), int fallback_index, + void (*sync) (ScreenPtr pScreen)) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + RegionPtr damage = DamageRegion (pExaPixmap->pDamage); + RegionRec CopyReg; + Bool save_use_gpu_copy; + int save_pitch; + BoxPtr pBox; + int nbox; + Bool access_prepared = FALSE; + Bool need_sync = FALSE; + + /* Damaged bits are valid in current copy but invalid in other one */ + if (pExaPixmap->use_gpu_copy) { + RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, + damage); + RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, + damage); + } else { + RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, + damage); + RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, + damage); + } + + RegionEmpty(damage); + + /* Copy bits valid in source but not in destination */ + RegionNull(&CopyReg); + RegionSubtract(&CopyReg, pValidSrc, pValidDst); + + if (migrate->as_dst) { + ExaScreenPriv (pPixmap->drawable.pScreen); + + /* XXX: The pending damage region will be marked as damaged after the + * operation, so it should serve as an upper bound for the region that + * needs to be synchronized for the operation. Unfortunately, this + * causes corruption in some cases, e.g. when starting compiz. See + * https://bugs.freedesktop.org/show_bug.cgi?id=12916 . + */ + if (pExaScr->optimize_migration) { + RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); + +#if DEBUG_MIGRATE + if (RegionNil(pending_damage)) { + static Bool firsttime = TRUE; + + if (firsttime) { + ErrorF("%s: Pending damage region empty!\n", __func__); + firsttime = FALSE; + } + } +#endif + + /* Try to prevent destination valid region from growing too many + * rects by filling it up to the extents of the union of the + * destination valid region and the pending damage region. + */ + if (RegionNumRects(pValidDst) > 10) { + BoxRec box; + BoxPtr pValidExt, pDamageExt; + RegionRec closure; + + pValidExt = RegionExtents(pValidDst); + pDamageExt = RegionExtents(pending_damage); + + box.x1 = min(pValidExt->x1, pDamageExt->x1); + box.y1 = min(pValidExt->y1, pDamageExt->y1); + box.x2 = max(pValidExt->x2, pDamageExt->x2); + box.y2 = max(pValidExt->y2, pDamageExt->y2); + + RegionInit(&closure, &box, 0); + RegionIntersect(&CopyReg, &CopyReg, &closure); + } else + RegionIntersect(&CopyReg, &CopyReg, pending_damage); + } + + /* The caller may provide a region to be subtracted from the calculated + * dirty region. This is to avoid migration of bits that don't + * contribute to the result of the operation. + */ + if (migrate->pReg) + RegionSubtract(&CopyReg, &CopyReg, migrate->pReg); + } else { + /* The caller may restrict the region to be migrated for source pixmaps + * to what's relevant for the operation. + */ + if (migrate->pReg) + RegionIntersect(&CopyReg, &CopyReg, migrate->pReg); + } + + pBox = RegionRects(&CopyReg); + nbox = RegionNumRects(&CopyReg); + + save_use_gpu_copy = pExaPixmap->use_gpu_copy; + save_pitch = pPixmap->devKind; + pExaPixmap->use_gpu_copy = TRUE; + pPixmap->devKind = pExaPixmap->fb_pitch; + + while (nbox--) { + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); + + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; + + if (!transfer || !transfer (pPixmap, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + (char *) (pExaPixmap->sys_ptr + + pBox->y1 * pExaPixmap->sys_pitch + + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), + pExaPixmap->sys_pitch)) + { + if (!access_prepared) { + ExaDoPrepareAccess(pPixmap, fallback_index); + access_prepared = TRUE; + } + if (fallback_index == EXA_PREPARE_DEST) { + exaMemcpyBox (pPixmap, pBox, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, + pPixmap->devPrivate.ptr, pPixmap->devKind); + } else { + exaMemcpyBox (pPixmap, pBox, + pPixmap->devPrivate.ptr, pPixmap->devKind, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); + } + } else + need_sync = TRUE; + + pBox++; + } + + pExaPixmap->use_gpu_copy = save_use_gpu_copy; + pPixmap->devKind = save_pitch; + + /* Try to prevent source valid region from growing too many rects by + * removing parts of it which are also in the destination valid region. + * Removing anything beyond that would lead to data loss. + */ + if (RegionNumRects(pValidSrc) > 20) + RegionSubtract(pValidSrc, pValidSrc, pValidDst); + + /* The copied bits are now valid in destination */ + RegionUnion(pValidDst, pValidDst, &CopyReg); + + RegionUninit(&CopyReg); + + if (access_prepared) + exaFinishAccess(&pPixmap->drawable, fallback_index); + else if (need_sync && sync) + sync (pPixmap->drawable.pScreen); +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * the framebuffer memory copy to the system memory copy. Both areas must be + * allocated. + */ +void +exaCopyDirtyToSys (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaScreenPriv (pPixmap->drawable.pScreen); + ExaPixmapPriv (pPixmap); + + exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB, + pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC, + exaWaitSync); +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * the system memory copy to the framebuffer memory copy. Both areas must be + * allocated. + */ +void +exaCopyDirtyToFb (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaScreenPriv (pPixmap->drawable.pScreen); + ExaPixmapPriv (pPixmap); + + exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys, + pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL); +} + +/** + * Allocates a framebuffer copy of the pixmap if necessary, and then copies + * any necessary pixmap data into the framebuffer copy and points the pixmap at + * it. + * + * Note that when first allocated, a pixmap will have FALSE dirty flag. + * This is intentional because pixmap data starts out undefined. So if we move + * it in due to the first operation against it being accelerated, it will have + * undefined framebuffer contents that we didn't have to upload. If we do + * moveouts (and moveins) after the first movein, then we will only have to copy + * back and forth if the pixmap was written to after the last synchronization of + * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away) + * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move + * all the data, since it's almost surely all valid now. + */ +static void +exaDoMoveInPixmap (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv (pScreen); + ExaPixmapPriv (pPixmap); + + /* If we're VT-switched away, no touching card memory allowed. */ + if (pExaScr->swappedOut) + return; + + /* If we're not allowed to move, then fail. */ + if (exaPixmapIsPinned(pPixmap)) + return; + + /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of + * fragility in EXA, and <8bpp is probably not used enough any more to care + * (at least, not in acceleratd paths). + */ + if (pPixmap->drawable.bitsPerPixel < 8) + return; + + if (pExaPixmap->accel_blocked) + return; + + if (pExaPixmap->area == NULL) { + pExaPixmap->area = + exaOffscreenAlloc (pScreen, pExaPixmap->fb_size, + pExaScr->info->pixmapOffsetAlign, FALSE, + exaPixmapSave, (pointer) pPixmap); + if (pExaPixmap->area == NULL) + return; + + pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase + + pExaPixmap->area->offset; + } + + exaCopyDirtyToFb (migrate); + + if (exaPixmapHasGpuCopy(pPixmap)) + return; + + DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap, + (ExaGetPixmapPriv(pPixmap)->area ? + ExaGetPixmapPriv(pPixmap)->area->offset : 0), + pPixmap->drawable.width, + pPixmap->drawable.height, + exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); + + pExaPixmap->use_gpu_copy = TRUE; + + pPixmap->devKind = pExaPixmap->fb_pitch; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; +} + +void +exaMoveInPixmap_classic (PixmapPtr pPixmap) +{ + static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, + .pReg = NULL }; + + migrate.pPix = pPixmap; + exaDoMoveInPixmap (&migrate); +} + +/** + * Switches the current active location of the pixmap to system memory, copying + * updated data out if necessary. + */ +static void +exaDoMoveOutPixmap (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap)) + return; + + exaCopyDirtyToSys (migrate); + + if (exaPixmapHasGpuCopy(pPixmap)) { + + DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap, + (void*)(ExaGetPixmapPriv(pPixmap)->area ? + ExaGetPixmapPriv(pPixmap)->area->offset : 0), + pPixmap->drawable.width, + pPixmap->drawable.height, + exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); + + pExaPixmap->use_gpu_copy = FALSE; + + pPixmap->devKind = pExaPixmap->sys_pitch; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } +} + +void +exaMoveOutPixmap_classic (PixmapPtr pPixmap) +{ + static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, + .pReg = NULL }; + + migrate.pPix = pPixmap; + exaDoMoveOutPixmap (&migrate); +} + + +/** + * Copies out important pixmap data and removes references to framebuffer area. + * Called when the memory manager decides it's time to kick the pixmap out of + * framebuffer entirely. + */ +void +exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area) +{ + PixmapPtr pPixmap = area->privData; + ExaPixmapPriv(pPixmap); + + exaMoveOutPixmap(pPixmap); + + pExaPixmap->fb_ptr = NULL; + pExaPixmap->area = NULL; + + /* Mark all FB bits as invalid, so all valid system bits get copied to FB + * next time */ + RegionEmpty(&pExaPixmap->validFB); +} + +/** + * For the "greedy" migration scheme, pushes the pixmap toward being located in + * framebuffer memory. + */ +static void +exaMigrateTowardFb (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) { + DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n", + (pointer)pPixmap)); + return; + } + + DBG_MIGRATE(("UseScreen %p score %d\n", + (pointer)pPixmap, pExaPixmap->score)); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) { + exaDoMoveInPixmap(migrate); + pExaPixmap->score = 0; + } + + if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX) + pExaPixmap->score++; + + if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && + !exaPixmapHasGpuCopy(pPixmap)) + { + exaDoMoveInPixmap(migrate); + } + + if (exaPixmapHasGpuCopy(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); +} + +/** + * For the "greedy" migration scheme, pushes the pixmap toward being located in + * system memory. + */ +static void +exaMigrateTowardSys (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score)); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) + return; + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) + pExaPixmap->score = 0; + + if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN) + pExaPixmap->score--; + + if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) + exaDoMoveOutPixmap(migrate); + + if (exaPixmapHasGpuCopy(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); +} + +/** + * If the pixmap has both a framebuffer and system memory copy, this function + * asserts that both of them are the same. + */ +static Bool +exaAssertNotDirty (PixmapPtr pPixmap) +{ + ExaPixmapPriv (pPixmap); + CARD8 *dst, *src; + RegionRec ValidReg; + int dst_pitch, src_pitch, cpp, y, nbox, save_pitch; + BoxPtr pBox; + Bool ret = TRUE, save_use_gpu_copy; + + if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL) + return ret; + + RegionNull(&ValidReg); + RegionIntersect(&ValidReg, &pExaPixmap->validFB, + &pExaPixmap->validSys); + nbox = RegionNumRects(&ValidReg); + + if (!nbox) + goto out; + + pBox = RegionRects(&ValidReg); + + dst_pitch = pExaPixmap->sys_pitch; + src_pitch = pExaPixmap->fb_pitch; + cpp = pPixmap->drawable.bitsPerPixel / 8; + + save_use_gpu_copy = pExaPixmap->use_gpu_copy; + save_pitch = pPixmap->devKind; + pExaPixmap->use_gpu_copy = TRUE; + pPixmap->devKind = pExaPixmap->fb_pitch; + + if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC)) + goto skip; + + while (nbox--) { + int rowbytes; + + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); + + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; + + rowbytes = (pBox->x2 - pBox->x1) * cpp; + src = (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch + pBox->x1 * cpp; + dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp; + + for (y = pBox->y1; y < pBox->y2; + y++, src += src_pitch, dst += dst_pitch) { + if (memcmp(dst, src, rowbytes) != 0) { + ret = FALSE; + exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, + pBox->y2); + break; + } + } + } + +skip: + exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + + pExaPixmap->use_gpu_copy = save_use_gpu_copy; + pPixmap->devKind = save_pitch; + +out: + RegionUninit(&ValidReg); + return ret; +} + +/** + * Performs migration of the pixmaps according to the operation information + * provided in pixmaps and can_accel and the migration scheme chosen in the + * config file. + */ +void +exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +{ + ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; + ExaScreenPriv(pScreen); + int i, j; + + /* If this debugging flag is set, check each pixmap for whether it is marked + * as clean, and if so, actually check if that's the case. This should help + * catch issues with failing to mark a drawable as dirty. While it will + * catch them late (after the operation happened), it at least explains what + * went wrong, and instrumenting the code to find what operation happened + * to the pixmap last shouldn't be hard. + */ + if (pExaScr->checkDirtyCorrectness) { + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapIsDirty (pixmaps[i].pPix) && + !exaAssertNotDirty (pixmaps[i].pPix)) + ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i); + } + } + /* If anything is pinned in system memory, we won't be able to + * accelerate. + */ + for (i = 0; i < npixmaps; i++) { + if (exaPixmapIsPinned (pixmaps[i].pPix) && + !exaPixmapHasGpuCopy (pixmaps[i].pPix)) + { + EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix, + pixmaps[i].pPix->drawable.width, + pixmaps[i].pPix->drawable.height)); + can_accel = FALSE; + break; + } + } + + if (pExaScr->migration == ExaMigrationSmart) { + /* If we've got something as a destination that we shouldn't cause to + * become newly dirtied, take the unaccelerated route. + */ + for (i = 0; i < npixmaps; i++) { + if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) && + !exaPixmapIsDirty (pixmaps[i].pPix)) + { + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapIsDirty (pixmaps[i].pPix)) + exaDoMoveOutPixmap (pixmaps + i); + } + return; + } + } + + /* If we aren't going to accelerate, then we migrate everybody toward + * system memory, and kick out if it's free. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) { + exaMigrateTowardSys (pixmaps + i); + if (!exaPixmapIsDirty (pixmaps[i].pPix)) + exaDoMoveOutPixmap (pixmaps + i); + } + return; + } + + /* Finally, the acceleration path. Move them all in. */ + for (i = 0; i < npixmaps; i++) { + exaMigrateTowardFb(pixmaps + i); + exaDoMoveInPixmap(pixmaps + i); + } + } else if (pExaScr->migration == ExaMigrationGreedy) { + /* If we can't accelerate, either because the driver can't or because one of + * the pixmaps is pinned in system memory, then we migrate everybody toward + * system memory. + * + * We also migrate toward system if all pixmaps involved are currently in + * system memory -- this can mitigate thrashing when there are significantly + * more pixmaps active than would fit in memory. + * + * If not, then we migrate toward FB so that hopefully acceleration can + * happen. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) + exaMigrateTowardSys (pixmaps + i); + return; + } + + for (i = 0; i < npixmaps; i++) { + if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) { + /* Found one in FB, so move all to FB. */ + for (j = 0; j < npixmaps; j++) + exaMigrateTowardFb(pixmaps + i); + return; + } + } + + /* Nobody's in FB, so move all away from FB. */ + for (i = 0; i < npixmaps; i++) + exaMigrateTowardSys(pixmaps + i); + } else if (pExaScr->migration == ExaMigrationAlways) { + /* Always move the pixmaps out if we can't accelerate. If we can + * accelerate, try to move them all in. If that fails, then move them + * back out. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) + exaDoMoveOutPixmap(pixmaps + i); + return; + } + + /* Now, try to move them all into FB */ + for (i = 0; i < npixmaps; i++) { + exaDoMoveInPixmap(pixmaps + i); + } + + /* If we couldn't fit everything in, abort */ + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) { + return; + } + } + + /* Yay, everything has a gpu copy, mark memory as used */ + for (i = 0; i < npixmaps; i++) { + ExaOffscreenMarkUsed (pixmaps[i].pPix); + } + } +} + +void +exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg) +{ + ExaMigrationRec pixmaps[1]; + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + } else { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + } + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = pReg; + + exaDoMigration(pixmaps, 1, FALSE); + + (void)ExaDoPrepareAccess(pPixmap, index); +} diff --git a/xorg-server/exa/exa_migration_mixed.c b/xorg-server/exa/exa_migration_mixed.c index 9489b2927..4b2261943 100644 --- a/xorg-server/exa/exa_migration_mixed.c +++ b/xorg-server/exa/exa_migration_mixed.c @@ -1,261 +1,261 @@ -/*
- * Copyright © 2009 Maarten Maathuis
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#include "exa_priv.h"
-#include "exa.h"
-
-void
-exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- ExaPixmapPriv(pPixmap);
- int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
- int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
- int usage_hint = pPixmap->usage_hint;
- int paddedWidth = pExaPixmap->sys_pitch;
-
- /* Already done. */
- if (pExaPixmap->driverPriv)
- return;
-
- if (exaPixmapIsPinned(pPixmap))
- return;
-
- /* Can't accel 1/4 bpp. */
- if (pExaPixmap->accel_blocked || bpp < 8)
- return;
-
- if (pExaScr->info->CreatePixmap2) {
- int new_pitch = 0;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
- paddedWidth = pExaPixmap->fb_pitch = new_pitch;
- } else {
- if (paddedWidth < pExaPixmap->fb_pitch)
- paddedWidth = pExaPixmap->fb_pitch;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0);
- }
-
- if (!pExaPixmap->driverPriv)
- return;
-
- (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
- paddedWidth, NULL);
-}
-
-void
-exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
-{
- int i;
-
- /* If anything is pinned in system memory, we won't be able to
- * accelerate.
- */
- for (i = 0; i < npixmaps; i++) {
- if (exaPixmapIsPinned (pixmaps[i].pPix) &&
- !exaPixmapHasGpuCopy (pixmaps[i].pPix))
- {
- can_accel = FALSE;
- break;
- }
- }
-
- /* We can do nothing. */
- if (!can_accel)
- return;
-
- for (i = 0; i < npixmaps; i++) {
- PixmapPtr pPixmap = pixmaps[i].pPix;
- ExaPixmapPriv(pPixmap);
-
- if (!pExaPixmap->driverPriv)
- exaCreateDriverPixmap_mixed(pPixmap);
-
- if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
- ExaScreenPriv(pPixmap->drawable.pScreen);
-
- /* This pitch is needed for proper acceleration. For some reason
- * there are pixmaps without pDamage and a bad fb_pitch value.
- * So setting devKind when only exaPixmapHasGpuCopy() is true
- * causes corruption. Pixmaps without pDamage are not migrated
- * and should have a valid devKind at all times, so that's why this
- * isn't causing problems. Pixmaps have their gpu pitch set the
- * first time in the MPH call from exaCreateDriverPixmap_mixed().
- */
- pPixmap->devKind = pExaPixmap->fb_pitch;
- exaCopyDirtyToFb(pixmaps + i);
-
- if (pExaScr->deferred_mixed_pixmap == pPixmap &&
- !pixmaps[i].as_dst && !pixmaps[i].pReg)
- pExaScr->deferred_mixed_pixmap = NULL;
- }
-
- pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
- }
-}
-
-void
-exaMoveInPixmap_mixed(PixmapPtr pPixmap)
-{
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = FALSE;
- pixmaps[0].as_src = TRUE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = NULL;
-
- exaDoMigration(pixmaps, 1, TRUE);
-}
-
-void
-exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
-{
- PixmapPtr pPixmap = closure;
- ExaPixmapPriv(pPixmap);
-
- /* Move back results of software rendering on system memory copy of mixed driver
- * pixmap (see exaPrepareAccessReg_mixed).
- *
- * Defer moving the destination back into the driver pixmap, to try and save
- * overhead on multiple subsequent software fallbacks.
- */
- if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
- ExaScreenPriv(pPixmap->drawable.pScreen);
-
- if (pExaScr->deferred_mixed_pixmap &&
- pExaScr->deferred_mixed_pixmap != pPixmap)
- exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
- pExaScr->deferred_mixed_pixmap = pPixmap;
- }
-}
-
-/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
- * use the DownloadFromScreen hook to retrieve contents to a copy in system
- * memory, perform software rendering on that and move back the results with the
- * UploadToScreen hook (see exaDamageReport_mixed).
- */
-void
-exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
-{
- ExaPixmapPriv(pPixmap);
- Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
- Bool success;
-
- success = ExaDoPrepareAccess(pPixmap, index);
-
- if (success && has_gpu_copy && pExaPixmap->pDamage) {
- /* You cannot do accelerated operations while a buffer is mapped. */
- exaFinishAccess(&pPixmap->drawable, index);
- /* Update the gpu view of both deferred destination pixmaps and of
- * source pixmaps that were migrated with a bounding region.
- */
- exaMoveInPixmap_mixed(pPixmap);
- success = ExaDoPrepareAccess(pPixmap, index);
-
- if (success) {
- /* We have a gpu pixmap that can be accessed, we don't need the cpu
- * copy anymore. Drivers that prefer DFS, should fail prepare
- * access.
- */
- DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
- DamageDestroy(pExaPixmap->pDamage);
- pExaPixmap->pDamage = NULL;
-
- free(pExaPixmap->sys_ptr);
- pExaPixmap->sys_ptr = NULL;
-
- return;
- }
- }
-
- if (!success) {
- ExaMigrationRec pixmaps[1];
-
- /* Do we need to allocate our system buffer? */
- if (!pExaPixmap->sys_ptr) {
- pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch *
- pPixmap->drawable.height);
- if (!pExaPixmap->sys_ptr)
- FatalError("EXA: malloc failed for size %d bytes\n",
- pExaPixmap->sys_pitch * pPixmap->drawable.height);
- }
-
- if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- } else {
- pixmaps[0].as_dst = FALSE;
- pixmaps[0].as_src = TRUE;
- }
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = pReg;
-
- if (!pExaPixmap->pDamage &&
- (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
- Bool as_dst = pixmaps[0].as_dst;
-
- /* Set up damage tracking */
- pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
- DamageReportNonEmpty, TRUE,
- pPixmap->drawable.pScreen,
- pPixmap);
-
- DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
- /* This ensures that pending damage reflects the current operation. */
- /* This is used by exa to optimize migration. */
- DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
-
- if (has_gpu_copy) {
- exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
- pPixmap->drawable.height);
-
- /* We don't know which region of the destination will be damaged,
- * have to assume all of it
- */
- if (as_dst) {
- pixmaps[0].as_dst = FALSE;
- pixmaps[0].as_src = TRUE;
- pixmaps[0].pReg = NULL;
- }
- exaCopyDirtyToSys(pixmaps);
- }
-
- if (as_dst)
- exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
- pPixmap->drawable.height);
- } else if (has_gpu_copy)
- exaCopyDirtyToSys(pixmaps);
-
- pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
- pPixmap->devKind = pExaPixmap->sys_pitch;
- pExaPixmap->use_gpu_copy = FALSE;
- }
-}
-
+/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +void +exaCreateDriverPixmap_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + int w = pPixmap->drawable.width, h = pPixmap->drawable.height; + int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel; + int usage_hint = pPixmap->usage_hint; + int paddedWidth = pExaPixmap->sys_pitch; + + /* Already done. */ + if (pExaPixmap->driverPriv) + return; + + if (exaPixmapIsPinned(pPixmap)) + return; + + /* Can't accel 1/4 bpp. */ + if (pExaPixmap->accel_blocked || bpp < 8) + return; + + if (pExaScr->info->CreatePixmap2) { + int new_pitch = 0; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch); + paddedWidth = pExaPixmap->fb_pitch = new_pitch; + } else { + if (paddedWidth < pExaPixmap->fb_pitch) + paddedWidth = pExaPixmap->fb_pitch; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0); + } + + if (!pExaPixmap->driverPriv) + return; + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); +} + +void +exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +{ + int i; + + /* If anything is pinned in system memory, we won't be able to + * accelerate. + */ + for (i = 0; i < npixmaps; i++) { + if (exaPixmapIsPinned (pixmaps[i].pPix) && + !exaPixmapHasGpuCopy (pixmaps[i].pPix)) + { + can_accel = FALSE; + break; + } + } + + /* We can do nothing. */ + if (!can_accel) + return; + + for (i = 0; i < npixmaps; i++) { + PixmapPtr pPixmap = pixmaps[i].pPix; + ExaPixmapPriv(pPixmap); + + if (!pExaPixmap->driverPriv) + exaCreateDriverPixmap_mixed(pPixmap); + + if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) { + ExaScreenPriv(pPixmap->drawable.pScreen); + + /* This pitch is needed for proper acceleration. For some reason + * there are pixmaps without pDamage and a bad fb_pitch value. + * So setting devKind when only exaPixmapHasGpuCopy() is true + * causes corruption. Pixmaps without pDamage are not migrated + * and should have a valid devKind at all times, so that's why this + * isn't causing problems. Pixmaps have their gpu pitch set the + * first time in the MPH call from exaCreateDriverPixmap_mixed(). + */ + pPixmap->devKind = pExaPixmap->fb_pitch; + exaCopyDirtyToFb(pixmaps + i); + + if (pExaScr->deferred_mixed_pixmap == pPixmap && + !pixmaps[i].as_dst && !pixmaps[i].pReg) + pExaScr->deferred_mixed_pixmap = NULL; + } + + pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + } +} + +void +exaMoveInPixmap_mixed(PixmapPtr pPixmap) +{ + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + + exaDoMigration(pixmaps, 1, TRUE); +} + +void +exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + PixmapPtr pPixmap = closure; + ExaPixmapPriv(pPixmap); + + /* Move back results of software rendering on system memory copy of mixed driver + * pixmap (see exaPrepareAccessReg_mixed). + * + * Defer moving the destination back into the driver pixmap, to try and save + * overhead on multiple subsequent software fallbacks. + */ + if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) { + ExaScreenPriv(pPixmap->drawable.pScreen); + + if (pExaScr->deferred_mixed_pixmap && + pExaScr->deferred_mixed_pixmap != pPixmap) + exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap); + pExaScr->deferred_mixed_pixmap = pPixmap; + } +} + +/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we + * use the DownloadFromScreen hook to retrieve contents to a copy in system + * memory, perform software rendering on that and move back the results with the + * UploadToScreen hook (see exaDamageReport_mixed). + */ +void +exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg) +{ + ExaPixmapPriv(pPixmap); + Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + Bool success; + + success = ExaDoPrepareAccess(pPixmap, index); + + if (success && has_gpu_copy && pExaPixmap->pDamage) { + /* You cannot do accelerated operations while a buffer is mapped. */ + exaFinishAccess(&pPixmap->drawable, index); + /* Update the gpu view of both deferred destination pixmaps and of + * source pixmaps that were migrated with a bounding region. + */ + exaMoveInPixmap_mixed(pPixmap); + success = ExaDoPrepareAccess(pPixmap, index); + + if (success) { + /* We have a gpu pixmap that can be accessed, we don't need the cpu + * copy anymore. Drivers that prefer DFS, should fail prepare + * access. + */ + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + + return; + } + } + + if (!success) { + ExaMigrationRec pixmaps[1]; + + /* Do we need to allocate our system buffer? */ + if (!pExaPixmap->sys_ptr) { + pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * + pPixmap->drawable.height); + if (!pExaPixmap->sys_ptr) + FatalError("EXA: malloc failed for size %d bytes\n", + pExaPixmap->sys_pitch * pPixmap->drawable.height); + } + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + } else { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + } + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = pReg; + + if (!pExaPixmap->pDamage && + (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) { + Bool as_dst = pixmaps[0].as_dst; + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, + DamageReportNonEmpty, TRUE, + pPixmap->drawable.pScreen, + pPixmap); + + DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); + + if (has_gpu_copy) { + exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, + pPixmap->drawable.height); + + /* We don't know which region of the destination will be damaged, + * have to assume all of it + */ + if (as_dst) { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + pixmaps[0].pReg = NULL; + } + exaCopyDirtyToSys(pixmaps); + } + + if (as_dst) + exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, + pPixmap->drawable.height); + } else if (has_gpu_copy) + exaCopyDirtyToSys(pixmaps); + + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + pExaPixmap->use_gpu_copy = FALSE; + } +} + diff --git a/xorg-server/exa/exa_mixed.c b/xorg-server/exa/exa_mixed.c index 188a7e0a6..58645aea0 100644 --- a/xorg-server/exa/exa_mixed.c +++ b/xorg-server/exa/exa_mixed.c @@ -1,290 +1,290 @@ -/*
- * Copyright © 2009 Maarten Maathuis
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#include "exa_priv.h"
-#include "exa.h"
-
-/* This file holds the driver allocated pixmaps + better initial placement code.
- */
-
-static _X_INLINE void*
-ExaGetPixmapAddress(PixmapPtr p)
-{
- ExaPixmapPriv(p);
-
- return pExaPixmap->sys_ptr;
-}
-
-/**
- * exaCreatePixmap() creates a new pixmap.
- */
-PixmapPtr
-exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
- unsigned usage_hint)
-{
- PixmapPtr pPixmap;
- ExaPixmapPrivPtr pExaPixmap;
- int bpp;
- size_t paddedWidth;
- ExaScreenPriv(pScreen);
-
- if (w > 32767 || h > 32767)
- return NullPixmap;
-
- swap(pExaScr, pScreen, CreatePixmap);
- pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
- swap(pExaScr, pScreen, CreatePixmap);
-
- if (!pPixmap)
- return NULL;
-
- pExaPixmap = ExaGetPixmapPriv(pPixmap);
- pExaPixmap->driverPriv = NULL;
-
- bpp = pPixmap->drawable.bitsPerPixel;
-
- paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
- if (paddedWidth / 4 > 32767 || h > 32767)
- return NullPixmap;
-
- /* We will allocate the system pixmap later if needed. */
- pPixmap->devPrivate.ptr = NULL;
- pExaPixmap->sys_ptr = NULL;
- pExaPixmap->sys_pitch = paddedWidth;
-
- pExaPixmap->area = NULL;
- pExaPixmap->fb_ptr = NULL;
- pExaPixmap->pDamage = NULL;
-
- exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
- exaSetAccelBlock(pExaScr, pExaPixmap,
- w, h, bpp);
-
- (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
- paddedWidth, NULL);
-
- /* A scratch pixmap will become a driver pixmap right away. */
- if (!w || !h) {
- exaCreateDriverPixmap_mixed(pPixmap);
- pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
- } else {
- pExaPixmap->use_gpu_copy = FALSE;
-
- if (w == 1 && h == 1) {
- pExaPixmap->sys_ptr = malloc(paddedWidth);
-
- /* Set up damage tracking */
- pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
- DamageReportNonEmpty, TRUE,
- pPixmap->drawable.pScreen,
- pPixmap);
-
- DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
- /* This ensures that pending damage reflects the current operation. */
- /* This is used by exa to optimize migration. */
- DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
- }
- }
-
- /* During a fallback we must prepare access. */
- if (pExaScr->fallback_counter)
- exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
-
- return pPixmap;
-}
-
-Bool
-exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
- int bitsPerPixel, int devKind, pointer pPixData)
-{
- ScreenPtr pScreen;
- ExaScreenPrivPtr pExaScr;
- ExaPixmapPrivPtr pExaPixmap;
- Bool ret, has_gpu_copy;
-
- if (!pPixmap)
- return FALSE;
-
- pScreen = pPixmap->drawable.pScreen;
- pExaScr = ExaGetScreenPriv(pScreen);
- pExaPixmap = ExaGetPixmapPriv(pPixmap);
-
- if (pPixData) {
- if (pExaPixmap->driverPriv) {
- if (pExaPixmap->pDamage) {
- DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
- DamageDestroy(pExaPixmap->pDamage);
- pExaPixmap->pDamage = NULL;
- }
-
- pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
- pExaPixmap->driverPriv = NULL;
- }
-
- pExaPixmap->use_gpu_copy = FALSE;
- pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
- }
-
- has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
-
- if (width <= 0)
- width = pPixmap->drawable.width;
-
- if (height <= 0)
- height = pPixmap->drawable.height;
-
- if (bitsPerPixel <= 0) {
- if (depth <= 0)
- bitsPerPixel = pPixmap->drawable.bitsPerPixel;
- else
- bitsPerPixel = BitsPerPixel(depth);
- }
-
- if (depth <= 0)
- depth = pPixmap->drawable.depth;
-
- if (width != pPixmap->drawable.width ||
- height != pPixmap->drawable.height ||
- depth != pPixmap->drawable.depth ||
- bitsPerPixel != pPixmap->drawable.bitsPerPixel) {
- if (pExaPixmap->driverPriv) {
- if (devKind > 0)
- pExaPixmap->fb_pitch = devKind;
- else
- exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
-
- exaSetAccelBlock(pExaScr, pExaPixmap,
- width, height, bitsPerPixel);
- RegionEmpty(&pExaPixmap->validFB);
- }
-
- /* Need to re-create system copy if there's also a GPU copy */
- if (has_gpu_copy && pExaPixmap->sys_ptr) {
- free(pExaPixmap->sys_ptr);
- pExaPixmap->sys_ptr = NULL;
- pExaPixmap->sys_pitch = PixmapBytePad(width, depth);
- DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
- DamageDestroy(pExaPixmap->pDamage);
- pExaPixmap->pDamage = NULL;
- RegionEmpty(&pExaPixmap->validSys);
-
- if (pExaScr->deferred_mixed_pixmap == pPixmap)
- pExaScr->deferred_mixed_pixmap = NULL;
- }
- }
-
- if (has_gpu_copy) {
- pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
- pPixmap->devKind = pExaPixmap->fb_pitch;
- } else {
- pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
- pPixmap->devKind = pExaPixmap->sys_pitch;
- }
-
- /* Only pass driver pixmaps to the driver. */
- if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
- ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
- bitsPerPixel, devKind, pPixData);
- if (ret == TRUE)
- goto out;
- }
-
- swap(pExaScr, pScreen, ModifyPixmapHeader);
- ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
- bitsPerPixel, devKind, pPixData);
- swap(pExaScr, pScreen, ModifyPixmapHeader);
-
-out:
- if (has_gpu_copy) {
- pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
- pExaPixmap->fb_pitch = pPixmap->devKind;
- } else {
- pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
- pExaPixmap->sys_pitch = pPixmap->devKind;
- }
- /* Always NULL this, we don't want lingering pointers. */
- pPixmap->devPrivate.ptr = NULL;
-
- return ret;
-}
-
-Bool
-exaDestroyPixmap_mixed(PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- Bool ret;
-
- if (pPixmap->refcnt == 1)
- {
- ExaPixmapPriv (pPixmap);
-
- exaDestroyPixmap(pPixmap);
-
- if (pExaScr->deferred_mixed_pixmap == pPixmap)
- pExaScr->deferred_mixed_pixmap = NULL;
-
- if (pExaPixmap->driverPriv)
- pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
- pExaPixmap->driverPriv = NULL;
-
- if (pExaPixmap->pDamage) {
- free(pExaPixmap->sys_ptr);
- pExaPixmap->sys_ptr = NULL;
- pExaPixmap->pDamage = NULL;
- }
- }
-
- swap(pExaScr, pScreen, DestroyPixmap);
- ret = pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
-
- return ret;
-}
-
-Bool
-exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- ExaPixmapPriv(pPixmap);
- pointer saved_ptr;
- Bool ret;
-
- if (!pExaPixmap->driverPriv)
- return FALSE;
-
- saved_ptr = pPixmap->devPrivate.ptr;
- pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
- ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
- pPixmap->devPrivate.ptr = saved_ptr;
-
- return ret;
-}
+/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the driver allocated pixmaps + better initial placement code. + */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + */ +PixmapPtr +exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + int bpp; + size_t paddedWidth; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + if (paddedWidth / 4 > 32767 || h > 32767) + return NullPixmap; + + /* We will allocate the system pixmap later if needed. */ + pPixmap->devPrivate.ptr = NULL; + pExaPixmap->sys_ptr = NULL; + pExaPixmap->sys_pitch = paddedWidth; + + pExaPixmap->area = NULL; + pExaPixmap->fb_ptr = NULL; + pExaPixmap->pDamage = NULL; + + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); + + /* A scratch pixmap will become a driver pixmap right away. */ + if (!w || !h) { + exaCreateDriverPixmap_mixed(pPixmap); + pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + } else { + pExaPixmap->use_gpu_copy = FALSE; + + if (w == 1 && h == 1) { + pExaPixmap->sys_ptr = malloc(paddedWidth); + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, + DamageReportNonEmpty, TRUE, + pPixmap->drawable.pScreen, + pPixmap); + + DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); + } + } + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret, has_gpu_copy; + + if (!pPixmap) + return FALSE; + + pScreen = pPixmap->drawable.pScreen; + pExaScr = ExaGetScreenPriv(pScreen); + pExaPixmap = ExaGetPixmapPriv(pPixmap); + + if (pPixData) { + if (pExaPixmap->driverPriv) { + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + } + + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + } + + pExaPixmap->use_gpu_copy = FALSE; + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + } + + has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + + if (width <= 0) + width = pPixmap->drawable.width; + + if (height <= 0) + height = pPixmap->drawable.height; + + if (bitsPerPixel <= 0) { + if (depth <= 0) + bitsPerPixel = pPixmap->drawable.bitsPerPixel; + else + bitsPerPixel = BitsPerPixel(depth); + } + + if (depth <= 0) + depth = pPixmap->drawable.depth; + + if (width != pPixmap->drawable.width || + height != pPixmap->drawable.height || + depth != pPixmap->drawable.depth || + bitsPerPixel != pPixmap->drawable.bitsPerPixel) { + if (pExaPixmap->driverPriv) { + if (devKind > 0) + pExaPixmap->fb_pitch = devKind; + else + exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel); + + exaSetAccelBlock(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + RegionEmpty(&pExaPixmap->validFB); + } + + /* Need to re-create system copy if there's also a GPU copy */ + if (has_gpu_copy && pExaPixmap->sys_ptr) { + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + pExaPixmap->sys_pitch = PixmapBytePad(width, depth); + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + RegionEmpty(&pExaPixmap->validSys); + + if (pExaScr->deferred_mixed_pixmap == pPixmap) + pExaScr->deferred_mixed_pixmap = NULL; + } + } + + if (has_gpu_copy) { + pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; + pPixmap->devKind = pExaPixmap->fb_pitch; + } else { + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + } + + /* Only pass driver pixmaps to the driver. */ + if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) { + ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + if (ret == TRUE) + goto out; + } + + swap(pExaScr, pScreen, ModifyPixmapHeader); + ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + swap(pExaScr, pScreen, ModifyPixmapHeader); + +out: + if (has_gpu_copy) { + pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->fb_pitch = pPixmap->devKind; + } else { + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + } + /* Always NULL this, we don't want lingering pointers. */ + pPixmap->devPrivate.ptr = NULL; + + return ret; +} + +Bool +exaDestroyPixmap_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + exaDestroyPixmap(pPixmap); + + if (pExaScr->deferred_mixed_pixmap == pPixmap) + pExaScr->deferred_mixed_pixmap = NULL; + + if (pExaPixmap->driverPriv) + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + + if (pExaPixmap->pDamage) { + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + pExaPixmap->pDamage = NULL; + } + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + pointer saved_ptr; + Bool ret; + + if (!pExaPixmap->driverPriv) + return FALSE; + + saved_ptr = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = saved_ptr; + + return ret; +} diff --git a/xorg-server/exa/exa_unaccel.c b/xorg-server/exa/exa_unaccel.c index df416d5ac..219f903b2 100644 --- a/xorg-server/exa/exa_unaccel.c +++ b/xorg-server/exa/exa_unaccel.c @@ -1,6 +1,6 @@ /* * - * Copyright © 1999 Keith Packard + * Copyright © 1999 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 diff --git a/xorg-server/hw/dmx/dmxinput.c b/xorg-server/hw/dmx/dmxinput.c index 517a5ee8c..f006af4d2 100644 --- a/xorg-server/hw/dmx/dmxinput.c +++ b/xorg-server/hw/dmx/dmxinput.c @@ -1,119 +1,120 @@ -/*
- * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
- *
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation on the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) 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
- * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
- * 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.
- */
-
-/*
- * Authors:
- * David H. Dawes <dawes@xfree86.org>
- * Kevin E. Martin <kem@redhat.com>
- * Rickard E. (Rik) Faith <faith@redhat.com>
- *
- */
-
-/** \file
- * Provide the main entry points for input initialization and processing
- * that arequired by the dix layer.
- */
-
-#ifdef HAVE_DMX_CONFIG_H
-#include <dmx-config.h>
-#endif
-
-#include "dmx.h"
-#include "dmxlog.h"
-#include "dmxinput.h"
-
-#include "inputstr.h"
-#include "input.h"
-#include "mi.h"
-
-/** Returns TRUE if the key is a valid modifier. For PC-class
- * keyboards, all keys can be used as modifiers, so return TRUE
- * always. */
-Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)
-{
- return TRUE;
-}
-
-/** Called from dix/main.c on each server generation to initialize
- * inputs. All the work is done in dmxInputInit. \see
- * dmxInputInit() */
-void InitInput(int argc, char **argv)
-{
- int i;
- DMXInputInfo *dmxInput;
-
- if (!dmxNumInputs)
- dmxLog(dmxFatal, "InitInput: no inputs specified\n");
-
- for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
- dmxInputInit(dmxInput);
-
- mieqInit();
-}
-
-void CloseInput(void)
-{
-}
-
-/** Called from dix/dispatch.c in Dispatch() whenever input events
- * require processing. All the work is done in the lower level
- * routines. */
-void ProcessInputEvents(void)
-{
- int i;
- DMXInputInfo *dmxInput;
-
- for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
- if (!dmxInput->detached && dmxInput->processInputEvents)
- dmxInput->processInputEvents(dmxInput);
-}
-
-/** This routine is called from \a dmxwindow.c whenever the layout of
- * windows on the display might have changed. This information is used
- * by input drivers (currently only the console driver) that provide
- * information about window layout to the user. */
-void dmxUpdateWindowInfo(DMXUpdateType type, WindowPtr pWindow)
-{
- int i;
- DMXInputInfo *dmxInput;
-
- for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
- if (!dmxInput->detached && dmxInput->updateWindowInfo)
- dmxInput->updateWindowInfo(dmxInput, type, pWindow);
-}
-
-int
-NewInputDeviceRequest (InputOption *options, InputAttributes *attrs,
- DeviceIntPtr *pdev)
-{
- return BadRequest;
-}
-
-void
-DeleteInputDeviceRequest(DeviceIntPtr pDev)
-{
-}
+/* + * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * David H. Dawes <dawes@xfree86.org> + * Kevin E. Martin <kem@redhat.com> + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Provide the main entry points for input initialization and processing + * that arequired by the dix layer. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxlog.h" +#include "dmxinput.h" + +#include "inputstr.h" +#include "input.h" +#include "mi.h" + +/** Returns TRUE if the key is a valid modifier. For PC-class + * keyboards, all keys can be used as modifiers, so return TRUE + * always. */ +Bool LegalModifier(unsigned int key, DeviceIntPtr pDev) +{ + return TRUE; +} + +/** Called from dix/main.c on each server generation to initialize + * inputs. All the work is done in dmxInputInit. \see + * dmxInputInit() */ +void InitInput(int argc, char **argv) +{ + int i; + DMXInputInfo *dmxInput; + + if (!dmxNumInputs) + dmxLog(dmxFatal, "InitInput: no inputs specified\n"); + + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) + dmxInputInit(dmxInput); + + mieqInit(); +} + +void CloseInput(void) +{ + mieqFini(); +} + +/** Called from dix/dispatch.c in Dispatch() whenever input events + * require processing. All the work is done in the lower level + * routines. */ +void ProcessInputEvents(void) +{ + int i; + DMXInputInfo *dmxInput; + + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) + if (!dmxInput->detached && dmxInput->processInputEvents) + dmxInput->processInputEvents(dmxInput); +} + +/** This routine is called from \a dmxwindow.c whenever the layout of + * windows on the display might have changed. This information is used + * by input drivers (currently only the console driver) that provide + * information about window layout to the user. */ +void dmxUpdateWindowInfo(DMXUpdateType type, WindowPtr pWindow) +{ + int i; + DMXInputInfo *dmxInput; + + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) + if (!dmxInput->detached && dmxInput->updateWindowInfo) + dmxInput->updateWindowInfo(dmxInput, type, pWindow); +} + +int +NewInputDeviceRequest (InputOption *options, InputAttributes *attrs, + DeviceIntPtr *pdev) +{ + return BadRequest; +} + +void +DeleteInputDeviceRequest(DeviceIntPtr pDev) +{ +} diff --git a/xorg-server/hw/dmx/input/dmxinputinit.c b/xorg-server/hw/dmx/input/dmxinputinit.c index 5cbd620c9..1b067c725 100644 --- a/xorg-server/hw/dmx/input/dmxinputinit.c +++ b/xorg-server/hw/dmx/input/dmxinputinit.c @@ -546,9 +546,6 @@ static void dmxProcessInputEvents(DMXInputInfo *dmxInput) return; for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) if (dmxInput->devs[i]->process_input) { -#if 11 /*BP*/ - miPointerUpdateSprite(dmxInput->devs[i]->pDevice); -#endif dmxInput->devs[i]->process_input(dmxInput->devs[i]->private); } diff --git a/xorg-server/hw/kdrive/ephyr/ephyr.c b/xorg-server/hw/kdrive/ephyr/ephyr.c index ac8e5bef9..7ebf1c253 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyr.c +++ b/xorg-server/hw/kdrive/ephyr/ephyr.c @@ -2,7 +2,7 @@ * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum <mallum@openedhand.com> * - * Copyright © 2004 Nokia + * Copyright © 2004 Nokia * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that diff --git a/xorg-server/hw/kdrive/ephyr/ephyr.h b/xorg-server/hw/kdrive/ephyr/ephyr.h index 41a82bf9d..23848004c 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyr.h +++ b/xorg-server/hw/kdrive/ephyr/ephyr.h @@ -2,7 +2,7 @@ * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum <mallum@o-hand.com> * - * Copyright © 2004 Nokia + * Copyright © 2004 Nokia * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that diff --git a/xorg-server/hw/kdrive/ephyr/ephyr_draw.c b/xorg-server/hw/kdrive/ephyr/ephyr_draw.c index f3e2be6eb..cf5f55394 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyr_draw.c +++ b/xorg-server/hw/kdrive/ephyr/ephyr_draw.c @@ -1,523 +1,523 @@ -/*
- * Copyright © 2006 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Authors:
- * Eric Anholt <eric@anholt.net>
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <kdrive-config.h>
-#endif
-
-#include "ephyr.h"
-#include "exa_priv.h"
-#include "fbpict.h"
-
-#define EPHYR_TRACE_DRAW 0
-
-#if EPHYR_TRACE_DRAW
-#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__);
-#else
-#define TRACE_DRAW() do { } while (0)
-#endif
-
-/* Use some oddball alignments, to expose issues in alignment handling in EXA. */
-#define EPHYR_OFFSET_ALIGN 24
-#define EPHYR_PITCH_ALIGN 24
-
-#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024)
-#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024)
-
-/**
- * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to
- * fb functions.
- */
-static void
-ephyrPreparePipelinedAccess(PixmapPtr pPix, int index)
-{
- KdScreenPriv(pPix->drawable.pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- assert(fakexa->saved_ptrs[index] == NULL);
- fakexa->saved_ptrs[index] = pPix->devPrivate.ptr;
-
- if (pPix->devPrivate.ptr != NULL)
- return;
-
- pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix);
-}
-
-/**
- * Restores the original devPrivate.ptr of the pixmap from before we messed with
- * it.
- */
-static void
-ephyrFinishPipelinedAccess(PixmapPtr pPix, int index)
-{
- KdScreenPriv(pPix->drawable.pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- pPix->devPrivate.ptr = fakexa->saved_ptrs[index];
- fakexa->saved_ptrs[index] = NULL;
-}
-
-/**
- * Sets up a scratch GC for fbFill, and saves other parameters for the
- * ephyrSolid implementation.
- */
-static Bool
-ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
-{
- ScreenPtr pScreen = pPix->drawable.pScreen;
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
- ChangeGCVal tmpval[3];
-
- ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST);
-
- fakexa->pDst = pPix;
- fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen);
-
- tmpval[0].val = alu;
- tmpval[1].val = pm;
- tmpval[2].val = fg;
- ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, tmpval);
-
- ValidateGC(&pPix->drawable, fakexa->pGC);
-
- TRACE_DRAW();
-
- return TRUE;
-}
-
-/**
- * Does an fbFill of the rectangle to be drawn.
- */
-static void
-ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
-{
- ScreenPtr pScreen = pPix->drawable.pScreen;
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1);
-}
-
-/**
- * Cleans up the scratch GC created in ephyrPrepareSolid.
- */
-static void
-ephyrDoneSolid(PixmapPtr pPix)
-{
- ScreenPtr pScreen = pPix->drawable.pScreen;
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- FreeScratchGC(fakexa->pGC);
-
- ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST);
-}
-
-/**
- * Sets up a scratch GC for fbCopyArea, and saves other parameters for the
- * ephyrCopy implementation.
- */
-static Bool
-ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu,
- Pixel pm)
-{
- ScreenPtr pScreen = pDst->drawable.pScreen;
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
- ChangeGCVal tmpval[2];
-
- ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
- ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
-
- fakexa->pSrc = pSrc;
- fakexa->pDst = pDst;
- fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen);
-
- tmpval[0].val = alu;
- tmpval[1].val = pm;
- ChangeGC (NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval);
-
- ValidateGC(&pDst->drawable, fakexa->pGC);
-
- TRACE_DRAW();
-
- return TRUE;
-}
-
-/**
- * Does an fbCopyArea to take care of the requested copy.
- */
-static void
-ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h)
-{
- ScreenPtr pScreen = pDst->drawable.pScreen;
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC,
- srcX, srcY, w, h, dstX, dstY);
-}
-
-/**
- * Cleans up the scratch GC created in ephyrPrepareCopy.
- */
-static void
-ephyrDoneCopy(PixmapPtr pDst)
-{
- ScreenPtr pScreen = pDst->drawable.pScreen;
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- FreeScratchGC (fakexa->pGC);
-
- ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
- ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
-}
-
-/**
- * Reports that we can always accelerate the given operation. This may not be
- * desirable from an EXA testing standpoint -- testing the fallback paths would
- * be useful, too.
- */
-static Bool
-ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
- PicturePtr pDstPicture)
-{
- /* Exercise the component alpha helper, so fail on this case like a normal
- * driver
- */
- if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver)
- return FALSE;
-
- return TRUE;
-}
-
-/**
- * Saves off the parameters for ephyrComposite.
- */
-static Bool
-ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
- PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask,
- PixmapPtr pDst)
-{
- KdScreenPriv(pDst->drawable.pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
- ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
- if (pMask != NULL)
- ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK);
-
- fakexa->op = op;
- fakexa->pSrcPicture = pSrcPicture;
- fakexa->pMaskPicture = pMaskPicture;
- fakexa->pDstPicture = pDstPicture;
- fakexa->pSrc = pSrc;
- fakexa->pMask = pMask;
- fakexa->pDst = pDst;
-
- TRACE_DRAW();
-
- return TRUE;
-}
-
-/**
- * Does an fbComposite to complete the requested drawing operation.
- */
-static void
-ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
- int dstX, int dstY, int w, int h)
-{
- KdScreenPriv(pDst->drawable.pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture,
- fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY,
- w, h);
-}
-
-static void
-ephyrDoneComposite(PixmapPtr pDst)
-{
- KdScreenPriv(pDst->drawable.pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- if (fakexa->pMask != NULL)
- ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK);
- ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
- ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
-}
-
-/**
- * Does fake acceleration of DownloadFromScren using memcpy.
- */
-static Bool
-ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
- int dst_pitch)
-{
- KdScreenPriv(pSrc->drawable.pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
- unsigned char *src;
- int src_pitch, cpp;
-
- if (pSrc->drawable.bitsPerPixel < 8)
- return FALSE;
-
- ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
-
- cpp = pSrc->drawable.bitsPerPixel / 8;
- src_pitch = exaGetPixmapPitch(pSrc);
- src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc);
- src += y * src_pitch + x * cpp;
-
- for (; h > 0; h--) {
- memcpy(dst, src, w * cpp);
- dst += dst_pitch;
- src += src_pitch;
- }
-
- exaMarkSync(pSrc->drawable.pScreen);
-
- ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC);
-
- return TRUE;
-}
-
-/**
- * Does fake acceleration of UploadToScreen using memcpy.
- */
-static Bool
-ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
- int src_pitch)
-{
- KdScreenPriv(pDst->drawable.pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
- unsigned char *dst;
- int dst_pitch, cpp;
-
- if (pDst->drawable.bitsPerPixel < 8)
- return FALSE;
-
- ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
-
- cpp = pDst->drawable.bitsPerPixel / 8;
- dst_pitch = exaGetPixmapPitch(pDst);
- dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst);
- dst += y * dst_pitch + x * cpp;
-
- for (; h > 0; h--) {
- memcpy(dst, src, w * cpp);
- dst += dst_pitch;
- src += src_pitch;
- }
-
- exaMarkSync(pDst->drawable.pScreen);
-
- ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST);
-
- return TRUE;
-}
-
-static Bool
-ephyrPrepareAccess(PixmapPtr pPix, int index)
-{
- /* Make sure we don't somehow end up with a pointer that is in framebuffer
- * and hasn't been readied for us.
- */
- assert(pPix->devPrivate.ptr != NULL);
-
- return TRUE;
-}
-
-/**
- * In fakexa, we currently only track whether we have synced to the latest
- * "accelerated" drawing that has happened or not. It's not used for anything
- * yet.
- */
-static int
-ephyrMarkSync(ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- fakexa->is_synced = FALSE;
-
- return 0;
-}
-
-/**
- * Assumes that we're waiting on the latest marker. When EXA gets smarter and
- * starts using markers in a fine-grained way (for example, waiting on drawing
- * to required pixmaps to complete, rather than waiting for all drawing to
- * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker
- * implementation fine-grained as well.
- */
-static void
-ephyrWaitMarker(ScreenPtr pScreen, int marker)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrFakexaPriv *fakexa = scrpriv->fakexa;
-
- fakexa->is_synced = TRUE;
-}
-
-/**
- * This function initializes EXA to use the fake acceleration implementation
- * which just falls through to software. The purpose is to have a reliable,
- * correct driver with which to test changes to the EXA core.
- */
-Bool
-ephyrDrawInit(ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- EphyrScrPriv *scrpriv = screen->driver;
- EphyrPriv *priv = screen->card->driver;
- EphyrFakexaPriv *fakexa;
- Bool success;
-
- fakexa = calloc(1, sizeof(*fakexa));
- if (fakexa == NULL)
- return FALSE;
-
- fakexa->exa = exaDriverAlloc();
- if (fakexa->exa == NULL) {
- free(fakexa);
- return FALSE;
- }
-
- fakexa->exa->memoryBase = (CARD8 *) (priv->base);
- fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen);
- fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height;
-
- /* Since we statically link against EXA, we shouldn't have to be smart about
- * versioning.
- */
- fakexa->exa->exa_major = 2;
- fakexa->exa->exa_minor = 0;
-
- fakexa->exa->PrepareSolid = ephyrPrepareSolid;
- fakexa->exa->Solid = ephyrSolid;
- fakexa->exa->DoneSolid = ephyrDoneSolid;
-
- fakexa->exa->PrepareCopy = ephyrPrepareCopy;
- fakexa->exa->Copy = ephyrCopy;
- fakexa->exa->DoneCopy = ephyrDoneCopy;
-
- fakexa->exa->CheckComposite = ephyrCheckComposite;
- fakexa->exa->PrepareComposite = ephyrPrepareComposite;
- fakexa->exa->Composite = ephyrComposite;
- fakexa->exa->DoneComposite = ephyrDoneComposite;
-
- fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen;
- fakexa->exa->UploadToScreen = ephyrUploadToScreen;
-
- fakexa->exa->MarkSync = ephyrMarkSync;
- fakexa->exa->WaitMarker = ephyrWaitMarker;
-
- fakexa->exa->PrepareAccess = ephyrPrepareAccess;
-
- fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN;
- fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN;
-
- fakexa->exa->maxX = 1023;
- fakexa->exa->maxY = 1023;
-
- fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS;
-
- success = exaDriverInit(pScreen, fakexa->exa);
- if (success) {
- ErrorF("Initialized fake EXA acceleration\n");
- scrpriv->fakexa = fakexa;
- } else {
- ErrorF("Failed to initialize EXA\n");
- free(fakexa->exa);
- free(fakexa);
- }
-
- return success;
-}
-
-void
-ephyrDrawEnable(ScreenPtr pScreen)
-{
-}
-
-void
-ephyrDrawDisable(ScreenPtr pScreen)
-{
-}
-
-void
-ephyrDrawFini(ScreenPtr pScreen)
-{
-}
-
-/**
- * exaDDXDriverInit is required by the top-level EXA module, and is used by
- * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since
- * we won't be enabling/disabling the FB.
- */
-void
-exaDDXDriverInit(ScreenPtr pScreen)
-{
- ExaScreenPriv(pScreen);
-
- pExaScr->migration = ExaMigrationSmart;
- pExaScr->checkDirtyCorrectness = TRUE;
-}
+/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif + +#include "ephyr.h" +#include "exa_priv.h" +#include "fbpict.h" + +#define EPHYR_TRACE_DRAW 0 + +#if EPHYR_TRACE_DRAW +#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__); +#else +#define TRACE_DRAW() do { } while (0) +#endif + +/* Use some oddball alignments, to expose issues in alignment handling in EXA. */ +#define EPHYR_OFFSET_ALIGN 24 +#define EPHYR_PITCH_ALIGN 24 + +#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024) +#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024) + +/** + * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to + * fb functions. + */ +static void +ephyrPreparePipelinedAccess(PixmapPtr pPix, int index) +{ + KdScreenPriv(pPix->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + assert(fakexa->saved_ptrs[index] == NULL); + fakexa->saved_ptrs[index] = pPix->devPrivate.ptr; + + if (pPix->devPrivate.ptr != NULL) + return; + + pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix); +} + +/** + * Restores the original devPrivate.ptr of the pixmap from before we messed with + * it. + */ +static void +ephyrFinishPipelinedAccess(PixmapPtr pPix, int index) +{ + KdScreenPriv(pPix->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + pPix->devPrivate.ptr = fakexa->saved_ptrs[index]; + fakexa->saved_ptrs[index] = NULL; +} + +/** + * Sets up a scratch GC for fbFill, and saves other parameters for the + * ephyrSolid implementation. + */ +static Bool +ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + ChangeGCVal tmpval[3]; + + ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST); + + fakexa->pDst = pPix; + fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen); + + tmpval[0].val = alu; + tmpval[1].val = pm; + tmpval[2].val = fg; + ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, tmpval); + + ValidateGC(&pPix->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbFill of the rectangle to be drawn. + */ +static void +ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareSolid. + */ +static void +ephyrDoneSolid(PixmapPtr pPix) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC(fakexa->pGC); + + ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST); +} + +/** + * Sets up a scratch GC for fbCopyArea, and saves other parameters for the + * ephyrCopy implementation. + */ +static Bool +ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, + Pixel pm) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + ChangeGCVal tmpval[2]; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + + fakexa->pSrc = pSrc; + fakexa->pDst = pDst; + fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen); + + tmpval[0].val = alu; + tmpval[1].val = pm; + ChangeGC (NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval); + + ValidateGC(&pDst->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbCopyArea to take care of the requested copy. + */ +static void +ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC, + srcX, srcY, w, h, dstX, dstY); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareCopy. + */ +static void +ephyrDoneCopy(PixmapPtr pDst) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC (fakexa->pGC); + + ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); + ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); +} + +/** + * Reports that we can always accelerate the given operation. This may not be + * desirable from an EXA testing standpoint -- testing the fallback paths would + * be useful, too. + */ +static Bool +ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + /* Exercise the component alpha helper, so fail on this case like a normal + * driver + */ + if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver) + return FALSE; + + return TRUE; +} + +/** + * Saves off the parameters for ephyrComposite. + */ +static Bool +ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, + PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + if (pMask != NULL) + ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK); + + fakexa->op = op; + fakexa->pSrcPicture = pSrcPicture; + fakexa->pMaskPicture = pMaskPicture; + fakexa->pDstPicture = pDstPicture; + fakexa->pSrc = pSrc; + fakexa->pMask = pMask; + fakexa->pDst = pDst; + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbComposite to complete the requested drawing operation. + */ +static void +ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int w, int h) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture, + fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY, + w, h); +} + +static void +ephyrDoneComposite(PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + if (fakexa->pMask != NULL) + ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK); + ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); + ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); +} + +/** + * Does fake acceleration of DownloadFromScren using memcpy. + */ +static Bool +ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst, + int dst_pitch) +{ + KdScreenPriv(pSrc->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + unsigned char *src; + int src_pitch, cpp; + + if (pSrc->drawable.bitsPerPixel < 8) + return FALSE; + + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + + cpp = pSrc->drawable.bitsPerPixel / 8; + src_pitch = exaGetPixmapPitch(pSrc); + src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc); + src += y * src_pitch + x * cpp; + + for (; h > 0; h--) { + memcpy(dst, src, w * cpp); + dst += dst_pitch; + src += src_pitch; + } + + exaMarkSync(pSrc->drawable.pScreen); + + ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC); + + return TRUE; +} + +/** + * Does fake acceleration of UploadToScreen using memcpy. + */ +static Bool +ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src, + int src_pitch) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + unsigned char *dst; + int dst_pitch, cpp; + + if (pDst->drawable.bitsPerPixel < 8) + return FALSE; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + + cpp = pDst->drawable.bitsPerPixel / 8; + dst_pitch = exaGetPixmapPitch(pDst); + dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst); + dst += y * dst_pitch + x * cpp; + + for (; h > 0; h--) { + memcpy(dst, src, w * cpp); + dst += dst_pitch; + src += src_pitch; + } + + exaMarkSync(pDst->drawable.pScreen); + + ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST); + + return TRUE; +} + +static Bool +ephyrPrepareAccess(PixmapPtr pPix, int index) +{ + /* Make sure we don't somehow end up with a pointer that is in framebuffer + * and hasn't been readied for us. + */ + assert(pPix->devPrivate.ptr != NULL); + + return TRUE; +} + +/** + * In fakexa, we currently only track whether we have synced to the latest + * "accelerated" drawing that has happened or not. It's not used for anything + * yet. + */ +static int +ephyrMarkSync(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = FALSE; + + return 0; +} + +/** + * Assumes that we're waiting on the latest marker. When EXA gets smarter and + * starts using markers in a fine-grained way (for example, waiting on drawing + * to required pixmaps to complete, rather than waiting for all drawing to + * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker + * implementation fine-grained as well. + */ +static void +ephyrWaitMarker(ScreenPtr pScreen, int marker) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = TRUE; +} + +/** + * This function initializes EXA to use the fake acceleration implementation + * which just falls through to software. The purpose is to have a reliable, + * correct driver with which to test changes to the EXA core. + */ +Bool +ephyrDrawInit(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrPriv *priv = screen->card->driver; + EphyrFakexaPriv *fakexa; + Bool success; + + fakexa = calloc(1, sizeof(*fakexa)); + if (fakexa == NULL) + return FALSE; + + fakexa->exa = exaDriverAlloc(); + if (fakexa->exa == NULL) { + free(fakexa); + return FALSE; + } + + fakexa->exa->memoryBase = (CARD8 *) (priv->base); + fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen); + fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height; + + /* Since we statically link against EXA, we shouldn't have to be smart about + * versioning. + */ + fakexa->exa->exa_major = 2; + fakexa->exa->exa_minor = 0; + + fakexa->exa->PrepareSolid = ephyrPrepareSolid; + fakexa->exa->Solid = ephyrSolid; + fakexa->exa->DoneSolid = ephyrDoneSolid; + + fakexa->exa->PrepareCopy = ephyrPrepareCopy; + fakexa->exa->Copy = ephyrCopy; + fakexa->exa->DoneCopy = ephyrDoneCopy; + + fakexa->exa->CheckComposite = ephyrCheckComposite; + fakexa->exa->PrepareComposite = ephyrPrepareComposite; + fakexa->exa->Composite = ephyrComposite; + fakexa->exa->DoneComposite = ephyrDoneComposite; + + fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen; + fakexa->exa->UploadToScreen = ephyrUploadToScreen; + + fakexa->exa->MarkSync = ephyrMarkSync; + fakexa->exa->WaitMarker = ephyrWaitMarker; + + fakexa->exa->PrepareAccess = ephyrPrepareAccess; + + fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN; + fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN; + + fakexa->exa->maxX = 1023; + fakexa->exa->maxY = 1023; + + fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS; + + success = exaDriverInit(pScreen, fakexa->exa); + if (success) { + ErrorF("Initialized fake EXA acceleration\n"); + scrpriv->fakexa = fakexa; + } else { + ErrorF("Failed to initialize EXA\n"); + free(fakexa->exa); + free(fakexa); + } + + return success; +} + +void +ephyrDrawEnable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawDisable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawFini(ScreenPtr pScreen) +{ +} + +/** + * exaDDXDriverInit is required by the top-level EXA module, and is used by + * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since + * we won't be enabling/disabling the FB. + */ +void +exaDDXDriverInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + + pExaScr->migration = ExaMigrationSmart; + pExaScr->checkDirtyCorrectness = TRUE; +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyrinit.c b/xorg-server/hw/kdrive/ephyr/ephyrinit.c index 2deb7b81d..b674bb8d0 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrinit.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrinit.c @@ -2,7 +2,7 @@ * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum <mallum@o-hand.com> * - * Copyright © 2004 Nokia + * Copyright © 2004 Nokia * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -97,6 +97,7 @@ InitInput (int argc, char **argv) void CloseInput (void) { + KdCloseInput(); } #ifdef DDXBEFORERESET diff --git a/xorg-server/hw/kdrive/ephyr/hostx.c b/xorg-server/hw/kdrive/ephyr/hostx.c index 648368124..4caf4516d 100644 --- a/xorg-server/hw/kdrive/ephyr/hostx.c +++ b/xorg-server/hw/kdrive/ephyr/hostx.c @@ -1,1447 +1,1447 @@ -/*
- * Xephyr - A kdrive X server thats runs in a host X window.
- * Authored by Matthew Allum <mallum@o-hand.com>
- *
- * Copyright © 2004 Nokia
- *
- * 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 Nokia not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Nokia makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL NOKIA 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_CONFIG_H
-#include <kdrive-config.h>
-#endif
-
-/*
- * including some server headers (like kdrive-config.h)
- * might define the macro _XSERVER64
- * on 64 bits machines. That macro must _NOT_ be defined for Xlib
- * client code, otherwise bad things happen.
- * So let's undef that macro if necessary.
- */
-#ifdef _XSERVER64
-#undef _XSERVER64
-#endif
-
-
-#include "hostx.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h> /* for memset */
-#include <time.h>
-
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/time.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <X11/keysym.h>
-#include <X11/extensions/XShm.h>
-#include <X11/extensions/shape.h>
-#ifdef XF86DRI
-#include <GL/glx.h>
-#endif /* XF86DRI */
-#include "ephyrlog.h"
-
-#ifdef XF86DRI
-extern Bool XF86DRIQueryExtension (Display *dpy,
- int *event_basep,
- int *error_basep);
-#endif
-
-/*
- * All xlib calls go here, which gets built as its own .a .
- * Mixing kdrive and xlib headers causes all sorts of types
- * to get clobbered.
- */
-
-struct EphyrHostScreen
-{
- Window win;
- Window win_pre_existing; /* Set via -parent option like xnest */
- Window peer_win; /* Used for GL; should be at most one */
- XImage *ximg;
- int win_width, win_height;
- int server_depth;
- unsigned char *fb_data; /* only used when host bpp != server bpp */
- XShmSegmentInfo shminfo;
-
- void *info; /* Pointer to the screen this is associated with */
- int mynum; /* Screen number */
-};
-
-struct EphyrHostXVars
-{
- char *server_dpy_name;
- Display *dpy;
- int screen;
- Visual *visual;
- Window winroot;
- GC gc;
- int depth;
- Bool use_host_cursor;
- Bool use_fullscreen;
- Bool have_shm;
-
- int n_screens;
- struct EphyrHostScreen *screens;
-
- long damage_debug_msec;
-
- unsigned long cmap[256];
-};
-
-/* memset ( missing> ) instead of below */
-/*static EphyrHostXVars HostX = { "?", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};*/
-static EphyrHostXVars HostX;
-
-static int HostXWantDamageDebug = 0;
-
-extern EphyrKeySyms ephyrKeySyms;
-
-extern int monitorResolution;
-
-char *ephyrResName = NULL;
-int ephyrResNameFromCmd = 0;
-char *ephyrTitle = NULL;
-
-static void
-hostx_set_fullscreen_hint(void);
-
-/* X Error traps */
-
-static int trapped_error_code = 0;
-static int (*old_error_handler) (Display *d, XErrorEvent *e);
-
-#define host_depth_matches_server(_vars) (HostX.depth == (_vars)->server_depth)
-
-static struct EphyrHostScreen *
-host_screen_from_screen_info (EphyrScreenInfo *screen)
-{
- int i;
-
- for (i = 0 ; i < HostX.n_screens ; i++)
- {
- if ( HostX.screens[i].info == screen)
- {
- return &HostX.screens[i];
- }
- }
- return NULL;
-}
-
-static int
-error_handler(Display *display,
- XErrorEvent *error)
-{
- trapped_error_code = error->error_code;
- return 0;
-}
-
-static void
-hostx_errors_trap(void)
-{
- trapped_error_code = 0;
- old_error_handler = XSetErrorHandler(error_handler);
-}
-
-static int
-hostx_errors_untrap(void)
-{
- XSetErrorHandler(old_error_handler);
- return trapped_error_code;
-}
-
-int
-hostx_want_screen_size (EphyrScreenInfo screen, int *width, int *height )
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- if (host_screen &&
- (host_screen->win_pre_existing != None ||
- HostX.use_fullscreen == True))
- {
- *width = host_screen->win_width;
- *height = host_screen->win_height;
- return 1;
- }
-
- return 0;
-}
-
-void
-hostx_add_screen (EphyrScreenInfo screen,
- unsigned long win_id,
- int screen_num)
-{
- int index = HostX.n_screens;
-
- HostX.n_screens += 1;
- HostX.screens = realloc (HostX.screens,
- HostX.n_screens * sizeof(struct EphyrHostScreen));
- memset (&HostX.screens[index], 0, sizeof (struct EphyrHostScreen));
-
- HostX.screens[index].info = screen;
- HostX.screens[index].win_pre_existing = win_id;
-}
-
-
-void
-hostx_set_display_name (char *name)
-{
- HostX.server_dpy_name = strdup (name);
-}
-
-void
-hostx_set_screen_number(EphyrScreenInfo screen, int number)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
- if (host_screen) {
- host_screen->mynum = number;
- hostx_set_win_title (host_screen->info, "") ;
- }}
-
-void
-hostx_set_win_title (EphyrScreenInfo screen, char *extra_text)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- if (!host_screen)
- return;
-
- if (ephyrTitle) {
- XStoreName(HostX.dpy, host_screen->win, ephyrTitle);
- } else {
-#define BUF_LEN 256
- char buf[BUF_LEN+1];
-
- memset (buf, 0, BUF_LEN+1) ;
- snprintf (buf, BUF_LEN, "Xephyr on %s.%d %s",
- HostX.server_dpy_name,
- host_screen->mynum,
- (extra_text != NULL) ? extra_text : "");
-
- XStoreName (HostX.dpy, host_screen->win, buf);
- }
-}
-
-int
-hostx_want_host_cursor (void)
-{
- return HostX.use_host_cursor;
-}
-
-void
-hostx_use_host_cursor (void)
-{
- HostX.use_host_cursor = True;
-}
-
-int
-hostx_want_preexisting_window (EphyrScreenInfo screen)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- if (host_screen && host_screen->win_pre_existing)
- {
- return 1;
- }
- else
- {
- return 0;
- }
-}
-
-void
-hostx_use_fullscreen (void)
-{
- HostX.use_fullscreen = True;
-}
-
-int
-hostx_want_fullscreen (void)
-{
- return HostX.use_fullscreen;
-}
-
-static void
-hostx_set_fullscreen_hint (void)
-{
- Atom atom_WINDOW_STATE, atom_WINDOW_STATE_FULLSCREEN;
- int index;
-
- atom_WINDOW_STATE
- = XInternAtom(HostX.dpy, "_NET_WM_STATE", False);
- atom_WINDOW_STATE_FULLSCREEN
- = XInternAtom(HostX.dpy, "_NET_WM_STATE_FULLSCREEN",False);
-
- for (index = 0 ; index < HostX.n_screens ; index++)
- {
- XChangeProperty (HostX.dpy, HostX.screens[index].win,
- atom_WINDOW_STATE, XA_ATOM, 32,
- PropModeReplace,
- (unsigned char *)&atom_WINDOW_STATE_FULLSCREEN, 1);
- }
-}
-
-
-static void
-hostx_toggle_damage_debug (void)
-{
- HostXWantDamageDebug ^= 1;
-}
-
-void
-hostx_handle_signal (int signum)
-{
- hostx_toggle_damage_debug();
- EPHYR_DBG ("Signal caught. Damage Debug:%i\n",
- HostXWantDamageDebug);
-}
-
-void
-hostx_use_resname (char *name, int fromcmd)
-{
- ephyrResName = name;
- ephyrResNameFromCmd = fromcmd;
-}
-
-void
-hostx_set_title (char *title)
-{
- ephyrTitle = title;
-}
-
-int
-hostx_init (void)
-{
- XSetWindowAttributes attr;
- Cursor empty_cursor;
- Pixmap cursor_pxm;
- XColor col;
- int index;
- char *tmpstr;
- XClassHint *class_hint;
-
- attr.event_mask =
- ButtonPressMask
- |ButtonReleaseMask
- |PointerMotionMask
- |KeyPressMask
- |KeyReleaseMask
- |ExposureMask;
-
- EPHYR_DBG("mark");
-
- if ((HostX.dpy = XOpenDisplay(getenv("DISPLAY"))) == NULL)
- {
- fprintf(stderr, "\nXephyr cannot open host display. Is DISPLAY set?\n");
- exit(1);
- }
-
- HostX.screen = DefaultScreen(HostX.dpy);
- HostX.winroot = RootWindow(HostX.dpy, HostX.screen);
- HostX.gc = XCreateGC(HostX.dpy, HostX.winroot, 0, NULL);
- HostX.depth = DefaultDepth(HostX.dpy, HostX.screen);
- HostX.visual = DefaultVisual(HostX.dpy, HostX.screen);
-
- class_hint = XAllocClassHint();
-
- for (index = 0 ; index < HostX.n_screens ; index++)
- {
- struct EphyrHostScreen *host_screen = &HostX.screens[index];
-
- host_screen->server_depth = HostX.depth;
- if (host_screen->win_pre_existing != None)
- {
- Status result;
- XWindowAttributes prewin_attr;
-
- /* Get screen size from existing window */
-
- hostx_errors_trap();
-
- result = XGetWindowAttributes (HostX.dpy,
- host_screen->win_pre_existing,
- &prewin_attr);
-
-
- if (hostx_errors_untrap() || !result)
- {
- fprintf (stderr, "\nXephyr -parent window' does not exist!\n");
- exit (1);
- }
-
- host_screen->win_width = prewin_attr.width;
- host_screen->win_height = prewin_attr.height;
-
- host_screen->win = XCreateWindow (HostX.dpy,
- host_screen->win_pre_existing,
- 0,0,
- host_screen->win_width,
- host_screen->win_height,
- 0,
- CopyFromParent,
- CopyFromParent,
- CopyFromParent,
- CWEventMask,
- &attr);
- }
- else
- {
- host_screen->win = XCreateWindow (HostX.dpy,
- HostX.winroot,
- 0,0,100,100, /* will resize */
- 0,
- CopyFromParent,
- CopyFromParent,
- CopyFromParent,
- CWEventMask,
- &attr);
-
- hostx_set_win_title (host_screen->info,
- "(ctrl+shift grabs mouse and keyboard)");
-
- if (HostX.use_fullscreen)
- {
- host_screen->win_width = DisplayWidth(HostX.dpy, HostX.screen);
- host_screen->win_height = DisplayHeight(HostX.dpy, HostX.screen);
-
- hostx_set_fullscreen_hint();
- }
-
- if (class_hint)
- {
- tmpstr = getenv("RESOURCE_NAME");
- if (tmpstr && (!ephyrResNameFromCmd))
- ephyrResName = tmpstr;
- class_hint->res_name = ephyrResName;
- class_hint->res_class = "Xephyr";
- XSetClassHint(hostx_get_display(), host_screen->win, class_hint);
-
- }
-
- }
- }
-
- if (class_hint)
- XFree(class_hint);
-
- XParseColor (HostX.dpy, DefaultColormap (HostX.dpy,HostX.screen),
- "red", &col);
- XAllocColor (HostX.dpy, DefaultColormap (HostX.dpy, HostX.screen),
- &col);
- XSetForeground (HostX.dpy, HostX.gc, col.pixel);
-
- if (!hostx_want_host_cursor ())
- {
- /* Ditch the cursor, we provide our 'own' */
- cursor_pxm = XCreatePixmap (HostX.dpy, HostX.winroot, 1, 1, 1);
- memset (&col, 0, sizeof (col));
- empty_cursor = XCreatePixmapCursor (HostX.dpy,
- cursor_pxm, cursor_pxm,
- &col, &col, 1, 1);
- for ( index = 0 ; index < HostX.n_screens ; index++ )
- {
- XDefineCursor (HostX.dpy,
- HostX.screens[index].win,
- empty_cursor);
- }
- XFreePixmap (HostX.dpy, cursor_pxm);
- }
-
- for (index = 0 ; index < HostX.n_screens ; index++)
- {
- HostX.screens[index].ximg = NULL;
- }
- /* Try to get share memory ximages for a little bit more speed */
-
- if (!XShmQueryExtension(HostX.dpy) || getenv("XEPHYR_NO_SHM"))
- {
- fprintf(stderr, "\nXephyr unable to use SHM XImages\n");
- HostX.have_shm = False;
- }
- else
- {
- /* Really really check we have shm - better way ?*/
- XShmSegmentInfo shminfo;
-
- HostX.have_shm = True;
-
- shminfo.shmid=shmget(IPC_PRIVATE, 1, IPC_CREAT|0777);
- shminfo.shmaddr=shmat(shminfo.shmid,0,0);
- shminfo.readOnly=True;
-
- hostx_errors_trap();
-
- XShmAttach(HostX.dpy, &shminfo);
- XSync(HostX.dpy, False);
-
- if (hostx_errors_untrap())
- {
- fprintf(stderr, "\nXephyr unable to use SHM XImages\n");
- HostX.have_shm = False;
- }
-
- shmdt(shminfo.shmaddr);
- shmctl(shminfo.shmid, IPC_RMID, 0);
-}
-
- XFlush(HostX.dpy);
-
- /* Setup the pause time between paints when debugging updates */
-
- HostX.damage_debug_msec = 20000; /* 1/50 th of a second */
-
- if (getenv ("XEPHYR_PAUSE"))
- {
- HostX.damage_debug_msec = strtol (getenv ("XEPHYR_PAUSE"), NULL, 0);
- EPHYR_DBG ("pause is %li\n", HostX.damage_debug_msec);
- }
-
- return 1;
-}
-
-int
-hostx_get_depth (void)
-{
- return HostX.depth;
-}
-
-int
-hostx_get_server_depth (EphyrScreenInfo screen)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- return host_screen ? host_screen->server_depth : 0;
-}
-
-void
-hostx_set_server_depth (EphyrScreenInfo screen, int depth)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- if (host_screen)
- host_screen->server_depth = depth;
-}
-
-int
-hostx_get_bpp (EphyrScreenInfo screen)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- if (!host_screen)
- return 0;
-
- if (host_depth_matches_server (host_screen))
- return HostX.visual->bits_per_rgb;
- else
- return host_screen->server_depth; /*XXX correct ?*/
-}
-
-void
-hostx_get_visual_masks (EphyrScreenInfo screen,
- CARD32 *rmsk,
- CARD32 *gmsk,
- CARD32 *bmsk)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- if (!host_screen)
- return;
-
- if (host_depth_matches_server(host_screen))
- {
- *rmsk = HostX.visual->red_mask;
- *gmsk = HostX.visual->green_mask;
- *bmsk = HostX.visual->blue_mask;
- }
- else if (host_screen->server_depth == 16)
- {
- /* Assume 16bpp 565 */
- *rmsk = 0xf800;
- *gmsk = 0x07e0;
- *bmsk = 0x001f;
- }
- else
- {
- *rmsk = 0x0;
- *gmsk = 0x0;
- *bmsk = 0x0;
- }
-}
-
-static int
-hostx_calculate_color_shift(unsigned long mask)
-{
- int shift = 1;
- /* count # of bits in mask */
- while ((mask = (mask >> 1))) shift++;
- /* cmap entry is an unsigned char so adjust it by size of that */
- shift = shift - sizeof(unsigned char) * 8;
- if (shift < 0) shift = 0;
- return shift;
-}
-
-void
-hostx_set_cmap_entry(unsigned char idx,
- unsigned char r,
- unsigned char g,
- unsigned char b)
-{
-/* need to calculate the shifts for RGB because server could be BGR. */
-/* XXX Not sure if this is correct for 8 on 16, but this works for 8 on 24.*/
- static int rshift, bshift, gshift = 0;
- static int first_time = 1;
- if (first_time) {
- first_time = 0;
- rshift = hostx_calculate_color_shift(HostX.visual->red_mask);
- gshift = hostx_calculate_color_shift(HostX.visual->green_mask);
- bshift = hostx_calculate_color_shift(HostX.visual->blue_mask);
- }
- HostX.cmap[idx] = ((r << rshift) & HostX.visual->red_mask) |
- ((g << gshift) & HostX.visual->green_mask) |
- ((b << bshift) & HostX.visual->blue_mask);
-}
-
-/**
- * hostx_screen_init creates the XImage that will contain the front buffer of
- * the ephyr screen, and possibly offscreen memory.
- *
- * @param width width of the screen
- * @param height height of the screen
- * @param buffer_height height of the rectangle to be allocated.
- *
- * hostx_screen_init() creates an XImage, using MIT-SHM if it's available.
- * buffer_height can be used to create a larger offscreen buffer, which is used
- * by fakexa for storing offscreen pixmap data.
- */
-void*
-hostx_screen_init (EphyrScreenInfo screen,
- int width, int height,
- int buffer_height)
-{
- int bitmap_pad;
- Bool shm_success = False;
- XSizeHints *size_hints;
-
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
- if (!host_screen)
- {
- fprintf (stderr, "%s: Error in accessing hostx data\n", __func__ );
- exit(1);
- }
-
- EPHYR_DBG ("host_screen=%p wxh=%dx%d, buffer_height=%d",
- host_screen, width, height, buffer_height);
-
- if (host_screen->ximg != NULL)
- {
- /* Free up the image data if previously used
- * i.ie called by server reset
- */
-
- if (HostX.have_shm)
- {
- XShmDetach(HostX.dpy, &host_screen->shminfo);
- XDestroyImage (host_screen->ximg);
- shmdt(host_screen->shminfo.shmaddr);
- shmctl(host_screen->shminfo.shmid, IPC_RMID, 0);
- }
- else
- {
- free(host_screen->ximg->data);
- host_screen->ximg->data = NULL;
-
- XDestroyImage(host_screen->ximg);
- }
- }
-
- if (HostX.have_shm)
- {
- host_screen->ximg = XShmCreateImage (HostX.dpy, HostX.visual, HostX.depth,
- ZPixmap, NULL, &host_screen->shminfo,
- width, buffer_height );
-
- host_screen->shminfo.shmid =
- shmget(IPC_PRIVATE,
- host_screen->ximg->bytes_per_line * buffer_height,
- IPC_CREAT|0777);
- host_screen->ximg->data = shmat(host_screen->shminfo.shmid, 0, 0);
- host_screen->shminfo.shmaddr = host_screen->ximg->data;
-
- if (host_screen->ximg->data == (char *)-1)
- {
- EPHYR_DBG("Can't attach SHM Segment, falling back to plain XImages");
- HostX.have_shm = False;
- XDestroyImage(host_screen->ximg);
- shmctl(host_screen->shminfo.shmid, IPC_RMID, 0);
- }
- else
- {
- EPHYR_DBG("SHM segment attached %p", host_screen->shminfo.shmaddr);
- host_screen->shminfo.readOnly = False;
- XShmAttach(HostX.dpy, &host_screen->shminfo);
- shm_success = True;
- }
- }
-
- if (!shm_success)
- {
- bitmap_pad = ( HostX.depth > 16 )? 32 : (( HostX.depth > 8 )? 16 : 8 );
-
- EPHYR_DBG("Creating image %dx%d for screen host_screen=%p\n",
- width, buffer_height, host_screen );
- host_screen->ximg = XCreateImage (HostX.dpy,
- HostX.visual,
- HostX.depth,
- ZPixmap, 0, 0,
- width,
- buffer_height,
- bitmap_pad,
- 0);
-
- host_screen->ximg->data =
- malloc (host_screen->ximg->bytes_per_line * buffer_height);
- }
-
- XResizeWindow (HostX.dpy, host_screen->win, width, height);
-
- /* Ask the WM to keep our size static */
- size_hints = XAllocSizeHints();
- size_hints->max_width = size_hints->min_width = width;
- size_hints->max_height = size_hints->min_height = height;
- size_hints->flags = PMinSize|PMaxSize;
- XSetWMNormalHints(HostX.dpy, host_screen->win, size_hints);
- XFree(size_hints);
-
- XMapWindow(HostX.dpy, host_screen->win);
-
- XSync(HostX.dpy, False);
-
- host_screen->win_width = width;
- host_screen->win_height = height;
-
- if (host_depth_matches_server(host_screen))
- {
- EPHYR_DBG("Host matches server");
- return host_screen->ximg->data;
- }
- else
- {
- EPHYR_DBG("server bpp %i", host_screen->server_depth>>3);
- host_screen->fb_data = malloc(width*buffer_height*(host_screen->server_depth>>3));
- return host_screen->fb_data;
- }
-}
-
-static void hostx_paint_debug_rect (struct EphyrHostScreen *host_screen,
- int x, int y,
- int width, int height);
-
-void
-hostx_paint_rect (EphyrScreenInfo screen,
- int sx, int sy,
- int dx, int dy,
- int width, int height)
-{
- struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
-
- EPHYR_DBG ("painting in screen %d\n", host_screen->mynum) ;
-
- /*
- * Copy the image data updated by the shadow layer
- * on to the window
- */
-
- if (HostXWantDamageDebug)
- {
- hostx_paint_debug_rect(host_screen, dx, dy, width, height);
- }
-
- /*
- * If the depth of the ephyr server is less than that of the host,
- * the kdrive fb does not point to the ximage data but to a buffer
- * ( fb_data ), we shift the various bits from this onto the XImage
- * so they match the host.
- *
- * Note, This code is pretty new ( and simple ) so may break on
- * endian issues, 32 bpp host etc.
- * Not sure if 8bpp case is right either.
- * ... and it will be slower than the matching depth case.
- */
-
- if (!host_depth_matches_server(host_screen))
- {
- int x,y,idx, bytes_per_pixel = (host_screen->server_depth>>3);
- unsigned char r,g,b;
- unsigned long host_pixel;
-
- EPHYR_DBG("Unmatched host depth host_screen=%p\n", host_screen);
- for (y=sy; y<sy+height; y++)
- for (x=sx; x<sx+width; x++)
- {
- idx = (host_screen->win_width*y*bytes_per_pixel)+(x*bytes_per_pixel);
-
- switch (host_screen->server_depth)
- {
- case 16:
- {
- unsigned short pixel = *(unsigned short*)(host_screen->fb_data+idx);
-
- r = ((pixel & 0xf800) >> 8);
- g = ((pixel & 0x07e0) >> 3);
- b = ((pixel & 0x001f) << 3);
-
- host_pixel = (r << 16) | (g << 8) | (b);
-
- XPutPixel(host_screen->ximg, x, y, host_pixel);
- break;
- }
- case 8:
- {
- unsigned char pixel = *(unsigned char*)(host_screen->fb_data+idx);
- XPutPixel(host_screen->ximg, x, y, HostX.cmap[pixel]);
- break;
- }
- default:
- break;
- }
- }
- }
-
- if (HostX.have_shm)
- {
- XShmPutImage (HostX.dpy, host_screen->win,
- HostX.gc, host_screen->ximg,
- sx, sy, dx, dy, width, height, False);
- }
- else
- {
- XPutImage (HostX.dpy, host_screen->win, HostX.gc, host_screen->ximg,
- sx, sy, dx, dy, width, height);
- }
-
- XSync (HostX.dpy, False);
-}
-
-static void
-hostx_paint_debug_rect (struct EphyrHostScreen *host_screen,
- int x, int y,
- int width, int height)
-{
- struct timespec tspec;
-
- tspec.tv_sec = HostX.damage_debug_msec / (1000000);
- tspec.tv_nsec = (HostX.damage_debug_msec % 1000000) * 1000;
-
- EPHYR_DBG("msec: %li tv_sec %li, tv_msec %li",
- HostX.damage_debug_msec, tspec.tv_sec, tspec.tv_nsec);
-
- /* fprintf(stderr, "Xephyr updating: %i+%i %ix%i\n", x, y, width, height); */
-
- XFillRectangle (HostX.dpy, host_screen->win, HostX.gc, x, y, width,height);
- XSync (HostX.dpy, False);
-
- /* nanosleep seems to work better than usleep for me... */
- nanosleep(&tspec, NULL);
-}
-
-void
-hostx_load_keymap(void)
-{
- XID *keymap;
- int host_width, min_keycode, max_keycode, width;
- int i,j;
-
- XDisplayKeycodes (HostX.dpy, &min_keycode, &max_keycode);
-
- EPHYR_DBG ("min: %d, max: %d", min_keycode, max_keycode);
-
- keymap = XGetKeyboardMapping (HostX.dpy,
- min_keycode,
- max_keycode - min_keycode + 1,
- &host_width);
-
- /* Try and copy the hosts keymap into our keymap to avoid loads
- * of messing around.
- *
- * kdrive cannot can have more than 4 keysyms per keycode
- * so we only copy at most the first 4 ( xorg has 6 per keycode, XVNC 2 )
- */
- width = (host_width > 4) ? 4 : host_width;
-
- ephyrKeySyms.map = (CARD32 *)calloc(sizeof(CARD32),
- (max_keycode - min_keycode + 1) *
- width);
- if (!ephyrKeySyms.map)
- return;
-
- for (i=0; i<(max_keycode - min_keycode+1); i++)
- for (j=0; j<width; j++)
- ephyrKeySyms.map[(i*width)+j] = (CARD32) keymap[(i*host_width) + j];
-
- EPHYR_DBG("keymap width, host:%d kdrive:%d", host_width, width);
-
- ephyrKeySyms.minKeyCode = min_keycode;
- ephyrKeySyms.maxKeyCode = max_keycode;
- ephyrKeySyms.mapWidth = width;
-
- XFree(keymap);
-}
-
-static struct EphyrHostScreen *
-host_screen_from_window (Window w)
-{
- int index = 0;
- struct EphyrHostScreen *result = NULL;
-
- for (index = 0 ; index < HostX.n_screens ; index++)
- {
- if (HostX.screens[index].win == w || HostX.screens[index].peer_win == w)
- {
- result = &HostX.screens[index];
- goto out;
- }
- }
-
-out:
- return result;
-}
-
-int
-hostx_get_event(EphyrHostXEvent *ev)
-{
- XEvent xev;
- static int grabbed_screen = -1;
-
- if (XPending(HostX.dpy))
- {
- XNextEvent(HostX.dpy, &xev);
-
- switch (xev.type)
- {
- case Expose:
- /* Not so great event compression, but works ok */
- while (XCheckTypedWindowEvent(HostX.dpy, xev.xexpose.window,
- Expose, &xev));
- {
- struct EphyrHostScreen *host_screen =
- host_screen_from_window (xev.xexpose.window);
- if (host_screen)
- {
- hostx_paint_rect (host_screen->info, 0, 0, 0, 0,
- host_screen->win_width,
- host_screen->win_height);
- }
- else
- {
- EPHYR_LOG_ERROR ("failed to get host screen\n");
- ev->type = EPHYR_EV_EXPOSE;
- ev->data.expose.window = xev.xexpose.window;
- return 1;
- }
- }
- return 0;
-
- case MotionNotify:
- {
- struct EphyrHostScreen *host_screen =
- host_screen_from_window (xev.xmotion.window);
-
- ev->type = EPHYR_EV_MOUSE_MOTION;
- ev->data.mouse_motion.x = xev.xmotion.x;
- ev->data.mouse_motion.y = xev.xmotion.y;
- ev->data.mouse_motion.window = xev.xmotion.window;
- ev->data.mouse_motion.screen = (host_screen ? host_screen->mynum : -1);
- }
- return 1;
-
- case ButtonPress:
- ev->type = EPHYR_EV_MOUSE_PRESS;
- ev->key_state = xev.xkey.state;
- /*
- * This is a bit hacky. will break for button 5 ( defined as 0x10 )
- * Check KD_BUTTON defines in kdrive.h
- */
- ev->data.mouse_down.button_num = 1<<(xev.xbutton.button-1);
- return 1;
-
- case ButtonRelease:
- ev->type = EPHYR_EV_MOUSE_RELEASE;
- ev->key_state = xev.xkey.state;
- ev->data.mouse_up.button_num = 1<<(xev.xbutton.button-1);
- return 1;
-
- case KeyPress:
- {
- ev->type = EPHYR_EV_KEY_PRESS;
- ev->key_state = xev.xkey.state;
- ev->data.key_down.scancode = xev.xkey.keycode;
- return 1;
- }
- case KeyRelease:
-
- if ((XKeycodeToKeysym(HostX.dpy,xev.xkey.keycode,0) == XK_Shift_L
- || XKeycodeToKeysym(HostX.dpy,xev.xkey.keycode,0) == XK_Shift_R)
- && (xev.xkey.state & ControlMask))
- {
- struct EphyrHostScreen *host_screen =
- host_screen_from_window (xev.xexpose.window);
-
- if (grabbed_screen != -1)
- {
- XUngrabKeyboard (HostX.dpy, CurrentTime);
- XUngrabPointer (HostX.dpy, CurrentTime);
- grabbed_screen = -1;
- hostx_set_win_title (host_screen->info,
- "(ctrl+shift grabs mouse and keyboard)");
- }
- else
- {
- /* Attempt grab */
- if (XGrabKeyboard (HostX.dpy, host_screen->win, True,
- GrabModeAsync,
- GrabModeAsync,
- CurrentTime) == 0)
- {
- if (XGrabPointer (HostX.dpy, host_screen->win, True,
- NoEventMask,
- GrabModeAsync,
- GrabModeAsync,
- host_screen->win, None, CurrentTime) == 0)
- {
- grabbed_screen = host_screen->mynum;
- hostx_set_win_title
- (host_screen->info,
- "(ctrl+shift releases mouse and keyboard)");
- }
- else /* Failed pointer grabm ungrab keyboard */
- XUngrabKeyboard (HostX.dpy, CurrentTime);
- }
- }
- }
-
- /* Still send the release event even if above has happened
- * server will get confused with just an up event.
- * Maybe it would be better to just block shift+ctrls getting to
- * kdrive all togeather.
- */
- ev->type = EPHYR_EV_KEY_RELEASE;
- ev->key_state = xev.xkey.state;
- ev->data.key_up.scancode = xev.xkey.keycode;
- return 1;
-
- default:
- break;
-
- }
- }
- return 0;
-}
-
-void*
-hostx_get_display(void)
-{
- return HostX.dpy ;
-}
-
-int
-hostx_get_window (int a_screen_number)
-{
- if (a_screen_number < 0 || a_screen_number >= HostX.n_screens) {
- EPHYR_LOG_ERROR ("bad screen number:%d\n", a_screen_number) ;
- return 0;
- }
- return HostX.screens[a_screen_number].win ;
-}
-
-int
-hostx_get_window_attributes (int a_window, EphyrHostWindowAttributes *a_attrs)
-{
- XWindowAttributes attrs ;
-
- memset (&attrs, 0, sizeof (attrs)) ;
-
- if (!XGetWindowAttributes (hostx_get_display (),
- a_window,
- &attrs)) {
- return FALSE ;
- }
- a_attrs->x = attrs.x ;
- a_attrs->y = attrs.y ;
- a_attrs->width = attrs.width ;
- a_attrs->height = attrs.height ;
- if (attrs.visual)
- a_attrs->visualid = attrs.visual->visualid ;
- return TRUE ;
-}
-
-int
-hostx_get_extension_info (const char *a_ext_name,
- int *a_major_opcode,
- int *a_first_event,
- int *a_first_error)
-{
- if (!a_ext_name || !a_major_opcode || !a_first_event || !a_first_error)
- return 0 ;
- if (!XQueryExtension (HostX.dpy,
- a_ext_name,
- a_major_opcode,
- a_first_event,
- a_first_error))
- {
- return 0 ;
- }
- return 1 ;
-}
-
-int
-hostx_get_visuals_info (EphyrHostVisualInfo **a_visuals,
- int *a_num_entries)
-{
- Display *dpy=hostx_get_display () ;
- Bool is_ok=False ;
- XVisualInfo templ, *visuals=NULL;
- EphyrHostVisualInfo *host_visuals=NULL ;
- int nb_items=0, i=0;
-
- EPHYR_RETURN_VAL_IF_FAIL (a_visuals && a_num_entries && dpy,
- False) ;
- EPHYR_LOG ("enter\n") ;
- memset (&templ, 0, sizeof (templ)) ;
- visuals = XGetVisualInfo (dpy, VisualNoMask, &templ, &nb_items) ;
- if (!visuals) {
- EPHYR_LOG_ERROR ("host does not advertise any visual\n") ;
- goto out ;
- }
- EPHYR_LOG ("host advertises %d visuals\n", nb_items) ;
- host_visuals = calloc (nb_items, sizeof (EphyrHostVisualInfo)) ;
- for (i=0; i<nb_items; i++) {
- host_visuals[i].visualid = visuals[i].visualid ;
- host_visuals[i].screen = visuals[i].screen ;
- host_visuals[i].depth = visuals[i].depth ;
- host_visuals[i].class = visuals[i].class ;
- host_visuals[i].red_mask = visuals[i].red_mask ;
- host_visuals[i].green_mask = visuals[i].green_mask ;
- host_visuals[i].blue_mask = visuals[i].blue_mask ;
- host_visuals[i].colormap_size = visuals[i].colormap_size ;
- host_visuals[i].bits_per_rgb = visuals[i].bits_per_rgb ;
- }
- *a_visuals = host_visuals ;
- *a_num_entries = nb_items;
- host_visuals=NULL;
-
- is_ok = TRUE;
-out:
- if (visuals) {
- XFree (visuals) ;
- visuals = NULL;
- }
- free(host_visuals);
- host_visuals = NULL;
- EPHYR_LOG ("leave\n") ;
- return is_ok ;
-
-}
-
-int
-hostx_create_window (int a_screen_number,
- EphyrBox *a_geometry,
- int a_visual_id,
- int *a_host_peer /*out parameter*/)
-{
- Bool is_ok=FALSE ;
- Display *dpy=hostx_get_display () ;
- XVisualInfo *visual_info=NULL, visual_info_templ;
- int visual_mask=VisualIDMask ;
- Window win=None ;
- int nb_visuals=0, winmask=0;
- XSetWindowAttributes attrs;
-
- EPHYR_RETURN_VAL_IF_FAIL (dpy && a_geometry, FALSE) ;
-
- EPHYR_LOG ("enter\n") ;
-
- /*get visual*/
- memset (&visual_info, 0, sizeof (visual_info)) ;
- visual_info_templ.visualid = a_visual_id ;
- visual_info = XGetVisualInfo (dpy, visual_mask,
- &visual_info_templ,
- &nb_visuals) ;
- if (!visual_info) {
- EPHYR_LOG_ERROR ("argh, could not find a remote visual with id:%d\n",
- a_visual_id) ;
- goto out ;
- }
- memset (&attrs, 0, sizeof (attrs)) ;
- attrs.colormap = XCreateColormap (dpy,
- RootWindow (dpy,
- visual_info->screen),
- visual_info->visual,
- AllocNone) ;
- attrs.event_mask = ButtonPressMask
- |ButtonReleaseMask
- |PointerMotionMask
- |KeyPressMask
- |KeyReleaseMask
- |ExposureMask;
- winmask = CWColormap|CWEventMask;
-
- win = XCreateWindow (dpy, hostx_get_window (a_screen_number),
- a_geometry->x, a_geometry->y,
- a_geometry->width, a_geometry->height, 0,
- visual_info->depth, CopyFromParent,
- visual_info->visual, winmask, &attrs) ;
- if (win == None) {
- EPHYR_LOG_ERROR ("failed to create peer window\n") ;
- goto out ;
- }
- if (HostX.screens[a_screen_number].peer_win == None) {
- HostX.screens[a_screen_number].peer_win = win;
- } else {
- EPHYR_LOG_ERROR ("multiple peer windows created for same screen\n") ;
- }
- XFlush (dpy) ;
- XMapWindow (dpy, win) ;
- *a_host_peer = win ;
- is_ok = TRUE ;
-out:
- EPHYR_LOG ("leave\n") ;
- return is_ok ;
-}
-
-int
-hostx_destroy_window (int a_win)
-{
- Display *dpy=hostx_get_display () ;
-
- EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
- XDestroyWindow (dpy, a_win) ;
- XFlush (dpy) ;
- return TRUE ;
-}
-
-int
-hostx_set_window_geometry (int a_win, EphyrBox *a_geo)
-{
- Display *dpy=hostx_get_display ();
-
- EPHYR_RETURN_VAL_IF_FAIL (dpy && a_geo, FALSE) ;
-
- EPHYR_LOG ("enter. x,y,w,h:(%d,%d,%d,%d)\n",
- a_geo->x, a_geo->y,
- a_geo->width, a_geo->height) ;
-
- XMoveWindow (dpy, a_win, a_geo->x, a_geo->y) ;
- XResizeWindow (dpy, a_win, a_geo->width, a_geo->height) ;
- EPHYR_LOG ("leave\n") ;
- return TRUE;
-}
-
-int
-hostx_set_window_bounding_rectangles (int a_window,
- EphyrRect *a_rects,
- int a_num_rects)
-{
- Bool is_ok=FALSE;
- Display *dpy=hostx_get_display () ;
- int i=0 ;
- XRectangle *rects=NULL ;
-
- EPHYR_RETURN_VAL_IF_FAIL (dpy && a_rects, FALSE) ;
-
- EPHYR_LOG ("enter. num rects:%d\n", a_num_rects) ;
-
- rects = calloc (a_num_rects, sizeof (XRectangle)) ;
- for (i=0; i<a_num_rects; i++) {
- rects[i].x = a_rects[i].x1 ;
- rects[i].y = a_rects[i].y1 ;
- rects[i].width = abs (a_rects[i].x2 - a_rects[i].x1);
- rects[i].height = abs (a_rects[i].y2 - a_rects[i].y1) ;
- EPHYR_LOG ("borders clipped to rect[x:%d,y:%d,w:%d,h:%d]\n",
- rects[i].x, rects[i].y,
- rects[i].width, rects[i].height) ;
- }
- /*this aways returns 1*/
- XShapeCombineRectangles (dpy, a_window, ShapeBounding, 0, 0,
- rects, a_num_rects, ShapeSet, YXBanded) ;
- is_ok = TRUE ;
-
- free(rects);
- rects = NULL;
- EPHYR_LOG ("leave\n") ;
- return is_ok;
-}
-
-int
-hostx_set_window_clipping_rectangles (int a_window,
- EphyrRect *a_rects,
- int a_num_rects)
-{
- Bool is_ok=FALSE;
- Display *dpy=hostx_get_display () ;
- int i=0 ;
- XRectangle *rects=NULL ;
-
- EPHYR_RETURN_VAL_IF_FAIL (dpy && a_rects, FALSE) ;
-
- EPHYR_LOG ("enter. num rects:%d\n", a_num_rects) ;
-
- rects = calloc (a_num_rects, sizeof (XRectangle)) ;
- for (i=0; i<a_num_rects; i++) {
- rects[i].x = a_rects[i].x1 ;
- rects[i].y = a_rects[i].y1 ;
- rects[i].width = abs (a_rects[i].x2 - a_rects[i].x1);
- rects[i].height = abs (a_rects[i].y2 - a_rects[i].y1) ;
- EPHYR_LOG ("clipped to rect[x:%d,y:%d,w:%d,h:%d]\n",
- rects[i].x, rects[i].y,
- rects[i].width, rects[i].height) ;
- }
- /*this aways returns 1*/
- XShapeCombineRectangles (dpy, a_window, ShapeClip, 0, 0,
- rects, a_num_rects, ShapeSet, YXBanded) ;
- is_ok = TRUE ;
-
- free(rects);
- rects = NULL;
- EPHYR_LOG ("leave\n") ;
- return is_ok;
-}
-
-int
-hostx_has_xshape (void)
-{
- int event_base=0, error_base=0 ;
- Display *dpy=hostx_get_display () ;
- if (!XShapeQueryExtension (dpy,
- &event_base,
- &error_base)) {
- return FALSE ;
- }
- return TRUE;
-}
-
-#ifdef XF86DRI
-typedef struct {
- int is_valid ;
- int local_id ;
- int remote_id ;
-} ResourcePair ;
-
-#define RESOURCE_PEERS_SIZE 1024*10
-static ResourcePair resource_peers[RESOURCE_PEERS_SIZE] ;
-
-
-int
-hostx_allocate_resource_id_peer (int a_local_resource_id,
- int *a_remote_resource_id)
-{
- int i=0 ;
- ResourcePair *peer=NULL ;
- Display *dpy=hostx_get_display ();
-
- /*
- * first make sure a resource peer
- * does not exist already for
- * a_local_resource_id
- */
- for (i=0; i<RESOURCE_PEERS_SIZE; i++) {
- if (resource_peers[i].is_valid
- && resource_peers[i].local_id == a_local_resource_id) {
- peer = &resource_peers[i] ;
- break ;
- }
- }
- /*
- * find one free peer entry, an feed it with
- */
- if (!peer) {
- for (i=0; i<RESOURCE_PEERS_SIZE; i++) {
- if (!resource_peers[i].is_valid) {
- peer = &resource_peers[i] ;
- break ;
- }
- }
- if (peer) {
- peer->remote_id = XAllocID (dpy);
- peer->local_id = a_local_resource_id ;
- peer->is_valid = TRUE ;
- }
- }
- if (peer) {
- *a_remote_resource_id = peer->remote_id ;
- return TRUE ;
- }
- return FALSE ;
-}
-
-int
-hostx_get_resource_id_peer (int a_local_resource_id,
- int *a_remote_resource_id)
-{
- int i=0 ;
- ResourcePair *peer=NULL ;
- for (i=0; i<RESOURCE_PEERS_SIZE; i++) {
- if (resource_peers[i].is_valid
- && resource_peers[i].local_id == a_local_resource_id) {
- peer = &resource_peers[i] ;
- break ;
- }
- }
- if (peer) {
- *a_remote_resource_id = peer->remote_id ;
- return TRUE ;
- }
- return FALSE ;
-}
-
-int
-hostx_has_dri (void)
-{
- int event_base=0, error_base=0 ;
- Display *dpy=hostx_get_display () ;
-
- if (!dpy)
- return FALSE ;
-
- if (!XF86DRIQueryExtension (dpy,
- &event_base,
- &error_base)) {
- return FALSE ;
- }
- return TRUE ;
-}
-
-int
-hostx_has_glx (void)
-{
- Display *dpy=hostx_get_display () ;
- int event_base=0, error_base=0 ;
-
- if (!glXQueryExtension (dpy, &event_base, &error_base)) {
- return FALSE ;
- }
- return TRUE ;
-}
-
-#endif /* XF86DRI */
+/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum <mallum@o-hand.com> + * + * Copyright © 2004 Nokia + * + * 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 Nokia not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Nokia makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL NOKIA 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_CONFIG_H +#include <kdrive-config.h> +#endif + +/* + * including some server headers (like kdrive-config.h) + * might define the macro _XSERVER64 + * on 64 bits machines. That macro must _NOT_ be defined for Xlib + * client code, otherwise bad things happen. + * So let's undef that macro if necessary. + */ +#ifdef _XSERVER64 +#undef _XSERVER64 +#endif + + +#include "hostx.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> /* for memset */ +#include <time.h> + +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/time.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include <X11/extensions/XShm.h> +#include <X11/extensions/shape.h> +#ifdef XF86DRI +#include <GL/glx.h> +#endif /* XF86DRI */ +#include "ephyrlog.h" + +#ifdef XF86DRI +extern Bool XF86DRIQueryExtension (Display *dpy, + int *event_basep, + int *error_basep); +#endif + +/* + * All xlib calls go here, which gets built as its own .a . + * Mixing kdrive and xlib headers causes all sorts of types + * to get clobbered. + */ + +struct EphyrHostScreen +{ + Window win; + Window win_pre_existing; /* Set via -parent option like xnest */ + Window peer_win; /* Used for GL; should be at most one */ + XImage *ximg; + int win_width, win_height; + int server_depth; + unsigned char *fb_data; /* only used when host bpp != server bpp */ + XShmSegmentInfo shminfo; + + void *info; /* Pointer to the screen this is associated with */ + int mynum; /* Screen number */ +}; + +struct EphyrHostXVars +{ + char *server_dpy_name; + Display *dpy; + int screen; + Visual *visual; + Window winroot; + GC gc; + int depth; + Bool use_host_cursor; + Bool use_fullscreen; + Bool have_shm; + + int n_screens; + struct EphyrHostScreen *screens; + + long damage_debug_msec; + + unsigned long cmap[256]; +}; + +/* memset ( missing> ) instead of below */ +/*static EphyrHostXVars HostX = { "?", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};*/ +static EphyrHostXVars HostX; + +static int HostXWantDamageDebug = 0; + +extern EphyrKeySyms ephyrKeySyms; + +extern int monitorResolution; + +char *ephyrResName = NULL; +int ephyrResNameFromCmd = 0; +char *ephyrTitle = NULL; + +static void +hostx_set_fullscreen_hint(void); + +/* X Error traps */ + +static int trapped_error_code = 0; +static int (*old_error_handler) (Display *d, XErrorEvent *e); + +#define host_depth_matches_server(_vars) (HostX.depth == (_vars)->server_depth) + +static struct EphyrHostScreen * +host_screen_from_screen_info (EphyrScreenInfo *screen) +{ + int i; + + for (i = 0 ; i < HostX.n_screens ; i++) + { + if ( HostX.screens[i].info == screen) + { + return &HostX.screens[i]; + } + } + return NULL; +} + +static int +error_handler(Display *display, + XErrorEvent *error) +{ + trapped_error_code = error->error_code; + return 0; +} + +static void +hostx_errors_trap(void) +{ + trapped_error_code = 0; + old_error_handler = XSetErrorHandler(error_handler); +} + +static int +hostx_errors_untrap(void) +{ + XSetErrorHandler(old_error_handler); + return trapped_error_code; +} + +int +hostx_want_screen_size (EphyrScreenInfo screen, int *width, int *height ) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + if (host_screen && + (host_screen->win_pre_existing != None || + HostX.use_fullscreen == True)) + { + *width = host_screen->win_width; + *height = host_screen->win_height; + return 1; + } + + return 0; +} + +void +hostx_add_screen (EphyrScreenInfo screen, + unsigned long win_id, + int screen_num) +{ + int index = HostX.n_screens; + + HostX.n_screens += 1; + HostX.screens = realloc (HostX.screens, + HostX.n_screens * sizeof(struct EphyrHostScreen)); + memset (&HostX.screens[index], 0, sizeof (struct EphyrHostScreen)); + + HostX.screens[index].info = screen; + HostX.screens[index].win_pre_existing = win_id; +} + + +void +hostx_set_display_name (char *name) +{ + HostX.server_dpy_name = strdup (name); +} + +void +hostx_set_screen_number(EphyrScreenInfo screen, int number) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + if (host_screen) { + host_screen->mynum = number; + hostx_set_win_title (host_screen->info, "") ; + }} + +void +hostx_set_win_title (EphyrScreenInfo screen, char *extra_text) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + if (!host_screen) + return; + + if (ephyrTitle) { + XStoreName(HostX.dpy, host_screen->win, ephyrTitle); + } else { +#define BUF_LEN 256 + char buf[BUF_LEN+1]; + + memset (buf, 0, BUF_LEN+1) ; + snprintf (buf, BUF_LEN, "Xephyr on %s.%d %s", + HostX.server_dpy_name, + host_screen->mynum, + (extra_text != NULL) ? extra_text : ""); + + XStoreName (HostX.dpy, host_screen->win, buf); + } +} + +int +hostx_want_host_cursor (void) +{ + return HostX.use_host_cursor; +} + +void +hostx_use_host_cursor (void) +{ + HostX.use_host_cursor = True; +} + +int +hostx_want_preexisting_window (EphyrScreenInfo screen) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + if (host_screen && host_screen->win_pre_existing) + { + return 1; + } + else + { + return 0; + } +} + +void +hostx_use_fullscreen (void) +{ + HostX.use_fullscreen = True; +} + +int +hostx_want_fullscreen (void) +{ + return HostX.use_fullscreen; +} + +static void +hostx_set_fullscreen_hint (void) +{ + Atom atom_WINDOW_STATE, atom_WINDOW_STATE_FULLSCREEN; + int index; + + atom_WINDOW_STATE + = XInternAtom(HostX.dpy, "_NET_WM_STATE", False); + atom_WINDOW_STATE_FULLSCREEN + = XInternAtom(HostX.dpy, "_NET_WM_STATE_FULLSCREEN",False); + + for (index = 0 ; index < HostX.n_screens ; index++) + { + XChangeProperty (HostX.dpy, HostX.screens[index].win, + atom_WINDOW_STATE, XA_ATOM, 32, + PropModeReplace, + (unsigned char *)&atom_WINDOW_STATE_FULLSCREEN, 1); + } +} + + +static void +hostx_toggle_damage_debug (void) +{ + HostXWantDamageDebug ^= 1; +} + +void +hostx_handle_signal (int signum) +{ + hostx_toggle_damage_debug(); + EPHYR_DBG ("Signal caught. Damage Debug:%i\n", + HostXWantDamageDebug); +} + +void +hostx_use_resname (char *name, int fromcmd) +{ + ephyrResName = name; + ephyrResNameFromCmd = fromcmd; +} + +void +hostx_set_title (char *title) +{ + ephyrTitle = title; +} + +int +hostx_init (void) +{ + XSetWindowAttributes attr; + Cursor empty_cursor; + Pixmap cursor_pxm; + XColor col; + int index; + char *tmpstr; + XClassHint *class_hint; + + attr.event_mask = + ButtonPressMask + |ButtonReleaseMask + |PointerMotionMask + |KeyPressMask + |KeyReleaseMask + |ExposureMask; + + EPHYR_DBG("mark"); + + if ((HostX.dpy = XOpenDisplay(getenv("DISPLAY"))) == NULL) + { + fprintf(stderr, "\nXephyr cannot open host display. Is DISPLAY set?\n"); + exit(1); + } + + HostX.screen = DefaultScreen(HostX.dpy); + HostX.winroot = RootWindow(HostX.dpy, HostX.screen); + HostX.gc = XCreateGC(HostX.dpy, HostX.winroot, 0, NULL); + HostX.depth = DefaultDepth(HostX.dpy, HostX.screen); + HostX.visual = DefaultVisual(HostX.dpy, HostX.screen); + + class_hint = XAllocClassHint(); + + for (index = 0 ; index < HostX.n_screens ; index++) + { + struct EphyrHostScreen *host_screen = &HostX.screens[index]; + + host_screen->server_depth = HostX.depth; + if (host_screen->win_pre_existing != None) + { + Status result; + XWindowAttributes prewin_attr; + + /* Get screen size from existing window */ + + hostx_errors_trap(); + + result = XGetWindowAttributes (HostX.dpy, + host_screen->win_pre_existing, + &prewin_attr); + + + if (hostx_errors_untrap() || !result) + { + fprintf (stderr, "\nXephyr -parent window' does not exist!\n"); + exit (1); + } + + host_screen->win_width = prewin_attr.width; + host_screen->win_height = prewin_attr.height; + + host_screen->win = XCreateWindow (HostX.dpy, + host_screen->win_pre_existing, + 0,0, + host_screen->win_width, + host_screen->win_height, + 0, + CopyFromParent, + CopyFromParent, + CopyFromParent, + CWEventMask, + &attr); + } + else + { + host_screen->win = XCreateWindow (HostX.dpy, + HostX.winroot, + 0,0,100,100, /* will resize */ + 0, + CopyFromParent, + CopyFromParent, + CopyFromParent, + CWEventMask, + &attr); + + hostx_set_win_title (host_screen->info, + "(ctrl+shift grabs mouse and keyboard)"); + + if (HostX.use_fullscreen) + { + host_screen->win_width = DisplayWidth(HostX.dpy, HostX.screen); + host_screen->win_height = DisplayHeight(HostX.dpy, HostX.screen); + + hostx_set_fullscreen_hint(); + } + + if (class_hint) + { + tmpstr = getenv("RESOURCE_NAME"); + if (tmpstr && (!ephyrResNameFromCmd)) + ephyrResName = tmpstr; + class_hint->res_name = ephyrResName; + class_hint->res_class = "Xephyr"; + XSetClassHint(hostx_get_display(), host_screen->win, class_hint); + + } + + } + } + + if (class_hint) + XFree(class_hint); + + XParseColor (HostX.dpy, DefaultColormap (HostX.dpy,HostX.screen), + "red", &col); + XAllocColor (HostX.dpy, DefaultColormap (HostX.dpy, HostX.screen), + &col); + XSetForeground (HostX.dpy, HostX.gc, col.pixel); + + if (!hostx_want_host_cursor ()) + { + /* Ditch the cursor, we provide our 'own' */ + cursor_pxm = XCreatePixmap (HostX.dpy, HostX.winroot, 1, 1, 1); + memset (&col, 0, sizeof (col)); + empty_cursor = XCreatePixmapCursor (HostX.dpy, + cursor_pxm, cursor_pxm, + &col, &col, 1, 1); + for ( index = 0 ; index < HostX.n_screens ; index++ ) + { + XDefineCursor (HostX.dpy, + HostX.screens[index].win, + empty_cursor); + } + XFreePixmap (HostX.dpy, cursor_pxm); + } + + for (index = 0 ; index < HostX.n_screens ; index++) + { + HostX.screens[index].ximg = NULL; + } + /* Try to get share memory ximages for a little bit more speed */ + + if (!XShmQueryExtension(HostX.dpy) || getenv("XEPHYR_NO_SHM")) + { + fprintf(stderr, "\nXephyr unable to use SHM XImages\n"); + HostX.have_shm = False; + } + else + { + /* Really really check we have shm - better way ?*/ + XShmSegmentInfo shminfo; + + HostX.have_shm = True; + + shminfo.shmid=shmget(IPC_PRIVATE, 1, IPC_CREAT|0777); + shminfo.shmaddr=shmat(shminfo.shmid,0,0); + shminfo.readOnly=True; + + hostx_errors_trap(); + + XShmAttach(HostX.dpy, &shminfo); + XSync(HostX.dpy, False); + + if (hostx_errors_untrap()) + { + fprintf(stderr, "\nXephyr unable to use SHM XImages\n"); + HostX.have_shm = False; + } + + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); +} + + XFlush(HostX.dpy); + + /* Setup the pause time between paints when debugging updates */ + + HostX.damage_debug_msec = 20000; /* 1/50 th of a second */ + + if (getenv ("XEPHYR_PAUSE")) + { + HostX.damage_debug_msec = strtol (getenv ("XEPHYR_PAUSE"), NULL, 0); + EPHYR_DBG ("pause is %li\n", HostX.damage_debug_msec); + } + + return 1; +} + +int +hostx_get_depth (void) +{ + return HostX.depth; +} + +int +hostx_get_server_depth (EphyrScreenInfo screen) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + return host_screen ? host_screen->server_depth : 0; +} + +void +hostx_set_server_depth (EphyrScreenInfo screen, int depth) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + if (host_screen) + host_screen->server_depth = depth; +} + +int +hostx_get_bpp (EphyrScreenInfo screen) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + if (!host_screen) + return 0; + + if (host_depth_matches_server (host_screen)) + return HostX.visual->bits_per_rgb; + else + return host_screen->server_depth; /*XXX correct ?*/ +} + +void +hostx_get_visual_masks (EphyrScreenInfo screen, + CARD32 *rmsk, + CARD32 *gmsk, + CARD32 *bmsk) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + if (!host_screen) + return; + + if (host_depth_matches_server(host_screen)) + { + *rmsk = HostX.visual->red_mask; + *gmsk = HostX.visual->green_mask; + *bmsk = HostX.visual->blue_mask; + } + else if (host_screen->server_depth == 16) + { + /* Assume 16bpp 565 */ + *rmsk = 0xf800; + *gmsk = 0x07e0; + *bmsk = 0x001f; + } + else + { + *rmsk = 0x0; + *gmsk = 0x0; + *bmsk = 0x0; + } +} + +static int +hostx_calculate_color_shift(unsigned long mask) +{ + int shift = 1; + /* count # of bits in mask */ + while ((mask = (mask >> 1))) shift++; + /* cmap entry is an unsigned char so adjust it by size of that */ + shift = shift - sizeof(unsigned char) * 8; + if (shift < 0) shift = 0; + return shift; +} + +void +hostx_set_cmap_entry(unsigned char idx, + unsigned char r, + unsigned char g, + unsigned char b) +{ +/* need to calculate the shifts for RGB because server could be BGR. */ +/* XXX Not sure if this is correct for 8 on 16, but this works for 8 on 24.*/ + static int rshift, bshift, gshift = 0; + static int first_time = 1; + if (first_time) { + first_time = 0; + rshift = hostx_calculate_color_shift(HostX.visual->red_mask); + gshift = hostx_calculate_color_shift(HostX.visual->green_mask); + bshift = hostx_calculate_color_shift(HostX.visual->blue_mask); + } + HostX.cmap[idx] = ((r << rshift) & HostX.visual->red_mask) | + ((g << gshift) & HostX.visual->green_mask) | + ((b << bshift) & HostX.visual->blue_mask); +} + +/** + * hostx_screen_init creates the XImage that will contain the front buffer of + * the ephyr screen, and possibly offscreen memory. + * + * @param width width of the screen + * @param height height of the screen + * @param buffer_height height of the rectangle to be allocated. + * + * hostx_screen_init() creates an XImage, using MIT-SHM if it's available. + * buffer_height can be used to create a larger offscreen buffer, which is used + * by fakexa for storing offscreen pixmap data. + */ +void* +hostx_screen_init (EphyrScreenInfo screen, + int width, int height, + int buffer_height) +{ + int bitmap_pad; + Bool shm_success = False; + XSizeHints *size_hints; + + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + if (!host_screen) + { + fprintf (stderr, "%s: Error in accessing hostx data\n", __func__ ); + exit(1); + } + + EPHYR_DBG ("host_screen=%p wxh=%dx%d, buffer_height=%d", + host_screen, width, height, buffer_height); + + if (host_screen->ximg != NULL) + { + /* Free up the image data if previously used + * i.ie called by server reset + */ + + if (HostX.have_shm) + { + XShmDetach(HostX.dpy, &host_screen->shminfo); + XDestroyImage (host_screen->ximg); + shmdt(host_screen->shminfo.shmaddr); + shmctl(host_screen->shminfo.shmid, IPC_RMID, 0); + } + else + { + free(host_screen->ximg->data); + host_screen->ximg->data = NULL; + + XDestroyImage(host_screen->ximg); + } + } + + if (HostX.have_shm) + { + host_screen->ximg = XShmCreateImage (HostX.dpy, HostX.visual, HostX.depth, + ZPixmap, NULL, &host_screen->shminfo, + width, buffer_height ); + + host_screen->shminfo.shmid = + shmget(IPC_PRIVATE, + host_screen->ximg->bytes_per_line * buffer_height, + IPC_CREAT|0777); + host_screen->ximg->data = shmat(host_screen->shminfo.shmid, 0, 0); + host_screen->shminfo.shmaddr = host_screen->ximg->data; + + if (host_screen->ximg->data == (char *)-1) + { + EPHYR_DBG("Can't attach SHM Segment, falling back to plain XImages"); + HostX.have_shm = False; + XDestroyImage(host_screen->ximg); + shmctl(host_screen->shminfo.shmid, IPC_RMID, 0); + } + else + { + EPHYR_DBG("SHM segment attached %p", host_screen->shminfo.shmaddr); + host_screen->shminfo.readOnly = False; + XShmAttach(HostX.dpy, &host_screen->shminfo); + shm_success = True; + } + } + + if (!shm_success) + { + bitmap_pad = ( HostX.depth > 16 )? 32 : (( HostX.depth > 8 )? 16 : 8 ); + + EPHYR_DBG("Creating image %dx%d for screen host_screen=%p\n", + width, buffer_height, host_screen ); + host_screen->ximg = XCreateImage (HostX.dpy, + HostX.visual, + HostX.depth, + ZPixmap, 0, 0, + width, + buffer_height, + bitmap_pad, + 0); + + host_screen->ximg->data = + malloc (host_screen->ximg->bytes_per_line * buffer_height); + } + + XResizeWindow (HostX.dpy, host_screen->win, width, height); + + /* Ask the WM to keep our size static */ + size_hints = XAllocSizeHints(); + size_hints->max_width = size_hints->min_width = width; + size_hints->max_height = size_hints->min_height = height; + size_hints->flags = PMinSize|PMaxSize; + XSetWMNormalHints(HostX.dpy, host_screen->win, size_hints); + XFree(size_hints); + + XMapWindow(HostX.dpy, host_screen->win); + + XSync(HostX.dpy, False); + + host_screen->win_width = width; + host_screen->win_height = height; + + if (host_depth_matches_server(host_screen)) + { + EPHYR_DBG("Host matches server"); + return host_screen->ximg->data; + } + else + { + EPHYR_DBG("server bpp %i", host_screen->server_depth>>3); + host_screen->fb_data = malloc(width*buffer_height*(host_screen->server_depth>>3)); + return host_screen->fb_data; + } +} + +static void hostx_paint_debug_rect (struct EphyrHostScreen *host_screen, + int x, int y, + int width, int height); + +void +hostx_paint_rect (EphyrScreenInfo screen, + int sx, int sy, + int dx, int dy, + int width, int height) +{ + struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen); + + EPHYR_DBG ("painting in screen %d\n", host_screen->mynum) ; + + /* + * Copy the image data updated by the shadow layer + * on to the window + */ + + if (HostXWantDamageDebug) + { + hostx_paint_debug_rect(host_screen, dx, dy, width, height); + } + + /* + * If the depth of the ephyr server is less than that of the host, + * the kdrive fb does not point to the ximage data but to a buffer + * ( fb_data ), we shift the various bits from this onto the XImage + * so they match the host. + * + * Note, This code is pretty new ( and simple ) so may break on + * endian issues, 32 bpp host etc. + * Not sure if 8bpp case is right either. + * ... and it will be slower than the matching depth case. + */ + + if (!host_depth_matches_server(host_screen)) + { + int x,y,idx, bytes_per_pixel = (host_screen->server_depth>>3); + unsigned char r,g,b; + unsigned long host_pixel; + + EPHYR_DBG("Unmatched host depth host_screen=%p\n", host_screen); + for (y=sy; y<sy+height; y++) + for (x=sx; x<sx+width; x++) + { + idx = (host_screen->win_width*y*bytes_per_pixel)+(x*bytes_per_pixel); + + switch (host_screen->server_depth) + { + case 16: + { + unsigned short pixel = *(unsigned short*)(host_screen->fb_data+idx); + + r = ((pixel & 0xf800) >> 8); + g = ((pixel & 0x07e0) >> 3); + b = ((pixel & 0x001f) << 3); + + host_pixel = (r << 16) | (g << 8) | (b); + + XPutPixel(host_screen->ximg, x, y, host_pixel); + break; + } + case 8: + { + unsigned char pixel = *(unsigned char*)(host_screen->fb_data+idx); + XPutPixel(host_screen->ximg, x, y, HostX.cmap[pixel]); + break; + } + default: + break; + } + } + } + + if (HostX.have_shm) + { + XShmPutImage (HostX.dpy, host_screen->win, + HostX.gc, host_screen->ximg, + sx, sy, dx, dy, width, height, False); + } + else + { + XPutImage (HostX.dpy, host_screen->win, HostX.gc, host_screen->ximg, + sx, sy, dx, dy, width, height); + } + + XSync (HostX.dpy, False); +} + +static void +hostx_paint_debug_rect (struct EphyrHostScreen *host_screen, + int x, int y, + int width, int height) +{ + struct timespec tspec; + + tspec.tv_sec = HostX.damage_debug_msec / (1000000); + tspec.tv_nsec = (HostX.damage_debug_msec % 1000000) * 1000; + + EPHYR_DBG("msec: %li tv_sec %li, tv_msec %li", + HostX.damage_debug_msec, tspec.tv_sec, tspec.tv_nsec); + + /* fprintf(stderr, "Xephyr updating: %i+%i %ix%i\n", x, y, width, height); */ + + XFillRectangle (HostX.dpy, host_screen->win, HostX.gc, x, y, width,height); + XSync (HostX.dpy, False); + + /* nanosleep seems to work better than usleep for me... */ + nanosleep(&tspec, NULL); +} + +void +hostx_load_keymap(void) +{ + XID *keymap; + int host_width, min_keycode, max_keycode, width; + int i,j; + + XDisplayKeycodes (HostX.dpy, &min_keycode, &max_keycode); + + EPHYR_DBG ("min: %d, max: %d", min_keycode, max_keycode); + + keymap = XGetKeyboardMapping (HostX.dpy, + min_keycode, + max_keycode - min_keycode + 1, + &host_width); + + /* Try and copy the hosts keymap into our keymap to avoid loads + * of messing around. + * + * kdrive cannot can have more than 4 keysyms per keycode + * so we only copy at most the first 4 ( xorg has 6 per keycode, XVNC 2 ) + */ + width = (host_width > 4) ? 4 : host_width; + + ephyrKeySyms.map = (CARD32 *)calloc(sizeof(CARD32), + (max_keycode - min_keycode + 1) * + width); + if (!ephyrKeySyms.map) + return; + + for (i=0; i<(max_keycode - min_keycode+1); i++) + for (j=0; j<width; j++) + ephyrKeySyms.map[(i*width)+j] = (CARD32) keymap[(i*host_width) + j]; + + EPHYR_DBG("keymap width, host:%d kdrive:%d", host_width, width); + + ephyrKeySyms.minKeyCode = min_keycode; + ephyrKeySyms.maxKeyCode = max_keycode; + ephyrKeySyms.mapWidth = width; + + XFree(keymap); +} + +static struct EphyrHostScreen * +host_screen_from_window (Window w) +{ + int index = 0; + struct EphyrHostScreen *result = NULL; + + for (index = 0 ; index < HostX.n_screens ; index++) + { + if (HostX.screens[index].win == w || HostX.screens[index].peer_win == w) + { + result = &HostX.screens[index]; + goto out; + } + } + +out: + return result; +} + +int +hostx_get_event(EphyrHostXEvent *ev) +{ + XEvent xev; + static int grabbed_screen = -1; + + if (XPending(HostX.dpy)) + { + XNextEvent(HostX.dpy, &xev); + + switch (xev.type) + { + case Expose: + /* Not so great event compression, but works ok */ + while (XCheckTypedWindowEvent(HostX.dpy, xev.xexpose.window, + Expose, &xev)); + { + struct EphyrHostScreen *host_screen = + host_screen_from_window (xev.xexpose.window); + if (host_screen) + { + hostx_paint_rect (host_screen->info, 0, 0, 0, 0, + host_screen->win_width, + host_screen->win_height); + } + else + { + EPHYR_LOG_ERROR ("failed to get host screen\n"); + ev->type = EPHYR_EV_EXPOSE; + ev->data.expose.window = xev.xexpose.window; + return 1; + } + } + return 0; + + case MotionNotify: + { + struct EphyrHostScreen *host_screen = + host_screen_from_window (xev.xmotion.window); + + ev->type = EPHYR_EV_MOUSE_MOTION; + ev->data.mouse_motion.x = xev.xmotion.x; + ev->data.mouse_motion.y = xev.xmotion.y; + ev->data.mouse_motion.window = xev.xmotion.window; + ev->data.mouse_motion.screen = (host_screen ? host_screen->mynum : -1); + } + return 1; + + case ButtonPress: + ev->type = EPHYR_EV_MOUSE_PRESS; + ev->key_state = xev.xkey.state; + /* + * This is a bit hacky. will break for button 5 ( defined as 0x10 ) + * Check KD_BUTTON defines in kdrive.h + */ + ev->data.mouse_down.button_num = 1<<(xev.xbutton.button-1); + return 1; + + case ButtonRelease: + ev->type = EPHYR_EV_MOUSE_RELEASE; + ev->key_state = xev.xkey.state; + ev->data.mouse_up.button_num = 1<<(xev.xbutton.button-1); + return 1; + + case KeyPress: + { + ev->type = EPHYR_EV_KEY_PRESS; + ev->key_state = xev.xkey.state; + ev->data.key_down.scancode = xev.xkey.keycode; + return 1; + } + case KeyRelease: + + if ((XKeycodeToKeysym(HostX.dpy,xev.xkey.keycode,0) == XK_Shift_L + || XKeycodeToKeysym(HostX.dpy,xev.xkey.keycode,0) == XK_Shift_R) + && (xev.xkey.state & ControlMask)) + { + struct EphyrHostScreen *host_screen = + host_screen_from_window (xev.xexpose.window); + + if (grabbed_screen != -1) + { + XUngrabKeyboard (HostX.dpy, CurrentTime); + XUngrabPointer (HostX.dpy, CurrentTime); + grabbed_screen = -1; + hostx_set_win_title (host_screen->info, + "(ctrl+shift grabs mouse and keyboard)"); + } + else + { + /* Attempt grab */ + if (XGrabKeyboard (HostX.dpy, host_screen->win, True, + GrabModeAsync, + GrabModeAsync, + CurrentTime) == 0) + { + if (XGrabPointer (HostX.dpy, host_screen->win, True, + NoEventMask, + GrabModeAsync, + GrabModeAsync, + host_screen->win, None, CurrentTime) == 0) + { + grabbed_screen = host_screen->mynum; + hostx_set_win_title + (host_screen->info, + "(ctrl+shift releases mouse and keyboard)"); + } + else /* Failed pointer grabm ungrab keyboard */ + XUngrabKeyboard (HostX.dpy, CurrentTime); + } + } + } + + /* Still send the release event even if above has happened + * server will get confused with just an up event. + * Maybe it would be better to just block shift+ctrls getting to + * kdrive all togeather. + */ + ev->type = EPHYR_EV_KEY_RELEASE; + ev->key_state = xev.xkey.state; + ev->data.key_up.scancode = xev.xkey.keycode; + return 1; + + default: + break; + + } + } + return 0; +} + +void* +hostx_get_display(void) +{ + return HostX.dpy ; +} + +int +hostx_get_window (int a_screen_number) +{ + if (a_screen_number < 0 || a_screen_number >= HostX.n_screens) { + EPHYR_LOG_ERROR ("bad screen number:%d\n", a_screen_number) ; + return 0; + } + return HostX.screens[a_screen_number].win ; +} + +int +hostx_get_window_attributes (int a_window, EphyrHostWindowAttributes *a_attrs) +{ + XWindowAttributes attrs ; + + memset (&attrs, 0, sizeof (attrs)) ; + + if (!XGetWindowAttributes (hostx_get_display (), + a_window, + &attrs)) { + return FALSE ; + } + a_attrs->x = attrs.x ; + a_attrs->y = attrs.y ; + a_attrs->width = attrs.width ; + a_attrs->height = attrs.height ; + if (attrs.visual) + a_attrs->visualid = attrs.visual->visualid ; + return TRUE ; +} + +int +hostx_get_extension_info (const char *a_ext_name, + int *a_major_opcode, + int *a_first_event, + int *a_first_error) +{ + if (!a_ext_name || !a_major_opcode || !a_first_event || !a_first_error) + return 0 ; + if (!XQueryExtension (HostX.dpy, + a_ext_name, + a_major_opcode, + a_first_event, + a_first_error)) + { + return 0 ; + } + return 1 ; +} + +int +hostx_get_visuals_info (EphyrHostVisualInfo **a_visuals, + int *a_num_entries) +{ + Display *dpy=hostx_get_display () ; + Bool is_ok=False ; + XVisualInfo templ, *visuals=NULL; + EphyrHostVisualInfo *host_visuals=NULL ; + int nb_items=0, i=0; + + EPHYR_RETURN_VAL_IF_FAIL (a_visuals && a_num_entries && dpy, + False) ; + EPHYR_LOG ("enter\n") ; + memset (&templ, 0, sizeof (templ)) ; + visuals = XGetVisualInfo (dpy, VisualNoMask, &templ, &nb_items) ; + if (!visuals) { + EPHYR_LOG_ERROR ("host does not advertise any visual\n") ; + goto out ; + } + EPHYR_LOG ("host advertises %d visuals\n", nb_items) ; + host_visuals = calloc (nb_items, sizeof (EphyrHostVisualInfo)) ; + for (i=0; i<nb_items; i++) { + host_visuals[i].visualid = visuals[i].visualid ; + host_visuals[i].screen = visuals[i].screen ; + host_visuals[i].depth = visuals[i].depth ; + host_visuals[i].class = visuals[i].class ; + host_visuals[i].red_mask = visuals[i].red_mask ; + host_visuals[i].green_mask = visuals[i].green_mask ; + host_visuals[i].blue_mask = visuals[i].blue_mask ; + host_visuals[i].colormap_size = visuals[i].colormap_size ; + host_visuals[i].bits_per_rgb = visuals[i].bits_per_rgb ; + } + *a_visuals = host_visuals ; + *a_num_entries = nb_items; + host_visuals=NULL; + + is_ok = TRUE; +out: + if (visuals) { + XFree (visuals) ; + visuals = NULL; + } + free(host_visuals); + host_visuals = NULL; + EPHYR_LOG ("leave\n") ; + return is_ok ; + +} + +int +hostx_create_window (int a_screen_number, + EphyrBox *a_geometry, + int a_visual_id, + int *a_host_peer /*out parameter*/) +{ + Bool is_ok=FALSE ; + Display *dpy=hostx_get_display () ; + XVisualInfo *visual_info=NULL, visual_info_templ; + int visual_mask=VisualIDMask ; + Window win=None ; + int nb_visuals=0, winmask=0; + XSetWindowAttributes attrs; + + EPHYR_RETURN_VAL_IF_FAIL (dpy && a_geometry, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + /*get visual*/ + memset (&visual_info, 0, sizeof (visual_info)) ; + visual_info_templ.visualid = a_visual_id ; + visual_info = XGetVisualInfo (dpy, visual_mask, + &visual_info_templ, + &nb_visuals) ; + if (!visual_info) { + EPHYR_LOG_ERROR ("argh, could not find a remote visual with id:%d\n", + a_visual_id) ; + goto out ; + } + memset (&attrs, 0, sizeof (attrs)) ; + attrs.colormap = XCreateColormap (dpy, + RootWindow (dpy, + visual_info->screen), + visual_info->visual, + AllocNone) ; + attrs.event_mask = ButtonPressMask + |ButtonReleaseMask + |PointerMotionMask + |KeyPressMask + |KeyReleaseMask + |ExposureMask; + winmask = CWColormap|CWEventMask; + + win = XCreateWindow (dpy, hostx_get_window (a_screen_number), + a_geometry->x, a_geometry->y, + a_geometry->width, a_geometry->height, 0, + visual_info->depth, CopyFromParent, + visual_info->visual, winmask, &attrs) ; + if (win == None) { + EPHYR_LOG_ERROR ("failed to create peer window\n") ; + goto out ; + } + if (HostX.screens[a_screen_number].peer_win == None) { + HostX.screens[a_screen_number].peer_win = win; + } else { + EPHYR_LOG_ERROR ("multiple peer windows created for same screen\n") ; + } + XFlush (dpy) ; + XMapWindow (dpy, win) ; + *a_host_peer = win ; + is_ok = TRUE ; +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +int +hostx_destroy_window (int a_win) +{ + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + XDestroyWindow (dpy, a_win) ; + XFlush (dpy) ; + return TRUE ; +} + +int +hostx_set_window_geometry (int a_win, EphyrBox *a_geo) +{ + Display *dpy=hostx_get_display (); + + EPHYR_RETURN_VAL_IF_FAIL (dpy && a_geo, FALSE) ; + + EPHYR_LOG ("enter. x,y,w,h:(%d,%d,%d,%d)\n", + a_geo->x, a_geo->y, + a_geo->width, a_geo->height) ; + + XMoveWindow (dpy, a_win, a_geo->x, a_geo->y) ; + XResizeWindow (dpy, a_win, a_geo->width, a_geo->height) ; + EPHYR_LOG ("leave\n") ; + return TRUE; +} + +int +hostx_set_window_bounding_rectangles (int a_window, + EphyrRect *a_rects, + int a_num_rects) +{ + Bool is_ok=FALSE; + Display *dpy=hostx_get_display () ; + int i=0 ; + XRectangle *rects=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy && a_rects, FALSE) ; + + EPHYR_LOG ("enter. num rects:%d\n", a_num_rects) ; + + rects = calloc (a_num_rects, sizeof (XRectangle)) ; + for (i=0; i<a_num_rects; i++) { + rects[i].x = a_rects[i].x1 ; + rects[i].y = a_rects[i].y1 ; + rects[i].width = abs (a_rects[i].x2 - a_rects[i].x1); + rects[i].height = abs (a_rects[i].y2 - a_rects[i].y1) ; + EPHYR_LOG ("borders clipped to rect[x:%d,y:%d,w:%d,h:%d]\n", + rects[i].x, rects[i].y, + rects[i].width, rects[i].height) ; + } + /*this aways returns 1*/ + XShapeCombineRectangles (dpy, a_window, ShapeBounding, 0, 0, + rects, a_num_rects, ShapeSet, YXBanded) ; + is_ok = TRUE ; + + free(rects); + rects = NULL; + EPHYR_LOG ("leave\n") ; + return is_ok; +} + +int +hostx_set_window_clipping_rectangles (int a_window, + EphyrRect *a_rects, + int a_num_rects) +{ + Bool is_ok=FALSE; + Display *dpy=hostx_get_display () ; + int i=0 ; + XRectangle *rects=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy && a_rects, FALSE) ; + + EPHYR_LOG ("enter. num rects:%d\n", a_num_rects) ; + + rects = calloc (a_num_rects, sizeof (XRectangle)) ; + for (i=0; i<a_num_rects; i++) { + rects[i].x = a_rects[i].x1 ; + rects[i].y = a_rects[i].y1 ; + rects[i].width = abs (a_rects[i].x2 - a_rects[i].x1); + rects[i].height = abs (a_rects[i].y2 - a_rects[i].y1) ; + EPHYR_LOG ("clipped to rect[x:%d,y:%d,w:%d,h:%d]\n", + rects[i].x, rects[i].y, + rects[i].width, rects[i].height) ; + } + /*this aways returns 1*/ + XShapeCombineRectangles (dpy, a_window, ShapeClip, 0, 0, + rects, a_num_rects, ShapeSet, YXBanded) ; + is_ok = TRUE ; + + free(rects); + rects = NULL; + EPHYR_LOG ("leave\n") ; + return is_ok; +} + +int +hostx_has_xshape (void) +{ + int event_base=0, error_base=0 ; + Display *dpy=hostx_get_display () ; + if (!XShapeQueryExtension (dpy, + &event_base, + &error_base)) { + return FALSE ; + } + return TRUE; +} + +#ifdef XF86DRI +typedef struct { + int is_valid ; + int local_id ; + int remote_id ; +} ResourcePair ; + +#define RESOURCE_PEERS_SIZE 1024*10 +static ResourcePair resource_peers[RESOURCE_PEERS_SIZE] ; + + +int +hostx_allocate_resource_id_peer (int a_local_resource_id, + int *a_remote_resource_id) +{ + int i=0 ; + ResourcePair *peer=NULL ; + Display *dpy=hostx_get_display (); + + /* + * first make sure a resource peer + * does not exist already for + * a_local_resource_id + */ + for (i=0; i<RESOURCE_PEERS_SIZE; i++) { + if (resource_peers[i].is_valid + && resource_peers[i].local_id == a_local_resource_id) { + peer = &resource_peers[i] ; + break ; + } + } + /* + * find one free peer entry, an feed it with + */ + if (!peer) { + for (i=0; i<RESOURCE_PEERS_SIZE; i++) { + if (!resource_peers[i].is_valid) { + peer = &resource_peers[i] ; + break ; + } + } + if (peer) { + peer->remote_id = XAllocID (dpy); + peer->local_id = a_local_resource_id ; + peer->is_valid = TRUE ; + } + } + if (peer) { + *a_remote_resource_id = peer->remote_id ; + return TRUE ; + } + return FALSE ; +} + +int +hostx_get_resource_id_peer (int a_local_resource_id, + int *a_remote_resource_id) +{ + int i=0 ; + ResourcePair *peer=NULL ; + for (i=0; i<RESOURCE_PEERS_SIZE; i++) { + if (resource_peers[i].is_valid + && resource_peers[i].local_id == a_local_resource_id) { + peer = &resource_peers[i] ; + break ; + } + } + if (peer) { + *a_remote_resource_id = peer->remote_id ; + return TRUE ; + } + return FALSE ; +} + +int +hostx_has_dri (void) +{ + int event_base=0, error_base=0 ; + Display *dpy=hostx_get_display () ; + + if (!dpy) + return FALSE ; + + if (!XF86DRIQueryExtension (dpy, + &event_base, + &error_base)) { + return FALSE ; + } + return TRUE ; +} + +int +hostx_has_glx (void) +{ + Display *dpy=hostx_get_display () ; + int event_base=0, error_base=0 ; + + if (!glXQueryExtension (dpy, &event_base, &error_base)) { + return FALSE ; + } + return TRUE ; +} + +#endif /* XF86DRI */ diff --git a/xorg-server/hw/kdrive/ephyr/hostx.h b/xorg-server/hw/kdrive/ephyr/hostx.h index e65e0c9bc..42578576a 100644 --- a/xorg-server/hw/kdrive/ephyr/hostx.h +++ b/xorg-server/hw/kdrive/ephyr/hostx.h @@ -2,7 +2,7 @@ * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum <mallum@o-hand.com> * - * Copyright © 2004 Nokia + * Copyright © 2004 Nokia * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that diff --git a/xorg-server/hw/kdrive/ephyr/os.c b/xorg-server/hw/kdrive/ephyr/os.c index 4bf6e8858..e4dc6787d 100644 --- a/xorg-server/hw/kdrive/ephyr/os.c +++ b/xorg-server/hw/kdrive/ephyr/os.c @@ -2,7 +2,7 @@ * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum <mallum@o-hand.com> * - * Copyright © 2004 Nokia + * Copyright © 2004 Nokia * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that diff --git a/xorg-server/hw/kdrive/fake/fakeinit.c b/xorg-server/hw/kdrive/fake/fakeinit.c index ba61959ef..e25093fbf 100644 --- a/xorg-server/hw/kdrive/fake/fakeinit.c +++ b/xorg-server/hw/kdrive/fake/fakeinit.c @@ -61,6 +61,7 @@ InitInput (int argc, char **argv) void CloseInput (void) { + KdCloseInput (); } #ifdef DDXBEFORERESET diff --git a/xorg-server/hw/kdrive/fake/kbd.c b/xorg-server/hw/kdrive/fake/kbd.c index 51fba044d..769730d64 100644 --- a/xorg-server/hw/kdrive/fake/kbd.c +++ b/xorg-server/hw/kdrive/fake/kbd.c @@ -1,5 +1,5 @@ /* - * Copyright © 1999 Keith Packard + * Copyright © 1999 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 diff --git a/xorg-server/hw/kdrive/fbdev/fbdev.c b/xorg-server/hw/kdrive/fbdev/fbdev.c index b127ab89b..661e5b491 100644 --- a/xorg-server/hw/kdrive/fbdev/fbdev.c +++ b/xorg-server/hw/kdrive/fbdev/fbdev.c @@ -1,826 +1,826 @@ -/*
- * Copyright © 1999 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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_CONFIG_H
-#include <kdrive-config.h>
-#endif
-#include "fbdev.h"
-#include <sys/ioctl.h>
-
-#include <errno.h>
-
-extern int KdTsPhyScreen;
-
-char *fbdevDevicePath = NULL;
-
-static Bool
-fbdevInitialize (KdCardInfo *card, FbdevPriv *priv)
-{
- unsigned long off;
-
- if (fbdevDevicePath == NULL)
- fbdevDevicePath = "/dev/fb0";
-
- if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0)
- {
- ErrorF("Error opening framebuffer %s: %s\n",
- fbdevDevicePath, strerror(errno));
- return FALSE;
- }
-
- /* quiet valgrind */
- memset (&priv->fix, '\0', sizeof (priv->fix));
- if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) {
- perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO");
- close (priv->fd);
- return FALSE;
- }
- /* quiet valgrind */
- memset (&priv->var, '\0', sizeof (priv->var));
- if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) {
- perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO");
- close (priv->fd);
- return FALSE;
- }
-
- priv->fb_base = (char *) mmap ((caddr_t) NULL,
- priv->fix.smem_len,
- PROT_READ|PROT_WRITE,
- MAP_SHARED,
- priv->fd, 0);
-
- if (priv->fb_base == (char *)-1)
- {
- perror("ERROR: mmap framebuffer fails!");
- close (priv->fd);
- return FALSE;
- }
- off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize();
- priv->fb = priv->fb_base + off;
- return TRUE;
-}
-
-Bool
-fbdevCardInit (KdCardInfo *card)
-{
- FbdevPriv *priv;
-
- priv = (FbdevPriv *) malloc(sizeof (FbdevPriv));
- if (!priv)
- return FALSE;
-
- if (!fbdevInitialize (card, priv))
- {
- free(priv);
- return FALSE;
- }
- card->driver = priv;
-
- return TRUE;
-}
-
-static Pixel
-fbdevMakeContig (Pixel orig, Pixel others)
-{
- Pixel low;
-
- low = lowbit (orig) >> 1;
- while (low && (others & low) == 0)
- {
- orig |= low;
- low >>= 1;
- }
- return orig;
-}
-
-static Bool
-fbdevModeSupported (KdScreenInfo *screen,
- const KdMonitorTiming *t)
-{
- return TRUE;
-}
-
-static void
-fbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var)
-{
- memset (var, 0, sizeof (struct fb_var_screeninfo));
-
- var->xres = t->horizontal;
- var->yres = t->vertical;
- var->xres_virtual = t->horizontal;
- var->yres_virtual = t->vertical;
- var->xoffset = 0;
- var->yoffset = 0;
- var->pixclock = t->clock ? 1000000000 / t->clock : 0;
- var->left_margin = t->hbp;
- var->right_margin = t->hfp;
- var->upper_margin = t->vbp;
- var->lower_margin = t->vfp;
- var->hsync_len = t->hblank - t->hfp - t->hbp;
- var->vsync_len = t->vblank - t->vfp - t->vbp;
-
- var->sync = 0;
- var->vmode = 0;
-
- if (t->hpol == KdSyncPositive)
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (t->vpol == KdSyncPositive)
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
-}
-
-static Bool
-fbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv)
-{
- FbdevPriv *priv = screen->card->driver;
- Pixel allbits;
- int depth;
- Bool gray;
- struct fb_var_screeninfo var;
- const KdMonitorTiming *t;
- int k;
-
- k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var);
-
- if (!screen->width || !screen->height)
- {
- if (k >= 0)
- {
- screen->width = var.xres;
- screen->height = var.yres;
- }
- else
- {
- screen->width = 1024;
- screen->height = 768;
- }
- screen->rate = 103; /* FIXME: should get proper value from fb driver */
- }
- if (!screen->fb.depth)
- {
- if (k >= 0)
- screen->fb.depth = var.bits_per_pixel;
- else
- screen->fb.depth = 16;
- }
-
- if ((screen->width != var.xres) || (screen->height != var.yres))
- {
- t = KdFindMode (screen, fbdevModeSupported);
- screen->rate = t->rate;
- screen->width = t->horizontal;
- screen->height = t->vertical;
-
- /* Now try setting the mode */
- if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres))
- fbdevConvertMonitorTiming (t, &var);
- }
-
- var.activate = FB_ACTIVATE_NOW;
- var.bits_per_pixel = screen->fb.depth;
- var.nonstd = 0;
- var.grayscale = 0;
-
- k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var);
-
- if (k < 0)
- {
- fprintf (stderr, "error: %s\n", strerror (errno));
- return FALSE;
- }
-
- /* Re-get the "fixed" parameters since they might have changed */
- k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix);
- if (k < 0)
- perror ("FBIOGET_FSCREENINFO");
-
- /* Now get the new screeninfo */
- ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var);
- depth = priv->var.bits_per_pixel;
- gray = priv->var.grayscale;
-
- switch (priv->fix.visual) {
- case FB_VISUAL_PSEUDOCOLOR:
- if (gray)
- {
- screen->fb.visuals = (1 << StaticGray);
- /* could also support GrayScale, but what's the point? */
- }
- else
- {
- screen->fb.visuals = ((1 << StaticGray) |
- (1 << GrayScale) |
- (1 << StaticColor) |
- (1 << PseudoColor) |
- (1 << TrueColor) |
- (1 << DirectColor));
- }
- screen->fb.blueMask = 0x00;
- screen->fb.greenMask = 0x00;
- screen->fb.redMask = 0x00;
- break;
- case FB_VISUAL_STATIC_PSEUDOCOLOR:
- if (gray)
- {
- screen->fb.visuals = (1 << StaticGray);
- }
- else
- {
- screen->fb.visuals = (1 << StaticColor);
- }
- screen->fb.blueMask = 0x00;
- screen->fb.greenMask = 0x00;
- screen->fb.redMask = 0x00;
- break;
- case FB_VISUAL_TRUECOLOR:
- case FB_VISUAL_DIRECTCOLOR:
- screen->fb.visuals = (1 << TrueColor);
-#define Mask(o,l) (((1 << l) - 1) << o)
- screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length);
- screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length);
- screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length);
-
- /*
- * This is a kludge so that Render will work -- fill in the gaps
- * in the pixel
- */
- screen->fb.redMask = fbdevMakeContig (screen->fb.redMask,
- screen->fb.greenMask|
- screen->fb.blueMask);
-
- screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask,
- screen->fb.redMask|
- screen->fb.blueMask);
-
- screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask,
- screen->fb.redMask|
- screen->fb.greenMask);
-
- allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask;
- depth = 32;
- while (depth && !(allbits & (1 << (depth - 1))))
- depth--;
- break;
- default:
- return FALSE;
- break;
- }
- screen->fb.depth = depth;
- screen->fb.bitsPerPixel = priv->var.bits_per_pixel;
-
- scrpriv->randr = screen->randr;
-
- return fbdevMapFramebuffer (screen);
-}
-
-Bool
-fbdevScreenInit (KdScreenInfo *screen)
-{
- FbdevScrPriv *scrpriv;
-
- scrpriv = calloc(1, sizeof (FbdevScrPriv));
- if (!scrpriv)
- return FALSE;
- screen->driver = scrpriv;
- if (!fbdevScreenInitialize (screen, scrpriv))
- {
- screen->driver = 0;
- free(scrpriv);
- return FALSE;
- }
- return TRUE;
-}
-
-static void *
-fbdevWindowLinear (ScreenPtr pScreen,
- CARD32 row,
- CARD32 offset,
- int mode,
- CARD32 *size,
- void *closure)
-{
- KdScreenPriv(pScreen);
- FbdevPriv *priv = pScreenPriv->card->driver;
-
- if (!pScreenPriv->enabled)
- return 0;
- *size = priv->fix.line_length;
- return (CARD8 *) priv->fb + row * priv->fix.line_length + offset;
-}
-
-Bool
-fbdevMapFramebuffer (KdScreenInfo *screen)
-{
- FbdevScrPriv *scrpriv = screen->driver;
- KdPointerMatrix m;
- FbdevPriv *priv = screen->card->driver;
-
- if (scrpriv->randr != RR_Rotate_0)
- scrpriv->shadow = TRUE;
- else
- scrpriv->shadow = FALSE;
-
- KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height);
-
- KdSetPointerMatrix (&m);
-
- screen->width = priv->var.xres;
- screen->height = priv->var.yres;
-
- if (scrpriv->shadow)
- {
- if (!KdShadowFbAlloc (screen,
- scrpriv->randr & (RR_Rotate_90|RR_Rotate_270)))
- return FALSE;
- }
- else
- {
- screen->fb.byteStride = priv->fix.line_length;
- screen->fb.pixelStride = (priv->fix.line_length * 8 /
- priv->var.bits_per_pixel);
- screen->fb.frameBuffer = (CARD8 *) (priv->fb);
- }
-
- return TRUE;
-}
-
-static void
-fbdevSetScreenSizes (ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- FbdevScrPriv *scrpriv = screen->driver;
- FbdevPriv *priv = screen->card->driver;
-
- if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180))
- {
- pScreen->width = priv->var.xres;
- pScreen->height = priv->var.yres;
- pScreen->mmWidth = screen->width_mm;
- pScreen->mmHeight = screen->height_mm;
- }
- else
- {
- pScreen->width = priv->var.yres;
- pScreen->height = priv->var.xres;
- pScreen->mmWidth = screen->height_mm;
- pScreen->mmHeight = screen->width_mm;
- }
-}
-
-static Bool
-fbdevUnmapFramebuffer (KdScreenInfo *screen)
-{
- KdShadowFbFree (screen);
- return TRUE;
-}
-
-static Bool
-fbdevSetShadow (ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- FbdevScrPriv *scrpriv = screen->driver;
- FbdevPriv *priv = screen->card->driver;
- ShadowUpdateProc update;
- ShadowWindowProc window;
- int useYX = 0;
-
-#ifdef __arm__
- /* Use variant copy routines that always read left to right in the
- shadow framebuffer. Reading vertical strips is exceptionally
- slow on XScale due to cache effects. */
- useYX = 1;
-#endif
-
- window = fbdevWindowLinear;
- update = 0;
- if (scrpriv->randr)
- if (priv->var.bits_per_pixel == 16) {
- switch (scrpriv->randr) {
- case RR_Rotate_90:
- if (useYX)
- update = shadowUpdateRotate16_90YX;
- else
- update = shadowUpdateRotate16_90;
- break;
- case RR_Rotate_180:
- update = shadowUpdateRotate16_180;
- break;
- case RR_Rotate_270:
- if (useYX)
- update = shadowUpdateRotate16_270YX;
- else
- update = shadowUpdateRotate16_270;
- break;
- default:
- update = shadowUpdateRotate16;
- break;
- }
- } else
- update = shadowUpdateRotatePacked;
- else
- update = shadowUpdatePacked;
- return KdShadowSet (pScreen, scrpriv->randr, update, window);
-}
-
-
-#ifdef RANDR
-static Bool
-fbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- FbdevScrPriv *scrpriv = screen->driver;
- RRScreenSizePtr pSize;
- Rotation randr;
- int n;
-
- *rotations = RR_Rotate_All|RR_Reflect_All;
-
- for (n = 0; n < pScreen->numDepths; n++)
- if (pScreen->allowedDepths[n].numVids)
- break;
- if (n == pScreen->numDepths)
- return FALSE;
-
- pSize = RRRegisterSize (pScreen,
- screen->width,
- screen->height,
- screen->width_mm,
- screen->height_mm);
-
- randr = KdSubRotation (scrpriv->randr, screen->randr);
-
- RRSetCurrentConfig (pScreen, randr, 0, pSize);
-
- return TRUE;
-}
-
-static Bool
-fbdevRandRSetConfig (ScreenPtr pScreen,
- Rotation randr,
- int rate,
- RRScreenSizePtr pSize)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
- FbdevScrPriv *scrpriv = screen->driver;
- Bool wasEnabled = pScreenPriv->enabled;
- FbdevScrPriv oldscr;
- int oldwidth;
- int oldheight;
- int oldmmwidth;
- int oldmmheight;
- int newwidth, newheight;
-
- if (screen->randr & (RR_Rotate_0|RR_Rotate_180))
- {
- newwidth = pSize->width;
- newheight = pSize->height;
- }
- else
- {
- newwidth = pSize->height;
- newheight = pSize->width;
- }
-
- if (wasEnabled)
- KdDisableScreen (pScreen);
-
- oldscr = *scrpriv;
-
- oldwidth = screen->width;
- oldheight = screen->height;
- oldmmwidth = pScreen->mmWidth;
- oldmmheight = pScreen->mmHeight;
-
- /*
- * Set new configuration
- */
-
- scrpriv->randr = KdAddRotation (screen->randr, randr);
-
- fbdevUnmapFramebuffer (screen);
-
- if (!fbdevMapFramebuffer (screen))
- goto bail4;
-
- KdShadowUnset (screen->pScreen);
-
- if (!fbdevSetShadow (screen->pScreen))
- goto bail4;
-
- fbdevSetScreenSizes (screen->pScreen);
-
- /*
- * Set frame buffer mapping
- */
- (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen),
- pScreen->width,
- pScreen->height,
- screen->fb.depth,
- screen->fb.bitsPerPixel,
- screen->fb.byteStride,
- screen->fb.frameBuffer);
-
- /* set the subpixel order */
-
- KdSetSubpixelOrder (pScreen, scrpriv->randr);
- if (wasEnabled)
- KdEnableScreen (pScreen);
-
- return TRUE;
-
-bail4:
- fbdevUnmapFramebuffer (screen);
- *scrpriv = oldscr;
- (void) fbdevMapFramebuffer (screen);
- pScreen->width = oldwidth;
- pScreen->height = oldheight;
- pScreen->mmWidth = oldmmwidth;
- pScreen->mmHeight = oldmmheight;
-
- if (wasEnabled)
- KdEnableScreen (pScreen);
- return FALSE;
-}
-
-static Bool
-fbdevRandRInit (ScreenPtr pScreen)
-{
- rrScrPrivPtr pScrPriv;
-
- if (!RRScreenInit (pScreen))
- return FALSE;
-
- pScrPriv = rrGetScrPriv(pScreen);
- pScrPriv->rrGetInfo = fbdevRandRGetInfo;
- pScrPriv->rrSetConfig = fbdevRandRSetConfig;
- return TRUE;
-}
-#endif
-
-static Bool
-fbdevCreateColormap (ColormapPtr pmap)
-{
- ScreenPtr pScreen = pmap->pScreen;
- KdScreenPriv(pScreen);
- FbdevPriv *priv = pScreenPriv->card->driver;
- VisualPtr pVisual;
- int i;
- int nent;
- xColorItem *pdefs;
-
- switch (priv->fix.visual) {
- case FB_VISUAL_STATIC_PSEUDOCOLOR:
- pVisual = pmap->pVisual;
- nent = pVisual->ColormapEntries;
- pdefs = malloc(nent * sizeof (xColorItem));
- if (!pdefs)
- return FALSE;
- for (i = 0; i < nent; i++)
- pdefs[i].pixel = i;
- fbdevGetColors (pScreen, nent, pdefs);
- for (i = 0; i < nent; i++)
- {
- pmap->red[i].co.local.red = pdefs[i].red;
- pmap->red[i].co.local.green = pdefs[i].green;
- pmap->red[i].co.local.blue = pdefs[i].blue;
- }
- free(pdefs);
- return TRUE;
- default:
- return fbInitializeColormap (pmap);
- }
-}
-
-Bool
-fbdevInitScreen (ScreenPtr pScreen)
-{
-#ifdef TOUCHSCREEN
- KdTsPhyScreen = pScreen->myNum;
-#endif
-
- pScreen->CreateColormap = fbdevCreateColormap;
- return TRUE;
-}
-
-Bool
-fbdevFinishInitScreen (ScreenPtr pScreen)
-{
- if (!shadowSetup (pScreen))
- return FALSE;
-
-#ifdef RANDR
- if (!fbdevRandRInit (pScreen))
- return FALSE;
-#endif
-
- return TRUE;
-}
-
-
-Bool
-fbdevCreateResources (ScreenPtr pScreen)
-{
- return fbdevSetShadow (pScreen);
-}
-
-void
-fbdevPreserve (KdCardInfo *card)
-{
-}
-
-static int
-fbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx)
-{
- struct fb_cmap cmap;
-
- cmap.start = minidx;
- cmap.len = maxidx - minidx + 1;
- cmap.red = &priv->red[minidx];
- cmap.green = &priv->green[minidx];
- cmap.blue = &priv->blue[minidx];
- cmap.transp = 0;
-
- return ioctl(priv->fd, FBIOPUTCMAP, &cmap);
-}
-
-Bool
-fbdevEnable (ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
- FbdevPriv *priv = pScreenPriv->card->driver;
- int k;
-
- priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL;
-
- /* display it on the LCD */
- k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var);
- if (k < 0)
- {
- perror ("FBIOPUT_VSCREENINFO");
- return FALSE;
- }
-
- if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR)
- {
- int i;
-
- for (i = 0;
- i < (1 << priv->var.red.length) ||
- i < (1 << priv->var.green.length) ||
- i < (1 << priv->var.blue.length); i++)
- {
- priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1);
- priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1);
- priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1);
- }
-
- fbdevUpdateFbColormap(priv, 0, i);
- }
- return TRUE;
-}
-
-Bool
-fbdevDPMS (ScreenPtr pScreen, int mode)
-{
- KdScreenPriv(pScreen);
- FbdevPriv *priv = pScreenPriv->card->driver;
- static int oldmode = -1;
-
- if (mode == oldmode)
- return TRUE;
-#ifdef FBIOPUT_POWERMODE
- if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0)
- {
- oldmode = mode;
- return TRUE;
- }
-#endif
-#ifdef FBIOBLANK
- if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0)
- {
- oldmode = mode;
- return TRUE;
- }
-#endif
- return FALSE;
-}
-
-void
-fbdevDisable (ScreenPtr pScreen)
-{
-}
-
-void
-fbdevRestore (KdCardInfo *card)
-{
-}
-
-void
-fbdevScreenFini (KdScreenInfo *screen)
-{
-}
-
-void
-fbdevCardFini (KdCardInfo *card)
-{
- FbdevPriv *priv = card->driver;
-
- munmap (priv->fb_base, priv->fix.smem_len);
- close (priv->fd);
- free(priv);
-}
-
-/*
- * Retrieve actual colormap and return selected n entries in pdefs.
- */
-void
-fbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs)
-{
- KdScreenPriv(pScreen);
- FbdevPriv *priv = pScreenPriv->card->driver;
- struct fb_cmap cmap;
- int p;
- int k;
- int min, max;
-
- min = 256;
- max = 0;
- for (k = 0; k < n; k++)
- {
- if (pdefs[k].pixel < min)
- min = pdefs[k].pixel;
- if (pdefs[k].pixel > max)
- max = pdefs[k].pixel;
- }
- cmap.start = min;
- cmap.len = max - min + 1;
- cmap.red = &priv->red[min];
- cmap.green = &priv->green[min];
- cmap.blue = &priv->blue[min];
- cmap.transp = 0;
- k = ioctl (priv->fd, FBIOGETCMAP, &cmap);
- if (k < 0)
- {
- perror ("can't get colormap");
- return;
- }
- while (n--)
- {
- p = pdefs->pixel;
- pdefs->red = priv->red[p];
- pdefs->green = priv->green[p];
- pdefs->blue = priv->blue[p];
- pdefs++;
- }
-}
-
-/*
- * Change colormap by updating n entries described in pdefs.
- */
-void
-fbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs)
-{
- KdScreenPriv(pScreen);
- FbdevPriv *priv = pScreenPriv->card->driver;
- int p;
- int min, max;
-
- min = 256;
- max = 0;
- while (n--)
- {
- p = pdefs->pixel;
- priv->red[p] = pdefs->red;
- priv->green[p] = pdefs->green;
- priv->blue[p] = pdefs->blue;
- if (p < min)
- min = p;
- if (p > max)
- max = p;
- pdefs++;
- }
-
- fbdevUpdateFbColormap(priv, min, max);
-}
+/* + * Copyright © 1999 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "fbdev.h" +#include <sys/ioctl.h> + +#include <errno.h> + +extern int KdTsPhyScreen; + +char *fbdevDevicePath = NULL; + +static Bool +fbdevInitialize (KdCardInfo *card, FbdevPriv *priv) +{ + unsigned long off; + + if (fbdevDevicePath == NULL) + fbdevDevicePath = "/dev/fb0"; + + if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0) + { + ErrorF("Error opening framebuffer %s: %s\n", + fbdevDevicePath, strerror(errno)); + return FALSE; + } + + /* quiet valgrind */ + memset (&priv->fix, '\0', sizeof (priv->fix)); + if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) { + perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO"); + close (priv->fd); + return FALSE; + } + /* quiet valgrind */ + memset (&priv->var, '\0', sizeof (priv->var)); + if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) { + perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO"); + close (priv->fd); + return FALSE; + } + + priv->fb_base = (char *) mmap ((caddr_t) NULL, + priv->fix.smem_len, + PROT_READ|PROT_WRITE, + MAP_SHARED, + priv->fd, 0); + + if (priv->fb_base == (char *)-1) + { + perror("ERROR: mmap framebuffer fails!"); + close (priv->fd); + return FALSE; + } + off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize(); + priv->fb = priv->fb_base + off; + return TRUE; +} + +Bool +fbdevCardInit (KdCardInfo *card) +{ + FbdevPriv *priv; + + priv = (FbdevPriv *) malloc(sizeof (FbdevPriv)); + if (!priv) + return FALSE; + + if (!fbdevInitialize (card, priv)) + { + free(priv); + return FALSE; + } + card->driver = priv; + + return TRUE; +} + +static Pixel +fbdevMakeContig (Pixel orig, Pixel others) +{ + Pixel low; + + low = lowbit (orig) >> 1; + while (low && (others & low) == 0) + { + orig |= low; + low >>= 1; + } + return orig; +} + +static Bool +fbdevModeSupported (KdScreenInfo *screen, + const KdMonitorTiming *t) +{ + return TRUE; +} + +static void +fbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var) +{ + memset (var, 0, sizeof (struct fb_var_screeninfo)); + + var->xres = t->horizontal; + var->yres = t->vertical; + var->xres_virtual = t->horizontal; + var->yres_virtual = t->vertical; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = t->clock ? 1000000000 / t->clock : 0; + var->left_margin = t->hbp; + var->right_margin = t->hfp; + var->upper_margin = t->vbp; + var->lower_margin = t->vfp; + var->hsync_len = t->hblank - t->hfp - t->hbp; + var->vsync_len = t->vblank - t->vfp - t->vbp; + + var->sync = 0; + var->vmode = 0; + + if (t->hpol == KdSyncPositive) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (t->vpol == KdSyncPositive) + var->sync |= FB_SYNC_VERT_HIGH_ACT; +} + +static Bool +fbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv) +{ + FbdevPriv *priv = screen->card->driver; + Pixel allbits; + int depth; + Bool gray; + struct fb_var_screeninfo var; + const KdMonitorTiming *t; + int k; + + k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var); + + if (!screen->width || !screen->height) + { + if (k >= 0) + { + screen->width = var.xres; + screen->height = var.yres; + } + else + { + screen->width = 1024; + screen->height = 768; + } + screen->rate = 103; /* FIXME: should get proper value from fb driver */ + } + if (!screen->fb.depth) + { + if (k >= 0) + screen->fb.depth = var.bits_per_pixel; + else + screen->fb.depth = 16; + } + + if ((screen->width != var.xres) || (screen->height != var.yres)) + { + t = KdFindMode (screen, fbdevModeSupported); + screen->rate = t->rate; + screen->width = t->horizontal; + screen->height = t->vertical; + + /* Now try setting the mode */ + if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres)) + fbdevConvertMonitorTiming (t, &var); + } + + var.activate = FB_ACTIVATE_NOW; + var.bits_per_pixel = screen->fb.depth; + var.nonstd = 0; + var.grayscale = 0; + + k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var); + + if (k < 0) + { + fprintf (stderr, "error: %s\n", strerror (errno)); + return FALSE; + } + + /* Re-get the "fixed" parameters since they might have changed */ + k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix); + if (k < 0) + perror ("FBIOGET_FSCREENINFO"); + + /* Now get the new screeninfo */ + ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var); + depth = priv->var.bits_per_pixel; + gray = priv->var.grayscale; + + switch (priv->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + if (gray) + { + screen->fb.visuals = (1 << StaticGray); + /* could also support GrayScale, but what's the point? */ + } + else + { + screen->fb.visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + } + screen->fb.blueMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.redMask = 0x00; + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + if (gray) + { + screen->fb.visuals = (1 << StaticGray); + } + else + { + screen->fb.visuals = (1 << StaticColor); + } + screen->fb.blueMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.redMask = 0x00; + break; + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_DIRECTCOLOR: + screen->fb.visuals = (1 << TrueColor); +#define Mask(o,l) (((1 << l) - 1) << o) + screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length); + screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length); + screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length); + + /* + * This is a kludge so that Render will work -- fill in the gaps + * in the pixel + */ + screen->fb.redMask = fbdevMakeContig (screen->fb.redMask, + screen->fb.greenMask| + screen->fb.blueMask); + + screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask, + screen->fb.redMask| + screen->fb.blueMask); + + screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask, + screen->fb.redMask| + screen->fb.greenMask); + + allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask; + depth = 32; + while (depth && !(allbits & (1 << (depth - 1)))) + depth--; + break; + default: + return FALSE; + break; + } + screen->fb.depth = depth; + screen->fb.bitsPerPixel = priv->var.bits_per_pixel; + + scrpriv->randr = screen->randr; + + return fbdevMapFramebuffer (screen); +} + +Bool +fbdevScreenInit (KdScreenInfo *screen) +{ + FbdevScrPriv *scrpriv; + + scrpriv = calloc(1, sizeof (FbdevScrPriv)); + if (!scrpriv) + return FALSE; + screen->driver = scrpriv; + if (!fbdevScreenInitialize (screen, scrpriv)) + { + screen->driver = 0; + free(scrpriv); + return FALSE; + } + return TRUE; +} + +static void * +fbdevWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size, + void *closure) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + + if (!pScreenPriv->enabled) + return 0; + *size = priv->fix.line_length; + return (CARD8 *) priv->fb + row * priv->fix.line_length + offset; +} + +Bool +fbdevMapFramebuffer (KdScreenInfo *screen) +{ + FbdevScrPriv *scrpriv = screen->driver; + KdPointerMatrix m; + FbdevPriv *priv = screen->card->driver; + + if (scrpriv->randr != RR_Rotate_0) + scrpriv->shadow = TRUE; + else + scrpriv->shadow = FALSE; + + KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); + + KdSetPointerMatrix (&m); + + screen->width = priv->var.xres; + screen->height = priv->var.yres; + + if (scrpriv->shadow) + { + if (!KdShadowFbAlloc (screen, + scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) + return FALSE; + } + else + { + screen->fb.byteStride = priv->fix.line_length; + screen->fb.pixelStride = (priv->fix.line_length * 8 / + priv->var.bits_per_pixel); + screen->fb.frameBuffer = (CARD8 *) (priv->fb); + } + + return TRUE; +} + +static void +fbdevSetScreenSizes (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + FbdevPriv *priv = screen->card->driver; + + if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) + { + pScreen->width = priv->var.xres; + pScreen->height = priv->var.yres; + pScreen->mmWidth = screen->width_mm; + pScreen->mmHeight = screen->height_mm; + } + else + { + pScreen->width = priv->var.yres; + pScreen->height = priv->var.xres; + pScreen->mmWidth = screen->height_mm; + pScreen->mmHeight = screen->width_mm; + } +} + +static Bool +fbdevUnmapFramebuffer (KdScreenInfo *screen) +{ + KdShadowFbFree (screen); + return TRUE; +} + +static Bool +fbdevSetShadow (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + FbdevPriv *priv = screen->card->driver; + ShadowUpdateProc update; + ShadowWindowProc window; + int useYX = 0; + +#ifdef __arm__ + /* Use variant copy routines that always read left to right in the + shadow framebuffer. Reading vertical strips is exceptionally + slow on XScale due to cache effects. */ + useYX = 1; +#endif + + window = fbdevWindowLinear; + update = 0; + if (scrpriv->randr) + if (priv->var.bits_per_pixel == 16) { + switch (scrpriv->randr) { + case RR_Rotate_90: + if (useYX) + update = shadowUpdateRotate16_90YX; + else + update = shadowUpdateRotate16_90; + break; + case RR_Rotate_180: + update = shadowUpdateRotate16_180; + break; + case RR_Rotate_270: + if (useYX) + update = shadowUpdateRotate16_270YX; + else + update = shadowUpdateRotate16_270; + break; + default: + update = shadowUpdateRotate16; + break; + } + } else + update = shadowUpdateRotatePacked; + else + update = shadowUpdatePacked; + return KdShadowSet (pScreen, scrpriv->randr, update, window); +} + + +#ifdef RANDR +static Bool +fbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + RRScreenSizePtr pSize; + Rotation randr; + int n; + + *rotations = RR_Rotate_All|RR_Reflect_All; + + for (n = 0; n < pScreen->numDepths; n++) + if (pScreen->allowedDepths[n].numVids) + break; + if (n == pScreen->numDepths) + return FALSE; + + pSize = RRRegisterSize (pScreen, + screen->width, + screen->height, + screen->width_mm, + screen->height_mm); + + randr = KdSubRotation (scrpriv->randr, screen->randr); + + RRSetCurrentConfig (pScreen, randr, 0, pSize); + + return TRUE; +} + +static Bool +fbdevRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + Bool wasEnabled = pScreenPriv->enabled; + FbdevScrPriv oldscr; + int oldwidth; + int oldheight; + int oldmmwidth; + int oldmmheight; + int newwidth, newheight; + + if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) + { + newwidth = pSize->width; + newheight = pSize->height; + } + else + { + newwidth = pSize->height; + newheight = pSize->width; + } + + if (wasEnabled) + KdDisableScreen (pScreen); + + oldscr = *scrpriv; + + oldwidth = screen->width; + oldheight = screen->height; + oldmmwidth = pScreen->mmWidth; + oldmmheight = pScreen->mmHeight; + + /* + * Set new configuration + */ + + scrpriv->randr = KdAddRotation (screen->randr, randr); + + fbdevUnmapFramebuffer (screen); + + if (!fbdevMapFramebuffer (screen)) + goto bail4; + + KdShadowUnset (screen->pScreen); + + if (!fbdevSetShadow (screen->pScreen)) + goto bail4; + + fbdevSetScreenSizes (screen->pScreen); + + /* + * Set frame buffer mapping + */ + (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), + pScreen->width, + pScreen->height, + screen->fb.depth, + screen->fb.bitsPerPixel, + screen->fb.byteStride, + screen->fb.frameBuffer); + + /* set the subpixel order */ + + KdSetSubpixelOrder (pScreen, scrpriv->randr); + if (wasEnabled) + KdEnableScreen (pScreen); + + return TRUE; + +bail4: + fbdevUnmapFramebuffer (screen); + *scrpriv = oldscr; + (void) fbdevMapFramebuffer (screen); + pScreen->width = oldwidth; + pScreen->height = oldheight; + pScreen->mmWidth = oldmmwidth; + pScreen->mmHeight = oldmmheight; + + if (wasEnabled) + KdEnableScreen (pScreen); + return FALSE; +} + +static Bool +fbdevRandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = fbdevRandRGetInfo; + pScrPriv->rrSetConfig = fbdevRandRSetConfig; + return TRUE; +} +#endif + +static Bool +fbdevCreateColormap (ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + VisualPtr pVisual; + int i; + int nent; + xColorItem *pdefs; + + switch (priv->fix.visual) { + case FB_VISUAL_STATIC_PSEUDOCOLOR: + pVisual = pmap->pVisual; + nent = pVisual->ColormapEntries; + pdefs = malloc(nent * sizeof (xColorItem)); + if (!pdefs) + return FALSE; + for (i = 0; i < nent; i++) + pdefs[i].pixel = i; + fbdevGetColors (pScreen, nent, pdefs); + for (i = 0; i < nent; i++) + { + pmap->red[i].co.local.red = pdefs[i].red; + pmap->red[i].co.local.green = pdefs[i].green; + pmap->red[i].co.local.blue = pdefs[i].blue; + } + free(pdefs); + return TRUE; + default: + return fbInitializeColormap (pmap); + } +} + +Bool +fbdevInitScreen (ScreenPtr pScreen) +{ +#ifdef TOUCHSCREEN + KdTsPhyScreen = pScreen->myNum; +#endif + + pScreen->CreateColormap = fbdevCreateColormap; + return TRUE; +} + +Bool +fbdevFinishInitScreen (ScreenPtr pScreen) +{ + if (!shadowSetup (pScreen)) + return FALSE; + +#ifdef RANDR + if (!fbdevRandRInit (pScreen)) + return FALSE; +#endif + + return TRUE; +} + + +Bool +fbdevCreateResources (ScreenPtr pScreen) +{ + return fbdevSetShadow (pScreen); +} + +void +fbdevPreserve (KdCardInfo *card) +{ +} + +static int +fbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx) +{ + struct fb_cmap cmap; + + cmap.start = minidx; + cmap.len = maxidx - minidx + 1; + cmap.red = &priv->red[minidx]; + cmap.green = &priv->green[minidx]; + cmap.blue = &priv->blue[minidx]; + cmap.transp = 0; + + return ioctl(priv->fd, FBIOPUTCMAP, &cmap); +} + +Bool +fbdevEnable (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + int k; + + priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL; + + /* display it on the LCD */ + k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var); + if (k < 0) + { + perror ("FBIOPUT_VSCREENINFO"); + return FALSE; + } + + if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) + { + int i; + + for (i = 0; + i < (1 << priv->var.red.length) || + i < (1 << priv->var.green.length) || + i < (1 << priv->var.blue.length); i++) + { + priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1); + priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1); + priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1); + } + + fbdevUpdateFbColormap(priv, 0, i); + } + return TRUE; +} + +Bool +fbdevDPMS (ScreenPtr pScreen, int mode) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + static int oldmode = -1; + + if (mode == oldmode) + return TRUE; +#ifdef FBIOPUT_POWERMODE + if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0) + { + oldmode = mode; + return TRUE; + } +#endif +#ifdef FBIOBLANK + if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0) + { + oldmode = mode; + return TRUE; + } +#endif + return FALSE; +} + +void +fbdevDisable (ScreenPtr pScreen) +{ +} + +void +fbdevRestore (KdCardInfo *card) +{ +} + +void +fbdevScreenFini (KdScreenInfo *screen) +{ +} + +void +fbdevCardFini (KdCardInfo *card) +{ + FbdevPriv *priv = card->driver; + + munmap (priv->fb_base, priv->fix.smem_len); + close (priv->fd); + free(priv); +} + +/* + * Retrieve actual colormap and return selected n entries in pdefs. + */ +void +fbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + struct fb_cmap cmap; + int p; + int k; + int min, max; + + min = 256; + max = 0; + for (k = 0; k < n; k++) + { + if (pdefs[k].pixel < min) + min = pdefs[k].pixel; + if (pdefs[k].pixel > max) + max = pdefs[k].pixel; + } + cmap.start = min; + cmap.len = max - min + 1; + cmap.red = &priv->red[min]; + cmap.green = &priv->green[min]; + cmap.blue = &priv->blue[min]; + cmap.transp = 0; + k = ioctl (priv->fd, FBIOGETCMAP, &cmap); + if (k < 0) + { + perror ("can't get colormap"); + return; + } + while (n--) + { + p = pdefs->pixel; + pdefs->red = priv->red[p]; + pdefs->green = priv->green[p]; + pdefs->blue = priv->blue[p]; + pdefs++; + } +} + +/* + * Change colormap by updating n entries described in pdefs. + */ +void +fbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + int p; + int min, max; + + min = 256; + max = 0; + while (n--) + { + p = pdefs->pixel; + priv->red[p] = pdefs->red; + priv->green[p] = pdefs->green; + priv->blue[p] = pdefs->blue; + if (p < min) + min = p; + if (p > max) + max = p; + pdefs++; + } + + fbdevUpdateFbColormap(priv, min, max); +} diff --git a/xorg-server/hw/kdrive/fbdev/fbdev.h b/xorg-server/hw/kdrive/fbdev/fbdev.h index ebac6ad8b..ec53784af 100644 --- a/xorg-server/hw/kdrive/fbdev/fbdev.h +++ b/xorg-server/hw/kdrive/fbdev/fbdev.h @@ -1,5 +1,5 @@ /* - * Copyright © 1999 Keith Packard + * Copyright © 1999 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 diff --git a/xorg-server/hw/kdrive/fbdev/fbinit.c b/xorg-server/hw/kdrive/fbdev/fbinit.c index 51e7e00d9..1d66fce32 100644 --- a/xorg-server/hw/kdrive/fbdev/fbinit.c +++ b/xorg-server/hw/kdrive/fbdev/fbinit.c @@ -1,5 +1,5 @@ /* - * Copyright © 1999 Keith Packard + * Copyright © 1999 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 @@ -47,6 +47,7 @@ InitInput (int argc, char **argv) void CloseInput (void) { + KdCloseInput (); } void diff --git a/xorg-server/hw/kdrive/linux/keyboard.c b/xorg-server/hw/kdrive/linux/keyboard.c index c888d14dc..f5f9d9b8a 100644 --- a/xorg-server/hw/kdrive/linux/keyboard.c +++ b/xorg-server/hw/kdrive/linux/keyboard.c @@ -1,765 +1,765 @@ -/*
- * Copyright © 1999 Keith Packard
- * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych <tf@o-hand.com>
- *
- * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c:
- * Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany.
- * Copyright © 1994-2001 by The XFree86 Project, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s)
- * and author(s) 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 copyright holder(s) and author(s).
- */
-
-#ifdef HAVE_CONFIG_H
-#include <kdrive-config.h>
-#endif
-#include "kdrive.h"
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-#define XK_PUBLISHING
-#include <X11/keysym.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-
-extern int LinuxConsoleFd;
-
-static const KeySym linux_to_x[256] = {
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, XK_Escape,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- XK_space, XK_exclam, XK_quotedbl, XK_numbersign,
- XK_dollar, XK_percent, XK_ampersand, XK_apostrophe,
- XK_parenleft, XK_parenright, XK_asterisk, XK_plus,
- XK_comma, XK_minus, XK_period, XK_slash,
- XK_0, XK_1, XK_2, XK_3,
- XK_4, XK_5, XK_6, XK_7,
- XK_8, XK_9, XK_colon, XK_semicolon,
- XK_less, XK_equal, XK_greater, XK_question,
- XK_at, XK_A, XK_B, XK_C,
- XK_D, XK_E, XK_F, XK_G,
- XK_H, XK_I, XK_J, XK_K,
- XK_L, XK_M, XK_N, XK_O,
- XK_P, XK_Q, XK_R, XK_S,
- XK_T, XK_U, XK_V, XK_W,
- XK_X, XK_Y, XK_Z, XK_bracketleft,
- XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore,
- XK_grave, XK_a, XK_b, XK_c,
- XK_d, XK_e, XK_f, XK_g,
- XK_h, XK_i, XK_j, XK_k,
- XK_l, XK_m, XK_n, XK_o,
- XK_p, XK_q, XK_r, XK_s,
- XK_t, XK_u, XK_v, XK_w,
- XK_x, XK_y, XK_z, XK_braceleft,
- XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- NoSymbol, NoSymbol, NoSymbol, NoSymbol,
- XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling,
- XK_currency, XK_yen, XK_brokenbar, XK_section,
- XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft,
- XK_notsign, XK_hyphen, XK_registered, XK_macron,
- XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior,
- XK_acute, XK_mu, XK_paragraph, XK_periodcentered,
- XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright,
- XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown,
- XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde,
- XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla,
- XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis,
- XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis,
- XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute,
- XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply,
- XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex,
- XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp,
- XK_agrave, XK_aacute, XK_acircumflex, XK_atilde,
- XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla,
- XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis,
- XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis,
- XK_eth, XK_ntilde, XK_ograve, XK_oacute,
- XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division,
- XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex,
- XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis
-};
-
-/*
- * Getting a keycode from scancode
- *
- * With XKB
- * --------
- *
- * We have to enqueue keyboard events using standard X keycodes which correspond
- * to AT scancode + 8; this means that we need to translate the Linux scancode
- * provided by the kernel to an AT scancode -- this translation is not linear
- * and requires that we use a LUT.
- *
- *
- * Without XKB
- * -----------
- *
- * We can use custom keycodes, which makes things simpler; we define our custom
- * keycodes as Linux scancodes + KD_KEY_OFFSET
-*/
-
-/*
- This LUT translates AT scancodes into Linux ones -- the keymap we create
- for the core X keyboard protocol has to be AT-scancode based so that it
- corresponds to the Xkb keymap.
-*/
-#if 0
-static unsigned char at2lnx[] =
-{
- 0x0, /* no valid scancode */
- 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */
- 0x03, /* KEY_2 */ 0x04, /* KEY_3 */
- 0x05, /* KEY_4 */ 0x06, /* KEY_5 */
- 0x07, /* KEY_6 */ 0x08, /* KEY_7 */
- 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */
- 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */
- 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */
- 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */
- 0x11, /* KEY_W */ 0x12, /* KEY_E */
- 0x13, /* KEY_R */ 0x14, /* KEY_T */
- 0x15, /* KEY_Y */ 0x16, /* KEY_U */
- 0x17, /* KEY_I */ 0x18, /* KEY_O */
- 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */
- 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */
- 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */
- 0x1f, /* KEY_S */ 0x20, /* KEY_D */
- 0x21, /* KEY_F */ 0x22, /* KEY_G */
- 0x23, /* KEY_H */ 0x24, /* KEY_J */
- 0x25, /* KEY_K */ 0x26, /* KEY_L */
- 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */
- 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */
- 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */
- 0x2d, /* KEY_X */ 0x2e, /* KEY_C */
- 0x2f, /* KEY_V */ 0x30, /* KEY_B */
- 0x31, /* KEY_N */ 0x32, /* KEY_M */
- 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */
- 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */
- 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */
- 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */
- 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */
- 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */
- 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */
- 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */
- 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */
- 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */
- 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */
- 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */
- 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */
- 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */
- 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */
- 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */
- 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */
- 0x00, /* 0x55 */ 0x56, /* KEY_Less */
- 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */
- 0x66, /* KEY_Home */ 0x67, /* KEY_Up */
- 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */
- 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */
- 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */
- 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */
- 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */
- 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */
- 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */
- 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */
- 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */
- 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */
- 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */
- 0x00, /* 0x71 */ 0x00, /* 0x72 */
- 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */
- 0x00, /* 0x75 */ 0x00, /* 0x76 */
- 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */
- 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */
- 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */
- 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */
- 0x00, /* 0x7f */
-};
-
-#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0]))
-#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0
-
-static unsigned char tbl[KD_MAX_WIDTH] =
-{
- 0,
- 1 << KG_SHIFT,
- (1 << KG_ALTGR),
- (1 << KG_ALTGR) | (1 << KG_SHIFT)
-};
-#endif
-
-static void
-readKernelMapping(KdKeyboardInfo *ki)
-{
-#if 0
- KeySym *k;
- int i, j;
- struct kbentry kbe;
- int minKeyCode, maxKeyCode;
- int row;
- int fd;
-
- if (!ki)
- return;
-
- fd = LinuxConsoleFd;
-
- minKeyCode = NR_KEYS;
- maxKeyCode = 0;
- row = 0;
- ki->keySyms.mapWidth = KD_MAX_WIDTH;
- for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i)
- {
- kbe.kb_index = LNX_KEY_INDEX(i);
-
- k = ki->keySyms.map + row * ki->keySyms.mapWidth;
-
- for (j = 0; j < ki->keySyms.mapWidth; ++j)
- {
- unsigned short kval;
-
- k[j] = NoSymbol;
-
- kbe.kb_table = tbl[j];
- kbe.kb_value = 0;
- if (ioctl(fd, KDGKBENT, &kbe))
- continue;
-
- kval = KVAL(kbe.kb_value);
- switch (KTYP(kbe.kb_value))
- {
- case KT_LATIN:
- case KT_LETTER:
- k[j] = linux_to_x[kval];
- break;
-
- case KT_FN:
- if (kval <= 19)
- k[j] = XK_F1 + kval;
- else switch (kbe.kb_value)
- {
- case K_FIND:
- k[j] = XK_Home; /* or XK_Find */
- break;
- case K_INSERT:
- k[j] = XK_Insert;
- break;
- case K_REMOVE:
- k[j] = XK_Delete;
- break;
- case K_SELECT:
- k[j] = XK_End; /* or XK_Select */
- break;
- case K_PGUP:
- k[j] = XK_Prior;
- break;
- case K_PGDN:
- k[j] = XK_Next;
- break;
- case K_HELP:
- k[j] = XK_Help;
- break;
- case K_DO:
- k[j] = XK_Execute;
- break;
- case K_PAUSE:
- k[j] = XK_Pause;
- break;
- case K_MACRO:
- k[j] = XK_Menu;
- break;
- default:
- break;
- }
- break;
-
- case KT_SPEC:
- switch (kbe.kb_value)
- {
- case K_ENTER:
- k[j] = XK_Return;
- break;
- case K_BREAK:
- k[j] = XK_Break;
- break;
- case K_CAPS:
- k[j] = XK_Caps_Lock;
- break;
- case K_NUM:
- k[j] = XK_Num_Lock;
- break;
- case K_HOLD:
- k[j] = XK_Scroll_Lock;
- break;
- case K_COMPOSE:
- k[j] = XK_Multi_key;
- break;
- default:
- break;
- }
- break;
-
- case KT_PAD:
- switch (kbe.kb_value)
- {
- case K_PPLUS:
- k[j] = XK_KP_Add;
- break;
- case K_PMINUS:
- k[j] = XK_KP_Subtract;
- break;
- case K_PSTAR:
- k[j] = XK_KP_Multiply;
- break;
- case K_PSLASH:
- k[j] = XK_KP_Divide;
- break;
- case K_PENTER:
- k[j] = XK_KP_Enter;
- break;
- case K_PCOMMA:
- k[j] = XK_KP_Separator;
- break;
- case K_PDOT:
- k[j] = XK_KP_Decimal;
- break;
- case K_PPLUSMINUS:
- k[j] = XK_KP_Subtract;
- break;
- default:
- if (kval <= 9)
- k[j] = XK_KP_0 + kval;
- break;
- }
- break;
-
- /*
- * KT_DEAD keys are for accelerated diacritical creation.
- */
- case KT_DEAD:
- switch (kbe.kb_value)
- {
- case K_DGRAVE:
- k[j] = XK_dead_grave;
- break;
- case K_DACUTE:
- k[j] = XK_dead_acute;
- break;
- case K_DCIRCM:
- k[j] = XK_dead_circumflex;
- break;
- case K_DTILDE:
- k[j] = XK_dead_tilde;
- break;
- case K_DDIERE:
- k[j] = XK_dead_diaeresis;
- break;
- }
- break;
-
- case KT_CUR:
- switch (kbe.kb_value)
- {
- case K_DOWN:
- k[j] = XK_Down;
- break;
- case K_LEFT:
- k[j] = XK_Left;
- break;
- case K_RIGHT:
- k[j] = XK_Right;
- break;
- case K_UP:
- k[j] = XK_Up;
- break;
- }
- break;
-
- case KT_SHIFT:
- switch (kbe.kb_value)
- {
- case K_ALTGR:
- k[j] = XK_Mode_switch;
- break;
- case K_ALT:
- k[j] = (kbe.kb_index == 0x64 ?
- XK_Alt_R : XK_Alt_L);
- break;
- case K_CTRL:
- k[j] = (kbe.kb_index == 0x61 ?
- XK_Control_R : XK_Control_L);
- break;
- case K_CTRLL:
- k[j] = XK_Control_L;
- break;
- case K_CTRLR:
- k[j] = XK_Control_R;
- break;
- case K_SHIFT:
- k[j] = (kbe.kb_index == 0x36 ?
- XK_Shift_R : XK_Shift_L);
- break;
- case K_SHIFTL:
- k[j] = XK_Shift_L;
- break;
- case K_SHIFTR:
- k[j] = XK_Shift_R;
- break;
- default:
- break;
- }
- break;
-
- /*
- * KT_ASCII keys accumulate a 3 digit decimal number that gets
- * emitted when the shift state changes. We can't emulate that.
- */
- case KT_ASCII:
- break;
-
- case KT_LOCK:
- if (kbe.kb_value == K_SHIFTLOCK)
- k[j] = XK_Shift_Lock;
- break;
-
-#ifdef KT_X
- case KT_X:
- /* depends on new keyboard symbols in file linux/keyboard.h */
- if(kbe.kb_value == K_XMENU) k[j] = XK_Menu;
- if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone;
- break;
-#endif
-#ifdef KT_XF
- case KT_XF:
- /* special linux keysyms which map directly to XF86 keysyms */
- k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00;
- break;
-#endif
-
- default:
- break;
- }
- if (i < minKeyCode)
- minKeyCode = i;
- if (i > maxKeyCode)
- maxKeyCode = i;
- }
-
- if (minKeyCode == NR_KEYS)
- continue;
-
- if (k[3] == k[2]) k[3] = NoSymbol;
- if (k[2] == k[1]) k[2] = NoSymbol;
- if (k[1] == k[0]) k[1] = NoSymbol;
- if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
- if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol;
- row++;
- }
- ki->minScanCode = minKeyCode;
- ki->maxScanCode = maxKeyCode;
-#endif
-}
-
-/*
- * We need these to handle extended scancodes correctly (I could just use the
- * numbers below, but this makes the code more readable
- */
-
-/* The prefix codes */
-#define KEY_Prefix0 /* special 0x60 */ 96
-#define KEY_Prefix1 /* special 0x61 */ 97
-
-/* The raw scancodes */
-#define KEY_Enter /* Enter 0x1c */ 28
-#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29
-#define KEY_Slash /* / (Slash) ? 0x35 */ 53
-#define KEY_KP_Multiply /* * 0x37 */ 55
-#define KEY_Alt /* Alt(left) 0x38 */ 56
-#define KEY_F3 /* F3 0x3d */ 61
-#define KEY_F4 /* F4 0x3e */ 62
-#define KEY_F5 /* F5 0x3f */ 63
-#define KEY_F6 /* F6 0x40 */ 64
-#define KEY_F7 /* F7 0x41 */ 65
-#define KEY_ScrollLock /* ScrollLock 0x46 */ 70
-#define KEY_KP_7 /* 7 Home 0x47 */ 71
-#define KEY_KP_8 /* 8 Up 0x48 */ 72
-#define KEY_KP_9 /* 9 PgUp 0x49 */ 73
-#define KEY_KP_Minus /* - (Minus) 0x4a */ 74
-#define KEY_KP_4 /* 4 Left 0x4b */ 75
-#define KEY_KP_5 /* 5 0x4c */ 76
-#define KEY_KP_6 /* 6 Right 0x4d */ 77
-#define KEY_KP_Plus /* + (Plus) 0x4e */ 78
-#define KEY_KP_1 /* 1 End 0x4f */ 79
-#define KEY_KP_2 /* 2 Down 0x50 */ 80
-#define KEY_KP_3 /* 3 PgDown 0x51 */ 81
-#define KEY_KP_0 /* 0 Insert 0x52 */ 82
-#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83
-#define KEY_Home /* Home 0x59 */ 89
-#define KEY_Up /* Up 0x5a */ 90
-#define KEY_PgUp /* PgUp 0x5b */ 91
-#define KEY_Left /* Left 0x5c */ 92
-#define KEY_Begin /* Begin 0x5d */ 93
-#define KEY_Right /* Right 0x5e */ 94
-#define KEY_End /* End 0x5f */ 95
-#define KEY_Down /* Down 0x60 */ 96
-#define KEY_PgDown /* PgDown 0x61 */ 97
-#define KEY_Insert /* Insert 0x62 */ 98
-#define KEY_Delete /* Delete 0x63 */ 99
-#define KEY_KP_Enter /* Enter 0x64 */ 100
-#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101
-#define KEY_Pause /* Pause 0x66 */ 102
-#define KEY_Print /* Print 0x67 */ 103
-#define KEY_KP_Divide /* Divide 0x68 */ 104
-#define KEY_AltLang /* AtlLang(right) 0x69 */ 105
-#define KEY_Break /* Break 0x6a */ 106
-#define KEY_LMeta /* Left Meta 0x6b */ 107
-#define KEY_RMeta /* Right Meta 0x6c */ 108
-#define KEY_Menu /* Menu 0x6d */ 109
-#define KEY_F13 /* F13 0x6e */ 110
-#define KEY_F14 /* F14 0x6f */ 111
-#define KEY_F15 /* F15 0x70 */ 112
-#define KEY_F16 /* F16 0x71 */ 113
-#define KEY_F17 /* F17 0x72 */ 114
-#define KEY_KP_DEC /* KP_DEC 0x73 */ 115
-
-static void
-LinuxKeyboardRead (int fd, void *closure)
-{
- unsigned char buf[256], *b;
- int n;
- unsigned char prefix = 0, scancode = 0;
-
- while ((n = read (fd, buf, sizeof (buf))) > 0) {
- b = buf;
- while (n--) {
- /*
- * With xkb we use RAW mode for reading the console, which allows us
- * process extended scancodes.
- *
- * See if this is a prefix extending the following keycode
- */
- if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0))
- {
- prefix = KEY_Prefix0;
- /* swallow this up */
- b++;
- continue;
- }
- else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1))
- {
- prefix = KEY_Prefix1;
- /* swallow this up */
- b++;
- continue;
- }
- scancode = b[0] & 0x7f;
-
- switch (prefix) {
- /* from xf86Events.c */
- case KEY_Prefix0:
- {
- switch (scancode) {
- case KEY_KP_7:
- scancode = KEY_Home; break; /* curs home */
- case KEY_KP_8:
- scancode = KEY_Up; break; /* curs up */
- case KEY_KP_9:
- scancode = KEY_PgUp; break; /* curs pgup */
- case KEY_KP_4:
- scancode = KEY_Left; break; /* curs left */
- case KEY_KP_5:
- scancode = KEY_Begin; break; /* curs begin */
- case KEY_KP_6:
- scancode = KEY_Right; break; /* curs right */
- case KEY_KP_1:
- scancode = KEY_End; break; /* curs end */
- case KEY_KP_2:
- scancode = KEY_Down; break; /* curs down */
- case KEY_KP_3:
- scancode = KEY_PgDown; break; /* curs pgdown */
- case KEY_KP_0:
- scancode = KEY_Insert; break; /* curs insert */
- case KEY_KP_Decimal:
- scancode = KEY_Delete; break; /* curs delete */
- case KEY_Enter:
- scancode = KEY_KP_Enter; break; /* keypad enter */
- case KEY_LCtrl:
- scancode = KEY_RCtrl; break; /* right ctrl */
- case KEY_KP_Multiply:
- scancode = KEY_Print; break; /* print */
- case KEY_Slash:
- scancode = KEY_KP_Divide; break; /* keyp divide */
- case KEY_Alt:
- scancode = KEY_AltLang; break; /* right alt */
- case KEY_ScrollLock:
- scancode = KEY_Break; break; /* curs break */
- case 0x5b:
- scancode = KEY_LMeta; break;
- case 0x5c:
- scancode = KEY_RMeta; break;
- case 0x5d:
- scancode = KEY_Menu; break;
- case KEY_F3:
- scancode = KEY_F13; break;
- case KEY_F4:
- scancode = KEY_F14; break;
- case KEY_F5:
- scancode = KEY_F15; break;
- case KEY_F6:
- scancode = KEY_F16; break;
- case KEY_F7:
- scancode = KEY_F17; break;
- case KEY_KP_Plus:
- scancode = KEY_KP_DEC; break;
- /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */
- case 0x2A:
- case 0x36:
- b++;
- prefix = 0;
- continue;
- default:
- /*
- * "Internet" keyboards are generating lots of new
- * codes. Let them pass. There is little consistency
- * between them, so don't bother with symbolic names at
- * this level.
- */
- scancode += 0x78;
- }
- break;
- }
-
- case KEY_Prefix1:
- {
- /* we do no handle these */
- b++;
- prefix = 0;
- continue;
- }
-
- default: /* should not happen*/
- case 0: /* do nothing */
- ;
- }
-
- prefix = 0;
- KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80);
- b++;
- }
- }
-}
-
-static int LinuxKbdTrans;
-static struct termios LinuxTermios;
-
-static Status
-LinuxKeyboardEnable (KdKeyboardInfo *ki)
-{
- struct termios nTty;
- unsigned char buf[256];
- int n;
- int fd;
-
- if (!ki)
- return !Success;
-
- fd = LinuxConsoleFd;
- ki->driverPrivate = (void *) fd;
-
- ioctl (fd, KDGKBMODE, &LinuxKbdTrans);
- tcgetattr (fd, &LinuxTermios);
- ioctl(fd, KDSKBMODE, K_RAW);
- nTty = LinuxTermios;
- nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
- nTty.c_oflag = 0;
- nTty.c_cflag = CREAD | CS8;
- nTty.c_lflag = 0;
- nTty.c_cc[VTIME]=0;
- nTty.c_cc[VMIN]=1;
- cfsetispeed(&nTty, 9600);
- cfsetospeed(&nTty, 9600);
- tcsetattr(fd, TCSANOW, &nTty);
- /*
- * Flush any pending keystrokes
- */
- while ((n = read (fd, buf, sizeof (buf))) > 0)
- ;
- KdRegisterFd (fd, LinuxKeyboardRead, ki);
- return Success;
-}
-
-static void
-LinuxKeyboardDisable (KdKeyboardInfo *ki)
-{
- int fd;
-
- if (!ki)
- return;
-
- fd = (int) ki->driverPrivate;
-
- KdUnregisterFd(ki, fd, FALSE);
- ioctl(fd, KDSKBMODE, LinuxKbdTrans);
- tcsetattr(fd, TCSANOW, &LinuxTermios);
-}
-
-static Status
-LinuxKeyboardInit (KdKeyboardInfo *ki)
-{
- if (!ki)
- return !Success;
-
- free(ki->path);
- ki->path = strdup("console");
- free(ki->name);
- ki->name = strdup("Linux console keyboard");
-
- readKernelMapping (ki);
-
- return Success;
-}
-
-static void
-LinuxKeyboardLeds (KdKeyboardInfo *ki, int leds)
-{
- if (!ki)
- return;
-
- ioctl ((int)ki->driverPrivate, KDSETLED, leds & 7);
-}
-
-KdKeyboardDriver LinuxKeyboardDriver = {
- "keyboard",
- .Init = LinuxKeyboardInit,
- .Enable = LinuxKeyboardEnable,
- .Leds = LinuxKeyboardLeds,
- .Disable = LinuxKeyboardDisable,
-};
+/* + * Copyright © 1999 Keith Packard + * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych <tf@o-hand.com> + * + * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c: + * Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * Copyright © 1994-2001 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" +#include <linux/keyboard.h> +#include <linux/kd.h> +#define XK_PUBLISHING +#include <X11/keysym.h> +#include <termios.h> +#include <sys/ioctl.h> + +extern int LinuxConsoleFd; + +static const KeySym linux_to_x[256] = { + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, XK_Escape, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_space, XK_exclam, XK_quotedbl, XK_numbersign, + XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, + XK_parenleft, XK_parenright, XK_asterisk, XK_plus, + XK_comma, XK_minus, XK_period, XK_slash, + XK_0, XK_1, XK_2, XK_3, + XK_4, XK_5, XK_6, XK_7, + XK_8, XK_9, XK_colon, XK_semicolon, + XK_less, XK_equal, XK_greater, XK_question, + XK_at, XK_A, XK_B, XK_C, + XK_D, XK_E, XK_F, XK_G, + XK_H, XK_I, XK_J, XK_K, + XK_L, XK_M, XK_N, XK_O, + XK_P, XK_Q, XK_R, XK_S, + XK_T, XK_U, XK_V, XK_W, + XK_X, XK_Y, XK_Z, XK_bracketleft, + XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, + XK_grave, XK_a, XK_b, XK_c, + XK_d, XK_e, XK_f, XK_g, + XK_h, XK_i, XK_j, XK_k, + XK_l, XK_m, XK_n, XK_o, + XK_p, XK_q, XK_r, XK_s, + XK_t, XK_u, XK_v, XK_w, + XK_x, XK_y, XK_z, XK_braceleft, + XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, + XK_currency, XK_yen, XK_brokenbar, XK_section, + XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, + XK_notsign, XK_hyphen, XK_registered, XK_macron, + XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, + XK_acute, XK_mu, XK_paragraph, XK_periodcentered, + XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, + XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, + XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, + XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, + XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, + XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, + XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, + XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, + XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, + XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, + XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, + XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, + XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, + XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, + XK_eth, XK_ntilde, XK_ograve, XK_oacute, + XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, + XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, + XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis +}; + +/* + * Getting a keycode from scancode + * + * With XKB + * -------- + * + * We have to enqueue keyboard events using standard X keycodes which correspond + * to AT scancode + 8; this means that we need to translate the Linux scancode + * provided by the kernel to an AT scancode -- this translation is not linear + * and requires that we use a LUT. + * + * + * Without XKB + * ----------- + * + * We can use custom keycodes, which makes things simpler; we define our custom + * keycodes as Linux scancodes + KD_KEY_OFFSET +*/ + +/* + This LUT translates AT scancodes into Linux ones -- the keymap we create + for the core X keyboard protocol has to be AT-scancode based so that it + corresponds to the Xkb keymap. +*/ +#if 0 +static unsigned char at2lnx[] = +{ + 0x0, /* no valid scancode */ + 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ + 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ + 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ + 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ + 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ + 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ + 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ + 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ + 0x11, /* KEY_W */ 0x12, /* KEY_E */ + 0x13, /* KEY_R */ 0x14, /* KEY_T */ + 0x15, /* KEY_Y */ 0x16, /* KEY_U */ + 0x17, /* KEY_I */ 0x18, /* KEY_O */ + 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ + 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ + 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ + 0x1f, /* KEY_S */ 0x20, /* KEY_D */ + 0x21, /* KEY_F */ 0x22, /* KEY_G */ + 0x23, /* KEY_H */ 0x24, /* KEY_J */ + 0x25, /* KEY_K */ 0x26, /* KEY_L */ + 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ + 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ + 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ + 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ + 0x2f, /* KEY_V */ 0x30, /* KEY_B */ + 0x31, /* KEY_N */ 0x32, /* KEY_M */ + 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ + 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ + 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ + 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ + 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ + 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ + 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ + 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ + 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ + 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ + 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ + 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ + 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ + 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ + 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ + 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ + 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ + 0x00, /* 0x55 */ 0x56, /* KEY_Less */ + 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ + 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ + 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ + 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ + 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ + 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ + 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ + 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ + 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ + 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ + 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ + 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ + 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ + 0x00, /* 0x71 */ 0x00, /* 0x72 */ + 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ + 0x00, /* 0x75 */ 0x00, /* 0x76 */ + 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ + 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ + 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ + 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ + 0x00, /* 0x7f */ +}; + +#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0])) +#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0 + +static unsigned char tbl[KD_MAX_WIDTH] = +{ + 0, + 1 << KG_SHIFT, + (1 << KG_ALTGR), + (1 << KG_ALTGR) | (1 << KG_SHIFT) +}; +#endif + +static void +readKernelMapping(KdKeyboardInfo *ki) +{ +#if 0 + KeySym *k; + int i, j; + struct kbentry kbe; + int minKeyCode, maxKeyCode; + int row; + int fd; + + if (!ki) + return; + + fd = LinuxConsoleFd; + + minKeyCode = NR_KEYS; + maxKeyCode = 0; + row = 0; + ki->keySyms.mapWidth = KD_MAX_WIDTH; + for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i) + { + kbe.kb_index = LNX_KEY_INDEX(i); + + k = ki->keySyms.map + row * ki->keySyms.mapWidth; + + for (j = 0; j < ki->keySyms.mapWidth; ++j) + { + unsigned short kval; + + k[j] = NoSymbol; + + kbe.kb_table = tbl[j]; + kbe.kb_value = 0; + if (ioctl(fd, KDGKBENT, &kbe)) + continue; + + kval = KVAL(kbe.kb_value); + switch (KTYP(kbe.kb_value)) + { + case KT_LATIN: + case KT_LETTER: + k[j] = linux_to_x[kval]; + break; + + case KT_FN: + if (kval <= 19) + k[j] = XK_F1 + kval; + else switch (kbe.kb_value) + { + case K_FIND: + k[j] = XK_Home; /* or XK_Find */ + break; + case K_INSERT: + k[j] = XK_Insert; + break; + case K_REMOVE: + k[j] = XK_Delete; + break; + case K_SELECT: + k[j] = XK_End; /* or XK_Select */ + break; + case K_PGUP: + k[j] = XK_Prior; + break; + case K_PGDN: + k[j] = XK_Next; + break; + case K_HELP: + k[j] = XK_Help; + break; + case K_DO: + k[j] = XK_Execute; + break; + case K_PAUSE: + k[j] = XK_Pause; + break; + case K_MACRO: + k[j] = XK_Menu; + break; + default: + break; + } + break; + + case KT_SPEC: + switch (kbe.kb_value) + { + case K_ENTER: + k[j] = XK_Return; + break; + case K_BREAK: + k[j] = XK_Break; + break; + case K_CAPS: + k[j] = XK_Caps_Lock; + break; + case K_NUM: + k[j] = XK_Num_Lock; + break; + case K_HOLD: + k[j] = XK_Scroll_Lock; + break; + case K_COMPOSE: + k[j] = XK_Multi_key; + break; + default: + break; + } + break; + + case KT_PAD: + switch (kbe.kb_value) + { + case K_PPLUS: + k[j] = XK_KP_Add; + break; + case K_PMINUS: + k[j] = XK_KP_Subtract; + break; + case K_PSTAR: + k[j] = XK_KP_Multiply; + break; + case K_PSLASH: + k[j] = XK_KP_Divide; + break; + case K_PENTER: + k[j] = XK_KP_Enter; + break; + case K_PCOMMA: + k[j] = XK_KP_Separator; + break; + case K_PDOT: + k[j] = XK_KP_Decimal; + break; + case K_PPLUSMINUS: + k[j] = XK_KP_Subtract; + break; + default: + if (kval <= 9) + k[j] = XK_KP_0 + kval; + break; + } + break; + + /* + * KT_DEAD keys are for accelerated diacritical creation. + */ + case KT_DEAD: + switch (kbe.kb_value) + { + case K_DGRAVE: + k[j] = XK_dead_grave; + break; + case K_DACUTE: + k[j] = XK_dead_acute; + break; + case K_DCIRCM: + k[j] = XK_dead_circumflex; + break; + case K_DTILDE: + k[j] = XK_dead_tilde; + break; + case K_DDIERE: + k[j] = XK_dead_diaeresis; + break; + } + break; + + case KT_CUR: + switch (kbe.kb_value) + { + case K_DOWN: + k[j] = XK_Down; + break; + case K_LEFT: + k[j] = XK_Left; + break; + case K_RIGHT: + k[j] = XK_Right; + break; + case K_UP: + k[j] = XK_Up; + break; + } + break; + + case KT_SHIFT: + switch (kbe.kb_value) + { + case K_ALTGR: + k[j] = XK_Mode_switch; + break; + case K_ALT: + k[j] = (kbe.kb_index == 0x64 ? + XK_Alt_R : XK_Alt_L); + break; + case K_CTRL: + k[j] = (kbe.kb_index == 0x61 ? + XK_Control_R : XK_Control_L); + break; + case K_CTRLL: + k[j] = XK_Control_L; + break; + case K_CTRLR: + k[j] = XK_Control_R; + break; + case K_SHIFT: + k[j] = (kbe.kb_index == 0x36 ? + XK_Shift_R : XK_Shift_L); + break; + case K_SHIFTL: + k[j] = XK_Shift_L; + break; + case K_SHIFTR: + k[j] = XK_Shift_R; + break; + default: + break; + } + break; + + /* + * KT_ASCII keys accumulate a 3 digit decimal number that gets + * emitted when the shift state changes. We can't emulate that. + */ + case KT_ASCII: + break; + + case KT_LOCK: + if (kbe.kb_value == K_SHIFTLOCK) + k[j] = XK_Shift_Lock; + break; + +#ifdef KT_X + case KT_X: + /* depends on new keyboard symbols in file linux/keyboard.h */ + if(kbe.kb_value == K_XMENU) k[j] = XK_Menu; + if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone; + break; +#endif +#ifdef KT_XF + case KT_XF: + /* special linux keysyms which map directly to XF86 keysyms */ + k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00; + break; +#endif + + default: + break; + } + if (i < minKeyCode) + minKeyCode = i; + if (i > maxKeyCode) + maxKeyCode = i; + } + + if (minKeyCode == NR_KEYS) + continue; + + if (k[3] == k[2]) k[3] = NoSymbol; + if (k[2] == k[1]) k[2] = NoSymbol; + if (k[1] == k[0]) k[1] = NoSymbol; + if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; + if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol; + row++; + } + ki->minScanCode = minKeyCode; + ki->maxScanCode = maxKeyCode; +#endif +} + +/* + * We need these to handle extended scancodes correctly (I could just use the + * numbers below, but this makes the code more readable + */ + +/* The prefix codes */ +#define KEY_Prefix0 /* special 0x60 */ 96 +#define KEY_Prefix1 /* special 0x61 */ 97 + +/* The raw scancodes */ +#define KEY_Enter /* Enter 0x1c */ 28 +#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 +#define KEY_Slash /* / (Slash) ? 0x35 */ 53 +#define KEY_KP_Multiply /* * 0x37 */ 55 +#define KEY_Alt /* Alt(left) 0x38 */ 56 +#define KEY_F3 /* F3 0x3d */ 61 +#define KEY_F4 /* F4 0x3e */ 62 +#define KEY_F5 /* F5 0x3f */ 63 +#define KEY_F6 /* F6 0x40 */ 64 +#define KEY_F7 /* F7 0x41 */ 65 +#define KEY_ScrollLock /* ScrollLock 0x46 */ 70 +#define KEY_KP_7 /* 7 Home 0x47 */ 71 +#define KEY_KP_8 /* 8 Up 0x48 */ 72 +#define KEY_KP_9 /* 9 PgUp 0x49 */ 73 +#define KEY_KP_Minus /* - (Minus) 0x4a */ 74 +#define KEY_KP_4 /* 4 Left 0x4b */ 75 +#define KEY_KP_5 /* 5 0x4c */ 76 +#define KEY_KP_6 /* 6 Right 0x4d */ 77 +#define KEY_KP_Plus /* + (Plus) 0x4e */ 78 +#define KEY_KP_1 /* 1 End 0x4f */ 79 +#define KEY_KP_2 /* 2 Down 0x50 */ 80 +#define KEY_KP_3 /* 3 PgDown 0x51 */ 81 +#define KEY_KP_0 /* 0 Insert 0x52 */ 82 +#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 +#define KEY_Home /* Home 0x59 */ 89 +#define KEY_Up /* Up 0x5a */ 90 +#define KEY_PgUp /* PgUp 0x5b */ 91 +#define KEY_Left /* Left 0x5c */ 92 +#define KEY_Begin /* Begin 0x5d */ 93 +#define KEY_Right /* Right 0x5e */ 94 +#define KEY_End /* End 0x5f */ 95 +#define KEY_Down /* Down 0x60 */ 96 +#define KEY_PgDown /* PgDown 0x61 */ 97 +#define KEY_Insert /* Insert 0x62 */ 98 +#define KEY_Delete /* Delete 0x63 */ 99 +#define KEY_KP_Enter /* Enter 0x64 */ 100 +#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 +#define KEY_Pause /* Pause 0x66 */ 102 +#define KEY_Print /* Print 0x67 */ 103 +#define KEY_KP_Divide /* Divide 0x68 */ 104 +#define KEY_AltLang /* AtlLang(right) 0x69 */ 105 +#define KEY_Break /* Break 0x6a */ 106 +#define KEY_LMeta /* Left Meta 0x6b */ 107 +#define KEY_RMeta /* Right Meta 0x6c */ 108 +#define KEY_Menu /* Menu 0x6d */ 109 +#define KEY_F13 /* F13 0x6e */ 110 +#define KEY_F14 /* F14 0x6f */ 111 +#define KEY_F15 /* F15 0x70 */ 112 +#define KEY_F16 /* F16 0x71 */ 113 +#define KEY_F17 /* F17 0x72 */ 114 +#define KEY_KP_DEC /* KP_DEC 0x73 */ 115 + +static void +LinuxKeyboardRead (int fd, void *closure) +{ + unsigned char buf[256], *b; + int n; + unsigned char prefix = 0, scancode = 0; + + while ((n = read (fd, buf, sizeof (buf))) > 0) { + b = buf; + while (n--) { + /* + * With xkb we use RAW mode for reading the console, which allows us + * process extended scancodes. + * + * See if this is a prefix extending the following keycode + */ + if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) + { + prefix = KEY_Prefix0; + /* swallow this up */ + b++; + continue; + } + else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) + { + prefix = KEY_Prefix1; + /* swallow this up */ + b++; + continue; + } + scancode = b[0] & 0x7f; + + switch (prefix) { + /* from xf86Events.c */ + case KEY_Prefix0: + { + switch (scancode) { + case KEY_KP_7: + scancode = KEY_Home; break; /* curs home */ + case KEY_KP_8: + scancode = KEY_Up; break; /* curs up */ + case KEY_KP_9: + scancode = KEY_PgUp; break; /* curs pgup */ + case KEY_KP_4: + scancode = KEY_Left; break; /* curs left */ + case KEY_KP_5: + scancode = KEY_Begin; break; /* curs begin */ + case KEY_KP_6: + scancode = KEY_Right; break; /* curs right */ + case KEY_KP_1: + scancode = KEY_End; break; /* curs end */ + case KEY_KP_2: + scancode = KEY_Down; break; /* curs down */ + case KEY_KP_3: + scancode = KEY_PgDown; break; /* curs pgdown */ + case KEY_KP_0: + scancode = KEY_Insert; break; /* curs insert */ + case KEY_KP_Decimal: + scancode = KEY_Delete; break; /* curs delete */ + case KEY_Enter: + scancode = KEY_KP_Enter; break; /* keypad enter */ + case KEY_LCtrl: + scancode = KEY_RCtrl; break; /* right ctrl */ + case KEY_KP_Multiply: + scancode = KEY_Print; break; /* print */ + case KEY_Slash: + scancode = KEY_KP_Divide; break; /* keyp divide */ + case KEY_Alt: + scancode = KEY_AltLang; break; /* right alt */ + case KEY_ScrollLock: + scancode = KEY_Break; break; /* curs break */ + case 0x5b: + scancode = KEY_LMeta; break; + case 0x5c: + scancode = KEY_RMeta; break; + case 0x5d: + scancode = KEY_Menu; break; + case KEY_F3: + scancode = KEY_F13; break; + case KEY_F4: + scancode = KEY_F14; break; + case KEY_F5: + scancode = KEY_F15; break; + case KEY_F6: + scancode = KEY_F16; break; + case KEY_F7: + scancode = KEY_F17; break; + case KEY_KP_Plus: + scancode = KEY_KP_DEC; break; + /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */ + case 0x2A: + case 0x36: + b++; + prefix = 0; + continue; + default: + /* + * "Internet" keyboards are generating lots of new + * codes. Let them pass. There is little consistency + * between them, so don't bother with symbolic names at + * this level. + */ + scancode += 0x78; + } + break; + } + + case KEY_Prefix1: + { + /* we do no handle these */ + b++; + prefix = 0; + continue; + } + + default: /* should not happen*/ + case 0: /* do nothing */ + ; + } + + prefix = 0; + KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80); + b++; + } + } +} + +static int LinuxKbdTrans; +static struct termios LinuxTermios; + +static Status +LinuxKeyboardEnable (KdKeyboardInfo *ki) +{ + struct termios nTty; + unsigned char buf[256]; + int n; + int fd; + + if (!ki) + return !Success; + + fd = LinuxConsoleFd; + ki->driverPrivate = (void *) fd; + + ioctl (fd, KDGKBMODE, &LinuxKbdTrans); + tcgetattr (fd, &LinuxTermios); + ioctl(fd, KDSKBMODE, K_RAW); + nTty = LinuxTermios; + nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); + nTty.c_oflag = 0; + nTty.c_cflag = CREAD | CS8; + nTty.c_lflag = 0; + nTty.c_cc[VTIME]=0; + nTty.c_cc[VMIN]=1; + cfsetispeed(&nTty, 9600); + cfsetospeed(&nTty, 9600); + tcsetattr(fd, TCSANOW, &nTty); + /* + * Flush any pending keystrokes + */ + while ((n = read (fd, buf, sizeof (buf))) > 0) + ; + KdRegisterFd (fd, LinuxKeyboardRead, ki); + return Success; +} + +static void +LinuxKeyboardDisable (KdKeyboardInfo *ki) +{ + int fd; + + if (!ki) + return; + + fd = (int) ki->driverPrivate; + + KdUnregisterFd(ki, fd, FALSE); + ioctl(fd, KDSKBMODE, LinuxKbdTrans); + tcsetattr(fd, TCSANOW, &LinuxTermios); +} + +static Status +LinuxKeyboardInit (KdKeyboardInfo *ki) +{ + if (!ki) + return !Success; + + free(ki->path); + ki->path = strdup("console"); + free(ki->name); + ki->name = strdup("Linux console keyboard"); + + readKernelMapping (ki); + + return Success; +} + +static void +LinuxKeyboardLeds (KdKeyboardInfo *ki, int leds) +{ + if (!ki) + return; + + ioctl ((int)ki->driverPrivate, KDSETLED, leds & 7); +} + +KdKeyboardDriver LinuxKeyboardDriver = { + "keyboard", + .Init = LinuxKeyboardInit, + .Enable = LinuxKeyboardEnable, + .Leds = LinuxKeyboardLeds, + .Disable = LinuxKeyboardDisable, +}; diff --git a/xorg-server/hw/kdrive/linux/linux.c b/xorg-server/hw/kdrive/linux/linux.c index 9863c1424..a53db4965 100644 --- a/xorg-server/hw/kdrive/linux/linux.c +++ b/xorg-server/hw/kdrive/linux/linux.c @@ -1,5 +1,5 @@ /* - * Copyright © 1999 Keith Packard + * Copyright © 1999 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 diff --git a/xorg-server/hw/kdrive/linux/mouse.c b/xorg-server/hw/kdrive/linux/mouse.c index 2e39d240e..93c207817 100644 --- a/xorg-server/hw/kdrive/linux/mouse.c +++ b/xorg-server/hw/kdrive/linux/mouse.c @@ -1,1030 +1,1030 @@ -/*
- * Copyright © 2001 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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_CONFIG_H
-#include <kdrive-config.h>
-#endif
-#include <errno.h>
-#include <termios.h>
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#include <X11/Xpoll.h>
-#include "inputstr.h"
-#include "scrnintstr.h"
-#include "kdrive.h"
-
-#undef DEBUG
-#undef DEBUG_BYTES
-#define KBUFIO_SIZE 256
-#define MOUSE_TIMEOUT 100
-
-typedef struct _kbufio {
- int fd;
- unsigned char buf[KBUFIO_SIZE];
- int avail;
- int used;
-} Kbufio;
-
-static Bool
-MouseWaitForReadable (int fd, int timeout)
-{
- fd_set set;
- struct timeval tv, *tp;
- int n;
- CARD32 done;
-
- done = GetTimeInMillis () + timeout;
- for (;;)
- {
- FD_ZERO (&set);
- FD_SET (fd, &set);
- if (timeout == -1)
- tp = 0;
- else
- {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- tp = &tv;
- }
- n = select (fd + 1, &set, 0, 0, tp);
- if (n > 0)
- return TRUE;
- if (n < 0 && (errno == EAGAIN || errno == EINTR))
- {
- timeout = (int) (done - GetTimeInMillis ());
- if (timeout > 0)
- continue;
- }
- break;
- }
- return FALSE;
-}
-
-static int
-MouseReadByte (Kbufio *b, int timeout)
-{
- int n;
- if (b->avail <= b->used)
- {
- if (timeout && !MouseWaitForReadable (b->fd, timeout))
- {
-#ifdef DEBUG_BYTES
- ErrorF ("\tTimeout %d\n", timeout);
-#endif
- return -1;
- }
- n = read (b->fd, b->buf, KBUFIO_SIZE);
- if (n <= 0)
- return -1;
- b->avail = n;
- b->used = 0;
- }
-#ifdef DEBUG_BYTES
- ErrorF ("\tget %02x\n", b->buf[b->used]);
-#endif
- return b->buf[b->used++];
-}
-
-#if NOTUSED
-static int
-MouseFlush (Kbufio *b, char *buf, int size)
-{
- CARD32 now = GetTimeInMillis ();
- CARD32 done = now + 100;
- int c;
- int n = 0;
-
- while ((c = MouseReadByte (b, done - now)) != -1)
- {
- if (buf)
- {
- if (n == size)
- {
- memmove (buf, buf + 1, size - 1);
- n--;
- }
- buf[n++] = c;
- }
- now = GetTimeInMillis ();
- if ((INT32) (now - done) >= 0)
- break;
- }
- return n;
-}
-
-static int
-MousePeekByte (Kbufio *b, int timeout)
-{
- int c;
-
- c = MouseReadByte (b, timeout);
- if (c != -1)
- --b->used;
- return c;
-}
-#endif /* NOTUSED */
-
-static Bool
-MouseWaitForWritable (int fd, int timeout)
-{
- fd_set set;
- struct timeval tv, *tp;
- int n;
-
- FD_ZERO (&set);
- FD_SET (fd, &set);
- if (timeout == -1)
- tp = 0;
- else
- {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- tp = &tv;
- }
- n = select (fd + 1, 0, &set, 0, tp);
- if (n > 0)
- return TRUE;
- return FALSE;
-}
-
-static Bool
-MouseWriteByte (int fd, unsigned char c, int timeout)
-{
- int ret;
-
-#ifdef DEBUG_BYTES
- ErrorF ("\tput %02x\n", c);
-#endif
- for (;;)
- {
- ret = write (fd, &c, 1);
- if (ret == 1)
- return TRUE;
- if (ret == 0)
- return FALSE;
- if (errno != EWOULDBLOCK)
- return FALSE;
- if (!MouseWaitForWritable (fd, timeout))
- return FALSE;
- }
-}
-
-static Bool
-MouseWriteBytes (int fd, unsigned char *c, int n, int timeout)
-{
- while (n--)
- if (!MouseWriteByte (fd, *c++, timeout))
- return FALSE;
- return TRUE;
-}
-
-#define MAX_MOUSE 10 /* maximum length of mouse protocol */
-#define MAX_SKIP 16 /* number of error bytes before switching */
-#define MAX_VALID 4 /* number of valid packets before accepting */
-
-typedef struct _kmouseProt {
- char *name;
- Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne);
- int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne);
- Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne);
- Bool (*Init) (KdPointerInfo *pi);
- unsigned char headerMask, headerValid;
- unsigned char dataMask, dataValid;
- Bool tty;
- unsigned int c_iflag;
- unsigned int c_oflag;
- unsigned int c_lflag;
- unsigned int c_cflag;
- unsigned int speed;
- unsigned char *init;
- unsigned long state;
-} KmouseProt;
-
-typedef enum _kmouseStage {
- MouseBroken, MouseTesting, MouseWorking
-} KmouseStage;
-
-typedef struct _kmouse {
- Kbufio iob;
- const KmouseProt *prot;
- int i_prot;
- KmouseStage stage; /* protocol verification stage */
- Bool tty; /* mouse device is a tty */
- int valid; /* sequential valid events */
- int tested; /* bytes scanned during Testing phase */
- int invalid;/* total invalid bytes for this protocol */
- unsigned long state; /* private per protocol, init to prot->state */
-} Kmouse;
-
-static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
- const KmouseProt *prot = km->prot;
- int i;
-
- for (i = 0; i < ne; i++)
- if ((ev[i] & prot->headerMask) == prot->headerValid)
- break;
- if (i != 0)
- return i;
- for (i = 1; i < ne; i++)
- if ((ev[i] & prot->dataMask) != prot->dataValid)
- return -1;
- return 0;
-}
-
-static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- return ne == 3;
-}
-
-static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- return ne == 4;
-}
-
-static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- return ne == 5;
-}
-
-static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy)
-{
- Kmouse *km = pi->driverPrivate;
-
- if (km->stage == MouseWorking)
- return TRUE;
- if (dx < -50 || dx > 50)
- {
-#ifdef DEBUG
- ErrorF ("Large X %d\n", dx);
-#endif
- return FALSE;
- }
- if (dy < -50 || dy > 50)
- {
-#ifdef DEBUG
- ErrorF ("Large Y %d\n", dy);
-#endif
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * Standard PS/2 mouse protocol
- */
-static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
- int dx, dy, dz;
- unsigned long flags;
- unsigned long flagsrelease = 0;
-
- flags = KD_MOUSE_DELTA;
- if (ev[0] & 4)
- flags |= KD_BUTTON_2;
- if (ev[0] & 2)
- flags |= KD_BUTTON_3;
- if (ev[0] & 1)
- flags |= KD_BUTTON_1;
-
- if (ne > 3)
- {
- dz = (int) (signed char) ev[3];
- if (dz < 0)
- {
- flags |= KD_BUTTON_4;
- flagsrelease = KD_BUTTON_4;
- }
- else if (dz > 0)
- {
- flags |= KD_BUTTON_5;
- flagsrelease = KD_BUTTON_5;
- }
- }
-
- dx = ev[1];
- if (ev[0] & 0x10)
- dx -= 256;
- dy = ev[2];
- if (ev[0] & 0x20)
- dy -= 256;
- dy = -dy;
- if (!MouseReasonable (pi, flags, dx, dy))
- return FALSE;
- if (km->stage == MouseWorking)
- {
- KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
- if (flagsrelease)
- {
- flags &= ~flagsrelease;
- KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
- }
- }
- return TRUE;
-}
-
-static Bool ps2Init (KdPointerInfo *pi);
-
-static const KmouseProt ps2Prot = {
- "ps/2",
- threeComplete, mouseValid, ps2Parse, ps2Init,
- 0x08, 0x08, 0x00, 0x00,
- FALSE
-};
-
-static const KmouseProt imps2Prot = {
- "imps/2",
- fourComplete, mouseValid, ps2Parse, ps2Init,
- 0x08, 0x08, 0x00, 0x00,
- FALSE
-};
-
-static const KmouseProt exps2Prot = {
- "exps/2",
- fourComplete, mouseValid, ps2Parse, ps2Init,
- 0x08, 0x08, 0x00, 0x00,
- FALSE
-};
-
-/*
- * Once the mouse is known to speak ps/2 protocol, go and find out
- * what advanced capabilities it has and turn them on
- */
-
-/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */
-
-/* aux device commands (sent to KBD_DATA_PORT) */
-#define PSMC_SET_SCALING11 0x00e6
-#define PSMC_SET_SCALING21 0x00e7
-#define PSMC_SET_RESOLUTION 0x00e8
-#define PSMC_SEND_DEV_STATUS 0x00e9
-#define PSMC_SET_STREAM_MODE 0x00ea
-#define PSMC_SEND_DEV_DATA 0x00eb
-#define PSMC_SET_REMOTE_MODE 0x00f0
-#define PSMC_SEND_DEV_ID 0x00f2
-#define PSMC_SET_SAMPLING_RATE 0x00f3
-#define PSMC_ENABLE_DEV 0x00f4
-#define PSMC_DISABLE_DEV 0x00f5
-#define PSMC_SET_DEFAULTS 0x00f6
-#define PSMC_RESET_DEV 0x00ff
-
-/* PSMC_SET_RESOLUTION argument */
-#define PSMD_RES_LOW 0 /* typically 25ppi */
-#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */
-#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */
-#define PSMD_RES_HIGH 3 /* typically 200ppi */
-#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH
-
-/* PSMC_SET_SAMPLING_RATE */
-#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */
-
-/* aux device ID */
-#define PSM_MOUSE_ID 0
-#define PSM_BALLPOINT_ID 2
-#define PSM_INTELLI_ID 3
-#define PSM_EXPLORER_ID 4
-#define PSM_4DMOUSE_ID 6
-#define PSM_4DPLUS_ID 8
-
-static unsigned char ps2_init[] = {
- PSMC_ENABLE_DEV,
- 0,
-};
-
-#define NINIT_PS2 1
-
-static unsigned char wheel_3button_init[] = {
- PSMC_SET_SAMPLING_RATE, 200,
- PSMC_SET_SAMPLING_RATE, 100,
- PSMC_SET_SAMPLING_RATE, 80,
- PSMC_SEND_DEV_ID,
- 0,
-};
-
-#define NINIT_IMPS2 4
-
-static unsigned char wheel_5button_init[] = {
- PSMC_SET_SAMPLING_RATE, 200,
- PSMC_SET_SAMPLING_RATE, 100,
- PSMC_SET_SAMPLING_RATE, 80,
- PSMC_SET_SAMPLING_RATE, 200,
- PSMC_SET_SAMPLING_RATE, 200,
- PSMC_SET_SAMPLING_RATE, 80,
- PSMC_SEND_DEV_ID,
- 0
-};
-
-#define NINIT_EXPS2 7
-
-static unsigned char intelli_init[] = {
- PSMC_SET_SAMPLING_RATE, 200,
- PSMC_SET_SAMPLING_RATE, 100,
- PSMC_SET_SAMPLING_RATE, 80,
- 0
-};
-
-#define NINIT_INTELLI 3
-
-static int
-ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next)
-{
- Kmouse *km = pi->driverPrivate;
- int c = -1;
- int skipping;
- Bool waiting;
-
- skipping = 0;
- waiting = FALSE;
- while (ninit || ret_next)
- {
- c = MouseReadByte (&km->iob, MOUSE_TIMEOUT);
- if (c == -1)
- break;
- /* look for ACK */
- if (c == 0xfa)
- {
- ninit--;
- if (ret_next)
- waiting = TRUE;
- }
- /* look for packet start -- not the response */
- else if ((c & 0x08) == 0x08)
- waiting = FALSE;
- else if (waiting)
- break;
- }
- return c;
-}
-
-static Bool
-ps2Init (KdPointerInfo *pi)
-{
- Kmouse *km = pi->driverPrivate;
- int skipping;
- Bool waiting;
- int id;
- unsigned char *init;
- int ninit;
-
- /* Send Intellimouse initialization sequence */
- MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100);
- /*
- * Send ID command
- */
- if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100))
- return FALSE;
- skipping = 0;
- waiting = FALSE;
- id = ps2SkipInit (pi, 0, TRUE);
- switch (id) {
- case 3:
- init = wheel_3button_init;
- ninit = NINIT_IMPS2;
- km->prot = &imps2Prot;
- break;
- case 4:
- init = wheel_5button_init;
- ninit = NINIT_EXPS2;
- km->prot = &exps2Prot;
- break;
- default:
- init = ps2_init;
- ninit = NINIT_PS2;
- km->prot = &ps2Prot;
- break;
- }
- if (init)
- MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100);
- /*
- * Flush out the available data to eliminate responses to the
- * initialization string. Make sure any partial event is
- * skipped
- */
- (void) ps2SkipInit (pi, ninit, FALSE);
- return TRUE;
-}
-
-static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
- int dx, dy;
- unsigned long flags;
-
- flags = KD_MOUSE_DELTA;
- dx = (signed char) ev[1];
- dy = -(signed char) ev[2];
- if ((ev[0] & 4) == 0)
- flags |= KD_BUTTON_1;
- if ((ev[0] & 2) == 0)
- flags |= KD_BUTTON_2;
- if ((ev[0] & 1) == 0)
- flags |= KD_BUTTON_3;
- if (!MouseReasonable (pi, flags, dx, dy))
- return FALSE;
- if (km->stage == MouseWorking)
- KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
- return TRUE;
-}
-
-static const KmouseProt busProt = {
- "bus",
- threeComplete, mouseValid, busParse, 0,
- 0xf8, 0x00, 0x00, 0x00,
- FALSE
-};
-
-/*
- * Standard MS serial protocol, three bytes
- */
-
-static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
- int dx, dy;
- unsigned long flags;
-
- flags = KD_MOUSE_DELTA;
-
- if (ev[0] & 0x20)
- flags |= KD_BUTTON_1;
- if (ev[0] & 0x10)
- flags |= KD_BUTTON_3;
-
- dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
- dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
- if (!MouseReasonable (pi, flags, dx, dy))
- return FALSE;
- if (km->stage == MouseWorking)
- KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
- return TRUE;
-}
-
-static const KmouseProt msProt = {
- "ms",
- threeComplete, mouseValid, msParse, 0,
- 0xc0, 0x40, 0xc0, 0x00,
- TRUE,
- IGNPAR,
- 0,
- 0,
- CS7 | CSTOPB | CREAD | CLOCAL,
- B1200,
-};
-
-/*
- * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the
- * first byte of a synchronized protocol stream and see if it's got
- * any bits turned on that can't occur in that fourth byte
- */
-static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
-
- if ((ev[0] & 0x40) == 0x40)
- return ne == 3;
- if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0)
- return ne == 1;
- return FALSE;
-}
-
-static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
- const KmouseProt *prot = km->prot;
- int i;
-
- for (i = 0; i < ne; i++)
- {
- if ((ev[i] & 0x40) == 0x40)
- break;
- if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0)
- break;
- }
- if (i != 0)
- return i;
- for (i = 1; i < ne; i++)
- if ((ev[i] & prot->dataMask) != prot->dataValid)
- return -1;
- return 0;
-}
-
-static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
- int dx, dy;
- unsigned long flags;
-
- flags = KD_MOUSE_DELTA;
-
- if (ne == 3)
- {
- if (ev[0] & 0x20)
- flags |= KD_BUTTON_1;
- if (ev[0] & 0x10)
- flags |= KD_BUTTON_3;
-
- dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
- dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
- flags |= km->state & KD_BUTTON_2;
- }
- else
- {
- if (ev[0] & 0x20)
- flags |= KD_BUTTON_2;
- dx = 0;
- dy = 0;
- flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3);
- }
-
- if (!MouseReasonable (pi, flags, dx, dy))
- return FALSE;
- if (km->stage == MouseWorking)
- KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
- return TRUE;
-}
-
-static const KmouseProt logiProt = {
- "logitech",
- logiComplete, logiValid, logiParse, 0,
- 0xc0, 0x40, 0xc0, 0x00,
- TRUE,
- IGNPAR,
- 0,
- 0,
- CS7 | CSTOPB | CREAD | CLOCAL,
- B1200,
-};
-
-/*
- * Mouse systems protocol, 5 bytes
- */
-static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne)
-{
- Kmouse *km = pi->driverPrivate;
- int dx, dy;
- unsigned long flags;
-
- flags = KD_MOUSE_DELTA;
-
- if (!(ev[0] & 0x4))
- flags |= KD_BUTTON_1;
- if (!(ev[0] & 0x2))
- flags |= KD_BUTTON_2;
- if (!(ev[0] & 0x1))
- flags |= KD_BUTTON_3;
- dx = (signed char)(ev[1]) + (signed char)(ev[3]);
- dy = - ((signed char)(ev[2]) + (signed char)(ev[4]));
-
- if (!MouseReasonable (pi, flags, dx, dy))
- return FALSE;
- if (km->stage == MouseWorking)
- KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
- return TRUE;
-}
-
-static const KmouseProt mscProt = {
- "msc",
- fiveComplete, mouseValid, mscParse, 0,
- 0xf8, 0x80, 0x00, 0x00,
- TRUE,
- IGNPAR,
- 0,
- 0,
- CS8 | CSTOPB | CREAD | CLOCAL,
- B1200,
-};
-
-/*
- * Use logitech before ms -- they're the same except that
- * logitech sometimes has a fourth byte
- */
-static const KmouseProt *kmouseProts[] = {
- &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt,
-};
-
-#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0]))
-
-static void
-MouseInitProtocol (Kmouse *km)
-{
- int ret;
- struct termios t;
-
- if (km->prot->tty)
- {
- ret = tcgetattr (km->iob.fd, &t);
-
- if (ret >= 0)
- {
- t.c_iflag = km->prot->c_iflag;
- t.c_oflag = km->prot->c_oflag;
- t.c_lflag = km->prot->c_lflag;
- t.c_cflag = km->prot->c_cflag;
- cfsetispeed (&t, km->prot->speed);
- cfsetospeed (&t, km->prot->speed);
- ret = tcsetattr (km->iob.fd, TCSANOW, &t);
- }
- }
- km->stage = MouseBroken;
- km->valid = 0;
- km->tested = 0;
- km->invalid = 0;
- km->state = km->prot->state;
-}
-
-static void
-MouseFirstProtocol (Kmouse *km, char *prot)
-{
- if (prot)
- {
- for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++)
- if (!strcmp (prot, kmouseProts[km->i_prot]->name))
- break;
- if (km->i_prot == NUM_PROT)
- {
- int i;
- ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot);
- for (i = 0; i < NUM_PROT; i++)
- ErrorF (" %s", kmouseProts[i]->name);
- ErrorF ("\n");
- }
- else
- {
- km->prot = kmouseProts[km->i_prot];
- if (km->tty && !km->prot->tty)
- ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n",
- prot);
- else if (!km->tty && km->prot->tty)
- ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n",
- prot);
- }
- }
- if (!km->prot)
- {
- for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++)
- ;
- km->prot = kmouseProts[km->i_prot];
- }
- MouseInitProtocol (km);
-}
-
-static void
-MouseNextProtocol (Kmouse *km)
-{
- do
- {
- if (!km->prot)
- km->i_prot = 0;
- else
- if (++km->i_prot == NUM_PROT) km->i_prot = 0;
- km->prot = kmouseProts[km->i_prot];
- } while (km->prot->tty != km->tty);
- MouseInitProtocol (km);
- ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name);
-}
-
-static void
-MouseRead (int mousePort, void *closure)
-{
- KdPointerInfo *pi = closure;
- Kmouse *km = pi->driverPrivate;
- unsigned char event[MAX_MOUSE];
- int ne;
- int c;
- int i;
- int timeout;
-
- timeout = 0;
- ne = 0;
- for(;;)
- {
- c = MouseReadByte (&km->iob, timeout);
- if (c == -1)
- {
- if (ne)
- {
- km->invalid += ne + km->tested;
- km->valid = 0;
- km->tested = 0;
- km->stage = MouseBroken;
- }
- break;
- }
- event[ne++] = c;
- i = (*km->prot->Valid) (pi, event, ne);
- if (i != 0)
- {
-#ifdef DEBUG
- ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n",
- km->prot->name, i > 0 ? i : ne, ne);
-#endif
- if (i > 0 && i < ne)
- {
- ne -= i;
- memmove (event, event + i, ne);
- }
- else
- {
- i = ne;
- ne = 0;
- }
- km->invalid += i + km->tested;
- km->valid = 0;
- km->tested = 0;
- if (km->stage == MouseWorking)
- km->i_prot--;
- km->stage = MouseBroken;
- if (km->invalid > MAX_SKIP)
- {
- MouseNextProtocol (km);
- ne = 0;
- }
- timeout = 0;
- }
- else
- {
- if ((*km->prot->Complete) (pi, event, ne))
- {
- if ((*km->prot->Parse) (pi, event, ne))
- {
- switch (km->stage)
- {
- case MouseBroken:
-#ifdef DEBUG
- ErrorF ("Mouse protocol %s seems OK\n",
- km->prot->name);
-#endif
- /* do not zero invalid to accumulate invalid bytes */
- km->valid = 0;
- km->tested = 0;
- km->stage = MouseTesting;
- /* fall through ... */
- case MouseTesting:
- km->valid++;
- km->tested += ne;
- if (km->valid > MAX_VALID)
- {
-#ifdef DEBUG
- ErrorF ("Mouse protocol %s working\n",
- km->prot->name);
-#endif
- km->stage = MouseWorking;
- km->invalid = 0;
- km->tested = 0;
- km->valid = 0;
- if (km->prot->Init && !(*km->prot->Init) (pi))
- km->stage = MouseBroken;
- }
- break;
- case MouseWorking:
- break;
- }
- }
- else
- {
- km->invalid += ne + km->tested;
- km->valid = 0;
- km->tested = 0;
- km->stage = MouseBroken;
- }
- ne = 0;
- timeout = 0;
- }
- else
- timeout = MOUSE_TIMEOUT;
- }
- }
-}
-
-int MouseInputType;
-
-char *kdefaultMouse[] = {
- "/dev/input/mice",
- "/dev/mouse",
- "/dev/psaux",
- "/dev/adbmouse",
- "/dev/ttyS0",
- "/dev/ttyS1",
-};
-
-#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))
-
-static Status
-MouseInit (KdPointerInfo *pi)
-{
- int i;
- int fd;
- Kmouse *km;
-
- if (!pi)
- return BadImplementation;
-
- if (!pi->path || strcmp(pi->path, "auto") == 0) {
- for (i = 0; i < NUM_DEFAULT_MOUSE; i++) {
- fd = open (kdefaultMouse[i], 2);
- if (fd >= 0) {
- pi->path = strdup (kdefaultMouse[i]);
- break;
- }
- }
- }
- else {
- fd = open (pi->path, 2);
- }
-
- if (fd < 0)
- return BadMatch;
-
- close(fd);
-
- km = (Kmouse *) malloc(sizeof (Kmouse));
- if (km) {
- km->iob.avail = km->iob.used = 0;
- MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2");
- /* MouseFirstProtocol sets state to MouseBroken for later protocol
- * checks. Skip these checks if a protocol was supplied */
- if (pi->protocol)
- km->state = MouseWorking;
- km->i_prot = 0;
- km->tty = isatty (fd);
- km->iob.fd = -1;
- pi->driverPrivate = km;
- }
- else {
- close (fd);
- return BadAlloc;
- }
-
- return Success;
-}
-
-static Status
-MouseEnable (KdPointerInfo *pi)
-{
- Kmouse *km;
-
- if (!pi || !pi->driverPrivate || !pi->path)
- return BadImplementation;
-
- km = pi->driverPrivate;
-
- km->iob.fd = open(pi->path, 2);
- if (km->iob.fd < 0)
- return BadMatch;
-
- if (!KdRegisterFd (km->iob.fd, MouseRead, pi))
- {
- close(km->iob.fd);
- return BadAlloc;
- }
-
- return Success;
-}
-
-static void
-MouseDisable (KdPointerInfo *pi)
-{
- Kmouse *km;
- if (!pi || !pi->driverPrivate)
- return;
-
- km = pi->driverPrivate;
- KdUnregisterFd (pi, km->iob.fd, TRUE);
-}
-
-static void
-MouseFini (KdPointerInfo *pi)
-{
- free(pi->driverPrivate);
- pi->driverPrivate = NULL;
-}
-
-KdPointerDriver LinuxMouseDriver = {
- "mouse",
- MouseInit,
- MouseEnable,
- MouseDisable,
- MouseFini,
- NULL,
-};
+/* + * Copyright © 2001 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include <errno.h> +#include <termios.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xpoll.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" + +#undef DEBUG +#undef DEBUG_BYTES +#define KBUFIO_SIZE 256 +#define MOUSE_TIMEOUT 100 + +typedef struct _kbufio { + int fd; + unsigned char buf[KBUFIO_SIZE]; + int avail; + int used; +} Kbufio; + +static Bool +MouseWaitForReadable (int fd, int timeout) +{ + fd_set set; + struct timeval tv, *tp; + int n; + CARD32 done; + + done = GetTimeInMillis () + timeout; + for (;;) + { + FD_ZERO (&set); + FD_SET (fd, &set); + if (timeout == -1) + tp = 0; + else + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tp = &tv; + } + n = select (fd + 1, &set, 0, 0, tp); + if (n > 0) + return TRUE; + if (n < 0 && (errno == EAGAIN || errno == EINTR)) + { + timeout = (int) (done - GetTimeInMillis ()); + if (timeout > 0) + continue; + } + break; + } + return FALSE; +} + +static int +MouseReadByte (Kbufio *b, int timeout) +{ + int n; + if (b->avail <= b->used) + { + if (timeout && !MouseWaitForReadable (b->fd, timeout)) + { +#ifdef DEBUG_BYTES + ErrorF ("\tTimeout %d\n", timeout); +#endif + return -1; + } + n = read (b->fd, b->buf, KBUFIO_SIZE); + if (n <= 0) + return -1; + b->avail = n; + b->used = 0; + } +#ifdef DEBUG_BYTES + ErrorF ("\tget %02x\n", b->buf[b->used]); +#endif + return b->buf[b->used++]; +} + +#if NOTUSED +static int +MouseFlush (Kbufio *b, char *buf, int size) +{ + CARD32 now = GetTimeInMillis (); + CARD32 done = now + 100; + int c; + int n = 0; + + while ((c = MouseReadByte (b, done - now)) != -1) + { + if (buf) + { + if (n == size) + { + memmove (buf, buf + 1, size - 1); + n--; + } + buf[n++] = c; + } + now = GetTimeInMillis (); + if ((INT32) (now - done) >= 0) + break; + } + return n; +} + +static int +MousePeekByte (Kbufio *b, int timeout) +{ + int c; + + c = MouseReadByte (b, timeout); + if (c != -1) + --b->used; + return c; +} +#endif /* NOTUSED */ + +static Bool +MouseWaitForWritable (int fd, int timeout) +{ + fd_set set; + struct timeval tv, *tp; + int n; + + FD_ZERO (&set); + FD_SET (fd, &set); + if (timeout == -1) + tp = 0; + else + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tp = &tv; + } + n = select (fd + 1, 0, &set, 0, tp); + if (n > 0) + return TRUE; + return FALSE; +} + +static Bool +MouseWriteByte (int fd, unsigned char c, int timeout) +{ + int ret; + +#ifdef DEBUG_BYTES + ErrorF ("\tput %02x\n", c); +#endif + for (;;) + { + ret = write (fd, &c, 1); + if (ret == 1) + return TRUE; + if (ret == 0) + return FALSE; + if (errno != EWOULDBLOCK) + return FALSE; + if (!MouseWaitForWritable (fd, timeout)) + return FALSE; + } +} + +static Bool +MouseWriteBytes (int fd, unsigned char *c, int n, int timeout) +{ + while (n--) + if (!MouseWriteByte (fd, *c++, timeout)) + return FALSE; + return TRUE; +} + +#define MAX_MOUSE 10 /* maximum length of mouse protocol */ +#define MAX_SKIP 16 /* number of error bytes before switching */ +#define MAX_VALID 4 /* number of valid packets before accepting */ + +typedef struct _kmouseProt { + char *name; + Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne); + int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne); + Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne); + Bool (*Init) (KdPointerInfo *pi); + unsigned char headerMask, headerValid; + unsigned char dataMask, dataValid; + Bool tty; + unsigned int c_iflag; + unsigned int c_oflag; + unsigned int c_lflag; + unsigned int c_cflag; + unsigned int speed; + unsigned char *init; + unsigned long state; +} KmouseProt; + +typedef enum _kmouseStage { + MouseBroken, MouseTesting, MouseWorking +} KmouseStage; + +typedef struct _kmouse { + Kbufio iob; + const KmouseProt *prot; + int i_prot; + KmouseStage stage; /* protocol verification stage */ + Bool tty; /* mouse device is a tty */ + int valid; /* sequential valid events */ + int tested; /* bytes scanned during Testing phase */ + int invalid;/* total invalid bytes for this protocol */ + unsigned long state; /* private per protocol, init to prot->state */ +} Kmouse; + +static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + const KmouseProt *prot = km->prot; + int i; + + for (i = 0; i < ne; i++) + if ((ev[i] & prot->headerMask) == prot->headerValid) + break; + if (i != 0) + return i; + for (i = 1; i < ne; i++) + if ((ev[i] & prot->dataMask) != prot->dataValid) + return -1; + return 0; +} + +static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 3; +} + +static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 4; +} + +static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 5; +} + +static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy) +{ + Kmouse *km = pi->driverPrivate; + + if (km->stage == MouseWorking) + return TRUE; + if (dx < -50 || dx > 50) + { +#ifdef DEBUG + ErrorF ("Large X %d\n", dx); +#endif + return FALSE; + } + if (dy < -50 || dy > 50) + { +#ifdef DEBUG + ErrorF ("Large Y %d\n", dy); +#endif + return FALSE; + } + return TRUE; +} + +/* + * Standard PS/2 mouse protocol + */ +static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy, dz; + unsigned long flags; + unsigned long flagsrelease = 0; + + flags = KD_MOUSE_DELTA; + if (ev[0] & 4) + flags |= KD_BUTTON_2; + if (ev[0] & 2) + flags |= KD_BUTTON_3; + if (ev[0] & 1) + flags |= KD_BUTTON_1; + + if (ne > 3) + { + dz = (int) (signed char) ev[3]; + if (dz < 0) + { + flags |= KD_BUTTON_4; + flagsrelease = KD_BUTTON_4; + } + else if (dz > 0) + { + flags |= KD_BUTTON_5; + flagsrelease = KD_BUTTON_5; + } + } + + dx = ev[1]; + if (ev[0] & 0x10) + dx -= 256; + dy = ev[2]; + if (ev[0] & 0x20) + dy -= 256; + dy = -dy; + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + { + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + if (flagsrelease) + { + flags &= ~flagsrelease; + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + } + } + return TRUE; +} + +static Bool ps2Init (KdPointerInfo *pi); + +static const KmouseProt ps2Prot = { + "ps/2", + threeComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +static const KmouseProt imps2Prot = { + "imps/2", + fourComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +static const KmouseProt exps2Prot = { + "exps/2", + fourComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +/* + * Once the mouse is known to speak ps/2 protocol, go and find out + * what advanced capabilities it has and turn them on + */ + +/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */ + +/* aux device commands (sent to KBD_DATA_PORT) */ +#define PSMC_SET_SCALING11 0x00e6 +#define PSMC_SET_SCALING21 0x00e7 +#define PSMC_SET_RESOLUTION 0x00e8 +#define PSMC_SEND_DEV_STATUS 0x00e9 +#define PSMC_SET_STREAM_MODE 0x00ea +#define PSMC_SEND_DEV_DATA 0x00eb +#define PSMC_SET_REMOTE_MODE 0x00f0 +#define PSMC_SEND_DEV_ID 0x00f2 +#define PSMC_SET_SAMPLING_RATE 0x00f3 +#define PSMC_ENABLE_DEV 0x00f4 +#define PSMC_DISABLE_DEV 0x00f5 +#define PSMC_SET_DEFAULTS 0x00f6 +#define PSMC_RESET_DEV 0x00ff + +/* PSMC_SET_RESOLUTION argument */ +#define PSMD_RES_LOW 0 /* typically 25ppi */ +#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ +#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ +#define PSMD_RES_HIGH 3 /* typically 200ppi */ +#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH + +/* PSMC_SET_SAMPLING_RATE */ +#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ + +/* aux device ID */ +#define PSM_MOUSE_ID 0 +#define PSM_BALLPOINT_ID 2 +#define PSM_INTELLI_ID 3 +#define PSM_EXPLORER_ID 4 +#define PSM_4DMOUSE_ID 6 +#define PSM_4DPLUS_ID 8 + +static unsigned char ps2_init[] = { + PSMC_ENABLE_DEV, + 0, +}; + +#define NINIT_PS2 1 + +static unsigned char wheel_3button_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SEND_DEV_ID, + 0, +}; + +#define NINIT_IMPS2 4 + +static unsigned char wheel_5button_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SEND_DEV_ID, + 0 +}; + +#define NINIT_EXPS2 7 + +static unsigned char intelli_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + 0 +}; + +#define NINIT_INTELLI 3 + +static int +ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next) +{ + Kmouse *km = pi->driverPrivate; + int c = -1; + int skipping; + Bool waiting; + + skipping = 0; + waiting = FALSE; + while (ninit || ret_next) + { + c = MouseReadByte (&km->iob, MOUSE_TIMEOUT); + if (c == -1) + break; + /* look for ACK */ + if (c == 0xfa) + { + ninit--; + if (ret_next) + waiting = TRUE; + } + /* look for packet start -- not the response */ + else if ((c & 0x08) == 0x08) + waiting = FALSE; + else if (waiting) + break; + } + return c; +} + +static Bool +ps2Init (KdPointerInfo *pi) +{ + Kmouse *km = pi->driverPrivate; + int skipping; + Bool waiting; + int id; + unsigned char *init; + int ninit; + + /* Send Intellimouse initialization sequence */ + MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100); + /* + * Send ID command + */ + if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100)) + return FALSE; + skipping = 0; + waiting = FALSE; + id = ps2SkipInit (pi, 0, TRUE); + switch (id) { + case 3: + init = wheel_3button_init; + ninit = NINIT_IMPS2; + km->prot = &imps2Prot; + break; + case 4: + init = wheel_5button_init; + ninit = NINIT_EXPS2; + km->prot = &exps2Prot; + break; + default: + init = ps2_init; + ninit = NINIT_PS2; + km->prot = &ps2Prot; + break; + } + if (init) + MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100); + /* + * Flush out the available data to eliminate responses to the + * initialization string. Make sure any partial event is + * skipped + */ + (void) ps2SkipInit (pi, ninit, FALSE); + return TRUE; +} + +static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + dx = (signed char) ev[1]; + dy = -(signed char) ev[2]; + if ((ev[0] & 4) == 0) + flags |= KD_BUTTON_1; + if ((ev[0] & 2) == 0) + flags |= KD_BUTTON_2; + if ((ev[0] & 1) == 0) + flags |= KD_BUTTON_3; + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt busProt = { + "bus", + threeComplete, mouseValid, busParse, 0, + 0xf8, 0x00, 0x00, 0x00, + FALSE +}; + +/* + * Standard MS serial protocol, three bytes + */ + +static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (ev[0] & 0x20) + flags |= KD_BUTTON_1; + if (ev[0] & 0x10) + flags |= KD_BUTTON_3; + + dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt msProt = { + "ms", + threeComplete, mouseValid, msParse, 0, + 0xc0, 0x40, 0xc0, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS7 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the + * first byte of a synchronized protocol stream and see if it's got + * any bits turned on that can't occur in that fourth byte + */ +static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + + if ((ev[0] & 0x40) == 0x40) + return ne == 3; + if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0) + return ne == 1; + return FALSE; +} + +static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + const KmouseProt *prot = km->prot; + int i; + + for (i = 0; i < ne; i++) + { + if ((ev[i] & 0x40) == 0x40) + break; + if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0) + break; + } + if (i != 0) + return i; + for (i = 1; i < ne; i++) + if ((ev[i] & prot->dataMask) != prot->dataValid) + return -1; + return 0; +} + +static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (ne == 3) + { + if (ev[0] & 0x20) + flags |= KD_BUTTON_1; + if (ev[0] & 0x10) + flags |= KD_BUTTON_3; + + dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); + flags |= km->state & KD_BUTTON_2; + } + else + { + if (ev[0] & 0x20) + flags |= KD_BUTTON_2; + dx = 0; + dy = 0; + flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3); + } + + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt logiProt = { + "logitech", + logiComplete, logiValid, logiParse, 0, + 0xc0, 0x40, 0xc0, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS7 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Mouse systems protocol, 5 bytes + */ +static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (!(ev[0] & 0x4)) + flags |= KD_BUTTON_1; + if (!(ev[0] & 0x2)) + flags |= KD_BUTTON_2; + if (!(ev[0] & 0x1)) + flags |= KD_BUTTON_3; + dx = (signed char)(ev[1]) + (signed char)(ev[3]); + dy = - ((signed char)(ev[2]) + (signed char)(ev[4])); + + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt mscProt = { + "msc", + fiveComplete, mouseValid, mscParse, 0, + 0xf8, 0x80, 0x00, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS8 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Use logitech before ms -- they're the same except that + * logitech sometimes has a fourth byte + */ +static const KmouseProt *kmouseProts[] = { + &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt, +}; + +#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0])) + +static void +MouseInitProtocol (Kmouse *km) +{ + int ret; + struct termios t; + + if (km->prot->tty) + { + ret = tcgetattr (km->iob.fd, &t); + + if (ret >= 0) + { + t.c_iflag = km->prot->c_iflag; + t.c_oflag = km->prot->c_oflag; + t.c_lflag = km->prot->c_lflag; + t.c_cflag = km->prot->c_cflag; + cfsetispeed (&t, km->prot->speed); + cfsetospeed (&t, km->prot->speed); + ret = tcsetattr (km->iob.fd, TCSANOW, &t); + } + } + km->stage = MouseBroken; + km->valid = 0; + km->tested = 0; + km->invalid = 0; + km->state = km->prot->state; +} + +static void +MouseFirstProtocol (Kmouse *km, char *prot) +{ + if (prot) + { + for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++) + if (!strcmp (prot, kmouseProts[km->i_prot]->name)) + break; + if (km->i_prot == NUM_PROT) + { + int i; + ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot); + for (i = 0; i < NUM_PROT; i++) + ErrorF (" %s", kmouseProts[i]->name); + ErrorF ("\n"); + } + else + { + km->prot = kmouseProts[km->i_prot]; + if (km->tty && !km->prot->tty) + ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n", + prot); + else if (!km->tty && km->prot->tty) + ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n", + prot); + } + } + if (!km->prot) + { + for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++) + ; + km->prot = kmouseProts[km->i_prot]; + } + MouseInitProtocol (km); +} + +static void +MouseNextProtocol (Kmouse *km) +{ + do + { + if (!km->prot) + km->i_prot = 0; + else + if (++km->i_prot == NUM_PROT) km->i_prot = 0; + km->prot = kmouseProts[km->i_prot]; + } while (km->prot->tty != km->tty); + MouseInitProtocol (km); + ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name); +} + +static void +MouseRead (int mousePort, void *closure) +{ + KdPointerInfo *pi = closure; + Kmouse *km = pi->driverPrivate; + unsigned char event[MAX_MOUSE]; + int ne; + int c; + int i; + int timeout; + + timeout = 0; + ne = 0; + for(;;) + { + c = MouseReadByte (&km->iob, timeout); + if (c == -1) + { + if (ne) + { + km->invalid += ne + km->tested; + km->valid = 0; + km->tested = 0; + km->stage = MouseBroken; + } + break; + } + event[ne++] = c; + i = (*km->prot->Valid) (pi, event, ne); + if (i != 0) + { +#ifdef DEBUG + ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n", + km->prot->name, i > 0 ? i : ne, ne); +#endif + if (i > 0 && i < ne) + { + ne -= i; + memmove (event, event + i, ne); + } + else + { + i = ne; + ne = 0; + } + km->invalid += i + km->tested; + km->valid = 0; + km->tested = 0; + if (km->stage == MouseWorking) + km->i_prot--; + km->stage = MouseBroken; + if (km->invalid > MAX_SKIP) + { + MouseNextProtocol (km); + ne = 0; + } + timeout = 0; + } + else + { + if ((*km->prot->Complete) (pi, event, ne)) + { + if ((*km->prot->Parse) (pi, event, ne)) + { + switch (km->stage) + { + case MouseBroken: +#ifdef DEBUG + ErrorF ("Mouse protocol %s seems OK\n", + km->prot->name); +#endif + /* do not zero invalid to accumulate invalid bytes */ + km->valid = 0; + km->tested = 0; + km->stage = MouseTesting; + /* fall through ... */ + case MouseTesting: + km->valid++; + km->tested += ne; + if (km->valid > MAX_VALID) + { +#ifdef DEBUG + ErrorF ("Mouse protocol %s working\n", + km->prot->name); +#endif + km->stage = MouseWorking; + km->invalid = 0; + km->tested = 0; + km->valid = 0; + if (km->prot->Init && !(*km->prot->Init) (pi)) + km->stage = MouseBroken; + } + break; + case MouseWorking: + break; + } + } + else + { + km->invalid += ne + km->tested; + km->valid = 0; + km->tested = 0; + km->stage = MouseBroken; + } + ne = 0; + timeout = 0; + } + else + timeout = MOUSE_TIMEOUT; + } + } +} + +int MouseInputType; + +char *kdefaultMouse[] = { + "/dev/input/mice", + "/dev/mouse", + "/dev/psaux", + "/dev/adbmouse", + "/dev/ttyS0", + "/dev/ttyS1", +}; + +#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0])) + +static Status +MouseInit (KdPointerInfo *pi) +{ + int i; + int fd; + Kmouse *km; + + if (!pi) + return BadImplementation; + + if (!pi->path || strcmp(pi->path, "auto") == 0) { + for (i = 0; i < NUM_DEFAULT_MOUSE; i++) { + fd = open (kdefaultMouse[i], 2); + if (fd >= 0) { + pi->path = strdup (kdefaultMouse[i]); + break; + } + } + } + else { + fd = open (pi->path, 2); + } + + if (fd < 0) + return BadMatch; + + close(fd); + + km = (Kmouse *) malloc(sizeof (Kmouse)); + if (km) { + km->iob.avail = km->iob.used = 0; + MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2"); + /* MouseFirstProtocol sets state to MouseBroken for later protocol + * checks. Skip these checks if a protocol was supplied */ + if (pi->protocol) + km->state = MouseWorking; + km->i_prot = 0; + km->tty = isatty (fd); + km->iob.fd = -1; + pi->driverPrivate = km; + } + else { + close (fd); + return BadAlloc; + } + + return Success; +} + +static Status +MouseEnable (KdPointerInfo *pi) +{ + Kmouse *km; + + if (!pi || !pi->driverPrivate || !pi->path) + return BadImplementation; + + km = pi->driverPrivate; + + km->iob.fd = open(pi->path, 2); + if (km->iob.fd < 0) + return BadMatch; + + if (!KdRegisterFd (km->iob.fd, MouseRead, pi)) + { + close(km->iob.fd); + return BadAlloc; + } + + return Success; +} + +static void +MouseDisable (KdPointerInfo *pi) +{ + Kmouse *km; + if (!pi || !pi->driverPrivate) + return; + + km = pi->driverPrivate; + KdUnregisterFd (pi, km->iob.fd, TRUE); +} + +static void +MouseFini (KdPointerInfo *pi) +{ + free(pi->driverPrivate); + pi->driverPrivate = NULL; +} + +KdPointerDriver LinuxMouseDriver = { + "mouse", + MouseInit, + MouseEnable, + MouseDisable, + MouseFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/linux/ps2.c b/xorg-server/hw/kdrive/linux/ps2.c index 552a3c7cb..465b963f2 100644 --- a/xorg-server/hw/kdrive/linux/ps2.c +++ b/xorg-server/hw/kdrive/linux/ps2.c @@ -1,5 +1,5 @@ /* - * Copyright © 1999 Keith Packard + * Copyright © 1999 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 diff --git a/xorg-server/hw/kdrive/linux/tslib.c b/xorg-server/hw/kdrive/linux/tslib.c index 8d6007390..1f30ccae7 100644 --- a/xorg-server/hw/kdrive/linux/tslib.c +++ b/xorg-server/hw/kdrive/linux/tslib.c @@ -1,197 +1,197 @@ -/*
- * TSLIB based touchscreen driver for KDrive
- * Porting to new input API and event queueing by Daniel Stone.
- * Derived from ts.c by Keith Packard
- * Derived from ps2.c by Jim Gettys
- *
- * Copyright © 1999 Keith Packard
- * Copyright © 2000 Compaq Computer Corporation
- * Copyright © 2002 MontaVista Software Inc.
- * Copyright © 2005 OpenedHand Ltd.
- * Copyright © 2006 Nokia Corporation
- *
- * 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 authors and/or copyright holders
- * not be used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission. The authors and/or
- * 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 AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR 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_KDRIVE_CONFIG_H
-#include <kdrive-config.h>
-#endif
-
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#include <X11/Xpoll.h>
-#include "inputstr.h"
-#include "scrnintstr.h"
-#include "kdrive.h"
-#include <sys/ioctl.h>
-#include <tslib.h>
-#include <dirent.h>
-#include <linux/input.h>
-
-struct TslibPrivate {
- int fd;
- int lastx, lasty;
- struct tsdev *tsDev;
- void (*raw_event_hook)(int x, int y, int pressure, void *closure);
- void *raw_event_closure;
- int phys_screen;
-};
-
-
-static void
-TsRead (int fd, void *closure)
-{
- KdPointerInfo *pi = closure;
- struct TslibPrivate *private = pi->driverPrivate;
- struct ts_sample event;
- long x = 0, y = 0;
- unsigned long flags;
-
- if (private->raw_event_hook) {
- while (ts_read_raw(private->tsDev, &event, 1) == 1)
- private->raw_event_hook (event.x, event.y, event.pressure,
- private->raw_event_closure);
- return;
- }
-
- while (ts_read(private->tsDev, &event, 1) == 1) {
- if (event.pressure) {
- flags = KD_BUTTON_1;
-
- /*
- * Here we test for the touch screen driver actually being on the
- * touch screen, if it is we send absolute coordinates. If not,
- * then we send delta's so that we can track the entire vga screen.
- */
- if (KdCurScreen == private->phys_screen) {
- x = event.x;
- y = event.y;
- } else {
- flags |= KD_MOUSE_DELTA;
- if ((private->lastx == 0) || (private->lasty == 0)) {
- x = event.x;
- y = event.y;
- } else {
- x = event.x - private->lastx;
- y = event.y - private->lasty;
- }
- }
- private->lastx = event.x;
- private->lasty = event.y;
- } else {
- flags = 0;
- x = private->lastx;
- y = private->lasty;
- }
-
- KdEnqueuePointerEvent (pi, flags, x, y, event.pressure);
- }
-}
-
-static Status
-TslibEnable (KdPointerInfo *pi)
-{
- struct TslibPrivate *private = pi->driverPrivate;
-
- private->raw_event_hook = NULL;
- private->raw_event_closure = NULL;
- if (!pi->path) {
- pi->path = strdup("/dev/input/touchscreen0");
- ErrorF("[tslib/TslibEnable] no device path given, trying %s\n", pi->path);
- }
-
- private->tsDev = ts_open(pi->path, 0);
- if (!private->tsDev) {
- ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path);
- return BadAlloc;
- }
-
- if (ts_config(private->tsDev)) {
- ErrorF("[tslib/TslibEnable] failed to load configuration\n");
- ts_close(private->tsDev);
- private->tsDev = NULL;
- return BadValue;
- }
-
- private->fd = ts_fd(private->tsDev);
-
- KdRegisterFd(private->fd, TsRead, pi);
-
- return Success;
-}
-
-
-static void
-TslibDisable (KdPointerInfo *pi)
-{
- struct TslibPrivate *private = pi->driverPrivate;
-
- if (private->fd)
- KdUnregisterFd(pi, private->fd, TRUE);
-
- if (private->tsDev)
- ts_close(private->tsDev);
-
- private->fd = 0;
- private->tsDev = NULL;
-}
-
-
-static Status
-TslibInit (KdPointerInfo *pi)
-{
- struct TslibPrivate *private = NULL;
-
- if (!pi || !pi->dixdev)
- return !Success;
-
- pi->driverPrivate = (struct TslibPrivate *)
- calloc(sizeof(struct TslibPrivate), 1);
- if (!pi->driverPrivate)
- return !Success;
-
- private = pi->driverPrivate;
- /* hacktastic */
- private->phys_screen = 0;
- pi->nAxes = 3;
- pi->name = strdup("Touchscreen");
- pi->inputClass = KD_TOUCHSCREEN;
-
- return Success;
-}
-
-
-static void
-TslibFini (KdPointerInfo *pi)
-{
- free(pi->driverPrivate);
- pi->driverPrivate = NULL;
-}
-
-
-KdPointerDriver TsDriver = {
- "tslib",
- TslibInit,
- TslibEnable,
- TslibDisable,
- TslibFini,
- NULL,
-};
+/* + * TSLIB based touchscreen driver for KDrive + * Porting to new input API and event queueing by Daniel Stone. + * Derived from ts.c by Keith Packard + * Derived from ps2.c by Jim Gettys + * + * Copyright © 1999 Keith Packard + * Copyright © 2000 Compaq Computer Corporation + * Copyright © 2002 MontaVista Software Inc. + * Copyright © 2005 OpenedHand Ltd. + * Copyright © 2006 Nokia Corporation + * + * 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 authors and/or copyright holders + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. The authors and/or + * 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 AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR 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_KDRIVE_CONFIG_H +#include <kdrive-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xpoll.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" +#include <sys/ioctl.h> +#include <tslib.h> +#include <dirent.h> +#include <linux/input.h> + +struct TslibPrivate { + int fd; + int lastx, lasty; + struct tsdev *tsDev; + void (*raw_event_hook)(int x, int y, int pressure, void *closure); + void *raw_event_closure; + int phys_screen; +}; + + +static void +TsRead (int fd, void *closure) +{ + KdPointerInfo *pi = closure; + struct TslibPrivate *private = pi->driverPrivate; + struct ts_sample event; + long x = 0, y = 0; + unsigned long flags; + + if (private->raw_event_hook) { + while (ts_read_raw(private->tsDev, &event, 1) == 1) + private->raw_event_hook (event.x, event.y, event.pressure, + private->raw_event_closure); + return; + } + + while (ts_read(private->tsDev, &event, 1) == 1) { + if (event.pressure) { + flags = KD_BUTTON_1; + + /* + * Here we test for the touch screen driver actually being on the + * touch screen, if it is we send absolute coordinates. If not, + * then we send delta's so that we can track the entire vga screen. + */ + if (KdCurScreen == private->phys_screen) { + x = event.x; + y = event.y; + } else { + flags |= KD_MOUSE_DELTA; + if ((private->lastx == 0) || (private->lasty == 0)) { + x = event.x; + y = event.y; + } else { + x = event.x - private->lastx; + y = event.y - private->lasty; + } + } + private->lastx = event.x; + private->lasty = event.y; + } else { + flags = 0; + x = private->lastx; + y = private->lasty; + } + + KdEnqueuePointerEvent (pi, flags, x, y, event.pressure); + } +} + +static Status +TslibEnable (KdPointerInfo *pi) +{ + struct TslibPrivate *private = pi->driverPrivate; + + private->raw_event_hook = NULL; + private->raw_event_closure = NULL; + if (!pi->path) { + pi->path = strdup("/dev/input/touchscreen0"); + ErrorF("[tslib/TslibEnable] no device path given, trying %s\n", pi->path); + } + + private->tsDev = ts_open(pi->path, 0); + if (!private->tsDev) { + ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path); + return BadAlloc; + } + + if (ts_config(private->tsDev)) { + ErrorF("[tslib/TslibEnable] failed to load configuration\n"); + ts_close(private->tsDev); + private->tsDev = NULL; + return BadValue; + } + + private->fd = ts_fd(private->tsDev); + + KdRegisterFd(private->fd, TsRead, pi); + + return Success; +} + + +static void +TslibDisable (KdPointerInfo *pi) +{ + struct TslibPrivate *private = pi->driverPrivate; + + if (private->fd) + KdUnregisterFd(pi, private->fd, TRUE); + + if (private->tsDev) + ts_close(private->tsDev); + + private->fd = 0; + private->tsDev = NULL; +} + + +static Status +TslibInit (KdPointerInfo *pi) +{ + struct TslibPrivate *private = NULL; + + if (!pi || !pi->dixdev) + return !Success; + + pi->driverPrivate = (struct TslibPrivate *) + calloc(sizeof(struct TslibPrivate), 1); + if (!pi->driverPrivate) + return !Success; + + private = pi->driverPrivate; + /* hacktastic */ + private->phys_screen = 0; + pi->nAxes = 3; + pi->name = strdup("Touchscreen"); + pi->inputClass = KD_TOUCHSCREEN; + + return Success; +} + + +static void +TslibFini (KdPointerInfo *pi) +{ + free(pi->driverPrivate); + pi->driverPrivate = NULL; +} + + +KdPointerDriver TsDriver = { + "tslib", + TslibInit, + TslibEnable, + TslibDisable, + TslibFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/src/kcmap.c b/xorg-server/hw/kdrive/src/kcmap.c index 127c7a078..6e0fc1417 100644 --- a/xorg-server/hw/kdrive/src/kcmap.c +++ b/xorg-server/hw/kdrive/src/kcmap.c @@ -1,246 +1,246 @@ -/*
- * Copyright © 1999 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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_CONFIG_H
-#include <kdrive-config.h>
-#endif
-#include "kdrive.h"
-
-/*
- * Put the entire colormap into the DAC
- */
-
-void
-KdSetColormap (ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
- ColormapPtr pCmap = pScreenPriv->pInstalledmap;
- Pixel pixels[KD_MAX_PSEUDO_SIZE];
- xrgb colors[KD_MAX_PSEUDO_SIZE];
- xColorItem defs[KD_MAX_PSEUDO_SIZE];
- int i;
-
- if (!pScreenPriv->card->cfuncs->putColors)
- return;
- if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH)
- return;
-
- if (!pScreenPriv->enabled)
- return;
-
- if (!pCmap)
- return;
-
- /*
- * Make DIX convert pixels into RGB values -- this handles
- * true/direct as well as pseudo/static visuals
- */
-
- for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++)
- pixels[i] = i;
-
- QueryColors (pCmap, (1 << pScreenPriv->screen->fb.depth), pixels, colors, serverClient);
-
- for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++)
- {
- defs[i].pixel = i;
- defs[i].red = colors[i].red;
- defs[i].green = colors[i].green;
- defs[i].blue = colors[i].blue;
- defs[i].flags = DoRed|DoGreen|DoBlue;
- }
-
- (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen,
- (1 << pScreenPriv->screen->fb.depth),
- defs);
-
- /* recolor hardware cursor */
- if (pScreenPriv->card->cfuncs->recolorCursor)
- (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, 0, 0);
-}
-
-/*
- * When the hardware is enabled, save the hardware colors and store
- * the current colormap
- */
-void
-KdEnableColormap (ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
- int i;
-
- if (!pScreenPriv->card->cfuncs->putColors)
- return;
-
- if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH)
- {
- for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++)
- pScreenPriv->systemPalette[i].pixel = i;
- (*pScreenPriv->card->cfuncs->getColors) (pScreen,
- (1 << pScreenPriv->screen->fb.depth),
- pScreenPriv->systemPalette);
- }
- KdSetColormap (pScreen);
-}
-
-void
-KdDisableColormap (ScreenPtr pScreen)
-{
- KdScreenPriv(pScreen);
-
- if (!pScreenPriv->card->cfuncs->putColors)
- return;
-
- if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH)
- {
- (*pScreenPriv->card->cfuncs->putColors) (pScreen,
- (1 << pScreenPriv->screen->fb.depth),
- pScreenPriv->systemPalette);
- }
-}
-
-/*
- * KdInstallColormap
- *
- * This function is called when the server receives a request to install a
- * colormap or when the server needs to install one on its own, like when
- * there's no window manager running and the user has moved the pointer over
- * an X client window. It needs to build an identity Windows palette for the
- * colormap and realize it into the Windows system palette.
- */
-void
-KdInstallColormap (ColormapPtr pCmap)
-{
- KdScreenPriv(pCmap->pScreen);
-
- if (pCmap == pScreenPriv->pInstalledmap)
- return;
-
- /* Tell X clients that the installed colormap is going away. */
- if (pScreenPriv->pInstalledmap)
- WalkTree(pScreenPriv->pInstalledmap->pScreen, TellLostMap,
- (pointer) &(pScreenPriv->pInstalledmap->mid));
-
- /* Take note of the new installed colorscreen-> */
- pScreenPriv->pInstalledmap = pCmap;
-
- KdSetColormap (pCmap->pScreen);
-
- /* Tell X clients of the new colormap */
- WalkTree(pCmap->pScreen, TellGainedMap, (pointer) &(pCmap->mid));
-}
-
-/*
- * KdUninstallColormap
- *
- * This function uninstalls a colormap by either installing
- * the default X colormap or erasing the installed colormap pointer.
- * The default X colormap itself cannot be uninstalled.
- */
-void
-KdUninstallColormap (ColormapPtr pCmap)
-{
- KdScreenPriv(pCmap->pScreen);
- Colormap defMapID;
- ColormapPtr defMap;
-
- /* ignore if not installed */
- if (pCmap != pScreenPriv->pInstalledmap)
- return;
-
- /* ignore attempts to uninstall default colormap */
- defMapID = pCmap->pScreen->defColormap;
- if ((Colormap) pCmap->mid == defMapID)
- return;
-
- /* install default */
- dixLookupResourceByType((pointer *)&defMap, defMapID, RT_COLORMAP,
- serverClient, DixInstallAccess);
- if (defMap)
- (*pCmap->pScreen->InstallColormap)(defMap);
- else
- {
- /* uninstall and clear colormap pointer */
- WalkTree(pCmap->pScreen, TellLostMap,
- (pointer) &(pCmap->mid));
- pScreenPriv->pInstalledmap = 0;
- }
-}
-
-int
-KdListInstalledColormaps (ScreenPtr pScreen, Colormap *pCmaps)
-{
- KdScreenPriv(pScreen);
- int n = 0;
-
- if (pScreenPriv->pInstalledmap)
- {
- *pCmaps++ = pScreenPriv->pInstalledmap->mid;
- n++;
- }
- return n;
-}
-
-/*
- * KdStoreColors
- *
- * This function is called whenever the server receives a request to store
- * color values into one or more entries in the currently installed X
- * colormap; it can be either the default colormap or a private colorscreen->
- */
-void
-KdStoreColors (ColormapPtr pCmap, int ndef, xColorItem *pdefs)
-{
- KdScreenPriv(pCmap->pScreen);
- VisualPtr pVisual;
- xColorItem expanddefs[KD_MAX_PSEUDO_SIZE];
-
- if (pCmap != pScreenPriv->pInstalledmap)
- return;
-
- if (!pScreenPriv->card->cfuncs->putColors)
- return;
-
- if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH)
- return;
-
- if (!pScreenPriv->enabled)
- return;
-
- /* Check for DirectColor or TrueColor being simulated on a PseudoColor device. */
- pVisual = pCmap->pVisual;
- if ((pVisual->class | DynamicClass) == DirectColor)
- {
- /*
- * Expand DirectColor or TrueColor color values into a PseudoColor
- * format. Defer to the Color Framebuffer (CFB) code to do that.
- */
- ndef = fbExpandDirectColors(pCmap, ndef, pdefs, expanddefs);
- pdefs = expanddefs;
- }
-
- (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs);
-
- /* recolor hardware cursor */
- if (pScreenPriv->card->cfuncs->recolorCursor)
- (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, ndef, pdefs);
-}
+/* + * Copyright © 1999 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" + +/* + * Put the entire colormap into the DAC + */ + +void +KdSetColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ColormapPtr pCmap = pScreenPriv->pInstalledmap; + Pixel pixels[KD_MAX_PSEUDO_SIZE]; + xrgb colors[KD_MAX_PSEUDO_SIZE]; + xColorItem defs[KD_MAX_PSEUDO_SIZE]; + int i; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) + return; + + if (!pScreenPriv->enabled) + return; + + if (!pCmap) + return; + + /* + * Make DIX convert pixels into RGB values -- this handles + * true/direct as well as pseudo/static visuals + */ + + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + pixels[i] = i; + + QueryColors (pCmap, (1 << pScreenPriv->screen->fb.depth), pixels, colors, serverClient); + + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + { + defs[i].pixel = i; + defs[i].red = colors[i].red; + defs[i].green = colors[i].green; + defs[i].blue = colors[i].blue; + defs[i].flags = DoRed|DoGreen|DoBlue; + } + + (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, + (1 << pScreenPriv->screen->fb.depth), + defs); + + /* recolor hardware cursor */ + if (pScreenPriv->card->cfuncs->recolorCursor) + (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, 0, 0); +} + +/* + * When the hardware is enabled, save the hardware colors and store + * the current colormap + */ +void +KdEnableColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + int i; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) + { + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + pScreenPriv->systemPalette[i].pixel = i; + (*pScreenPriv->card->cfuncs->getColors) (pScreen, + (1 << pScreenPriv->screen->fb.depth), + pScreenPriv->systemPalette); + } + KdSetColormap (pScreen); +} + +void +KdDisableColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) + { + (*pScreenPriv->card->cfuncs->putColors) (pScreen, + (1 << pScreenPriv->screen->fb.depth), + pScreenPriv->systemPalette); + } +} + +/* + * KdInstallColormap + * + * This function is called when the server receives a request to install a + * colormap or when the server needs to install one on its own, like when + * there's no window manager running and the user has moved the pointer over + * an X client window. It needs to build an identity Windows palette for the + * colormap and realize it into the Windows system palette. + */ +void +KdInstallColormap (ColormapPtr pCmap) +{ + KdScreenPriv(pCmap->pScreen); + + if (pCmap == pScreenPriv->pInstalledmap) + return; + + /* Tell X clients that the installed colormap is going away. */ + if (pScreenPriv->pInstalledmap) + WalkTree(pScreenPriv->pInstalledmap->pScreen, TellLostMap, + (pointer) &(pScreenPriv->pInstalledmap->mid)); + + /* Take note of the new installed colorscreen-> */ + pScreenPriv->pInstalledmap = pCmap; + + KdSetColormap (pCmap->pScreen); + + /* Tell X clients of the new colormap */ + WalkTree(pCmap->pScreen, TellGainedMap, (pointer) &(pCmap->mid)); +} + +/* + * KdUninstallColormap + * + * This function uninstalls a colormap by either installing + * the default X colormap or erasing the installed colormap pointer. + * The default X colormap itself cannot be uninstalled. + */ +void +KdUninstallColormap (ColormapPtr pCmap) +{ + KdScreenPriv(pCmap->pScreen); + Colormap defMapID; + ColormapPtr defMap; + + /* ignore if not installed */ + if (pCmap != pScreenPriv->pInstalledmap) + return; + + /* ignore attempts to uninstall default colormap */ + defMapID = pCmap->pScreen->defColormap; + if ((Colormap) pCmap->mid == defMapID) + return; + + /* install default */ + dixLookupResourceByType((pointer *)&defMap, defMapID, RT_COLORMAP, + serverClient, DixInstallAccess); + if (defMap) + (*pCmap->pScreen->InstallColormap)(defMap); + else + { + /* uninstall and clear colormap pointer */ + WalkTree(pCmap->pScreen, TellLostMap, + (pointer) &(pCmap->mid)); + pScreenPriv->pInstalledmap = 0; + } +} + +int +KdListInstalledColormaps (ScreenPtr pScreen, Colormap *pCmaps) +{ + KdScreenPriv(pScreen); + int n = 0; + + if (pScreenPriv->pInstalledmap) + { + *pCmaps++ = pScreenPriv->pInstalledmap->mid; + n++; + } + return n; +} + +/* + * KdStoreColors + * + * This function is called whenever the server receives a request to store + * color values into one or more entries in the currently installed X + * colormap; it can be either the default colormap or a private colorscreen-> + */ +void +KdStoreColors (ColormapPtr pCmap, int ndef, xColorItem *pdefs) +{ + KdScreenPriv(pCmap->pScreen); + VisualPtr pVisual; + xColorItem expanddefs[KD_MAX_PSEUDO_SIZE]; + + if (pCmap != pScreenPriv->pInstalledmap) + return; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) + return; + + if (!pScreenPriv->enabled) + return; + + /* Check for DirectColor or TrueColor being simulated on a PseudoColor device. */ + pVisual = pCmap->pVisual; + if ((pVisual->class | DynamicClass) == DirectColor) + { + /* + * Expand DirectColor or TrueColor color values into a PseudoColor + * format. Defer to the Color Framebuffer (CFB) code to do that. + */ + ndef = fbExpandDirectColors(pCmap, ndef, pdefs, expanddefs); + pdefs = expanddefs; + } + + (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs); + + /* recolor hardware cursor */ + if (pScreenPriv->card->cfuncs->recolorCursor) + (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, ndef, pdefs); +} diff --git a/xorg-server/hw/kdrive/src/kdrive.h b/xorg-server/hw/kdrive/src/kdrive.h index 2ab535aef..9ac5a19d7 100644 --- a/xorg-server/hw/kdrive/src/kdrive.h +++ b/xorg-server/hw/kdrive/src/kdrive.h @@ -1,5 +1,5 @@ /* - * Copyright © 1999 Keith Packard + * Copyright © 1999 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 @@ -500,6 +500,8 @@ KdScreenInfoDispose (KdScreenInfo *si); /* kinput.c */ void KdInitInput(void); +void +KdCloseInput(void); void KdAddPointerDriver(KdPointerDriver *); diff --git a/xorg-server/hw/kdrive/src/kinfo.c b/xorg-server/hw/kdrive/src/kinfo.c index 90fe37ae9..7055fbf4a 100644 --- a/xorg-server/hw/kdrive/src/kinfo.c +++ b/xorg-server/hw/kdrive/src/kinfo.c @@ -1,163 +1,163 @@ -/*
- * Copyright © 1999 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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_CONFIG_H
-#include <kdrive-config.h>
-#endif
-#include "kdrive.h"
-
-KdCardInfo *kdCardInfo;
-
-KdCardInfo *
-KdCardInfoAdd (KdCardFuncs *funcs,
- void *closure)
-{
- KdCardInfo *ci, **prev;
-
- ci = calloc(1, sizeof (KdCardInfo));
- if (!ci)
- return 0;
- for (prev = &kdCardInfo; *prev; prev = &(*prev)->next);
- *prev = ci;
- ci->cfuncs = funcs;
- ci->closure = closure;
- ci->screenList = 0;
- ci->selected = 0;
- ci->next = 0;
- return ci;
-}
-
-KdCardInfo *
-KdCardInfoLast (void)
-{
- KdCardInfo *ci;
-
- if (!kdCardInfo)
- return 0;
- for (ci = kdCardInfo; ci->next; ci = ci->next);
- return ci;
-}
-
-void
-KdCardInfoDispose (KdCardInfo *ci)
-{
- KdCardInfo **prev;
-
- for (prev = &kdCardInfo; *prev; prev = &(*prev)->next)
- if (*prev == ci)
- {
- *prev = ci->next;
- free(ci);
- break;
- }
-}
-
-KdScreenInfo *
-KdScreenInfoAdd (KdCardInfo *ci)
-{
- KdScreenInfo *si, **prev;
- int n;
-
- si = calloc(1, sizeof (KdScreenInfo));
- if (!si)
- return 0;
- for (prev = &ci->screenList, n = 0; *prev; prev = &(*prev)->next, n++);
- *prev = si;
- si->next = 0;
- si->card = ci;
- si->mynum = n;
- return si;
-}
-
-void
-KdScreenInfoDispose (KdScreenInfo *si)
-{
- KdCardInfo *ci = si->card;
- KdScreenInfo **prev;
-
- for (prev = &ci->screenList; *prev; prev = &(*prev)->next) {
- if (*prev == si)
- {
- *prev = si->next;
- free(si);
- if (!ci->screenList)
- KdCardInfoDispose (ci);
- break;
- }
- }
-}
-
-KdPointerInfo *
-KdNewPointer (void)
-{
- KdPointerInfo *pi;
- int i;
-
- pi = (KdPointerInfo *)calloc(1, sizeof(KdPointerInfo));
- if (!pi)
- return NULL;
-
- pi->name = strdup("Generic Pointer");
- pi->path = NULL;
- pi->inputClass = KD_MOUSE;
- pi->driver = NULL;
- pi->driverPrivate = NULL;
- pi->next = NULL;
- pi->options = NULL;
- pi->nAxes = 3;
- pi->nButtons = KD_MAX_BUTTON;
- for (i = 1; i < KD_MAX_BUTTON; i++)
- pi->map[i] = i;
-
- return pi;
-}
-
-void
-KdFreePointer(KdPointerInfo *pi)
-{
- InputOption *option, *prev = NULL;
-
- free(pi->name);
- free(pi->path);
-
- for (option = pi->options; option; option = option->next) {
- free(prev);
- free(option->key);
- free(option->value);
- prev = option;
- }
-
- free(prev);
- free(pi);
-}
-
-void
-KdFreeKeyboard(KdKeyboardInfo *ki)
-{
- free(ki->name);
- free(ki->path);
- free(ki->xkbRules);
- free(ki->xkbModel);
- free(ki->xkbLayout);
- ki->next = NULL;
- free(ki);
-}
+/* + * Copyright © 1999 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" + +KdCardInfo *kdCardInfo; + +KdCardInfo * +KdCardInfoAdd (KdCardFuncs *funcs, + void *closure) +{ + KdCardInfo *ci, **prev; + + ci = calloc(1, sizeof (KdCardInfo)); + if (!ci) + return 0; + for (prev = &kdCardInfo; *prev; prev = &(*prev)->next); + *prev = ci; + ci->cfuncs = funcs; + ci->closure = closure; + ci->screenList = 0; + ci->selected = 0; + ci->next = 0; + return ci; +} + +KdCardInfo * +KdCardInfoLast (void) +{ + KdCardInfo *ci; + + if (!kdCardInfo) + return 0; + for (ci = kdCardInfo; ci->next; ci = ci->next); + return ci; +} + +void +KdCardInfoDispose (KdCardInfo *ci) +{ + KdCardInfo **prev; + + for (prev = &kdCardInfo; *prev; prev = &(*prev)->next) + if (*prev == ci) + { + *prev = ci->next; + free(ci); + break; + } +} + +KdScreenInfo * +KdScreenInfoAdd (KdCardInfo *ci) +{ + KdScreenInfo *si, **prev; + int n; + + si = calloc(1, sizeof (KdScreenInfo)); + if (!si) + return 0; + for (prev = &ci->screenList, n = 0; *prev; prev = &(*prev)->next, n++); + *prev = si; + si->next = 0; + si->card = ci; + si->mynum = n; + return si; +} + +void +KdScreenInfoDispose (KdScreenInfo *si) +{ + KdCardInfo *ci = si->card; + KdScreenInfo **prev; + + for (prev = &ci->screenList; *prev; prev = &(*prev)->next) { + if (*prev == si) + { + *prev = si->next; + free(si); + if (!ci->screenList) + KdCardInfoDispose (ci); + break; + } + } +} + +KdPointerInfo * +KdNewPointer (void) +{ + KdPointerInfo *pi; + int i; + + pi = (KdPointerInfo *)calloc(1, sizeof(KdPointerInfo)); + if (!pi) + return NULL; + + pi->name = strdup("Generic Pointer"); + pi->path = NULL; + pi->inputClass = KD_MOUSE; + pi->driver = NULL; + pi->driverPrivate = NULL; + pi->next = NULL; + pi->options = NULL; + pi->nAxes = 3; + pi->nButtons = KD_MAX_BUTTON; + for (i = 1; i < KD_MAX_BUTTON; i++) + pi->map[i] = i; + + return pi; +} + +void +KdFreePointer(KdPointerInfo *pi) +{ + InputOption *option, *prev = NULL; + + free(pi->name); + free(pi->path); + + for (option = pi->options; option; option = option->next) { + free(prev); + free(option->key); + free(option->value); + prev = option; + } + + free(prev); + free(pi); +} + +void +KdFreeKeyboard(KdKeyboardInfo *ki) +{ + free(ki->name); + free(ki->path); + free(ki->xkbRules); + free(ki->xkbModel); + free(ki->xkbLayout); + ki->next = NULL; + free(ki); +} diff --git a/xorg-server/hw/kdrive/src/kinput.c b/xorg-server/hw/kdrive/src/kinput.c index cdf55d7f9..c14dd8241 100644 --- a/xorg-server/hw/kdrive/src/kinput.c +++ b/xorg-server/hw/kdrive/src/kinput.c @@ -1,6 +1,6 @@ /* - * Copyright © 1999 Keith Packard - * Copyright © 2006 Nokia Corporation + * Copyright © 1999 Keith Packard + * Copyright © 2006 Nokia Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -1305,6 +1305,12 @@ KdInitInput (void) mieqInit(); } +void +KdCloseInput (void) +{ + mieqFini(); +} + /* * Middle button emulation state machine * @@ -2159,7 +2165,6 @@ void ProcessInputEvents (void) { mieqProcessInputEvents(); - miPointerUpdateSprite(inputInfo.pointer); if (kdSwitchPending) KdProcessSwitch (); KdCheckLock (); diff --git a/xorg-server/hw/kdrive/src/kshadow.c b/xorg-server/hw/kdrive/src/kshadow.c index 4454020f0..63bb87bc6 100644 --- a/xorg-server/hw/kdrive/src/kshadow.c +++ b/xorg-server/hw/kdrive/src/kshadow.c @@ -1,81 +1,81 @@ -/*
- * Copyright © 1999 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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_CONFIG_H
-#include <kdrive-config.h>
-#endif
-#include "kdrive.h"
-
-Bool
-KdShadowFbAlloc (KdScreenInfo *screen, Bool rotate)
-{
- int paddedWidth;
- void *buf;
- int width = rotate ? screen->height : screen->width;
- int height = rotate ? screen->width : screen->height;
- int bpp = screen->fb.bitsPerPixel;
-
- /* use fb computation for width */
- paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits);
- buf = malloc(paddedWidth * height);
- if (!buf)
- return FALSE;
- if (screen->fb.shadow)
- free(screen->fb.frameBuffer);
- screen->fb.shadow = TRUE;
- screen->fb.frameBuffer = buf;
- screen->fb.byteStride = paddedWidth;
- screen->fb.pixelStride = paddedWidth * 8 / bpp;
- return TRUE;
-}
-
-void
-KdShadowFbFree (KdScreenInfo *screen)
-{
- if (screen->fb.shadow)
- {
- free(screen->fb.frameBuffer);
- screen->fb.frameBuffer = 0;
- screen->fb.shadow = FALSE;
- }
-}
-
-Bool
-KdShadowSet (ScreenPtr pScreen, int randr, ShadowUpdateProc update, ShadowWindowProc window)
-{
- KdScreenPriv(pScreen);
- KdScreenInfo *screen = pScreenPriv->screen;
-
- shadowRemove (pScreen, pScreen->GetScreenPixmap(pScreen));
- if(screen->fb.shadow)
- {
- return shadowAdd (pScreen, pScreen->GetScreenPixmap(pScreen),
- update, window, randr, 0);
- }
- return TRUE;
-}
-
-void
-KdShadowUnset (ScreenPtr pScreen)
-{
- shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
-}
+/* + * Copyright © 1999 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" + +Bool +KdShadowFbAlloc (KdScreenInfo *screen, Bool rotate) +{ + int paddedWidth; + void *buf; + int width = rotate ? screen->height : screen->width; + int height = rotate ? screen->width : screen->height; + int bpp = screen->fb.bitsPerPixel; + + /* use fb computation for width */ + paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); + buf = malloc(paddedWidth * height); + if (!buf) + return FALSE; + if (screen->fb.shadow) + free(screen->fb.frameBuffer); + screen->fb.shadow = TRUE; + screen->fb.frameBuffer = buf; + screen->fb.byteStride = paddedWidth; + screen->fb.pixelStride = paddedWidth * 8 / bpp; + return TRUE; +} + +void +KdShadowFbFree (KdScreenInfo *screen) +{ + if (screen->fb.shadow) + { + free(screen->fb.frameBuffer); + screen->fb.frameBuffer = 0; + screen->fb.shadow = FALSE; + } +} + +Bool +KdShadowSet (ScreenPtr pScreen, int randr, ShadowUpdateProc update, ShadowWindowProc window) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + shadowRemove (pScreen, pScreen->GetScreenPixmap(pScreen)); + if(screen->fb.shadow) + { + return shadowAdd (pScreen, pScreen->GetScreenPixmap(pScreen), + update, window, randr, 0); + } + return TRUE; +} + +void +KdShadowUnset (ScreenPtr pScreen) +{ + shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen)); +} diff --git a/xorg-server/hw/vfb/InitInput.c b/xorg-server/hw/vfb/InitInput.c index aba1a95fb..8836bbd7f 100644 --- a/xorg-server/hw/vfb/InitInput.c +++ b/xorg-server/hw/vfb/InitInput.c @@ -1,151 +1,152 @@ -/*
-
-Copyright 1993, 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.
-
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include "mi.h"
-#include <X11/Xproto.h>
-#include "scrnintstr.h"
-#include "inputstr.h"
-#include <X11/Xos.h>
-#include "mibstore.h"
-#include "mipointer.h"
-#include "xkbsrv.h"
-#include <X11/keysym.h>
-#include "xserver-properties.h"
-#include "exevents.h"
-#include "extinit.h"
-
-Bool
-LegalModifier(unsigned int key, DeviceIntPtr pDev)
-{
- return TRUE;
-}
-
-void
-ProcessInputEvents(void)
-{
- mieqProcessInputEvents();
-}
-
-void DDXRingBell(int volume, int pitch, int duration)
-{
-}
-
-#define VFB_MIN_KEY 8
-#define VFB_MAX_KEY 255
-
-static int
-vfbKeybdProc(DeviceIntPtr pDevice, int onoff)
-{
- DevicePtr pDev = (DevicePtr)pDevice;
-
- switch (onoff)
- {
- case DEVICE_INIT:
- InitKeyboardDeviceStruct(pDevice, NULL, NULL, NULL);
- break;
- case DEVICE_ON:
- pDev->on = TRUE;
- break;
- case DEVICE_OFF:
- pDev->on = FALSE;
- break;
- case DEVICE_CLOSE:
- break;
- }
- return Success;
-}
-
-static int
-vfbMouseProc(DeviceIntPtr pDevice, int onoff)
-{
-#define NBUTTONS 3
-#define NAXES 2
-
- BYTE map[NBUTTONS + 1];
- DevicePtr pDev = (DevicePtr)pDevice;
- Atom btn_labels[NBUTTONS] = {0};
- Atom axes_labels[NAXES] = {0};
-
- switch (onoff)
- {
- case DEVICE_INIT:
- map[1] = 1;
- map[2] = 2;
- map[3] = 3;
-
- btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
- btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
- btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
-
- axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
- axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
-
- InitPointerDeviceStruct(pDev, map, NBUTTONS, btn_labels,
- (PtrCtrlProcPtr)NoopDDA, GetMotionHistorySize(), NAXES, axes_labels);
- break;
-
- case DEVICE_ON:
- pDev->on = TRUE;
- break;
-
- case DEVICE_OFF:
- pDev->on = FALSE;
- break;
-
- case DEVICE_CLOSE:
- break;
- }
- return Success;
-
-#undef NBUTTONS
-#undef NAXES
-}
-
-void
-InitInput(int argc, char *argv[])
-{
- DeviceIntPtr p, k;
- Atom xiclass;
- p = AddInputDevice(serverClient, vfbMouseProc, TRUE);
- k = AddInputDevice(serverClient, vfbKeybdProc, TRUE);
- xiclass = MakeAtom(XI_MOUSE, sizeof(XI_MOUSE) - 1, TRUE);
- AssignTypeAndName(p, xiclass, "Xvfb mouse");
- xiclass = MakeAtom(XI_KEYBOARD, sizeof(XI_KEYBOARD) - 1, TRUE);
- AssignTypeAndName(k, xiclass, "Xvfb keyboard");
- (void)mieqInit();
-}
-
-void
-CloseInput (void)
-{
-}
+/* + +Copyright 1993, 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. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "mi.h" +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "inputstr.h" +#include <X11/Xos.h> +#include "mibstore.h" +#include "mipointer.h" +#include "xkbsrv.h" +#include <X11/keysym.h> +#include "xserver-properties.h" +#include "exevents.h" +#include "extinit.h" + +Bool +LegalModifier(unsigned int key, DeviceIntPtr pDev) +{ + return TRUE; +} + +void +ProcessInputEvents(void) +{ + mieqProcessInputEvents(); +} + +void DDXRingBell(int volume, int pitch, int duration) +{ +} + +#define VFB_MIN_KEY 8 +#define VFB_MAX_KEY 255 + +static int +vfbKeybdProc(DeviceIntPtr pDevice, int onoff) +{ + DevicePtr pDev = (DevicePtr)pDevice; + + switch (onoff) + { + case DEVICE_INIT: + InitKeyboardDeviceStruct(pDevice, NULL, NULL, NULL); + break; + case DEVICE_ON: + pDev->on = TRUE; + break; + case DEVICE_OFF: + pDev->on = FALSE; + break; + case DEVICE_CLOSE: + break; + } + return Success; +} + +static int +vfbMouseProc(DeviceIntPtr pDevice, int onoff) +{ +#define NBUTTONS 3 +#define NAXES 2 + + BYTE map[NBUTTONS + 1]; + DevicePtr pDev = (DevicePtr)pDevice; + Atom btn_labels[NBUTTONS] = {0}; + Atom axes_labels[NAXES] = {0}; + + switch (onoff) + { + case DEVICE_INIT: + map[1] = 1; + map[2] = 2; + map[3] = 3; + + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + + InitPointerDeviceStruct(pDev, map, NBUTTONS, btn_labels, + (PtrCtrlProcPtr)NoopDDA, GetMotionHistorySize(), NAXES, axes_labels); + break; + + case DEVICE_ON: + pDev->on = TRUE; + break; + + case DEVICE_OFF: + pDev->on = FALSE; + break; + + case DEVICE_CLOSE: + break; + } + return Success; + +#undef NBUTTONS +#undef NAXES +} + +void +InitInput(int argc, char *argv[]) +{ + DeviceIntPtr p, k; + Atom xiclass; + p = AddInputDevice(serverClient, vfbMouseProc, TRUE); + k = AddInputDevice(serverClient, vfbKeybdProc, TRUE); + xiclass = MakeAtom(XI_MOUSE, sizeof(XI_MOUSE) - 1, TRUE); + AssignTypeAndName(p, xiclass, "Xvfb mouse"); + xiclass = MakeAtom(XI_KEYBOARD, sizeof(XI_KEYBOARD) - 1, TRUE); + AssignTypeAndName(k, xiclass, "Xvfb keyboard"); + (void)mieqInit(); +} + +void +CloseInput (void) +{ + mieqFini(); +} diff --git a/xorg-server/hw/xfree86/common/xf86Init.c b/xorg-server/hw/xfree86/common/xf86Init.c index 53f763aaf..15fdbc349 100644 --- a/xorg-server/hw/xfree86/common/xf86Init.c +++ b/xorg-server/hw/xfree86/common/xf86Init.c @@ -825,6 +825,7 @@ void CloseInput (void) { config_fini(); + mieqFini(); } /* diff --git a/xorg-server/hw/xfree86/dixmods/xkbPrivate.c b/xorg-server/hw/xfree86/dixmods/xkbPrivate.c index 9742eaf31..06d1c2b3d 100644 --- a/xorg-server/hw/xfree86/dixmods/xkbPrivate.c +++ b/xorg-server/hw/xfree86/dixmods/xkbPrivate.c @@ -13,6 +13,7 @@ #define XKBSRV_NEED_FILE_FUNCS #include <xkbsrv.h> +#include "dixgrabs.h" #include "os.h" #include "xf86.h" @@ -29,6 +30,20 @@ XkbDDXPrivate(DeviceIntPtr dev,KeyCode key,XkbAction *act) xf86ProcessActionEvent(ACTION_PREV_MODE, NULL); else if (strcasecmp(msgbuf, "+vmode")==0) xf86ProcessActionEvent(ACTION_NEXT_MODE, NULL); + else if (strcasecmp(msgbuf, "prgrbs")==0) { + DeviceIntPtr tmp; + xf86Msg(X_INFO, "Printing all currently active device grabs:\n"); + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) + if (tmp->deviceGrab.grab) + PrintDeviceGrabInfo(tmp); + xf86Msg(X_INFO, "End list of active device grabs\n"); + } + else if (strcasecmp(msgbuf, "ungrab")==0) + UngrabAllDevices(FALSE); + else if (strcasecmp(msgbuf, "clsgrb")==0) + UngrabAllDevices(TRUE); + else if (strcasecmp(msgbuf, "prwins")==0) + PrintWindowTree(); } return 0; diff --git a/xorg-server/hw/xfree86/dri2/dri2.c b/xorg-server/hw/xfree86/dri2/dri2.c index bf7ebb9f8..af3bcaefe 100644 --- a/xorg-server/hw/xfree86/dri2/dri2.c +++ b/xorg-server/hw/xfree86/dri2/dri2.c @@ -1185,6 +1185,7 @@ void DRI2CloseScreen(ScreenPtr pScreen) { DRI2ScreenPtr ds = DRI2GetScreen(pScreen); + pScreen->ConfigNotify = ds->ConfigNotify; free(ds->driverNames); free(ds); diff --git a/xorg-server/hw/xfree86/exa/examodule.c b/xorg-server/hw/xfree86/exa/examodule.c index 356fd16ca..15560513d 100644 --- a/xorg-server/hw/xfree86/exa/examodule.c +++ b/xorg-server/hw/xfree86/exa/examodule.c @@ -1,201 +1,201 @@ -/*
- * Copyright © 2006 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Authors:
- * Eric Anholt <anholt@FreeBSD.org>
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <xorg-config.h>
-#endif
-
-#include <string.h>
-
-#include "exa_priv.h"
-
-#include "xf86str.h"
-#include "xf86.h"
-
-typedef struct _ExaXorgScreenPrivRec {
- CloseScreenProcPtr SavedCloseScreen;
- EnableDisableFBAccessProcPtr SavedEnableDisableFBAccess;
- OptionInfoPtr options;
-} ExaXorgScreenPrivRec, *ExaXorgScreenPrivPtr;
-
-static DevPrivateKeyRec exaXorgScreenPrivateKeyRec;
-#define exaXorgScreenPrivateKey (&exaXorgScreenPrivateKeyRec)
-
-typedef enum {
- EXAOPT_MIGRATION_HEURISTIC,
- EXAOPT_NO_COMPOSITE,
- EXAOPT_NO_UTS,
- EXAOPT_NO_DFS,
- EXAOPT_OPTIMIZE_MIGRATION
-} EXAOpts;
-
-static const OptionInfoRec EXAOptions[] = {
- { EXAOPT_MIGRATION_HEURISTIC, "MigrationHeuristic",
- OPTV_ANYSTR, {0}, FALSE },
- { EXAOPT_NO_COMPOSITE, "EXANoComposite",
- OPTV_BOOLEAN, {0}, FALSE },
- { EXAOPT_NO_UTS, "EXANoUploadToScreen",
- OPTV_BOOLEAN, {0}, FALSE },
- { EXAOPT_NO_DFS, "EXANoDownloadFromScreen",
- OPTV_BOOLEAN, {0}, FALSE },
- { EXAOPT_OPTIMIZE_MIGRATION, "EXAOptimizeMigration",
- OPTV_BOOLEAN, {0}, FALSE },
- { -1, NULL,
- OPTV_NONE, {0}, FALSE }
-};
-
-static Bool
-exaXorgCloseScreen (int i, ScreenPtr pScreen)
-{
- ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
- ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr)
- dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey);
-
- pScreen->CloseScreen = pScreenPriv->SavedCloseScreen;
-
- pScrn->EnableDisableFBAccess = pScreenPriv->SavedEnableDisableFBAccess;
-
- free(pScreenPriv->options);
- free(pScreenPriv);
-
- return pScreen->CloseScreen (i, pScreen);
-}
-
-static void
-exaXorgEnableDisableFBAccess (int index, Bool enable)
-{
- ScreenPtr pScreen = screenInfo.screens[index];
- ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr)
- dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey);
-
- if (!enable)
- exaEnableDisableFBAccess (index, enable);
-
- if (pScreenPriv->SavedEnableDisableFBAccess)
- pScreenPriv->SavedEnableDisableFBAccess (index, enable);
-
- if (enable)
- exaEnableDisableFBAccess (index, enable);
-}
-
-/**
- * This will be called during exaDriverInit, giving us the chance to set options
- * and hook in our EnableDisableFBAccess.
- */
-void
-exaDDXDriverInit(ScreenPtr pScreen)
-{
- ExaScreenPriv(pScreen);
- /* Do NOT use XF86SCRNINFO macro here!! */
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- ExaXorgScreenPrivPtr pScreenPriv;
-
- if (!dixRegisterPrivateKey(&exaXorgScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
- return;
-
- pScreenPriv = calloc(1, sizeof(ExaXorgScreenPrivRec));
- if (pScreenPriv == NULL)
- return;
-
- pScreenPriv->options = xnfalloc (sizeof(EXAOptions));
- memcpy(pScreenPriv->options, EXAOptions, sizeof(EXAOptions));
- xf86ProcessOptions (pScrn->scrnIndex, pScrn->options, pScreenPriv->options);
-
- if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) {
- if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) &&
- pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
- char *heuristicName;
-
- heuristicName = xf86GetOptValString (pScreenPriv->options,
- EXAOPT_MIGRATION_HEURISTIC);
- if (heuristicName != NULL) {
- if (strcmp(heuristicName, "greedy") == 0)
- pExaScr->migration = ExaMigrationGreedy;
- else if (strcmp(heuristicName, "always") == 0)
- pExaScr->migration = ExaMigrationAlways;
- else if (strcmp(heuristicName, "smart") == 0)
- pExaScr->migration = ExaMigrationSmart;
- else {
- xf86DrvMsg (pScreen->myNum, X_WARNING,
- "EXA: unknown migration heuristic %s\n",
- heuristicName);
- }
- }
- }
-
- pExaScr->optimize_migration =
- xf86ReturnOptValBool(pScreenPriv->options,
- EXAOPT_OPTIMIZE_MIGRATION,
- TRUE);
- }
-
- if (xf86ReturnOptValBool(pScreenPriv->options,
- EXAOPT_NO_COMPOSITE, FALSE)) {
- xf86DrvMsg(pScreen->myNum, X_CONFIG,
- "EXA: Disabling Composite operation "
- "(RENDER acceleration)\n");
- pExaScr->info->CheckComposite = NULL;
- pExaScr->info->PrepareComposite = NULL;
- }
-
- if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_UTS, FALSE)) {
- xf86DrvMsg(pScreen->myNum, X_CONFIG,
- "EXA: Disabling UploadToScreen\n");
- pExaScr->info->UploadToScreen = NULL;
- }
-
- if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_DFS, FALSE)) {
- xf86DrvMsg(pScreen->myNum, X_CONFIG,
- "EXA: Disabling DownloadFromScreen\n");
- pExaScr->info->DownloadFromScreen = NULL;
- }
-
- dixSetPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey, pScreenPriv);
-
- pScreenPriv->SavedEnableDisableFBAccess = pScrn->EnableDisableFBAccess;
- pScrn->EnableDisableFBAccess = exaXorgEnableDisableFBAccess;
-
- pScreenPriv->SavedCloseScreen = pScreen->CloseScreen;
- pScreen->CloseScreen = exaXorgCloseScreen;
-
-}
-
-static XF86ModuleVersionInfo exaVersRec =
-{
- "exa",
- MODULEVENDORSTRING,
- MODINFOSTRING1,
- MODINFOSTRING2,
- XORG_VERSION_CURRENT,
- EXA_VERSION_MAJOR, EXA_VERSION_MINOR, EXA_VERSION_RELEASE,
- ABI_CLASS_VIDEODRV, /* requires the video driver ABI */
- ABI_VIDEODRV_VERSION,
- MOD_CLASS_NONE,
- {0,0,0,0}
-};
-
-_X_EXPORT XF86ModuleData exaModuleData = { &exaVersRec, NULL, NULL };
+/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Eric Anholt <anholt@FreeBSD.org> + * + */ + +#ifdef HAVE_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" + +#include "xf86str.h" +#include "xf86.h" + +typedef struct _ExaXorgScreenPrivRec { + CloseScreenProcPtr SavedCloseScreen; + EnableDisableFBAccessProcPtr SavedEnableDisableFBAccess; + OptionInfoPtr options; +} ExaXorgScreenPrivRec, *ExaXorgScreenPrivPtr; + +static DevPrivateKeyRec exaXorgScreenPrivateKeyRec; +#define exaXorgScreenPrivateKey (&exaXorgScreenPrivateKeyRec) + +typedef enum { + EXAOPT_MIGRATION_HEURISTIC, + EXAOPT_NO_COMPOSITE, + EXAOPT_NO_UTS, + EXAOPT_NO_DFS, + EXAOPT_OPTIMIZE_MIGRATION +} EXAOpts; + +static const OptionInfoRec EXAOptions[] = { + { EXAOPT_MIGRATION_HEURISTIC, "MigrationHeuristic", + OPTV_ANYSTR, {0}, FALSE }, + { EXAOPT_NO_COMPOSITE, "EXANoComposite", + OPTV_BOOLEAN, {0}, FALSE }, + { EXAOPT_NO_UTS, "EXANoUploadToScreen", + OPTV_BOOLEAN, {0}, FALSE }, + { EXAOPT_NO_DFS, "EXANoDownloadFromScreen", + OPTV_BOOLEAN, {0}, FALSE }, + { EXAOPT_OPTIMIZE_MIGRATION, "EXAOptimizeMigration", + OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, + OPTV_NONE, {0}, FALSE } +}; + +static Bool +exaXorgCloseScreen (int i, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr) + dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey); + + pScreen->CloseScreen = pScreenPriv->SavedCloseScreen; + + pScrn->EnableDisableFBAccess = pScreenPriv->SavedEnableDisableFBAccess; + + free(pScreenPriv->options); + free(pScreenPriv); + + return pScreen->CloseScreen (i, pScreen); +} + +static void +exaXorgEnableDisableFBAccess (int index, Bool enable) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr) + dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey); + + if (!enable) + exaEnableDisableFBAccess (index, enable); + + if (pScreenPriv->SavedEnableDisableFBAccess) + pScreenPriv->SavedEnableDisableFBAccess (index, enable); + + if (enable) + exaEnableDisableFBAccess (index, enable); +} + +/** + * This will be called during exaDriverInit, giving us the chance to set options + * and hook in our EnableDisableFBAccess. + */ +void +exaDDXDriverInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + /* Do NOT use XF86SCRNINFO macro here!! */ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ExaXorgScreenPrivPtr pScreenPriv; + + if (!dixRegisterPrivateKey(&exaXorgScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) + return; + + pScreenPriv = calloc(1, sizeof(ExaXorgScreenPrivRec)); + if (pScreenPriv == NULL) + return; + + pScreenPriv->options = xnfalloc (sizeof(EXAOptions)); + memcpy(pScreenPriv->options, EXAOptions, sizeof(EXAOptions)); + xf86ProcessOptions (pScrn->scrnIndex, pScrn->options, pScreenPriv->options); + + if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) { + if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && + pExaScr->info->offScreenBase < pExaScr->info->memorySize) { + char *heuristicName; + + heuristicName = xf86GetOptValString (pScreenPriv->options, + EXAOPT_MIGRATION_HEURISTIC); + if (heuristicName != NULL) { + if (strcmp(heuristicName, "greedy") == 0) + pExaScr->migration = ExaMigrationGreedy; + else if (strcmp(heuristicName, "always") == 0) + pExaScr->migration = ExaMigrationAlways; + else if (strcmp(heuristicName, "smart") == 0) + pExaScr->migration = ExaMigrationSmart; + else { + xf86DrvMsg (pScreen->myNum, X_WARNING, + "EXA: unknown migration heuristic %s\n", + heuristicName); + } + } + } + + pExaScr->optimize_migration = + xf86ReturnOptValBool(pScreenPriv->options, + EXAOPT_OPTIMIZE_MIGRATION, + TRUE); + } + + if (xf86ReturnOptValBool(pScreenPriv->options, + EXAOPT_NO_COMPOSITE, FALSE)) { + xf86DrvMsg(pScreen->myNum, X_CONFIG, + "EXA: Disabling Composite operation " + "(RENDER acceleration)\n"); + pExaScr->info->CheckComposite = NULL; + pExaScr->info->PrepareComposite = NULL; + } + + if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_UTS, FALSE)) { + xf86DrvMsg(pScreen->myNum, X_CONFIG, + "EXA: Disabling UploadToScreen\n"); + pExaScr->info->UploadToScreen = NULL; + } + + if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_DFS, FALSE)) { + xf86DrvMsg(pScreen->myNum, X_CONFIG, + "EXA: Disabling DownloadFromScreen\n"); + pExaScr->info->DownloadFromScreen = NULL; + } + + dixSetPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey, pScreenPriv); + + pScreenPriv->SavedEnableDisableFBAccess = pScrn->EnableDisableFBAccess; + pScrn->EnableDisableFBAccess = exaXorgEnableDisableFBAccess; + + pScreenPriv->SavedCloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = exaXorgCloseScreen; + +} + +static XF86ModuleVersionInfo exaVersRec = +{ + "exa", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + EXA_VERSION_MAJOR, EXA_VERSION_MINOR, EXA_VERSION_RELEASE, + ABI_CLASS_VIDEODRV, /* requires the video driver ABI */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +_X_EXPORT XF86ModuleData exaModuleData = { &exaVersRec, NULL, NULL }; diff --git a/xorg-server/hw/xfree86/modes/xf86Modes.h b/xorg-server/hw/xfree86/modes/xf86Modes.h index 38927b128..c72a93537 100644 --- a/xorg-server/hw/xfree86/modes/xf86Modes.h +++ b/xorg-server/hw/xfree86/modes/xf86Modes.h @@ -1,5 +1,5 @@ /* - * Copyright © 2006 Intel Corporation + * Copyright © 2006 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), diff --git a/xorg-server/hw/xfree86/modes/xf86cvt.c b/xorg-server/hw/xfree86/modes/xf86cvt.c index 9992fa4c4..d5fecccb5 100644 --- a/xorg-server/hw/xfree86/modes/xf86cvt.c +++ b/xorg-server/hw/xfree86/modes/xf86cvt.c @@ -1,293 +1,293 @@ -/*
- * Copyright 2005-2006 Luc Verhaegen.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- */
-
-/*
- * The reason for having this function in a file of its own is
- * so that ../utils/cvt/cvt can link to it, and that xf86CVTMode
- * code is shared directly.
- */
-
-#ifdef HAVE_XORG_CONFIG_H
-#include <xorg-config.h>
-#else
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#endif
-
-#include "xf86.h"
-#include "xf86Modes.h"
-
-#include <string.h>
-
-/*
- * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh.
- *
- * These calculations are stolen from the CVT calculation spreadsheet written
- * by Graham Loveridge. He seems to be claiming no copyright and there seems to
- * be no license attached to this. He apparently just wants to see his name
- * mentioned.
- *
- * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls
- *
- * Comments and structure corresponds to the comments and structure of the xls.
- * This should ease importing of future changes to the standard (not very
- * likely though).
- *
- * About margins; i'm sure that they are to be the bit between HDisplay and
- * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and
- * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking
- * outside sync "margin" for some reason. Since we prefer seeing proper
- * blanking instead of the overscan colour, and since the Crtc* values will
- * probably get altered after us, we will disable margins altogether. With
- * these calculations, Margins will plainly expand H/VDisplay, and we don't
- * want that. -- libv
- *
- */
-DisplayModePtr
-xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced,
- Bool Interlaced)
-{
- DisplayModeRec *Mode = xnfcalloc(1, sizeof(DisplayModeRec));
-
- /* 1) top/bottom margin size (% of height) - default: 1.8 */
-#define CVT_MARGIN_PERCENTAGE 1.8
-
- /* 2) character cell horizontal granularity (pixels) - default 8 */
-#define CVT_H_GRANULARITY 8
-
- /* 4) Minimum vertical porch (lines) - default 3 */
-#define CVT_MIN_V_PORCH 3
-
- /* 4) Minimum number of vertical back porch lines - default 6 */
-#define CVT_MIN_V_BPORCH 6
-
- /* Pixel Clock step (kHz) */
-#define CVT_CLOCK_STEP 250
-
- Bool Margins = FALSE;
- float VFieldRate, HPeriod;
- int HDisplayRnd, HMargin;
- int VDisplayRnd, VMargin, VSync;
- float Interlace; /* Please rename this */
-
- /* CVT default is 60.0Hz */
- if (!VRefresh)
- VRefresh = 60.0;
-
- /* 1. Required field rate */
- if (Interlaced)
- VFieldRate = VRefresh * 2;
- else
- VFieldRate = VRefresh;
-
- /* 2. Horizontal pixels */
- HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY);
-
- /* 3. Determine left and right borders */
- if (Margins) {
- /* right margin is actually exactly the same as left */
- HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
- HMargin -= HMargin % CVT_H_GRANULARITY;
- } else
- HMargin = 0;
-
- /* 4. Find total active pixels */
- Mode->HDisplay = HDisplayRnd + 2*HMargin;
-
- /* 5. Find number of lines per field */
- if (Interlaced)
- VDisplayRnd = VDisplay / 2;
- else
- VDisplayRnd = VDisplay;
-
- /* 6. Find top and bottom margins */
- /* nope. */
- if (Margins)
- /* top and bottom margins are equal again. */
- VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
- else
- VMargin = 0;
-
- Mode->VDisplay = VDisplay + 2*VMargin;
-
- /* 7. Interlace */
- if (Interlaced)
- Interlace = 0.5;
- else
- Interlace = 0.0;
-
- /* Determine VSync Width from aspect ratio */
- if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay))
- VSync = 4;
- else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay))
- VSync = 5;
- else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay))
- VSync = 6;
- else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay))
- VSync = 7;
- else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))
- VSync = 7;
- else /* Custom */
- VSync = 10;
-
- if (!Reduced) { /* simplified GTF calculation */
-
- /* 4) Minimum time of vertical sync + back porch interval (µs)
- * default 550.0 */
-#define CVT_MIN_VSYNC_BP 550.0
-
- /* 3) Nominal HSync width (% of line period) - default 8 */
-#define CVT_HSYNC_PERCENTAGE 8
-
- float HBlankPercentage;
- int VSyncAndBackPorch, VBackPorch;
- int HBlank;
-
- /* 8. Estimated Horizontal period */
- HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) /
- (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace);
-
- /* 9. Find number of lines in sync + backporch */
- if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH))
- VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH;
- else
- VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1;
-
- /* 10. Find number of lines in back porch */
- VBackPorch = VSyncAndBackPorch - VSync;
-
- /* 11. Find total number of lines in vertical field */
- Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace
- + CVT_MIN_V_PORCH;
-
- /* 5) Definition of Horizontal blanking time limitation */
- /* Gradient (%/kHz) - default 600 */
-#define CVT_M_FACTOR 600
-
- /* Offset (%) - default 40 */
-#define CVT_C_FACTOR 40
-
- /* Blanking time scaling factor - default 128 */
-#define CVT_K_FACTOR 128
-
- /* Scaling factor weighting - default 20 */
-#define CVT_J_FACTOR 20
-
-#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256
-#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
- CVT_J_FACTOR
-
- /* 12. Find ideal blanking duty cycle from formula */
- HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0;
-
- /* 13. Blanking time */
- if (HBlankPercentage < 20)
- HBlankPercentage = 20;
-
- HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage);
- HBlank -= HBlank % (2*CVT_H_GRANULARITY);
-
- /* 14. Find total number of pixels in a line. */
- Mode->HTotal = Mode->HDisplay + HBlank;
-
- /* Fill in HSync values */
- Mode->HSyncEnd = Mode->HDisplay + HBlank / 2;
-
- Mode->HSyncStart = Mode->HSyncEnd -
- (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100;
- Mode->HSyncStart += CVT_H_GRANULARITY -
- Mode->HSyncStart % CVT_H_GRANULARITY;
-
- /* Fill in VSync values */
- Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH;
- Mode->VSyncEnd = Mode->VSyncStart + VSync;
-
- } else { /* Reduced blanking */
- /* Minimum vertical blanking interval time (µs) - default 460 */
-#define CVT_RB_MIN_VBLANK 460.0
-
- /* Fixed number of clocks for horizontal sync */
-#define CVT_RB_H_SYNC 32.0
-
- /* Fixed number of clocks for horizontal blanking */
-#define CVT_RB_H_BLANK 160.0
-
- /* Fixed number of lines for vertical front porch - default 3 */
-#define CVT_RB_VFPORCH 3
-
- int VBILines;
-
- /* 8. Estimate Horizontal period. */
- HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) /
- (VDisplayRnd + 2*VMargin);
-
- /* 9. Find number of lines in vertical blanking */
- VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
-
- /* 10. Check if vertical blanking is sufficient */
- if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
- VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
-
- /* 11. Find total number of lines in vertical field */
- Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines;
-
- /* 12. Find total number of pixels in a line */
- Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK;
-
- /* Fill in HSync values */
- Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2;
- Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC;
-
- /* Fill in VSync values */
- Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH;
- Mode->VSyncEnd = Mode->VSyncStart + VSync;
- }
-
- /* 15/13. Find pixel clock frequency (kHz for xf86) */
- Mode->Clock = Mode->HTotal * 1000.0 / HPeriod;
- Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP;
-
- /* 16/14. Find actual Horizontal Frequency (kHz) */
- Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal);
-
- /* 17/15. Find actual Field rate */
- Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
- ((float) (Mode->HTotal * Mode->VTotal));
-
- /* 18/16. Find actual vertical frame frequency */
- /* ignore - just set the mode flag for interlaced */
- if (Interlaced)
- Mode->VTotal *= 2;
-
- XNFasprintf(&Mode->name, "%dx%d", HDisplay, VDisplay);
-
- if (Reduced)
- Mode->Flags |= V_PHSYNC | V_NVSYNC;
- else
- Mode->Flags |= V_NHSYNC | V_PVSYNC;
-
- if (Interlaced)
- Mode->Flags |= V_INTERLACE;
-
- return Mode;
-}
+/* + * Copyright 2005-2006 Luc Verhaegen. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +/* + * The reason for having this function in a file of its own is + * so that ../utils/cvt/cvt can link to it, and that xf86CVTMode + * code is shared directly. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86Modes.h" + +#include <string.h> + +/* + * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh. + * + * These calculations are stolen from the CVT calculation spreadsheet written + * by Graham Loveridge. He seems to be claiming no copyright and there seems to + * be no license attached to this. He apparently just wants to see his name + * mentioned. + * + * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls + * + * Comments and structure corresponds to the comments and structure of the xls. + * This should ease importing of future changes to the standard (not very + * likely though). + * + * About margins; i'm sure that they are to be the bit between HDisplay and + * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and + * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking + * outside sync "margin" for some reason. Since we prefer seeing proper + * blanking instead of the overscan colour, and since the Crtc* values will + * probably get altered after us, we will disable margins altogether. With + * these calculations, Margins will plainly expand H/VDisplay, and we don't + * want that. -- libv + * + */ +DisplayModePtr +xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, + Bool Interlaced) +{ + DisplayModeRec *Mode = xnfcalloc(1, sizeof(DisplayModeRec)); + + /* 1) top/bottom margin size (% of height) - default: 1.8 */ +#define CVT_MARGIN_PERCENTAGE 1.8 + + /* 2) character cell horizontal granularity (pixels) - default 8 */ +#define CVT_H_GRANULARITY 8 + + /* 4) Minimum vertical porch (lines) - default 3 */ +#define CVT_MIN_V_PORCH 3 + + /* 4) Minimum number of vertical back porch lines - default 6 */ +#define CVT_MIN_V_BPORCH 6 + + /* Pixel Clock step (kHz) */ +#define CVT_CLOCK_STEP 250 + + Bool Margins = FALSE; + float VFieldRate, HPeriod; + int HDisplayRnd, HMargin; + int VDisplayRnd, VMargin, VSync; + float Interlace; /* Please rename this */ + + /* CVT default is 60.0Hz */ + if (!VRefresh) + VRefresh = 60.0; + + /* 1. Required field rate */ + if (Interlaced) + VFieldRate = VRefresh * 2; + else + VFieldRate = VRefresh; + + /* 2. Horizontal pixels */ + HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY); + + /* 3. Determine left and right borders */ + if (Margins) { + /* right margin is actually exactly the same as left */ + HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + HMargin -= HMargin % CVT_H_GRANULARITY; + } else + HMargin = 0; + + /* 4. Find total active pixels */ + Mode->HDisplay = HDisplayRnd + 2*HMargin; + + /* 5. Find number of lines per field */ + if (Interlaced) + VDisplayRnd = VDisplay / 2; + else + VDisplayRnd = VDisplay; + + /* 6. Find top and bottom margins */ + /* nope. */ + if (Margins) + /* top and bottom margins are equal again. */ + VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + else + VMargin = 0; + + Mode->VDisplay = VDisplay + 2*VMargin; + + /* 7. Interlace */ + if (Interlaced) + Interlace = 0.5; + else + Interlace = 0.0; + + /* Determine VSync Width from aspect ratio */ + if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) + VSync = 4; + else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) + VSync = 5; + else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) + VSync = 6; + else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) + VSync = 7; + else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay)) + VSync = 7; + else /* Custom */ + VSync = 10; + + if (!Reduced) { /* simplified GTF calculation */ + + /* 4) Minimum time of vertical sync + back porch interval (µs) + * default 550.0 */ +#define CVT_MIN_VSYNC_BP 550.0 + + /* 3) Nominal HSync width (% of line period) - default 8 */ +#define CVT_HSYNC_PERCENTAGE 8 + + float HBlankPercentage; + int VSyncAndBackPorch, VBackPorch; + int HBlank; + + /* 8. Estimated Horizontal period */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) / + (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace); + + /* 9. Find number of lines in sync + backporch */ + if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH)) + VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH; + else + VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1; + + /* 10. Find number of lines in back porch */ + VBackPorch = VSyncAndBackPorch - VSync; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace + + CVT_MIN_V_PORCH; + + /* 5) Definition of Horizontal blanking time limitation */ + /* Gradient (%/kHz) - default 600 */ +#define CVT_M_FACTOR 600 + + /* Offset (%) - default 40 */ +#define CVT_C_FACTOR 40 + + /* Blanking time scaling factor - default 128 */ +#define CVT_K_FACTOR 128 + + /* Scaling factor weighting - default 20 */ +#define CVT_J_FACTOR 20 + +#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256 +#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \ + CVT_J_FACTOR + + /* 12. Find ideal blanking duty cycle from formula */ + HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0; + + /* 13. Blanking time */ + if (HBlankPercentage < 20) + HBlankPercentage = 20; + + HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage); + HBlank -= HBlank % (2*CVT_H_GRANULARITY); + + /* 14. Find total number of pixels in a line. */ + Mode->HTotal = Mode->HDisplay + HBlank; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + HBlank / 2; + + Mode->HSyncStart = Mode->HSyncEnd - + (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100; + Mode->HSyncStart += CVT_H_GRANULARITY - + Mode->HSyncStart % CVT_H_GRANULARITY; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + + } else { /* Reduced blanking */ + /* Minimum vertical blanking interval time (µs) - default 460 */ +#define CVT_RB_MIN_VBLANK 460.0 + + /* Fixed number of clocks for horizontal sync */ +#define CVT_RB_H_SYNC 32.0 + + /* Fixed number of clocks for horizontal blanking */ +#define CVT_RB_H_BLANK 160.0 + + /* Fixed number of lines for vertical front porch - default 3 */ +#define CVT_RB_VFPORCH 3 + + int VBILines; + + /* 8. Estimate Horizontal period. */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / + (VDisplayRnd + 2*VMargin); + + /* 9. Find number of lines in vertical blanking */ + VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1; + + /* 10. Check if vertical blanking is sufficient */ + if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH)) + VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines; + + /* 12. Find total number of pixels in a line */ + Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2; + Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + } + + /* 15/13. Find pixel clock frequency (kHz for xf86) */ + Mode->Clock = Mode->HTotal * 1000.0 / HPeriod; + Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP; + + /* 16/14. Find actual Horizontal Frequency (kHz) */ + Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal); + + /* 17/15. Find actual Field rate */ + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + + /* 18/16. Find actual vertical frame frequency */ + /* ignore - just set the mode flag for interlaced */ + if (Interlaced) + Mode->VTotal *= 2; + + XNFasprintf(&Mode->name, "%dx%d", HDisplay, VDisplay); + + if (Reduced) + Mode->Flags |= V_PHSYNC | V_NVSYNC; + else + Mode->Flags |= V_NHSYNC | V_PVSYNC; + + if (Interlaced) + Mode->Flags |= V_INTERLACE; + + return Mode; +} diff --git a/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c b/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c index 8c5c45843..0331ac1c5 100644 --- a/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c +++ b/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c @@ -1,327 +1,327 @@ -/*
- * Abstraction of the AGP GART interface.
- *
- * This version is for Solaris.
- *
- * Copyright © 2000 VA Linux Systems, Inc.
- * Copyright © 2001 The XFree86 Project, Inc.
- */
-/* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- */
-
-#ifdef HAVE_XORG_CONFIG_H
-#include <xorg-config.h>
-#endif
-
-#include <X11/X.h>
-#include "xf86.h"
-#include "xf86Priv.h"
-#include "xf86_OSlib.h"
-#include "xf86_OSproc.h"
-#include <unistd.h>
-#include <sys/ioccom.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/agpgart.h>
-
-/* AGP page size is independent of the host page size. */
-#ifndef AGP_PAGE_SIZE
-#define AGP_PAGE_SIZE 4096
-#endif
-
-static int gartFd = -1;
-static int acquiredScreen = -1;
-static Bool initDone = FALSE;
-/*
- * Close /dev/agpgart. This frees all associated memory allocated during
- * this server generation.
- */
-Bool
-xf86GARTCloseScreen(int screenNum)
-{
- if (gartFd != -1) {
- close(gartFd);
- acquiredScreen = -1;
- gartFd = -1;
- initDone = FALSE;
-
- xf86DrvMsg(screenNum, X_INFO,
- "xf86GARTCloseScreen: device closed successfully\n");
-
- }
- return TRUE;
-}
-
-/*
- * Open /dev/agpgart. Keep it open until xf86GARTCloseScreen is called.
- */
-static Bool
-GARTInit(int screenNum)
-{
- if (initDone)
- return gartFd != -1;
-
- if (gartFd == -1)
- gartFd = open(AGP_DEVICE, O_RDWR);
- else
- return FALSE;
-
- if (gartFd == -1) {
- xf86DrvMsg(screenNum, X_ERROR,
- "GARTInit: Unable to open " AGP_DEVICE " (%s)\n",
- strerror(errno));
- return FALSE;
- }
-
- initDone = TRUE;
- xf86DrvMsg(screenNum, X_INFO,
- "GARTInit: " AGP_DEVICE " opened successfully\n");
-
- return TRUE;
-}
-
-Bool
-xf86AgpGARTSupported(void)
-{
- return (GARTInit(-1));
-
-}
-
-AgpInfoPtr
-xf86GetAGPInfo(int screenNum)
-{
- agp_info_t agpinf;
- AgpInfoPtr info;
-
- if (!GARTInit(screenNum))
- return NULL;
-
- if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) {
- xf86DrvMsg(screenNum, X_ERROR,
- "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n",
- strerror(errno));
- return NULL;
- }
-
- if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) {
- xf86DrvMsg(screenNum, X_ERROR,
- "xf86GetAGPInfo: Failed to allocate AgpInfo\n");
- return NULL;
- }
-
- info->bridgeId = agpinf.agpi_devid;
- info->agpMode = agpinf.agpi_mode;
- info->base = agpinf.agpi_aperbase;
- info->size = agpinf.agpi_apersize;
- info->totalPages = (unsigned long)agpinf.agpi_pgtotal;
- info->systemPages = (unsigned long)agpinf.agpi_pgsystem;
- info->usedPages = (unsigned long)agpinf.agpi_pgused;
-
- return info;
-}
-
-Bool
-xf86AcquireGART(int screenNum)
-{
-
- if (!GARTInit(screenNum))
- return FALSE;
-
- if (acquiredScreen != screenNum) {
- if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) {
- xf86DrvMsg(screenNum, X_WARNING,
- "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n",
- strerror(errno));
- return FALSE;
- }
- acquiredScreen = screenNum;
- xf86DrvMsg(screenNum, X_INFO,
- "xf86AcquireGART: AGPIOC_ACQUIRE succeeded\n");
- }
- return TRUE;
-}
-
-Bool
-xf86ReleaseGART(int screenNum)
-{
-
- if (!GARTInit(screenNum))
- return FALSE;
-
- if (acquiredScreen == screenNum) {
- /*
- * The FreeBSD agp driver removes allocations on release.
- * The Solaris driver doesn't. xf86ReleaseGART() is expected
- * to give up access to the GART, but not to remove any
- * allocations.
- */
-
- if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) {
- xf86DrvMsg(screenNum, X_WARNING,
- "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n",
- strerror(errno));
- return FALSE;
- }
- acquiredScreen = -1;
- xf86DrvMsg(screenNum, X_INFO,
- "xf86ReleaseGART: AGPIOC_RELEASE succeeded\n");
- return TRUE;
- }
- return FALSE;
-}
-
-int
-xf86AllocateGARTMemory(int screenNum, unsigned long size, int type,
- unsigned long *physical)
-{
- agp_allocate_t alloc;
- int pages;
-
- /*
- * Allocates "size" bytes of GART memory (rounds up to the next
- * page multiple) or type "type". A handle (key) for the allocated
- * memory is returned. On error, the return value is -1.
- * "size" should be larger than 0, or AGPIOC_ALLOCATE ioctl will
- * return error.
- */
-
- if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
- return -1;
-
- pages = (size / AGP_PAGE_SIZE);
- if (size % AGP_PAGE_SIZE != 0)
- pages++;
-
- alloc.agpa_pgcount = pages;
- alloc.agpa_type = type;
-
- if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) {
- xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: "
- "allocation of %d pages failed\n\t(%s)\n", pages,
- strerror(errno));
- return -1;
- }
-
- if (physical)
- *physical = (unsigned long)alloc.agpa_physical;
-
- return alloc.agpa_key;
-}
-
-Bool
-xf86DeallocateGARTMemory(int screenNum, int key)
-{
- if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
- return FALSE;
-
- if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) {
- xf86DrvMsg(screenNum, X_WARNING, "xf86DeAllocateGARTMemory: "
- "deallocation of gart memory with key %d failed\n"
- "\t(%s)\n", key, strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Bind GART memory with "key" at "offset" */
-Bool
-xf86BindGARTMemory(int screenNum, int key, unsigned long offset)
-{
- agp_bind_t bind;
- int pageOffset;
-
- if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
- return FALSE;
-
- if (offset % AGP_PAGE_SIZE != 0) {
- xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: "
- "offset (0x%lx) is not page-aligned (%d)\n",
- offset, AGP_PAGE_SIZE);
- return FALSE;
- }
- pageOffset = offset / AGP_PAGE_SIZE;
-
- xf86DrvMsgVerb(screenNum, X_INFO, 3,
- "xf86BindGARTMemory: bind key %d at 0x%08lx "
- "(pgoffset %d)\n", key, offset, pageOffset);
-
- bind.agpb_pgstart = pageOffset;
- bind.agpb_key = key;
-
- if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) {
- xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: "
- "binding of gart memory with key %d\n"
- "\tat offset 0x%lx failed (%s)\n",
- key, offset, strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Unbind GART memory with "key" */
-Bool
-xf86UnbindGARTMemory(int screenNum, int key)
-{
- agp_unbind_t unbind;
-
- if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
- return FALSE;
-
- unbind.agpu_pri = 0;
- unbind.agpu_key = key;
-
- if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) {
- xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: "
- "unbinding of gart memory with key %d "
- "failed (%s)\n", key, strerror(errno));
- return FALSE;
- }
-
- xf86DrvMsgVerb(screenNum, X_INFO, 3,
- "xf86UnbindGARTMemory: unbind key %d\n", key);
-
- return TRUE;
-}
-
-
-/* XXX Interface may change. */
-Bool
-xf86EnableAGP(int screenNum, CARD32 mode)
-{
- agp_setup_t setup;
-
- if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
- return FALSE;
-
- setup.agps_mode = mode;
- if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) {
- xf86DrvMsg(screenNum, X_WARNING, "xf86EnableAGP: "
- "AGPIOC_SETUP with mode %x failed (%s)\n",
- (unsigned int) mode, strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
+/* + * Abstraction of the AGP GART interface. + * + * This version is for Solaris. + * + * Copyright © 2000 VA Linux Systems, Inc. + * Copyright © 2001 The XFree86 Project, Inc. + */ +/* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "xf86_OSproc.h" +#include <unistd.h> +#include <sys/ioccom.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/agpgart.h> + +/* AGP page size is independent of the host page size. */ +#ifndef AGP_PAGE_SIZE +#define AGP_PAGE_SIZE 4096 +#endif + +static int gartFd = -1; +static int acquiredScreen = -1; +static Bool initDone = FALSE; +/* + * Close /dev/agpgart. This frees all associated memory allocated during + * this server generation. + */ +Bool +xf86GARTCloseScreen(int screenNum) +{ + if (gartFd != -1) { + close(gartFd); + acquiredScreen = -1; + gartFd = -1; + initDone = FALSE; + + xf86DrvMsg(screenNum, X_INFO, + "xf86GARTCloseScreen: device closed successfully\n"); + + } + return TRUE; +} + +/* + * Open /dev/agpgart. Keep it open until xf86GARTCloseScreen is called. + */ +static Bool +GARTInit(int screenNum) +{ + if (initDone) + return gartFd != -1; + + if (gartFd == -1) + gartFd = open(AGP_DEVICE, O_RDWR); + else + return FALSE; + + if (gartFd == -1) { + xf86DrvMsg(screenNum, X_ERROR, + "GARTInit: Unable to open " AGP_DEVICE " (%s)\n", + strerror(errno)); + return FALSE; + } + + initDone = TRUE; + xf86DrvMsg(screenNum, X_INFO, + "GARTInit: " AGP_DEVICE " opened successfully\n"); + + return TRUE; +} + +Bool +xf86AgpGARTSupported(void) +{ + return (GARTInit(-1)); + +} + +AgpInfoPtr +xf86GetAGPInfo(int screenNum) +{ + agp_info_t agpinf; + AgpInfoPtr info; + + if (!GARTInit(screenNum)) + return NULL; + + if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n", + strerror(errno)); + return NULL; + } + + if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86GetAGPInfo: Failed to allocate AgpInfo\n"); + return NULL; + } + + info->bridgeId = agpinf.agpi_devid; + info->agpMode = agpinf.agpi_mode; + info->base = agpinf.agpi_aperbase; + info->size = agpinf.agpi_apersize; + info->totalPages = (unsigned long)agpinf.agpi_pgtotal; + info->systemPages = (unsigned long)agpinf.agpi_pgsystem; + info->usedPages = (unsigned long)agpinf.agpi_pgused; + + return info; +} + +Bool +xf86AcquireGART(int screenNum) +{ + + if (!GARTInit(screenNum)) + return FALSE; + + if (acquiredScreen != screenNum) { + if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) { + xf86DrvMsg(screenNum, X_WARNING, + "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = screenNum; + xf86DrvMsg(screenNum, X_INFO, + "xf86AcquireGART: AGPIOC_ACQUIRE succeeded\n"); + } + return TRUE; +} + +Bool +xf86ReleaseGART(int screenNum) +{ + + if (!GARTInit(screenNum)) + return FALSE; + + if (acquiredScreen == screenNum) { + /* + * The FreeBSD agp driver removes allocations on release. + * The Solaris driver doesn't. xf86ReleaseGART() is expected + * to give up access to the GART, but not to remove any + * allocations. + */ + + if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) { + xf86DrvMsg(screenNum, X_WARNING, + "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = -1; + xf86DrvMsg(screenNum, X_INFO, + "xf86ReleaseGART: AGPIOC_RELEASE succeeded\n"); + return TRUE; + } + return FALSE; +} + +int +xf86AllocateGARTMemory(int screenNum, unsigned long size, int type, + unsigned long *physical) +{ + agp_allocate_t alloc; + int pages; + + /* + * Allocates "size" bytes of GART memory (rounds up to the next + * page multiple) or type "type". A handle (key) for the allocated + * memory is returned. On error, the return value is -1. + * "size" should be larger than 0, or AGPIOC_ALLOCATE ioctl will + * return error. + */ + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return -1; + + pages = (size / AGP_PAGE_SIZE); + if (size % AGP_PAGE_SIZE != 0) + pages++; + + alloc.agpa_pgcount = pages; + alloc.agpa_type = type; + + if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: " + "allocation of %d pages failed\n\t(%s)\n", pages, + strerror(errno)); + return -1; + } + + if (physical) + *physical = (unsigned long)alloc.agpa_physical; + + return alloc.agpa_key; +} + +Bool +xf86DeallocateGARTMemory(int screenNum, int key) +{ + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86DeAllocateGARTMemory: " + "deallocation of gart memory with key %d failed\n" + "\t(%s)\n", key, strerror(errno)); + return FALSE; + } + + return TRUE; +} + +/* Bind GART memory with "key" at "offset" */ +Bool +xf86BindGARTMemory(int screenNum, int key, unsigned long offset) +{ + agp_bind_t bind; + int pageOffset; + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + if (offset % AGP_PAGE_SIZE != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " + "offset (0x%lx) is not page-aligned (%d)\n", + offset, AGP_PAGE_SIZE); + return FALSE; + } + pageOffset = offset / AGP_PAGE_SIZE; + + xf86DrvMsgVerb(screenNum, X_INFO, 3, + "xf86BindGARTMemory: bind key %d at 0x%08lx " + "(pgoffset %d)\n", key, offset, pageOffset); + + bind.agpb_pgstart = pageOffset; + bind.agpb_key = key; + + if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " + "binding of gart memory with key %d\n" + "\tat offset 0x%lx failed (%s)\n", + key, offset, strerror(errno)); + return FALSE; + } + + return TRUE; +} + +/* Unbind GART memory with "key" */ +Bool +xf86UnbindGARTMemory(int screenNum, int key) +{ + agp_unbind_t unbind; + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + unbind.agpu_pri = 0; + unbind.agpu_key = key; + + if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: " + "unbinding of gart memory with key %d " + "failed (%s)\n", key, strerror(errno)); + return FALSE; + } + + xf86DrvMsgVerb(screenNum, X_INFO, 3, + "xf86UnbindGARTMemory: unbind key %d\n", key); + + return TRUE; +} + + +/* XXX Interface may change. */ +Bool +xf86EnableAGP(int screenNum, CARD32 mode) +{ + agp_setup_t setup; + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + setup.agps_mode = mode; + if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86EnableAGP: " + "AGPIOC_SETUP with mode %x failed (%s)\n", + (unsigned int) mode, strerror(errno)); + return FALSE; + } + + return TRUE; +} + diff --git a/xorg-server/hw/xnest/Init.c b/xorg-server/hw/xnest/Init.c index ee74101d2..ea0669a6a 100644 --- a/xorg-server/hw/xnest/Init.c +++ b/xorg-server/hw/xnest/Init.c @@ -108,6 +108,7 @@ InitInput(int argc, char *argv[]) void CloseInput(void) { + mieqFini(); } /* diff --git a/xorg-server/hw/xquartz/darwin.c b/xorg-server/hw/xquartz/darwin.c index 29ab83677..73685b0d4 100644 --- a/xorg-server/hw/xquartz/darwin.c +++ b/xorg-server/hw/xquartz/darwin.c @@ -505,6 +505,10 @@ void InitInput( int argc, char **argv ) QuartzInitInput(argc, argv); } +void CloseInput(void) +{ + DarwinEQFini(); +} /* * DarwinAdjustScreenOrigins diff --git a/xorg-server/hw/xquartz/darwinEvents.c b/xorg-server/hw/xquartz/darwinEvents.c index fe744b741..1f22099d6 100644 --- a/xorg-server/hw/xquartz/darwinEvents.c +++ b/xorg-server/hw/xquartz/darwinEvents.c @@ -371,6 +371,10 @@ Bool DarwinEQInit(void) { return TRUE; } +Bool DarwinEQFini(void) { + mieqFini(); +} + /* * ProcessInputEvents * Read and process events from the event queue until it is empty. diff --git a/xorg-server/hw/xquartz/darwinEvents.h b/xorg-server/hw/xquartz/darwinEvents.h index 6769c8bd8..bd29d51fd 100644 --- a/xorg-server/hw/xquartz/darwinEvents.h +++ b/xorg-server/hw/xquartz/darwinEvents.h @@ -32,6 +32,7 @@ #define XQUARTZ_VALUATOR_LIMIT (1 << 16) Bool DarwinEQInit(void); +Bool DarwinEQFini(void); void DarwinEQEnqueue(const xEventPtr e); void DarwinEQPointerPost(DeviceIntPtr pDev, xEventPtr e); void DarwinEQSwitchScreen(ScreenPtr pScreen, Bool fromDIX); diff --git a/xorg-server/hw/xquartz/darwinXinput.c b/xorg-server/hw/xquartz/darwinXinput.c index 3ef34fec0..94c31bb23 100644 --- a/xorg-server/hw/xquartz/darwinXinput.c +++ b/xorg-server/hw/xquartz/darwinXinput.c @@ -149,8 +149,3 @@ DeleteInputDeviceRequest(DeviceIntPtr dev) DEBUG_LOG("DeleteInputDeviceRequest(%p)\n", dev); } -void -CloseInput (void) -{ -} - diff --git a/xorg-server/hw/xwin/InitInput.c b/xorg-server/hw/xwin/InitInput.c index 5f51fc457..bc48a9360 100644 --- a/xorg-server/hw/xwin/InitInput.c +++ b/xorg-server/hw/xwin/InitInput.c @@ -1,159 +1,160 @@ -/*
-
- Copyright 1993, 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.
-
-*/
-
-#ifdef HAVE_XWIN_CONFIG_H
-#include <xwin-config.h>
-#endif
-#include "win.h"
-#include "dixstruct.h"
-#include "inputstr.h"
-
-
-/*
- * Local function prototypes
- */
-
-#ifdef XWIN_CLIPBOARD
-int winProcEstablishConnection(ClientPtr /* client */);
-int winProcQueryTree(ClientPtr /* client */);
-int winProcSetSelectionOwner(ClientPtr /* client */);
-#endif
-
-
-/*
- * Local global declarations
- */
-
-DeviceIntPtr g_pwinPointer;
-DeviceIntPtr g_pwinKeyboard;
-
-/* Called from dix/devices.c */
-/*
- * All of our keys generate up and down transition notifications,
- * so all of our keys can be used as modifiers.
- *
- * An example of a modifier is mapping the A key to the Control key.
- * A has to be a legal modifier. I think.
- */
-
-Bool
-LegalModifier (unsigned int uiKey, DeviceIntPtr pDevice)
-{
- return TRUE;
-}
-
-
-/* Called from dix/dispatch.c */
-/*
- * Run through the Windows message queue(s) one more time.
- * Tell mi to dequeue the events that we have sent it.
- */
-void
-ProcessInputEvents (void)
-{
-#if 0
- ErrorF ("ProcessInputEvents\n");
-#endif
-
- mieqProcessInputEvents ();
-
-#if 0
- ErrorF ("ProcessInputEvents - returning\n");
-#endif
-}
-
-
-void DDXRingBell(int volume, int pitch, int duration)
-{
- /* winKeybdBell is used instead */
- return;
-}
-
-
-/* See Porting Layer Definition - p. 17 */
-void
-InitInput (int argc, char *argv[])
-{
-#if CYGDEBUG
- winDebug ("InitInput\n");
-#endif
-
-#ifdef XWIN_CLIPBOARD
- /*
- * Wrap some functions at every generation of the server.
- */
- if (InitialVector[2] != winProcEstablishConnection)
- {
- winProcEstablishConnectionOrig = InitialVector[2];
- InitialVector[2] = winProcEstablishConnection;
- }
- if (g_fXdmcpEnabled
- && ProcVector[X_QueryTree] != winProcQueryTree)
- {
- winProcQueryTreeOrig = ProcVector[X_QueryTree];
- ProcVector[X_QueryTree] = winProcQueryTree;
- }
-#endif
-
- g_pwinPointer = AddInputDevice (serverClient, winMouseProc, TRUE);
- g_pwinKeyboard = AddInputDevice (serverClient, winKeybdProc, TRUE);
- g_pwinPointer->name = strdup("Windows mouse");
- g_pwinKeyboard->name = strdup("Windows keyboard");
-
- mieqInit ();
-
- /* Initialize the mode key states */
- winInitializeModeKeyStates ();
-
-#ifdef HAS_DEVWINDOWS
- /* Only open the windows message queue device once */
- if (g_fdMessageQueue == WIN_FD_INVALID)
- {
- /* Open a file descriptor for the Windows message queue */
- g_fdMessageQueue = open (WIN_MSG_QUEUE_FNAME, O_RDONLY);
-
- if (g_fdMessageQueue == -1)
- {
- FatalError ("InitInput - Failed opening %s\n",
- WIN_MSG_QUEUE_FNAME);
- }
-
- /* Add the message queue as a device to wait for in WaitForSomething */
- AddEnabledDevice (g_fdMessageQueue);
- }
-#endif
-
-#if CYGDEBUG
- winDebug ("InitInput - returning\n");
-#endif
-}
-
-void
-CloseInput (void)
-{
-}
+/* + + Copyright 1993, 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. + +*/ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif +#include "win.h" +#include "dixstruct.h" +#include "inputstr.h" + + +/* + * Local function prototypes + */ + +#ifdef XWIN_CLIPBOARD +int winProcEstablishConnection(ClientPtr /* client */); +int winProcQueryTree(ClientPtr /* client */); +int winProcSetSelectionOwner(ClientPtr /* client */); +#endif + + +/* + * Local global declarations + */ + +DeviceIntPtr g_pwinPointer; +DeviceIntPtr g_pwinKeyboard; + +/* Called from dix/devices.c */ +/* + * All of our keys generate up and down transition notifications, + * so all of our keys can be used as modifiers. + * + * An example of a modifier is mapping the A key to the Control key. + * A has to be a legal modifier. I think. + */ + +Bool +LegalModifier (unsigned int uiKey, DeviceIntPtr pDevice) +{ + return TRUE; +} + + +/* Called from dix/dispatch.c */ +/* + * Run through the Windows message queue(s) one more time. + * Tell mi to dequeue the events that we have sent it. + */ +void +ProcessInputEvents (void) +{ +#if 0 + ErrorF ("ProcessInputEvents\n"); +#endif + + mieqProcessInputEvents (); + +#if 0 + ErrorF ("ProcessInputEvents - returning\n"); +#endif +} + + +void DDXRingBell(int volume, int pitch, int duration) +{ + /* winKeybdBell is used instead */ + return; +} + + +/* See Porting Layer Definition - p. 17 */ +void +InitInput (int argc, char *argv[]) +{ +#if CYGDEBUG + winDebug ("InitInput\n"); +#endif + +#ifdef XWIN_CLIPBOARD + /* + * Wrap some functions at every generation of the server. + */ + if (InitialVector[2] != winProcEstablishConnection) + { + winProcEstablishConnectionOrig = InitialVector[2]; + InitialVector[2] = winProcEstablishConnection; + } + if (g_fXdmcpEnabled + && ProcVector[X_QueryTree] != winProcQueryTree) + { + winProcQueryTreeOrig = ProcVector[X_QueryTree]; + ProcVector[X_QueryTree] = winProcQueryTree; + } +#endif + + g_pwinPointer = AddInputDevice (serverClient, winMouseProc, TRUE); + g_pwinKeyboard = AddInputDevice (serverClient, winKeybdProc, TRUE); + g_pwinPointer->name = strdup("Windows mouse"); + g_pwinKeyboard->name = strdup("Windows keyboard"); + + mieqInit (); + + /* Initialize the mode key states */ + winInitializeModeKeyStates (); + +#ifdef HAS_DEVWINDOWS + /* Only open the windows message queue device once */ + if (g_fdMessageQueue == WIN_FD_INVALID) + { + /* Open a file descriptor for the Windows message queue */ + g_fdMessageQueue = open (WIN_MSG_QUEUE_FNAME, O_RDONLY); + + if (g_fdMessageQueue == -1) + { + FatalError ("InitInput - Failed opening %s\n", + WIN_MSG_QUEUE_FNAME); + } + + /* Add the message queue as a device to wait for in WaitForSomething */ + AddEnabledDevice (g_fdMessageQueue); + } +#endif + +#if CYGDEBUG + winDebug ("InitInput - returning\n"); +#endif +} + +void +CloseInput (void) +{ + mieqFini (); +} diff --git a/xorg-server/include/dixgrabs.h b/xorg-server/include/dixgrabs.h index 3b2a46d72..229c8bb53 100644 --- a/xorg-server/include/dixgrabs.h +++ b/xorg-server/include/dixgrabs.h @@ -28,6 +28,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. struct _GrabParameters; +extern void PrintDeviceGrabInfo(DeviceIntPtr dev); +extern void UngrabAllDevices(Bool kill_client); + extern GrabPtr CreateGrab( int /* client */, DeviceIntPtr /* device */, diff --git a/xorg-server/include/input.h b/xorg-server/include/input.h index 56847ed8d..5377a0c13 100644 --- a/xorg-server/include/input.h +++ b/xorg-server/include/input.h @@ -62,10 +62,11 @@ SOFTWARE. #define DEVICE_OFF 2 #define DEVICE_CLOSE 3 -#define POINTER_RELATIVE (1 << 1) -#define POINTER_ABSOLUTE (1 << 2) -#define POINTER_ACCELERATE (1 << 3) -#define POINTER_SCREEN (1 << 4) /* Data in screen coordinates */ +#define POINTER_RELATIVE (1 << 1) +#define POINTER_ABSOLUTE (1 << 2) +#define POINTER_ACCELERATE (1 << 3) +#define POINTER_SCREEN (1 << 4) /* Data in screen coordinates */ +#define POINTER_NORAW (1 << 5) /* Don't generate RawEvents */ /*int constants for pointer acceleration schemes*/ #define PtrAccelNoOp 0 diff --git a/xorg-server/include/window.h b/xorg-server/include/window.h index 1e4e9bfa4..e13598b88 100644 --- a/xorg-server/include/window.h +++ b/xorg-server/include/window.h @@ -267,4 +267,6 @@ extern _X_EXPORT void EnableMapUnmapEvents( WindowPtr /* pWin */ ); extern _X_EXPORT void SetRootClip(ScreenPtr pScreen, Bool enable); +extern _X_EXPORT void PrintWindowTree(void); + #endif /* WINDOW_H */ diff --git a/xorg-server/mi/mipointer.c b/xorg-server/mi/mipointer.c index 322be9e44..7680ca19b 100644 --- a/xorg-server/mi/mipointer.c +++ b/xorg-server/mi/mipointer.c @@ -683,7 +683,7 @@ miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) valuator_mask_set_range(&mask, 0, 2, valuators); nevents = GetPointerEvents(events, pDev, MotionNotify, 0, - POINTER_SCREEN | POINTER_ABSOLUTE, &mask); + POINTER_SCREEN | POINTER_ABSOLUTE | POINTER_NORAW, &mask); OsBlockSignals(); #ifdef XQUARTZ diff --git a/xorg-server/miext/shadow/shadow.c b/xorg-server/miext/shadow/shadow.c index 7bc1d9ca0..95f11cd21 100644 --- a/xorg-server/miext/shadow/shadow.c +++ b/xorg-server/miext/shadow/shadow.c @@ -1,252 +1,252 @@ -/*
- * Copyright © 2000 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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 <stdlib.h>
-
-#include <X11/X.h>
-#include "scrnintstr.h"
-#include "windowstr.h"
-#include "dixfontstr.h"
-#include "mi.h"
-#include "regionstr.h"
-#include "globals.h"
-#include "gcstruct.h"
-#include "shadow.h"
-
-static DevPrivateKeyRec shadowScrPrivateKeyRec;
-#define shadowScrPrivateKey (&shadowScrPrivateKeyRec)
-
-#define wrap(priv, real, mem) {\
- priv->mem = real->mem; \
- real->mem = shadow##mem; \
-}
-
-#define unwrap(priv, real, mem) {\
- real->mem = priv->mem; \
-}
-
-static void
-shadowRedisplay(ScreenPtr pScreen)
-{
- shadowBuf(pScreen);
- RegionPtr pRegion;
-
- if (!pBuf || !pBuf->pDamage || !pBuf->update)
- return;
- pRegion = DamageRegion(pBuf->pDamage);
- if (RegionNotEmpty(pRegion)) {
- (*pBuf->update)(pScreen, pBuf);
- DamageEmpty(pBuf->pDamage);
- }
-}
-
-static void
-shadowBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead)
-{
- ScreenPtr pScreen = (ScreenPtr) data;
-
- shadowRedisplay(pScreen);
-}
-
-static void
-shadowWakeupHandler(pointer data, int i, pointer LastSelectMask)
-{
-}
-
-static void
-shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
- unsigned int format, unsigned long planeMask, char *pdstLine)
-{
- ScreenPtr pScreen = pDrawable->pScreen;
- shadowBuf(pScreen);
-
- /* Many apps use GetImage to sync with the visable frame buffer */
- if (pDrawable->type == DRAWABLE_WINDOW)
- shadowRedisplay(pScreen);
- unwrap(pBuf, pScreen, GetImage);
- pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
- wrap(pBuf, pScreen, GetImage);
-}
-
-#define BACKWARDS_COMPATIBILITY
-
-static Bool
-shadowCloseScreen(int i, ScreenPtr pScreen)
-{
- shadowBuf(pScreen);
-
- unwrap(pBuf, pScreen, GetImage);
- unwrap(pBuf, pScreen, CloseScreen);
- shadowRemove(pScreen, pBuf->pPixmap);
- DamageDestroy(pBuf->pDamage);
-#ifdef BACKWARDS_COMPATIBILITY
- RegionUninit(&pBuf->damage); /* bc */
-#endif
- if (pBuf->pPixmap)
- pScreen->DestroyPixmap(pBuf->pPixmap);
- free(pBuf);
- return pScreen->CloseScreen(i, pScreen);
-}
-
-#ifdef BACKWARDS_COMPATIBILITY
-static void
-shadowReportFunc(DamagePtr pDamage, RegionPtr pRegion, void *closure)
-{
- ScreenPtr pScreen = closure;
- shadowBufPtr pBuf = (shadowBufPtr)
- dixLookupPrivate(&pScreen->devPrivates, shadowScrPrivateKey);
-
- /* Register the damaged region, use DamageReportNone below when we
- * want to break BC below... */
- RegionUnion(&pDamage->damage, &pDamage->damage, pRegion);
-
- /*
- * BC hack. In 7.0 and earlier several drivers would inspect the
- * 'damage' member directly, so we have to keep it existing.
- */
- RegionCopy(&pBuf->damage, pRegion);
-}
-#endif
-
-Bool
-shadowSetup(ScreenPtr pScreen)
-{
- shadowBufPtr pBuf;
-
- if (!dixRegisterPrivateKey(&shadowScrPrivateKeyRec, PRIVATE_SCREEN, 0))
- return FALSE;
-
- if (!DamageSetup(pScreen))
- return FALSE;
-
- pBuf = malloc(sizeof(shadowBufRec));
- if (!pBuf)
- return FALSE;
-#ifdef BACKWARDS_COMPATIBILITY
- pBuf->pDamage = DamageCreate((DamageReportFunc)shadowReportFunc,
- (DamageDestroyFunc)NULL,
- DamageReportRawRegion,
- TRUE, pScreen, pScreen);
-#else
- pBuf->pDamage = DamageCreate((DamageReportFunc)NULL,
- (DamageDestroyFunc)NULL,
- DamageReportNone,
- TRUE, pScreen, pScreen);
-#endif
- if (!pBuf->pDamage) {
- free(pBuf);
- return FALSE;
- }
-
- wrap(pBuf, pScreen, CloseScreen);
- wrap(pBuf, pScreen, GetImage);
- pBuf->update = 0;
- pBuf->window = 0;
- pBuf->pPixmap = 0;
- pBuf->closure = 0;
- pBuf->randr = 0;
-#ifdef BACKWARDS_COMPATIBILITY
- RegionNull(&pBuf->damage); /* bc */
-#endif
-
- dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf);
- return TRUE;
-}
-
-Bool
-shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update,
- ShadowWindowProc window, int randr, void *closure)
-{
- shadowBuf(pScreen);
-
- if (!RegisterBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler,
- (pointer)pScreen))
- return FALSE;
-
- /*
- * Map simple rotation values to bitmasks; fortunately,
- * these are all unique
- */
- switch (randr) {
- case 0:
- randr = SHADOW_ROTATE_0;
- break;
- case 90:
- randr = SHADOW_ROTATE_90;
- break;
- case 180:
- randr = SHADOW_ROTATE_180;
- break;
- case 270:
- randr = SHADOW_ROTATE_270;
- break;
- }
- pBuf->update = update;
- pBuf->window = window;
- pBuf->randr = randr;
- pBuf->closure = closure;
- pBuf->pPixmap = pPixmap;
- DamageRegister(&pPixmap->drawable, pBuf->pDamage);
- return TRUE;
-}
-
-void
-shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap)
-{
- shadowBuf(pScreen);
-
- if (pBuf->pPixmap) {
- DamageUnregister(&pBuf->pPixmap->drawable, pBuf->pDamage);
- pBuf->update = 0;
- pBuf->window = 0;
- pBuf->randr = 0;
- pBuf->closure = 0;
- pBuf->pPixmap = 0;
- }
-
- RemoveBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler,
- (pointer) pScreen);
-}
-
-Bool
-shadowInit(ScreenPtr pScreen, ShadowUpdateProc update, ShadowWindowProc window)
-{
- PixmapPtr pPixmap;
-
- pPixmap = pScreen->CreatePixmap(pScreen, pScreen->width, pScreen->height,
- pScreen->rootDepth, 0);
- if (!pPixmap)
- return FALSE;
-
- if (!shadowSetup(pScreen)) {
- pScreen->DestroyPixmap(pPixmap);
- return FALSE;
- }
-
- shadowAdd(pScreen, pPixmap, update, window, SHADOW_ROTATE_0, 0);
-
- return TRUE;
-}
+/* + * Copyright © 2000 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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 <stdlib.h> + +#include <X11/X.h> +#include "scrnintstr.h" +#include "windowstr.h" +#include "dixfontstr.h" +#include "mi.h" +#include "regionstr.h" +#include "globals.h" +#include "gcstruct.h" +#include "shadow.h" + +static DevPrivateKeyRec shadowScrPrivateKeyRec; +#define shadowScrPrivateKey (&shadowScrPrivateKeyRec) + +#define wrap(priv, real, mem) {\ + priv->mem = real->mem; \ + real->mem = shadow##mem; \ +} + +#define unwrap(priv, real, mem) {\ + real->mem = priv->mem; \ +} + +static void +shadowRedisplay(ScreenPtr pScreen) +{ + shadowBuf(pScreen); + RegionPtr pRegion; + + if (!pBuf || !pBuf->pDamage || !pBuf->update) + return; + pRegion = DamageRegion(pBuf->pDamage); + if (RegionNotEmpty(pRegion)) { + (*pBuf->update)(pScreen, pBuf); + DamageEmpty(pBuf->pDamage); + } +} + +static void +shadowBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead) +{ + ScreenPtr pScreen = (ScreenPtr) data; + + shadowRedisplay(pScreen); +} + +static void +shadowWakeupHandler(pointer data, int i, pointer LastSelectMask) +{ +} + +static void +shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + shadowBuf(pScreen); + + /* Many apps use GetImage to sync with the visable frame buffer */ + if (pDrawable->type == DRAWABLE_WINDOW) + shadowRedisplay(pScreen); + unwrap(pBuf, pScreen, GetImage); + pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); + wrap(pBuf, pScreen, GetImage); +} + +#define BACKWARDS_COMPATIBILITY + +static Bool +shadowCloseScreen(int i, ScreenPtr pScreen) +{ + shadowBuf(pScreen); + + unwrap(pBuf, pScreen, GetImage); + unwrap(pBuf, pScreen, CloseScreen); + shadowRemove(pScreen, pBuf->pPixmap); + DamageDestroy(pBuf->pDamage); +#ifdef BACKWARDS_COMPATIBILITY + RegionUninit(&pBuf->damage); /* bc */ +#endif + if (pBuf->pPixmap) + pScreen->DestroyPixmap(pBuf->pPixmap); + free(pBuf); + return pScreen->CloseScreen(i, pScreen); +} + +#ifdef BACKWARDS_COMPATIBILITY +static void +shadowReportFunc(DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + ScreenPtr pScreen = closure; + shadowBufPtr pBuf = (shadowBufPtr) + dixLookupPrivate(&pScreen->devPrivates, shadowScrPrivateKey); + + /* Register the damaged region, use DamageReportNone below when we + * want to break BC below... */ + RegionUnion(&pDamage->damage, &pDamage->damage, pRegion); + + /* + * BC hack. In 7.0 and earlier several drivers would inspect the + * 'damage' member directly, so we have to keep it existing. + */ + RegionCopy(&pBuf->damage, pRegion); +} +#endif + +Bool +shadowSetup(ScreenPtr pScreen) +{ + shadowBufPtr pBuf; + + if (!dixRegisterPrivateKey(&shadowScrPrivateKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + if (!DamageSetup(pScreen)) + return FALSE; + + pBuf = malloc(sizeof(shadowBufRec)); + if (!pBuf) + return FALSE; +#ifdef BACKWARDS_COMPATIBILITY + pBuf->pDamage = DamageCreate((DamageReportFunc)shadowReportFunc, + (DamageDestroyFunc)NULL, + DamageReportRawRegion, + TRUE, pScreen, pScreen); +#else + pBuf->pDamage = DamageCreate((DamageReportFunc)NULL, + (DamageDestroyFunc)NULL, + DamageReportNone, + TRUE, pScreen, pScreen); +#endif + if (!pBuf->pDamage) { + free(pBuf); + return FALSE; + } + + wrap(pBuf, pScreen, CloseScreen); + wrap(pBuf, pScreen, GetImage); + pBuf->update = 0; + pBuf->window = 0; + pBuf->pPixmap = 0; + pBuf->closure = 0; + pBuf->randr = 0; +#ifdef BACKWARDS_COMPATIBILITY + RegionNull(&pBuf->damage); /* bc */ +#endif + + dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf); + return TRUE; +} + +Bool +shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update, + ShadowWindowProc window, int randr, void *closure) +{ + shadowBuf(pScreen); + + if (!RegisterBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, + (pointer)pScreen)) + return FALSE; + + /* + * Map simple rotation values to bitmasks; fortunately, + * these are all unique + */ + switch (randr) { + case 0: + randr = SHADOW_ROTATE_0; + break; + case 90: + randr = SHADOW_ROTATE_90; + break; + case 180: + randr = SHADOW_ROTATE_180; + break; + case 270: + randr = SHADOW_ROTATE_270; + break; + } + pBuf->update = update; + pBuf->window = window; + pBuf->randr = randr; + pBuf->closure = closure; + pBuf->pPixmap = pPixmap; + DamageRegister(&pPixmap->drawable, pBuf->pDamage); + return TRUE; +} + +void +shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap) +{ + shadowBuf(pScreen); + + if (pBuf->pPixmap) { + DamageUnregister(&pBuf->pPixmap->drawable, pBuf->pDamage); + pBuf->update = 0; + pBuf->window = 0; + pBuf->randr = 0; + pBuf->closure = 0; + pBuf->pPixmap = 0; + } + + RemoveBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, + (pointer) pScreen); +} + +Bool +shadowInit(ScreenPtr pScreen, ShadowUpdateProc update, ShadowWindowProc window) +{ + PixmapPtr pPixmap; + + pPixmap = pScreen->CreatePixmap(pScreen, pScreen->width, pScreen->height, + pScreen->rootDepth, 0); + if (!pPixmap) + return FALSE; + + if (!shadowSetup(pScreen)) { + pScreen->DestroyPixmap(pPixmap); + return FALSE; + } + + shadowAdd(pScreen, pPixmap, update, window, SHADOW_ROTATE_0, 0); + + return TRUE; +} diff --git a/xorg-server/test/Makefile.am b/xorg-server/test/Makefile.am index 370e09a18..7ef408c93 100644 --- a/xorg-server/test/Makefile.am +++ b/xorg-server/test/Makefile.am @@ -40,5 +40,6 @@ libxservertest_la_LIBADD = \ $(top_builddir)/mi/libmi.la \ $(top_builddir)/os/libos.la \ @XORG_LIBS@ +libxservertest_la_DEPENDENCIES = $(libxservertest_la_LIBADD) endif endif diff --git a/xorg-server/test/xi2/protocol-eventconvert.c b/xorg-server/test/xi2/protocol-eventconvert.c index edba974bf..6e61d74b4 100644 --- a/xorg-server/test/xi2/protocol-eventconvert.c +++ b/xorg-server/test/xi2/protocol-eventconvert.c @@ -70,6 +70,8 @@ static void test_values_XIRawEvent(RawDeviceEvent *in, xXIRawEvent *out, for (i = 0; out->valuators_len && i < sizeof(in->valuators.mask) * 8; i++) { + if (i >= MAX_VALUATORS) + assert (!XIMaskIsSet(in->valuators.mask, i)); assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); if (XIMaskIsSet(in->valuators.mask, i)) bits_set++; @@ -238,7 +240,7 @@ static void test_convert_XIRawEvent(void) test_XIRawEvent(&in); printf("Testing valuator masks\n"); - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + for (i = 0; i < MAX_VALUATORS; i++) { XISetMask(in.valuators.mask, i); test_XIRawEvent(&in); @@ -257,7 +259,7 @@ static void test_convert_XIRawEvent(void) XIClearMask(in.valuators.mask, i); } - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + for (i = 0; i < MAX_VALUATORS; i++) { XISetMask(in.valuators.mask, i); test_XIRawEvent(&in); @@ -354,7 +356,7 @@ static void test_values_XIDeviceEvent(DeviceEvent *in, xXIDeviceEvent *out, valuators = 0; - for (i = 0; i < sizeof(in->valuators.mask) * 8; i++) + for (i = 0; i < MAX_VALUATORS; i++) if (XIMaskIsSet(in->valuators.mask, i)) valuators++; @@ -365,7 +367,9 @@ static void test_values_XIDeviceEvent(DeviceEvent *in, xXIDeviceEvent *out, for (i = 0; i < sizeof(in->valuators.mask) * 8 || i < (out->valuators_len * 4) * 8; i++) { - if (i > sizeof(in->valuators.mask) * 8) + if (i >= MAX_VALUATORS) + assert(!XIMaskIsSet(in->valuators.mask, i) && !XIMaskIsSet(ptr, i)); + else if (i > sizeof(in->valuators.mask) * 8) assert(!XIMaskIsSet(ptr, i)); else if (i > out->valuators_len * 4 * 8) assert(!XIMaskIsSet(in->valuators.mask, i)); @@ -610,14 +614,14 @@ static void test_convert_XIDeviceEvent(void) } printf("Testing valuator masks\n"); - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + for (i = 0; i < MAX_VALUATORS; i++) { XISetMask(in.valuators.mask, i); test_XIDeviceEvent(&in); XIClearMask(in.valuators.mask, i); } - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + for (i = 0; i < MAX_VALUATORS; i++) { XISetMask(in.valuators.mask, i); @@ -627,7 +631,7 @@ static void test_convert_XIDeviceEvent(void) XIClearMask(in.valuators.mask, i); } - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + for (i = 0; i < MAX_VALUATORS; i++) { XISetMask(in.valuators.mask, i); test_XIDeviceEvent(&in); |